Skip to content

Commit

Permalink
bugfix: make sure to update timestamp of last batch verification to p…
Browse files Browse the repository at this point in the history
…revent double redemption (#5239)
  • Loading branch information
jstuczyn authored Dec 10, 2024
1 parent c29fce0 commit 66fea38
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 18 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion nym-api/src/ecash/api_routes/spending.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ async fn batch_redeem_tickets(

// 5. check if **every** serial number included in the request has been verified by us
// if we have more than requested, tough luck, they're going to lose them
let verified = state.get_redeemable_tickets(provider_info).await?;
let verified = state.get_redeemable_tickets(&provider_info).await?;
let verified_tickets: HashSet<_> = verified.iter().map(|sn| sn.deref()).collect();

for sn in &received {
Expand All @@ -215,8 +215,14 @@ async fn batch_redeem_tickets(
}
}

// 6. vote on the proposal
// TODO: offload it to separate task with work queue and batching (of tx messages) to vote for multiple proposals in the same tx
// similarly to what we do inside the credential proxy
state.accept_proposal(proposal_id).await?;

// 7. update the time of the last verification for this provider
state.update_last_batch_verification(&provider_info).await?;

Ok(Json(EcashBatchTicketRedemptionResponse {
proposal_accepted: true,
}))
Expand Down
10 changes: 9 additions & 1 deletion nym-api/src/ecash/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -890,7 +890,7 @@ impl EcashState {

pub async fn get_redeemable_tickets(
&self,
provider_info: TicketProvider,
provider_info: &TicketProvider,
) -> Result<Vec<SerialNumberWrapper>> {
let since = provider_info
.last_batch_verification
Expand All @@ -903,6 +903,14 @@ impl EcashState {
.map_err(Into::into)
}

pub async fn update_last_batch_verification(&self, provider: &TicketProvider) -> Result<()> {
Ok(self
.aux
.storage
.update_last_batch_verification(provider.id, OffsetDateTime::now_utc())
.await?)
}

pub async fn get_ticket_data_by_serial_number(
&self,
serial_number: &[u8],
Expand Down
54 changes: 39 additions & 15 deletions nym-api/src/ecash/storage/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ pub trait EcashStorageManagerExt {
provider_id: i64,
since: OffsetDateTime,
) -> Result<Vec<SerialNumberWrapper>, sqlx::Error>;
async fn update_last_batch_verification(
&self,
provider_id: i64,
last_batch_verification: OffsetDateTime,
) -> Result<(), sqlx::Error>;

async fn get_spent_tickets_on(
&self,
Expand Down Expand Up @@ -215,15 +220,15 @@ impl EcashStorageManagerExt for StorageManager {
"#,
expiration_date
)
.fetch_all(&self.connection_pool)
.await?
.into_iter()
.filter_map(|r| r.merkle_leaf.try_into().inspect_err(|_| error!("possible database corruption: one of the stored merkle leaves is not a valid 32byte hash")).ok().map(|merkle_leaf| IssuedHash {
deposit_id: r.deposit_id,
merkle_leaf,
merkle_index: r.merkle_index as usize,
}))
.collect())
.fetch_all(&self.connection_pool)
.await?
.into_iter()
.filter_map(|r| r.merkle_leaf.try_into().inspect_err(|_| error!("possible database corruption: one of the stored merkle leaves is not a valid 32byte hash")).ok().map(|merkle_leaf| IssuedHash {
deposit_id: r.deposit_id,
merkle_leaf,
merkle_index: r.merkle_index as usize,
}))
.collect())
}

/// Store the provided issued credential information.
Expand Down Expand Up @@ -344,8 +349,8 @@ impl EcashStorageManagerExt for StorageManager {
verified_at,
provider_id
)
.execute(&self.connection_pool)
.await?;
.execute(&self.connection_pool)
.await?;

Ok(())
}
Expand Down Expand Up @@ -382,6 +387,25 @@ impl EcashStorageManagerExt for StorageManager {
.await
}

async fn update_last_batch_verification(
&self,
provider_id: i64,
last_batch_verification: OffsetDateTime,
) -> Result<(), sqlx::Error> {
sqlx::query!(
r#"
UPDATE ticket_providers
SET last_batch_verification = ?
WHERE id = ?
"#,
last_batch_verification,
provider_id
)
.execute(&self.connection_pool)
.await?;
Ok(())
}

async fn get_spent_tickets_on(
&self,
date: Date,
Expand Down Expand Up @@ -510,8 +534,8 @@ impl EcashStorageManagerExt for StorageManager {
epoch_id,
data
)
.execute(&self.connection_pool)
.await?;
.execute(&self.connection_pool)
.await?;
Ok(())
}

Expand Down Expand Up @@ -544,8 +568,8 @@ impl EcashStorageManagerExt for StorageManager {
epoch_id,
data
)
.execute(&self.connection_pool)
.await?;
.execute(&self.connection_pool)
.await?;
Ok(())
}

Expand Down
16 changes: 16 additions & 0 deletions nym-api/src/ecash/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ pub trait EcashStorageExt {
provider_id: i64,
since: OffsetDateTime,
) -> Result<Vec<SerialNumberWrapper>, NymApiStorageError>;
async fn update_last_batch_verification(
&self,
provider_id: i64,
last_batch_verification: OffsetDateTime,
) -> Result<(), NymApiStorageError>;

async fn get_all_spent_tickets_on(
&self,
Expand Down Expand Up @@ -395,6 +400,17 @@ impl EcashStorageExt for NymApiStorage {
.map_err(Into::into)
}

async fn update_last_batch_verification(
&self,
provider_id: i64,
last_batch_verification: OffsetDateTime,
) -> Result<(), NymApiStorageError> {
Ok(self
.manager
.update_last_batch_verification(provider_id, last_batch_verification)
.await?)
}

async fn get_all_spent_tickets_on(
&self,
date: Date,
Expand Down

0 comments on commit 66fea38

Please sign in to comment.