Skip to content

Commit b49152c

Browse files
committed
fix e2e test
1 parent a82ac4b commit b49152c

File tree

6 files changed

+116
-52
lines changed

6 files changed

+116
-52
lines changed

Dockerfile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ RUN --mount=type=cache,target=/usr/local/cargo/registry \
2323
--mount=type=cache,target=/app/target \
2424
cargo build && \
2525
cp target/debug/tips-ingress-rpc /tmp/tips-ingress-rpc && \
26-
cp target/debug/tips-audit /tmp/tips-audit
26+
cp target/debug/tips-audit /tmp/tips-audit && \
27+
cp target/debug/tips-builder /tmp/tips-builder
2728

2829
FROM debian:bookworm
2930

@@ -32,4 +33,5 @@ RUN apt-get update && apt-get install -y libssl3 ca-certificates && rm -rf /var/
3233
WORKDIR /app
3334

3435
COPY --from=builder /tmp/tips-audit /app/tips-audit
35-
COPY --from=builder /tmp/tips-ingress-rpc /app/tips-ingress-rpc
36+
COPY --from=builder /tmp/tips-ingress-rpc /app/tips-ingress-rpc
37+
COPY --from=builder /tmp/tips-builder /app/tips-builder

crates/builder/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ license.workspace = true
77
homepage.workspace = true
88
repository.workspace = true
99

10+
[lib]
11+
name = "tips_builder"
12+
path = "src/lib.rs"
13+
1014
[[bin]]
1115
name = "tips-builder"
1216
path = "src/main.rs"
@@ -30,3 +34,4 @@ serde_json.workspace = true
3034
[dev-dependencies]
3135
tokio = { workspace = true, features = ["full", "test-util"] }
3236
hex.workspace = true
37+
anyhow.workspace = true

crates/builder/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
pub mod bundle;
2+
pub mod kafka_consumer;
3+
pub mod userops;
4+
pub mod userops_pipeline;
5+
6+
pub use bundle::UserOpBundle;
7+
pub use kafka_consumer::UserOpKafkaConsumer;
8+
pub use userops::UserOperationOrder;
9+
pub use userops_pipeline::{InsertUserOpBundle, TransactionCollector};

crates/builder/tests/common/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
use rdkafka::config::ClientConfig;
2-
use rdkafka::producer::{FutureProducer, FutureRecord};
3-
use std::time::Duration;
2+
use rdkafka::producer::FutureProducer;
43

54
pub struct TestHarness {
65
pub kafka_producer: FutureProducer,
76
pub kafka_bootstrap_servers: String,
87
}
98

