Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New database tables for auction and solver competition #2980

Merged
merged 46 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
10a1bc1
Redesign settlement_scores table
sunce86 Sep 12, 2024
97aa50e
new table for storing proposed solutions
sunce86 Sep 16, 2024
8c82c6a
split into two tables
sunce86 Sep 17, 2024
9608b4b
cr fixes
sunce86 Sep 18, 2024
70152f4
don't force solution_id to be unique globally
sunce86 Sep 18, 2024
b387a16
fix index
sunce86 Sep 18, 2024
9a39a0f
remove obsolete index
sunce86 Sep 18, 2024
10197dc
removed deadline from solutions
sunce86 Sep 18, 2024
b7d8b81
move orders to separate table
sunce86 Sep 26, 2024
eb29854
rename latest_auction
sunce86 Sep 26, 2024
85c2c25
fix proposed jit orders
sunce86 Sep 26, 2024
ff2a816
Merge branch 'main' into auction-winners-table
sunce86 Sep 30, 2024
c3dcc38
rename latest_auction
sunce86 Sep 30, 2024
25034d7
consolidate auctions table
sunce86 Sep 30, 2024
2375340
Merge branch 'main' into auction-winners-table
sunce86 Oct 1, 2024
9895072
merge
sunce86 Oct 1, 2024
8f6042d
one time migration of auction
sunce86 Oct 2, 2024
83bcee1
Merge branch 'main' into auction-winners-table
sunce86 Oct 7, 2024
54ee105
revert merge conflit
sunce86 Oct 7, 2024
3b37da4
save/fetch solutions
sunce86 Oct 8, 2024
c1948b4
read/save proposed solutions
sunce86 Oct 8, 2024
c573566
Merge branch 'main' into auction-winners-table
sunce86 Oct 8, 2024
ee81863
save score afterall
sunce86 Oct 8, 2024
511dd47
fix db bugs
sunce86 Oct 8, 2024
2f165b6
fix db test
sunce86 Oct 8, 2024
92cc314
follow up
sunce86 Oct 8, 2024
5e9b5f3
remove renaming
sunce86 Oct 8, 2024
84aace6
fix post_processing
sunce86 Oct 8, 2024
26fd3d8
added comment for external prices
sunce86 Oct 8, 2024
44d384f
resolve uniqueness of solution id
sunce86 Oct 8, 2024
1b7b37d
winner merged with Participant
sunce86 Oct 8, 2024
442d568
Fix failing test
sunce86 Oct 8, 2024
f3e304f
remove migration code
sunce86 Oct 9, 2024
def2583
resolve future conflicts
sunce86 Oct 9, 2024
e5729ff
add docs
sunce86 Oct 9, 2024
0e9f679
improve saving of solutions
sunce86 Oct 9, 2024
86e8c5d
fix test
sunce86 Oct 9, 2024
b2dbe4d
Merge branch 'main' into auction-winners-table
sunce86 Oct 10, 2024
4b90f8e
merge
sunce86 Oct 10, 2024
7e6c362
small move
sunce86 Oct 10, 2024
fb31a15
local struct for fetching
sunce86 Oct 10, 2024
a4f4d9c
cr fixes
sunce86 Oct 11, 2024
0cc9f39
cr fixes from ilya
sunce86 Oct 14, 2024
8fb30ec
Split into functions
sunce86 Oct 14, 2024
166da4d
Merge branch 'main' into auction-winners-table
sunce86 Oct 14, 2024
3870108
Merge branch 'main' into auction-winners-table
sunce86 Oct 17, 2024
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
10 changes: 7 additions & 3 deletions crates/autopilot/src/database/competition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,13 @@ impl super::Postgres {

let mut ex = self.pool.begin().await.context("begin")?;

database::solver_competition::save(&mut ex, competition.auction_id, json)
.await
.context("solver_competition::save")?;
database::solver_competition::save_solver_competition(
&mut ex,
competition.auction_id,
json,
)
.await
.context("solver_competition::save_solver_competition")?;

database::settlement_scores::insert(
&mut ex,
Expand Down
9 changes: 9 additions & 0 deletions crates/autopilot/src/infra/persistence/dto/order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,3 +359,12 @@ impl From<FeePolicy> for domain::fee::Policy {
}
}
}

