Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 33 additions & 17 deletions crates/driver/src/domain/competition/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -771,8 +771,10 @@ impl Competition {
}

pub fn ensure_settle_queue_capacity(&self) -> Result<(), Error> {
Comment thread
jmg-duarte marked this conversation as resolved.
if !self.submitter_pool.has_capacity() {
tracing::warn!("no idle submission slots; auction is rejected");
if !self.submitter_pool.has_capacity() && self.settle_queue.capacity() == 0 {
tracing::warn!(
Comment on lines +774 to +775
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 check self.settle_queue.capacity() == 0 is unreliable for determining if the settlement backlog is full. The process_settle_requests loop dequeues requests and spawns tasks immediately, which means the settle_queue channel is almost always empty, even when many settlements are pending (waiting for a submission slot). While DoS concerns are not applicable for these trusted requests per repository rules, this logic error allows the driver to accept more auctions than it can handle concurrently, potentially leading to penalties for the solver due to settlements not being mined in time. To fix this, the process_settle_requests loop should be modified to limit the number of concurrent spawned tasks to total_slots. This would cause the settle_queue channel to actually buffer the backlog and make the capacity check meaningful.

"backlog of still to be submitted solutions too big; auction is rejected"
);
Err(Error::TooManyPendingSettlements)
} else {
Ok(())
Expand All @@ -788,13 +790,32 @@ impl Competition {
// up, the pool's acquire() blocks until the slot is free, serializing
// settlements.
let this = Arc::clone(&self);

// Acquire a submission slot before spawning a submission task.
// This blocks until a slot can be acquired which applies backpressure
// and allows the settle queue to grow correctly in case the driver
// can't submit solutions as fast as the solver is winning.
let permit = match self.submitter_pool.acquire().await {
Some(guard) => guard,
None => {
if let Err(err) = request.response_sender.send(Err(Error::SubmissionError)) {
tracing::warn!(?err, "failed to report submission error");
}
return;
}
};
Comment on lines +798 to +806
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.

Suggested change
let permit = match self.submitter_pool.acquire().await {
Some(guard) => guard,
None => {
if let Err(err) = request.response_sender.send(Err(Error::SubmissionError)) {
tracing::warn!(?err, "failed to report submission error");
}
return;
}
};
let Some(permit) = match self.submitter_pool.acquire().await else {
if let Err(err) = request.response_sender.send(Err(Error::SubmissionError)) {
tracing::warn!(?err, "failed to report submission error");
}
return;
};


tokio::spawn(async move {
this.handle_settle_request(request).await;
this.handle_settle_request(request, permit).await;
});
}
}

async fn handle_settle_request(self: &Arc<Self>, request: SettleRequest) {
async fn handle_settle_request(
self: &Arc<Self>,
request: SettleRequest,
permit: SubmitterGuard,
) {
let SettleRequest {
auction_id,
solution_id,
Expand All @@ -814,8 +835,12 @@ impl Competition {
}

observe::settling();
let settle_fut =
Box::pin(self.process_settle_request(auction_id, solution_id, submission_deadline));
let settle_fut = Box::pin(self.process_settle_request(
auction_id,
solution_id,
submission_deadline,
permit,
));
let closed_fut = Box::pin(response_sender.closed());
let result = match futures::future::select(closed_fut, settle_fut).await {
// Cancel the settlement task if the sender is closed (client likely
Expand Down Expand Up @@ -846,6 +871,7 @@ impl Competition {
auction_id: auction::Id,
solution_id: u64,
submission_deadline: BlockNo,
permit: SubmitterGuard,
) -> Result<Settled, Error> {
let settlement = {
let mut lock = self.settlements.lock().unwrap();
Expand Down Expand Up @@ -875,19 +901,9 @@ impl Competition {
});
}

// Acquire a submission slot. The pool prefers the direct solver EOA
// (no forwarding overhead); falls back to a delegated EIP-7702
// submission account when the solver EOA is busy.
let guard = self
.submitter_pool
.acquire()
.await
.ok_or(Error::SubmissionError)?;
let mode = guard.submission_mode();

let executed = self
.mempools
.execute(&settlement, submission_deadline, &mode)
.execute(&settlement, submission_deadline, &permit.submission_mode())
.await;

notify::executed(
Expand Down
Loading