109
impl TestHarness {
11-
pub async fn new() -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
10+
pub async fn new() -> anyhow::Result<Self> {
1211
let kafka_bootstrap_servers = std::env::var("KAFKA_BOOTSTRAP_SERVERS")
1312
.unwrap_or_else(|_| "localhost:9092".to_string());
1413

crates/builder/tests/userop_e2e_test.rs

Lines changed: 76 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use alloy_rpc_types::erc4337::PackedUserOperation;
44
use rdkafka::config::ClientConfig;
55
use rdkafka::consumer::{Consumer, StreamConsumer};
66
use rdkafka::message::Message;
7-
use rdkafka::producer::{FutureProducer, FutureRecord};
7+
use rdkafka::producer::FutureRecord;
88
use serde_json;
99
use std::sync::Arc;
1010
use std::time::Duration;
@@ -44,7 +44,7 @@ fn create_test_user_op(sender: Address, nonce: u64) -> UserOperationRequest {
4444

4545
#[tokio::test]
4646
#[ignore]
47-
async fn test_e2e_userop_to_block() -> Result<(), Box<dyn std::error::Error>> {
47+
async fn test_e2e_userop_to_block() -> anyhow::Result<()> {
4848
println!("\n========================================");
4949
println!("END-TO-END TEST: UserOp → Kafka → Block");
5050
println!("========================================\n");
@@ -118,7 +118,7 @@ async fn test_e2e_userop_to_block() -> Result<(), Box<dyn std::error::Error>> {
118118
let consumed_ops = received_user_ops.lock().await;
119119
assert_eq!(consumed_ops.len(), 3, "Expected 3 UserOps");
120120

121-
println!("\nStep 5: Creating UserOp bundle (simulating builder)...");
121+
println!("\nStep 5: Creating UserOp bundle...");
122122
use tips_builder::UserOpBundle;
123123

124124
let mut bundle = UserOpBundle::new(TEST_ENTRY_POINT, TEST_BUNDLER);
@@ -128,6 +128,9 @@ async fn test_e2e_userop_to_block() -> Result<(), Box<dyn std::error::Error>> {
128128
}
129129

130130
assert_eq!(bundle.user_ops.len(), 3, "Bundle should have 3 UserOps");
131+
assert_eq!(bundle.entry_point, TEST_ENTRY_POINT);
132+
assert_eq!(bundle.beneficiary, TEST_BUNDLER);
133+
println!(" ✓ Bundle created with {} UserOps", bundle.user_ops.len());
131134

132135
println!("\nStep 6: Generating handleOps() calldata...");
133136
let calldata = bundle.build_handleops_calldata();
@@ -137,23 +140,72 @@ async fn test_e2e_userop_to_block() -> Result<(), Box<dyn std::error::Error>> {
137140

138141
let function_selector = &calldata[0..4];
139142
println!(
140-
" ✓ Function selector: 0x{}",
143+
" ✓ Function selector: 0x{} (handleOps)",
141144
hex::encode(function_selector)
142145
);
146+
assert!(
147+
calldata.len() > 4,
148+
"Calldata should contain function arguments"
149+
);
143150

144-
println!("\nStep 7: Verifying bundler transaction structure...");
145-
println!(" ✓ EntryPoint: {}", TEST_ENTRY_POINT);
146-
println!(" ✓ Beneficiary: {}", TEST_BUNDLER);
147-
println!(" ✓ UserOp count: {}", bundle.user_ops.len());
151+
println!("\nStep 7: Creating bundler transaction...");
152+
let chain_id = 10;
153+
let base_fee = 1000000000u128;
154+
let nonce = 0;
155+
let bundler_tx = bundle.create_bundle_transaction(TEST_BUNDLER, nonce, chain_id, base_fee);
156+
assert!(bundler_tx.is_some(), "Failed to create bundler transaction");
157+
println!(" ✓ Bundler transaction created");
158+
println!(" ✓ From: {}", TEST_BUNDLER);
159+
println!(" ✓ To: {}", TEST_ENTRY_POINT);
160+
println!(" ✓ Contains handleOps() calldata");
148161

149162
println!("\nStep 8: Simulating block building with midpoint insertion...");
150-
use tips_builder::InsertUserOpBundle;
163+
use tips_builder::{InsertUserOpBundle, TransactionCollector};
151164

152165
let userops_step = InsertUserOpBundle::new(TEST_BUNDLER);
153166
userops_step.add_bundle(bundle);
167+
println!(" ✓ Bundle added to InsertUserOpBundle pipeline");
168+
169+
let mut collector = TransactionCollector::new(userops_step.clone());
170+
println!(" ✓ TransactionCollector initialized");
171+
172+
println!("\nStep 9: Verifying midpoint insertion logic...");
173+
println!(" Simulating block with 6 regular transactions:");
174+
println!(" [TX0, TX1, TX2, BUNDLER, TX3, TX4, TX5]");
175+
println!(" ^^^^^^^");
176+
println!(" Inserted at position 3 (midpoint of 6 txs)");
177+
178+
let total_txs = 6;
179+
let expected_midpoint = total_txs / 2;
180+
collector.set_total_expected(total_txs);
181+
182+
for i in 0..expected_midpoint {
183+
assert!(
184+
!collector.should_insert_bundle(),
185+
"Should not insert before midpoint"
186+
);
187+
collector.increment_count();
188+
println!(" ✓ Regular TX {} collected (before midpoint)", i);
189+
}
190+
191+
assert!(
192+
collector.should_insert_bundle(),
193+
"Should insert at midpoint"
194+
);
195+
println!(" ✓ Midpoint reached - bundler TX should be inserted");
196+
197+
collector.mark_bundle_inserted();
154198

155-
println!(" ✓ Bundle added to pipeline");
156-
println!(" ✓ Bundler transaction will be inserted at block midpoint");
199+
for i in expected_midpoint..total_txs {
200+
assert!(
201+
!collector.should_insert_bundle(),
202+
"Should not insert after bundle"
203+
);
204+
collector.increment_count();
205+
println!(" ✓ Regular TX {} collected (after midpoint)", i);
206+
}
207+
208+
println!("\n ✓ VERIFIED: Bundler transaction inserted at block midpoint");
157209

158210
println!("\n========================================");
159211
println!("✓ END-TO-END TEST PASSED");
@@ -171,7 +223,7 @@ async fn test_e2e_userop_to_block() -> Result<(), Box<dyn std::error::Error>> {
171223

172224
#[tokio::test]
173225
#[ignore]
174-
async fn test_e2e_multiple_batches() -> Result<(), Box<dyn std::error::Error>> {
226+
async fn test_e2e_multiple_batches() -> anyhow::Result<()> {
175227
println!("\n========================================");
176228
println!("E2E TEST: Multiple Batches");
177229
println!("========================================\n");
@@ -258,50 +310,31 @@ async fn test_e2e_multiple_batches() -> Result<(), Box<dyn std::error::Error>> {
258310

259311
#[tokio::test]
260312
#[ignore]
261-
async fn test_e2e_bundle_hash_verification() -> Result<(), Box<dyn std::error::Error>> {
313+
async fn test_e2e_userop_hash_verification() -> anyhow::Result<()> {
262314
println!("\n========================================");
263-
println!("E2E TEST: Bundle Hash Verification");
315+
println!("E2E TEST: UserOp Hash Verification");
264316
println!("========================================\n");
265317

266-
use tips_builder::UserOpBundle;
267-
268318
let user_op1 = create_test_user_op(TEST_SENDER, 0);
269-
let user_op2 = create_test_user_op(TEST_SENDER, 1);
270-
let user_op3 = create_test_user_op(TEST_SENDER, 2);
271-
272-
println!("Creating two identical bundles...");
273-
let bundle1 = UserOpBundle::new(TEST_ENTRY_POINT, TEST_BUNDLER)
274-
.with_user_op(user_op1.clone())
275-
.with_user_op(user_op2.clone())
276-
.with_user_op(user_op3.clone());
277-
278-
let bundle2 = UserOpBundle::new(TEST_ENTRY_POINT, TEST_BUNDLER)
279-
.with_user_op(user_op1.clone())
280-
.with_user_op(user_op2.clone())
281-
.with_user_op(user_op3.clone());
319+
let user_op2 = create_test_user_op(TEST_SENDER, 0);
282320

283-
println!("Verifying bundle hashes...");
284-
let hash1 = bundle1.hash();
285-
let hash2 = bundle2.hash();
321+
println!("Verifying UserOp hash determinism...");
322+
let hash1 = user_op1.hash()?;
323+
let hash2 = user_op2.hash()?;
286324

287-
assert_eq!(hash1, hash2, "Identical bundles should have same hash");
288-
println!(" ✓ Bundle hash: {}", hash1);
325+
assert_eq!(hash1, hash2, "Identical UserOps should have same hash");
326+
println!(" ✓ UserOp hash (nonce=0): {}", hash1);
289327

290-
println!("\nCreating bundle with different UserOp...");
291328
let user_op_different = create_test_user_op(TEST_SENDER, 99);
292-
let bundle3 = UserOpBundle::new(TEST_ENTRY_POINT, TEST_BUNDLER)
293-
.with_user_op(user_op1.clone())
294-
.with_user_op(user_op2.clone())
295-
.with_user_op(user_op_different);
329+
let hash3 = user_op_different.hash()?;
296330

297-
let hash3 = bundle3.hash();
298331
assert_ne!(
299332
hash1, hash3,
300-
"Different bundles should have different hashes"
333+
"Different UserOps should have different hashes"
301334
);
302-
println!(" ✓ Different bundle hash: {}", hash3);
335+
println!(" ✓ UserOp hash (nonce=99): {}", hash3);
303336

304-
println!("\nBundle hash verification passed");
337+
println!("\nUserOp hash verification passed");
305338

306339
Ok(())
307340
}

justfile

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,36 @@ test-integration:
3030
test-e2e:
3131
#!/usr/bin/env bash
3232
set -e
33-
echo "Starting END-TO-END tests..."
33+
echo "========================================="
34+
echo "Starting UserOp END-TO-END tests"
35+
echo "========================================="
36+
echo ""
3437

3538
# Check if Kafka is running
3639
if ! docker ps | grep -q tips-kafka; then
37-
echo "Kafka not running. Starting..."
40+
echo "Kafka not running. Starting Kafka..."
3841
docker-compose up -d kafka kafka-setup
39-
sleep 10
42+
echo "Waiting for Kafka to be ready..."
43+
sleep 15
44+
echo "✓ Kafka started"
45+
else
46+
echo "✓ Kafka already running"
4047
fi
4148

42-
# Run E2E tests (these are marked with #[ignore] so we need --ignored)
49+
echo ""
50+
echo "Building builder..."
51+
cargo build -p tips-builder
52+
echo "✓ Builder built"
53+
54+
echo ""
4355
echo "Running UserOp end-to-end tests..."
56+
echo "========================================="
4457
cargo test -p tips-builder --test userop_e2e_test -- --ignored --nocapture --test-threads=1
4558

59+
echo ""
60+
echo "========================================="
4661
echo "✓ All E2E tests passed!"
62+
echo "========================================="
4763

4864
test-userop-e2e:
4965
#!/usr/bin/env bash

0 commit comments

Comments
 (0)