Skip to content

Commit d3359c1

Browse files
authored
refactor(core): collect runs batched checks (#180)
The checks are specifically made to check the receipts that are to be aggregated only in their own context. Helps for uniqueness checks for example, where we avoid calling the storage backend and only check that the collected receipts are unique. Signed-off-by: Alexis Asseman <[email protected]>
1 parent 4fbc6df commit d3359c1

File tree

3 files changed

+178
-7
lines changed

3 files changed

+178
-7
lines changed

tap_core/src/tap_manager/manager.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,19 @@ impl<
236236
let mut accepted_signed_receipts = Vec::<SignedReceipt>::new();
237237
let mut failed_signed_receipts = Vec::<SignedReceipt>::new();
238238

239-
for (receipt_id, mut received_receipt) in received_receipts {
240-
received_receipt
241-
.finalize_receipt_checks(receipt_id, &self.receipt_auditor)
242-
.await?;
239+
let mut received_receipts: Vec<ReceivedReceipt> =
240+
received_receipts.into_iter().map(|e| e.1).collect();
241+
242+
for check in self.required_checks.iter() {
243+
ReceivedReceipt::perform_check_batch(
244+
&mut received_receipts,
245+
check,
246+
&self.receipt_auditor,
247+
)
248+
.await?;
249+
}
250+
251+
for received_receipt in received_receipts {
243252
if received_receipt.is_accepted() {
244253
accepted_signed_receipts.push(received_receipt.signed_receipt);
245254
} else {

tap_core/src/tap_receipt/receipt_auditor.rs

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
// Copyright 2023-, Semiotic AI, Inc.
22
// SPDX-License-Identifier: Apache-2.0
33

4+
use std::collections::HashSet;
5+
46
use alloy_sol_types::Eip712Domain;
7+
use ethers::types::Signature;
58
use tokio::sync::RwLock;
69

710
use crate::{
@@ -12,6 +15,8 @@ use crate::{
1215
Error, Result,
1316
};
1417

18+
use super::ReceivedReceipt;
19+
1520
pub struct ReceiptAuditor<EA: EscrowAdapter, RCA: ReceiptChecksAdapter> {
1621
domain_separator: Eip712Domain,
1722
escrow_adapter: EA,
@@ -58,6 +63,25 @@ impl<EA: EscrowAdapter, RCA: ReceiptChecksAdapter> ReceiptAuditor<EA, RCA> {
5863
}
5964
}
6065

66+
pub async fn check_batch(
67+
&self,
68+
receipt_check: &ReceiptCheck,
69+
received_receipts: &mut [ReceivedReceipt],
70+
) -> Vec<ReceiptResult<()>> {
71+
match receipt_check {
72+
ReceiptCheck::CheckUnique => self.check_uniqueness_batch(received_receipts).await,
73+
ReceiptCheck::CheckAllocationId => {
74+
self.check_allocation_id_batch(received_receipts).await
75+
}
76+
ReceiptCheck::CheckSignature => self.check_signature_batch(received_receipts).await,
77+
ReceiptCheck::CheckTimestamp => self.check_timestamp_batch(received_receipts).await,
78+
ReceiptCheck::CheckValue => self.check_value_batch(received_receipts).await,
79+
ReceiptCheck::CheckAndReserveEscrow => {
80+
self.check_and_reserve_escrow_batch(received_receipts).await
81+
}
82+
}
83+
}
84+
6185
async fn check_uniqueness(
6286
&self,
6387
signed_receipt: &EIP712SignedMessage<Receipt>,
@@ -76,6 +100,33 @@ impl<EA: EscrowAdapter, RCA: ReceiptChecksAdapter> ReceiptAuditor<EA, RCA> {
76100
Ok(())
77101
}
78102

103+
async fn check_uniqueness_batch(
104+
&self,
105+
received_receipts: &mut [ReceivedReceipt],
106+
) -> Vec<ReceiptResult<()>> {
107+
let mut results = Vec::new();
108+
109+
// If at least one of the receipts in the batch hasn't been checked for uniqueness yet, check the whole batch.
110+
if received_receipts
111+
.iter()
112+
.filter(|r| r.checks.contains_key(&ReceiptCheck::CheckUnique))
113+
.any(|r| r.checks[&ReceiptCheck::CheckUnique].is_none())
114+
{
115+
let mut signatures: HashSet<Signature> = HashSet::new();
116+
117+
for received_receipt in received_receipts {
118+
let signature = received_receipt.signed_receipt.signature;
119+
if signatures.insert(signature) {
120+
results.push(Ok(()));
121+
} else {
122+
results.push(Err(ReceiptError::NonUniqueReceipt));
123+
}
124+
}
125+
}
126+
127+
results
128+
}
129+
79130
async fn check_allocation_id(
80131
&self,
81132
signed_receipt: &EIP712SignedMessage<Receipt>,
@@ -95,6 +146,25 @@ impl<EA: EscrowAdapter, RCA: ReceiptChecksAdapter> ReceiptAuditor<EA, RCA> {
95146
Ok(())
96147
}
97148

149+
async fn check_allocation_id_batch(
150+
&self,
151+
received_receipts: &mut [ReceivedReceipt],
152+
) -> Vec<ReceiptResult<()>> {
153+
let mut results = Vec::new();
154+
155+
for received_receipt in received_receipts
156+
.iter_mut()
157+
.filter(|r| r.checks.contains_key(&ReceiptCheck::CheckAllocationId))
158+
{
159+
if received_receipt.checks[&ReceiptCheck::CheckAllocationId].is_none() {
160+
let signed_receipt = &received_receipt.signed_receipt;
161+
results.push(self.check_allocation_id(signed_receipt).await);
162+
}
163+
}
164+
165+
results
166+
}
167+
98168
async fn check_timestamp(
99169
&self,
100170
signed_receipt: &EIP712SignedMessage<Receipt>,
@@ -108,6 +178,26 @@ impl<EA: EscrowAdapter, RCA: ReceiptChecksAdapter> ReceiptAuditor<EA, RCA> {
108178
}
109179
Ok(())
110180
}
181+
182+
async fn check_timestamp_batch(
183+
&self,
184+
received_receipts: &mut [ReceivedReceipt],
185+
) -> Vec<ReceiptResult<()>> {
186+
let mut results = Vec::new();
187+
188+
for received_receipt in received_receipts
189+
.iter_mut()
190+
.filter(|r| r.checks.contains_key(&ReceiptCheck::CheckTimestamp))
191+
{
192+
if received_receipt.checks[&ReceiptCheck::CheckTimestamp].is_none() {
193+
let signed_receipt = &received_receipt.signed_receipt;
194+
results.push(self.check_timestamp(signed_receipt).await);
195+
}
196+
}
197+
198+
results
199+
}
200+
111201
async fn check_value(
112202
&self,
113203
signed_receipt: &EIP712SignedMessage<Receipt>,
@@ -128,6 +218,28 @@ impl<EA: EscrowAdapter, RCA: ReceiptChecksAdapter> ReceiptAuditor<EA, RCA> {
128218
Ok(())
129219
}
130220

221+
async fn check_value_batch(
222+
&self,
223+
received_receipts: &mut [ReceivedReceipt],
224+
) -> Vec<ReceiptResult<()>> {
225+
let mut results = Vec::new();
226+
227+
for received_receipt in received_receipts
228+
.iter_mut()
229+
.filter(|r| r.checks.contains_key(&ReceiptCheck::CheckValue))
230+
{
231+
if received_receipt.checks[&ReceiptCheck::CheckValue].is_none() {
232+
let signed_receipt = &received_receipt.signed_receipt;
233+
results.push(
234+
self.check_value(signed_receipt, received_receipt.query_id)
235+
.await,
236+
);
237+
}
238+
}
239+
240+
results
241+
}
242+
131243
async fn check_signature(
132244
&self,
133245
signed_receipt: &EIP712SignedMessage<Receipt>,
@@ -155,6 +267,25 @@ impl<EA: EscrowAdapter, RCA: ReceiptChecksAdapter> ReceiptAuditor<EA, RCA> {
155267
Ok(())
156268
}
157269

270+
async fn check_signature_batch(
271+
&self,
272+
received_receipts: &mut [ReceivedReceipt],
273+
) -> Vec<ReceiptResult<()>> {
274+
let mut results = Vec::new();
275+
276+
for received_receipt in received_receipts
277+
.iter_mut()
278+
.filter(|r| r.checks.contains_key(&ReceiptCheck::CheckSignature))
279+
{
280+
if received_receipt.checks[&ReceiptCheck::CheckSignature].is_none() {
281+
let signed_receipt = &received_receipt.signed_receipt;
282+
results.push(self.check_signature(signed_receipt).await);
283+
}
284+
}
285+
286+
results
287+
}
288+
158289
async fn check_and_reserve_escrow(
159290
&self,
160291
signed_receipt: &EIP712SignedMessage<Receipt>,
@@ -176,6 +307,22 @@ impl<EA: EscrowAdapter, RCA: ReceiptChecksAdapter> ReceiptAuditor<EA, RCA> {
176307
Ok(())
177308
}
178309

310+
async fn check_and_reserve_escrow_batch(
311+
&self,
312+
received_receipts: &mut [ReceivedReceipt],
313+
) -> Vec<ReceiptResult<()>> {
314+
let mut results = Vec::new();
315+
316+
for received_receipt in received_receipts.iter_mut().filter(|r| {
317+
r.escrow_reserve_attempt_required() && !r.escrow_reserve_attempt_completed()
318+
}) {
319+
let signed_receipt = &received_receipt.signed_receipt;
320+
results.push(self.check_and_reserve_escrow(signed_receipt).await);
321+
}
322+
323+
results
324+
}
325+
179326
pub async fn check_rav_signature(
180327
&self,
181328
signed_rav: &EIP712SignedMessage<ReceiptAggregateVoucher>,

tap_core/src/tap_receipt/received_receipt.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,21 @@ impl ReceivedReceipt {
147147
result
148148
}
149149

150+
pub async fn perform_check_batch<CA: EscrowAdapter, RCA: ReceiptChecksAdapter>(
151+
batch: &mut [Self],
152+
check: &ReceiptCheck,
153+
receipt_auditor: &ReceiptAuditor<CA, RCA>,
154+
) -> Result<()> {
155+
let results = receipt_auditor.check_batch(check, batch).await;
156+
157+
for (receipt, result) in batch.iter_mut().zip(results) {
158+
receipt.update_check(check, Some(result))?;
159+
receipt.update_state();
160+
}
161+
162+
Ok(())
163+
}
164+
150165
/// Completes a list of *incomplete* check and stores the result, if the check already has a result it is skipped
151166
///
152167
/// Returns `Err` only if unable to complete a check, returns `Ok` if the checks were completed (*Important:* this is not the result of the check, just the result of _completing_ the check)
@@ -293,7 +308,7 @@ impl ReceivedReceipt {
293308
}
294309

295310
/// Updates receieved receipt state based on internal values, should be called anytime internal state changes
296-
fn update_state(&mut self) {
311+
pub(crate) fn update_state(&mut self) {
297312
let mut next_state = self.state.clone();
298313
match self.state {
299314
ReceiptState::Received => {
@@ -357,14 +372,14 @@ impl ReceivedReceipt {
357372
ReceiptState::AwaitingReserveEscrow
358373
}
359374

360-
fn escrow_reserve_attempt_completed(&self) -> bool {
375+
pub(crate) fn escrow_reserve_attempt_completed(&self) -> bool {
361376
if let Some(escrow_reserve_attempt) = &self.escrow_reserved {
362377
return escrow_reserve_attempt.is_some();
363378
}
364379
false
365380
}
366381

367-
fn escrow_reserve_attempt_required(&self) -> bool {
382+
pub(crate) fn escrow_reserve_attempt_required(&self) -> bool {
368383
self.escrow_reserved.is_some()
369384
}
370385

0 commit comments

Comments
 (0)