-
Notifications
You must be signed in to change notification settings - Fork 97
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
Remove auction_transaction #2283
Changes from 20 commits
e0f006a
4522a1b
61a4f9d
eabc187
5171b2c
f6eabc7
a039a1a
53ce32e
757e76b
b94835e
94beabc
2f8a070
c2e9478
9ee0a4f
0346f80
b221e8c
fca0198
062549c
f10361d
f000781
f6a0152
1e684c0
bae70f5
5e4401e
40138bf
d9f2996
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,14 +39,40 @@ use { | |
decoded_settlement::{DecodedSettlement, DecodingError}, | ||
infra, | ||
}, | ||
anyhow::{anyhow, Context, Result}, | ||
anyhow::{Context, Result}, | ||
futures::StreamExt, | ||
primitive_types::H256, | ||
shared::{event_handling::MAX_REORG_BLOCK_COUNT, external_prices::ExternalPrices}, | ||
shared::external_prices::ExternalPrices, | ||
sqlx::PgConnection, | ||
web3::types::Transaction, | ||
}; | ||
|
||
#[derive(Debug, Copy, Clone)] | ||
pub enum AuctionKind { | ||
/// This auction is regular and all the auction dependent data should be | ||
/// updated. | ||
Valid { auction_id: i64 }, | ||
/// Some possible reasons to have invalid auction are: | ||
/// - This auction was created by another environment (e.g. | ||
/// production/staging) | ||
/// - Failed to decode settlement calldata | ||
/// - Failed to recover auction id from calldata | ||
/// - Settlement transaction was submitted by solver other than the winner | ||
/// | ||
/// In this case, settlement event should be marked as invalid and no | ||
/// auction dependent data is updated. | ||
Invalid, | ||
} | ||
|
||
impl AuctionKind { | ||
pub fn auction_id(&self) -> Option<i64> { | ||
match self { | ||
AuctionKind::Valid { auction_id } => Some(*auction_id), | ||
AuctionKind::Invalid => None, | ||
} | ||
} | ||
} | ||
|
||
pub struct OnSettlementEventUpdater { | ||
pub eth: infra::Ethereum, | ||
pub db: Postgres, | ||
|
@@ -57,7 +83,7 @@ impl OnSettlementEventUpdater { | |
let mut current_block = self.eth.current_block().borrow().to_owned(); | ||
let mut block_stream = ethrpc::current_block::into_stream(self.eth.current_block().clone()); | ||
loop { | ||
match self.update(current_block.number).await { | ||
match self.update().await { | ||
Ok(true) => { | ||
tracing::debug!( | ||
block = current_block.number, | ||
|
@@ -77,31 +103,27 @@ impl OnSettlementEventUpdater { | |
} | ||
} | ||
current_block = block_stream.next().await.expect("blockchains never end"); | ||
|
||
// Wait a bit more to not race with the event indexer. | ||
// Otherwise we might miss event and have to wait for next block to retrigger | ||
// loop. | ||
tokio::time::sleep(std::time::Duration::from_secs(1)).await; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Relying on a fixed time sleep here is super hacky. I think having one block delay wouldn't be so bad, but if it's a must I think we should combine the two event updater (which one is the other one?) and make sure they are processing events in the order we want them to. |
||
} | ||
} | ||
|
||
/// Update database for settlement events that have not been processed yet. | ||
/// | ||
/// Returns whether an update was performed. | ||
async fn update(&self, current_block: u64) -> Result<bool> { | ||
let reorg_safe_block: i64 = current_block | ||
.checked_sub(MAX_REORG_BLOCK_COUNT) | ||
.context("no reorg safe block")? | ||
.try_into() | ||
.context("convert block")?; | ||
|
||
async fn update(&self) -> Result<bool> { | ||
let mut ex = self | ||
.db | ||
.pool | ||
.begin() | ||
.await | ||
.context("acquire DB connection")?; | ||
let event = match database::auction_transaction::get_settlement_event_without_tx_info( | ||
&mut ex, | ||
reorg_safe_block, | ||
) | ||
.await | ||
.context("get_settlement_event_without_tx_info")? | ||
let event = match database::settlements::get_settlement_without_auction(&mut ex) | ||
.await | ||
.context("get_settlement_without_auction")? | ||
{ | ||
Some(event) => event, | ||
None => return Ok(false), | ||
|
@@ -115,22 +137,13 @@ impl OnSettlementEventUpdater { | |
.transaction(hash) | ||
.await? | ||
.with_context(|| format!("no tx {hash:?}"))?; | ||
let tx_from = transaction | ||
.from | ||
.with_context(|| format!("no from {hash:?}"))?; | ||
let tx_nonce: i64 = transaction | ||
.nonce | ||
.try_into() | ||
.map_err(|err| anyhow!("{}", err)) | ||
.with_context(|| format!("convert nonce {hash:?}"))?; | ||
|
||
let auction_id = Self::recover_auction_id_from_calldata(&mut ex, &transaction).await?; | ||
let auction_kind = Self::get_auction_kind(&mut ex, &transaction).await?; | ||
|
||
let mut update = SettlementUpdate { | ||
block_number: event.block_number, | ||
log_index: event.log_index, | ||
tx_from, | ||
tx_nonce, | ||
auction_kind, | ||
auction_data: None, | ||
}; | ||
|
||
|
@@ -140,7 +153,7 @@ impl OnSettlementEventUpdater { | |
// | ||
// If auction_id exists, we expect all other relevant information to exist as | ||
// well. | ||
if let Some(auction_id) = auction_id { | ||
if let AuctionKind::Valid { auction_id } = auction_kind { | ||
let receipt = self | ||
.eth | ||
.transaction_receipt(hash) | ||
|
@@ -236,11 +249,9 @@ impl OnSettlementEventUpdater { | |
/// `auction_id` to the settlement calldata. This function tries to | ||
/// recover that `auction_id`. This function only returns an error if | ||
/// retrying the operation makes sense. If all went well and there | ||
/// simply is no sensible `auction_id` `Ok(None)` will be returned. | ||
async fn recover_auction_id_from_calldata( | ||
ex: &mut PgConnection, | ||
tx: &Transaction, | ||
) -> Result<Option<i64>> { | ||
/// simply is no sensible `auction_id` `AuctionKind::Invalid` will be | ||
/// returned. | ||
async fn get_auction_kind(ex: &mut PgConnection, tx: &Transaction) -> Result<AuctionKind> { | ||
let tx_from = tx.from.context("tx is missing sender")?; | ||
let metadata = match DecodedSettlement::new(&tx.input.0) { | ||
Ok(settlement) => settlement.metadata, | ||
|
@@ -250,45 +261,39 @@ impl OnSettlementEventUpdater { | |
?err, | ||
"could not decode settlement tx, unclear which auction it belongs to" | ||
); | ||
return Ok(None); | ||
return Ok(AuctionKind::Invalid); | ||
} | ||
}; | ||
let auction_id = match metadata { | ||
Some(bytes) => i64::from_be_bytes(bytes.0), | ||
None => { | ||
tracing::warn!(?tx, "could not recover the auction_id from the calldata"); | ||
return Ok(None); | ||
return Ok(AuctionKind::Invalid); | ||
} | ||
}; | ||
|
||
let score = database::settlement_scores::fetch(ex, auction_id).await?; | ||
let data_already_recorded = | ||
database::auction_transaction::data_exists(ex, auction_id).await?; | ||
match (score, data_already_recorded) { | ||
(None, _) => { | ||
match score { | ||
None => { | ||
tracing::debug!( | ||
auction_id, | ||
"calldata claims to settle auction that has no competition" | ||
); | ||
Ok(None) | ||
Ok(AuctionKind::Invalid) | ||
} | ||
(Some(score), _) if score.winner.0 != tx_from.0 => { | ||
tracing::warn!( | ||
auction_id, | ||
?tx_from, | ||
winner = ?score.winner, | ||
"solution submitted by solver other than the winner" | ||
); | ||
Ok(None) | ||
} | ||
(Some(_), true) => { | ||
tracing::warn!( | ||
auction_id, | ||
"settlement data already recorded for this auction" | ||
); | ||
Ok(None) | ||
Some(score) => { | ||
if score.winner.0 != tx_from.0 { | ||
tracing::warn!( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this and not being able to recover auction_id from calldata be error logs now (or even return an error)? |
||
auction_id, | ||
?tx_from, | ||
winner = ?score.winner, | ||
"solution submitted by solver other than the winner" | ||
); | ||
Ok(AuctionKind::Invalid) | ||
} else { | ||
Ok(AuctionKind::Valid { auction_id }) | ||
} | ||
} | ||
(Some(_), false) => Ok(Some(auction_id)), | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a fan of this type. It has the same entropy as an
Option<AuctionId>
with the added complication that in the database it exists in three flavours (including unprocessed)