impl From<domain::auction::order::Side> for database::orders::OrderKind {
fn from(side: domain::auction::order::Side) -> Self {
match side {
domain::auction::order::Side::Buy => Self::Buy,
domain::auction::order::Side::Sell => Self::Sell,
}
}
}
120 changes: 112 additions & 8 deletions crates/autopilot/src/infra/persistence/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use {
SigningScheme as DbSigningScheme,
},
settlement_observations::Observation,
solver_competition::{Order, Solution},
},
domain::auction::order::{
BuyTokenDestination as DomainBuyTokenDestination,
Expand Down Expand Up @@ -127,6 +128,70 @@ impl Persistence {
.map_err(DatabaseError)
}

/// Save all valid solutions that participated in the competition for an
/// auction.
pub async fn save_solutions(
&self,
auction_id: domain::auction::Id,
solutions: &[domain::competition::Participant],
) -> Result<(), DatabaseError> {
let _timer = Metrics::get()
.database_queries
.with_label_values(&["save_solutions"])
.start_timer();

let mut ex = self.postgres.pool.begin().await?;

database::solver_competition::save(
&mut ex,
auction_id,
&solutions
.iter()
.enumerate()
.map(|(uid, participant)| {
let solution = Solution {
uid: uid.try_into().context("uid overflow")?,
Comment on lines +150 to +153
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The db docs made it seem like this uid is supposed to be globally unique, which I think is a nicer property than just having it be the index within one auction.

Copy link
Contributor Author

@sunce86 sunce86 Oct 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unique id of the proposed solution within a single auction this is in the docs

Global uniqueness is not required.

id: i64::try_from(participant.solution().id()).context("block overflow")?,
solver: ByteArray(participant.solution().solver().0 .0),
is_winner: participant.is_winner(),
score: u256_to_big_decimal(&participant.solution().score().get().0),
orders: participant
.solution()
.orders()
.iter()
.map(|(order_uid, order)| Order {
uid: ByteArray(order_uid.0),
sell_token: ByteArray(order.sell.token.0 .0),
buy_token: ByteArray(order.buy.token.0 .0),
limit_sell: u256_to_big_decimal(&order.sell.amount.0),
limit_buy: u256_to_big_decimal(&order.buy.amount.0),
executed_sell: u256_to_big_decimal(&order.executed_sell.0),
executed_buy: u256_to_big_decimal(&order.executed_buy.0),
side: order.side.into(),
})
.collect(),
price_tokens: participant
.solution()
.prices()
.keys()
.map(|token| ByteArray(token.0 .0))
.collect(),
price_values: participant
.solution()
.prices()
.values()
.map(|price| u256_to_big_decimal(&price.get().0))
.collect(),
};
Ok::<_, DatabaseError>(solution)
})
.collect::<Result<Vec<_>, DatabaseError>>()?,
)
.await?;

Ok(ex.commit().await?)
m-lord-renkse marked this conversation as resolved.
Show resolved Hide resolved
}

/// Saves the surplus capturing jit order owners to the DB
pub async fn save_surplus_capturing_jit_order_owners(
&self,
Expand Down Expand Up @@ -227,6 +292,52 @@ impl Persistence {
Ok(database::settlements::already_processed(&mut ex, auction_id).await?)
}

/// Save auction related data to the database.
pub async fn save_auction(
&self,
auction: &domain::Auction,
deadline: u64, // to become part of the auction struct
) -> Result<(), DatabaseError> {
let _timer = Metrics::get()
.database_queries
.with_label_values(&["save_auction"])
.start_timer();

let mut ex = self.postgres.pool.begin().await?;

database::auction::save(
&mut ex,
database::auction::Auction {
id: auction.id,
block: i64::try_from(auction.block).context("block overflow")?,
deadline: i64::try_from(deadline).context("deadline overflow")?,
order_uids: auction
.orders
.iter()
.map(|order| ByteArray(order.uid.0))
.collect(),
price_tokens: auction
.prices
.keys()
.map(|token| ByteArray(token.0 .0))
.collect(),
price_values: auction
.prices
.values()
.map(|price| u256_to_big_decimal(&price.get().0))
.collect(),
surplus_capturing_jit_order_owners: auction
.surplus_capturing_jit_order_owners
.iter()
.map(|owner| ByteArray(owner.0 .0))
.collect(),
},
)
.await?;

Ok(ex.commit().await?)
}

/// Get auction data.
pub async fn get_auction(
&self,
Expand Down Expand Up @@ -655,14 +766,7 @@ impl Persistence {
valid_to: i64::from(jit_order.valid_to),
app_data: ByteArray(jit_order.app_data.0),
fee_amount: u256_to_big_decimal(&jit_order.fee_amount.0),
kind: match jit_order.side {
domain::auction::order::Side::Buy => {
database::orders::OrderKind::Buy
}
domain::auction::order::Side::Sell => {
database::orders::OrderKind::Sell
}
},
kind: jit_order.side.into(),
partially_fillable: jit_order.partially_fillable,
signature: jit_order.signature.to_bytes(),
receiver: ByteArray(jit_order.receiver.0 .0),
Expand Down
13 changes: 13 additions & 0 deletions crates/autopilot/src/run_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,19 @@ impl RunLoop {
competition_table,
};

if let Err(err) = futures::try_join!(
self.persistence
.save_auction(auction, block_deadline)
.map_err(|e| e.0.context("failed to save auction")),
self.persistence
.save_solutions(auction.id, solutions)
.map_err(|e| e.0.context("failed to save solutions")),
) {
// Don't error if saving of auction and solution fails, until stable.
// Various edge cases with JIT orders verifiable only in production.
tracing::warn!(?err, "failed to save new competition data");
}

tracing::trace!(?competition, "saving competition");
futures::try_join!(
self.persistence
Expand Down
60 changes: 58 additions & 2 deletions crates/database/src/auction.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use sqlx::{types::JsonValue, PgConnection};
use {
crate::{Address, OrderUid},
bigdecimal::BigDecimal,
sqlx::{types::JsonValue, PgConnection},
};

pub type AuctionId = i64;

Expand Down Expand Up @@ -31,9 +35,46 @@ RETURNING id;
Ok(id)
}

#[derive(Debug, Clone, PartialEq, sqlx::FromRow)]
pub struct Auction {
pub id: AuctionId,
pub block: i64,
pub deadline: i64,
pub order_uids: Vec<OrderUid>,
// External native prices
pub price_tokens: Vec<Address>,
pub price_values: Vec<BigDecimal>,
pub surplus_capturing_jit_order_owners: Vec<Address>,
}

pub async fn save(ex: &mut PgConnection, auction: Auction) -> Result<(), sqlx::Error> {
const QUERY: &str = r#"
INSERT INTO competition_auctions (id, block, deadline, order_uids, price_tokens, price_values, surplus_capturing_jit_order_owners)
VALUES ($1, $2, $3, $4, $5, $6, $7)
;"#;

sqlx::query(QUERY)
.bind(auction.id)
.bind(auction.block)
.bind(auction.deadline)
.bind(auction.order_uids)
.bind(auction.price_tokens)
.bind(auction.price_values)
.bind(auction.surplus_capturing_jit_order_owners)
.execute(ex)
.await?;

Ok(())
}

pub async fn fetch(ex: &mut PgConnection, id: AuctionId) -> Result<Option<Auction>, sqlx::Error> {
const QUERY: &str = r#"SELECT * FROM competition_auctions WHERE id = $1;"#;
sqlx::query_as(QUERY).bind(id).fetch_optional(ex).await
}

#[cfg(test)]
mod tests {
use {super::*, sqlx::Connection};
use {super::*, crate::byte_array::ByteArray, sqlx::Connection};

#[tokio::test]
#[ignore]
Expand All @@ -54,5 +95,20 @@ mod tests {
let (id, value_) = load_most_recent(&mut db).await.unwrap().unwrap();
assert_eq!(value, value_);
assert_eq!(id_, id);

// let's assume the second auction contains a valid competition data so it's
// meaningful to save it into `competition_auctions` table as well
let auction = Auction {
id: id_,
block: 1,
deadline: 2,
order_uids: vec![ByteArray([1u8; 56])],
price_tokens: vec![ByteArray([1u8; 20])],
price_values: vec![BigDecimal::from(1)],
surplus_capturing_jit_order_owners: vec![ByteArray([1u8; 20])],
};
save(&mut db, auction.clone()).await.unwrap();
let auction_ = fetch(&mut db, id_).await.unwrap().unwrap();
assert_eq!(auction, auction_);
}
}
1 change: 1 addition & 0 deletions crates/database/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub const TABLES: &[&str] = &[
"order_quotes",
"solver_competitions",
"auctions",
"competition_auctions",
"onchain_placed_orders",
"ethflow_orders",
"order_execution",
Expand Down
Loading
Loading