Conversation
Greptile SummaryThis PR introduces a fire-and-forget mint sender with a dedicated batch-confirmation poll task (
Confidence Score: 4/5Safe to merge after fixing the poll-task cancellation ordering in the shutdown path and the BENCH_RPC_URL env-var collision. Two P1 findings: the poll task is not cancelled before drain_in_flight runs (incorrect comment + real race), and the BENCH_RPC_URL env var is reused with conflicting defaults. Both are actionable fixes. The core fire-and-forget architecture is sound, idempotency is preserved, and the DB recovery path handles the shutdown edge case. Tests are comprehensive. indexer/src/operator/sender/mod.rs (shutdown ordering), bench-tps/src/args.rs (env var naming)
|
| Filename | Overview |
|---|---|
| indexer/src/operator/sender/mod.rs | New drain_in_flight graceful-shutdown helper and sender main loop restructured; contains an incorrect comment and a real race between drain_in_flight and the still-running poll task. |
| indexer/src/operator/sender/transaction.rs | Core fire-and-forget logic: fire_and_store, run_poll_task, poll_in_flight, and route_poll_results — logic is sound; multi-chunk RPC failure discards already-fetched statuses (acceptable, undocumented). |
| indexer/src/operator/sender/types.rs | New InFlightQueue (Arc-wrapped Mutex+Vec+Notify) and InFlightTx/PollTaskResult types — design is clean and thread-safe. |
| bench-tps/src/args.rs | New contra_rpc_url field added to DepositArgs but reuses BENCH_RPC_URL env var with a conflicting default value vs existing fields. |
| bench-tps/src/setup_deposit.rs | Adds Contra mint pre-initialisation step (task 6b) using new contra_rpc_url parameter — logic is straightforward. |
| indexer/src/operator/utils/rpc_util.rs | New tests for with_retry covering permanent errors (-32601, AccountNotFound) and backoff clamping — good coverage, no issues. |
| indexer/src/operator/utils/transaction_util.rs | New mockito-based tests for check_transaction_status and sign_and_send_transaction — comprehensive, no issues. |
| indexer/src/operator/sender/state.rs | Adds in_flight: InFlightQueue::new() to SenderState construction and test helpers; minor trailing blank line added before closing brace. |
Sequence Diagram
sequenceDiagram
participant P as Processor
participant S as Sender Loop
participant IFQ as InFlightQueue
participant PT as Poll Task
participant RPC as Solana RPC
participant DB as Storage
P->>S: TransactionBuilder (Mint/InitializeMint)
S->>S: find_existing_mint_signature (idempotency)
S->>S: handle_transaction_builder → InstructionWithSigners
S->>RPC: sendTransaction (fire_and_store)
RPC-->>S: Signature
S->>IFQ: push(InFlightTx) + notify_one()
loop Poll Task (dedicated task)
IFQ-->>PT: notify.notified()
PT->>PT: sleep(poll_interval_ms)
PT->>IFQ: drain_all()
PT->>RPC: getSignatureStatuses (batched, 256/call)
RPC-->>PT: statuses[]
alt Confirmed Success
PT->>DB: TransactionStatusUpdate(Completed)
PT->>S: PollTaskResult::ConfirmedSuccess(txn_id)
S->>S: mint_builders.remove(txn_id)
else On-chain Error / Timeout
PT->>S: PollTaskResult::NeedsRouting(tx, status)
S->>S: route_poll_results → handle_confirmation_result
else Still Pending
PT->>IFQ: push(tx) [poll_attempts++]
end
end
note over S,PT: Graceful Shutdown
S->>S: drain processor channel
S->>S: drain_in_flight (poll_in_flight loop, 30s timeout)
S->>PT: poll_shutdown.cancel()
S->>PT: await poll_task_handle
Reviews (1): Last reviewed commit: "feat(operator): fire-and-forget mint sen..." | Re-trigger Greptile
cargo-build-sbf bundles its own LLVM/Clang, and the litesvm-based integration tests vendor OpenSSL — no system packages are needed. The apt install was downloading ~60 MB (libclang-18-dev alone is 28.8 MB) at ~30 KB/s on the CI runner, consistently hitting the 20-minute job timeout before setup finished.
Remove the .port_range((2000, 2200)) constraint added to TestValidatorGenesis and the unique_port_range_for_tests/find_available_port_in_range plumbing. Forcing all validator sockets (gossip, TPU, TVU) into a fixed 2000-2200 range conflicted with occupied UDP ports on the CI runner, causing "Address already in use" failures. The OS kernel assigns port=0 sockets atomically — concurrent nextest validators never collide, so the port range isolation was solving a non-problem while introducing a real one.
Summary
Decouples
sendTransactionlatency from the sender loop for Mint/InitializeMint transactions. Instead of blocking until each tx confirms, the sender signs and sends immediately, stores the signature, and moves on. A dedicated poll task batches all in-flight signatures into a singlegetSignatureStatusescall per interval.Notify, accumulates one poll interval, resolves all N signatures in one RPC call. Confirmed-success is handled entirely in the poll task; only errors and timeouts wake the sender loop.MAX_IN_FLIGHT = 1000permits.select!recv arm guarded byavailable_permits() > 0; when exhausted, the processor channel backs up and the fetcher stops.AccountNotFoundnow permanent: previously retried 5× with backoff (~1.5 s wasted per JIT mint lookup).setup_depositnow initialises the Contra-side SPL mint upfront so the operator doesn't hit JIT init on the first deposit.Files changed
sender/types.rsInFlightTx,InFlightQueue(Arc<Mutex<Vec>>+Notify),PollTaskResultsender/transaction.rsspawn_fire_and_store,fire_and_store,run_poll_task,poll_in_flight; branches inhandle_transaction_submissionsender/mod.rsdrain_in_flightsender/state.rssemaphore: Arc<Semaphore>added toSenderStaterpc_util.rsAccountNotFound→ permanent errorbench-tps/BENCH_CONTRA_RPC_URLenv varTests
spawn_fire_and_store: cap exhausted returns false, permit consumed on successrun_poll_task: cancellation (idle + mid-sleep), closed result channel exitdrain_in_flight: empty queue no-op, 30 s timeoutInFlightQueue: push/drain roundtrip, capacity preserved acrossdrain_allis_permanent_rpc_error:Method not FoundandAccountNotFoundexit immediatelyImpact
Deposit TPS: ~9 -> ~500

Coverage Report