Skip to content

Commit b2da3b1

Browse files
authored
Merge pull request #7 from xdecentralix/sync/upstream-merge-20250808
Sync/upstream merge 20250808
2 parents bedc79e + 4d55e0a commit b2da3b1

File tree

47 files changed

+332
-671
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+332
-671
lines changed

crates/autopilot/src/arguments.rs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -232,17 +232,9 @@ pub struct Arguments {
232232
#[clap(long, env, default_value = "0s", value_parser = humantime::parse_duration)]
233233
pub run_loop_native_price_timeout: Duration,
234234

235-
#[clap(long, env)]
236-
/// When set, enables combinatorial auctions for auctions with a deadline
237-
/// later than this timestamp.
238-
// TODO: Remove after the cutover has fully taken effect.
239-
pub combinatorial_auctions_cutover: Option<chrono::DateTime<chrono::Utc>>,
240-
241-
#[clap(long, env, default_value = "1")]
235+
#[clap(long, env, default_value = "20")]
242236
/// The maximum number of winners per auction. Each winner will be allowed
243237
/// to settle their winning orders at the same time.
244-
/// This setting only applies to auctions occurring after
245-
/// `combinatorial_auctions_cutover`.
246238
pub max_winners_per_auction: NonZeroUsize,
247239

248240
#[clap(long, env, default_value = "3")]
@@ -380,7 +372,6 @@ impl std::fmt::Display for Arguments {
380372
cow_amm_configs,
381373
max_run_loop_delay,
382374
run_loop_native_price_timeout,
383-
combinatorial_auctions_cutover,
384375
max_winners_per_auction,
385376
archive_node_url,
386377
max_solutions_per_solver,
@@ -449,10 +440,6 @@ impl std::fmt::Display for Arguments {
449440
f,
450441
"run_loop_native_price_timeout: {run_loop_native_price_timeout:?}"
451442
)?;
452-
writeln!(
453-
f,
454-
"combinatorial_auctions_cutover: {combinatorial_auctions_cutover:?}"
455-
)?;
456443
writeln!(f, "max_winners_per_auction: {max_winners_per_auction:?}")?;
457444
writeln!(f, "archive_node_url: {archive_node_url:?}")?;
458445
writeln!(f, "max_solutions_per_solver: {max_solutions_per_solver:?}")?;

crates/autopilot/src/database/competition.rs

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ use {
1919
#[derive(Clone, Default, Debug)]
2020
pub struct Competition {
2121
pub auction_id: AuctionId,
22-
// TODO: remove when `settlement_scores` table is no longer used
23-
pub legacy: Option<LegacyScore>,
2422
pub reference_scores: HashMap<eth::Address, Score>,
2523
/// Addresses to which the CIP20 participation rewards will be payed out.
2624
/// Usually the same as the solver addresses.
@@ -60,33 +58,6 @@ impl super::Postgres {
6058
.await
6159
.context("solver_competition::save")?;
6260

63-
// TODO: this is deprecated and needs to be removed once the solver team has
64-
// switched to the reference_scores table.
65-
// If we enable combinatorial auctions before that switch the solver rewards
66-
// payout will be blocked until the switch happens since no data would be
67-
// stored in the old format anymore.
68-
if let Some(legacy) = &competition.legacy {
69-
database::settlement_scores::insert(
70-
&mut ex,
71-
database::settlement_scores::Score {
72-
auction_id: competition.auction_id,
73-
winner: ByteArray(legacy.winner.0),
74-
winning_score: u256_to_big_decimal(&legacy.winning_score),
75-
reference_score: u256_to_big_decimal(&legacy.reference_score),
76-
block_deadline: competition
77-
.block_deadline
78-
.try_into()
79-
.context("convert block deadline")?,
80-
simulation_block: competition
81-
.competition_simulation_block
82-
.try_into()
83-
.context("convert simulation block")?,
84-
},
85-
)
86-
.await
87-
.context("settlement_scores::insert")?;
88-
}
89-
9061
let reference_scores: Vec<_> = competition
9162
.reference_scores
9263
.iter()

crates/autopilot/src/database/mod.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use {
2+
num::ToPrimitive,
23
sqlx::{Executor, PgConnection, PgPool},
34
std::{num::NonZeroUsize, time::Duration},
45
tracing::Instrument,
@@ -27,12 +28,34 @@ pub struct Postgres {
2728

2829
impl Postgres {
2930
pub async fn new(url: &str, insert_batch_size: NonZeroUsize) -> sqlx::Result<Self> {
31+
let pool = PgPool::connect(url).await?;
32+
33+
Self::start_db_metrics_job(pool.clone());
34+
3035
Ok(Self {
31-
pool: PgPool::connect(url).await?,
36+
pool,
3237
config: Config { insert_batch_size },
3338
})
3439
}
3540

41+
fn start_db_metrics_job(pool: PgPool) {
42+
tokio::spawn(async move {
43+
let mut ticker = tokio::time::interval(Duration::from_secs(5));
44+
loop {
45+
ticker.tick().await;
46+
47+
let Some(idle) = pool.num_idle().to_i64() else {
48+
tracing::error!("Failed to get number of idle connections from the pool");
49+
continue;
50+
};
51+
let active = i64::from(pool.size()) - idle;
52+
53+
Metrics::get().active_connections.set(active);
54+
Metrics::get().idle_connections.set(idle);
55+
}
56+
});
57+
}
58+
3659
pub async fn with_defaults() -> sqlx::Result<Self> {
3760
Self::new("postgresql://", NonZeroUsize::new(500).unwrap()).await
3861
}
@@ -118,6 +141,14 @@ struct Metrics {
118141
/// Timing of db queries.
119142
#[metric(name = "autopilot_database_queries", labels("type"))]
120143
database_queries: prometheus::HistogramVec,
144+
145+
/// Number of active connections in the database pool.
146+
#[metric(name = "database_active_connections")]
147+
active_connections: prometheus::IntGauge,
148+
149+
/// Number of idle connections in the database pool.
150+
#[metric(name = "database_idle_connections")]
151+
idle_connections: prometheus::IntGauge,
121152
}
122153

123154
impl Metrics {

crates/autopilot/src/database/onchain_order_events/ethflow_events.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use {
2626
hex_literal::hex,
2727
sqlx::{PgPool, types::BigDecimal},
2828
std::{collections::HashMap, convert::TryInto},
29+
tracing::instrument,
2930
web3::types::U64,
3031
};
3132

@@ -160,6 +161,7 @@ async fn settlement_deployment_block_number_hash(
160161
/// The block from which to start indexing eth-flow events. Note that this
161162
/// function is expected to be used at the start of the services and will panic
162163
/// if it cannot retrieve the information it needs.
164+
#[instrument(skip_all)]
163165
pub async fn determine_ethflow_indexing_start(
164166
skip_event_sync_start: &Option<BlockNumberHash>,
165167
ethflow_indexing_start: Option<u64>,
@@ -201,6 +203,7 @@ pub async fn determine_ethflow_indexing_start(
201203
/// # Panics
202204
/// Note that this function is expected to be used at the start of the services
203205
/// and will panic if it cannot retrieve the information it needs.
206+
#[instrument(skip_all)]
204207
pub async fn determine_ethflow_refund_indexing_start(
205208
skip_event_sync_start: &Option<BlockNumberHash>,
206209
ethflow_indexing_start: Option<u64>,

crates/autopilot/src/domain/competition/winner_selection/combinatorial.rs renamed to crates/autopilot/src/domain/competition/winner_selection.rs

Lines changed: 88 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
//! That is effectively a measurement of how much better each order got executed
2525
//! because solver S participated in the competition.
2626
use {
27-
super::{Arbitrator, PartitionedSolutions, Ranking},
2827
crate::domain::{
2928
self,
3029
OrderUid,
@@ -48,7 +47,43 @@ use {
4847
},
4948
};
5049

51-
impl Arbitrator for Config {
50+
/// Implements auction arbitration in 3 phases:
51+
/// 1. filter unfair solutions
52+
/// 2. mark winners
53+
/// 3. compute reference scores
54+
///
55+
/// The functions assume the `Arbitrator` is the only one
56+
/// changing the ordering or the `participants`.
57+
impl Arbitrator {
58+
/// Runs the entire auction mechanism on the passed in solutions.
59+
pub fn arbitrate(
60+
&self,
61+
participants: Vec<Participant<Unranked>>,
62+
auction: &domain::Auction,
63+
) -> Ranking {
64+
let partitioned = self.partition_unfair_solutions(participants, auction);
65+
let filtered_out = partitioned
66+
.discarded
67+
.into_iter()
68+
.map(|participant| participant.rank(Ranked::FilteredOut))
69+
.collect();
70+
71+
let mut ranked = self.mark_winners(partitioned.kept);
72+
ranked.sort_by_key(|participant| {
73+
(
74+
// winners before non-winners
75+
std::cmp::Reverse(participant.is_winner()),
76+
// high score before low score
77+
std::cmp::Reverse(participant.solution().computed_score().cloned()),
78+
)
79+
});
80+
Ranking {
81+
filtered_out,
82+
ranked,
83+
}
84+
}
85+
86+
/// Removes unfair solutions from the set of all solutions.
5287
fn partition_unfair_solutions(
5388
&self,
5489
mut participants: Vec<Participant<Unranked>>,
@@ -99,6 +134,8 @@ impl Arbitrator for Config {
99134
}
100135
}
101136

137+
/// Picks winners and sorts all solutions where winners come before
138+
/// non-winners and higher scores come before lower scores.
102139
fn mark_winners(&self, participants: Vec<Participant<Unranked>>) -> Vec<Participant> {
103140
let winner_indexes = self.pick_winners(participants.iter().map(|p| p.solution()));
104141
participants
@@ -114,7 +151,9 @@ impl Arbitrator for Config {
114151
.collect()
115152
}
116153

117-
fn compute_reference_scores(&self, ranking: &Ranking) -> HashMap<eth::Address, Score> {
154+
/// Computes the reference scores which are used to compute
155+
/// rewards for the winning solvers.
156+
pub fn compute_reference_scores(&self, ranking: &Ranking) -> HashMap<eth::Address, Score> {
118157
let mut reference_scores = HashMap::default();
119158

120159
for participant in &ranking.ranked {
@@ -150,9 +189,7 @@ impl Arbitrator for Config {
150189

151190
reference_scores
152191
}
153-
}
154192

155-
impl Config {
156193
/// Returns indices of winning solutions.
157194
/// Assumes that `solutions` is sorted by score descendingly.
158195
/// This logic was moved into a helper function to avoid a ton of `.clone()`
@@ -312,7 +349,7 @@ fn score_by_token_pair(solution: &Solution, auction: &Auction) -> Result<ScoreBy
312349
Ok(scores)
313350
}
314351

315-
pub struct Config {
352+
pub struct Arbitrator {
316353
pub max_winners: usize,
317354
pub weth: WrappedNativeToken,
318355
}
@@ -378,6 +415,48 @@ type ScoreByDirection = HashMap<DirectedTokenPair, Score>;
378415
/// of the auction.
379416
type ScoresBySolution = HashMap<SolutionKey, ScoreByDirection>;
380417

418+
pub struct Ranking {
419+
/// Solutions that were discarded because they were malformed
420+
/// in some way or deemed unfair by the selection mechanism.
421+
filtered_out: Vec<Participant<Ranked>>,
422+
/// Final ranking of the solutions that passed the fairness
423+
/// check. Winners come before non-winners and higher total
424+
/// scores come before lower scores.
425+
ranked: Vec<Participant<Ranked>>,
426+
}
427+
428+
impl Ranking {
429+
/// All solutions including the ones that got filtered out.
430+
pub fn all(&self) -> impl Iterator<Item = &Participant<Ranked>> {
431+
self.ranked.iter().chain(&self.filtered_out)
432+
}
433+
434+
/// Enumerates all solutions. The index is used as solution UID.
435+
pub fn enumerated(&self) -> impl Iterator<Item = (usize, &Participant<Ranked>)> {
436+
self.all().enumerate()
437+
}
438+
439+
/// All solutions that won the right to get executed.
440+
pub fn winners(&self) -> impl Iterator<Item = &Participant<Ranked>> {
441+
self.ranked.iter().filter(|p| p.is_winner())
442+
}
443+
444+
/// All solutions that were not filtered out but also did not win.
445+
pub fn non_winners(&self) -> impl Iterator<Item = &Participant<Ranked>> {
446+
self.ranked.iter().filter(|p| !p.is_winner())
447+
}
448+
449+
/// All solutions that passed the filtering step.
450+
pub fn ranked(&self) -> impl Iterator<Item = &Participant<Ranked>> {
451+
self.ranked.iter()
452+
}
453+
}
454+
455+
struct PartitionedSolutions {
456+
kept: Vec<Participant<Unranked>>,
457+
discarded: Vec<Participant<Unranked>>,
458+
}
459+
381460
#[cfg(test)]
382461
mod tests {
383462
use {
@@ -390,14 +469,7 @@ mod tests {
390469
Price,
391470
order::{self, AppDataHash},
392471
},
393-
competition::{
394-
Participant,
395-
Score,
396-
Solution,
397-
TradedOrder,
398-
Unranked,
399-
winner_selection::Arbitrator,
400-
},
472+
competition::{Participant, Score, Solution, TradedOrder, Unranked},
401473
eth::{self, TokenAddress},
402474
},
403475
infra::Driver,
@@ -1196,8 +1268,8 @@ mod tests {
11961268
pub buy_amount: eth::U256,
11971269
}
11981270

1199-
fn create_test_arbitrator() -> super::Config {
1200-
super::Config {
1271+
fn create_test_arbitrator() -> super::Arbitrator {
1272+
super::Arbitrator {
12011273
max_winners: 10,
12021274
weth: H160::from_slice(&hex!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")).into(),
12031275
}

0 commit comments

Comments
 (0)