Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion tap_aggregator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ name = "tap_aggregator"
path = "src/main.rs"

[dependencies]
tap_core = { path = "../tap_core", version = "2.0.0" }
tap_core = { path = "../tap_core", version = "2.0.0", features = ["test"] }
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not really liking this feature here in tap_aggregator

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah... Why is it required?

serde.workspace = true
alloy.workspace = true
anyhow.workspace = true
Expand Down
14 changes: 8 additions & 6 deletions tap_aggregator/src/aggregator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ use alloy::{
use anyhow::{bail, Ok, Result};
use rayon::prelude::*;
use tap_core::{
rav::ReceiptAggregateVoucher,
rav::{Aggregate, ReceiptAggregateVoucher},
receipt::Receipt,
signed_message::{EIP712SignedMessage, SignatureBytes, SignatureBytesExt},
};

pub fn check_and_aggregate_receipts(
domain_separator: &Eip712Domain,
receipts: &[EIP712SignedMessage<Receipt>],
receipts: Vec<EIP712SignedMessage<Receipt>>,
previous_rav: Option<EIP712SignedMessage<ReceiptAggregateVoucher>>,
wallet: &PrivateKeySigner,
accepted_addresses: &HashSet<Address>,
) -> Result<EIP712SignedMessage<ReceiptAggregateVoucher>> {
check_signatures_unique(receipts)?;
check_signatures_unique(&receipts)?;

// Check that the receipts are signed by an accepted signer address
receipts.par_iter().try_for_each(|receipt| {
Expand All @@ -39,7 +39,7 @@ pub fn check_and_aggregate_receipts(
}

// Check that the receipts timestamp is greater than the previous rav
check_receipt_timestamps(receipts, previous_rav.as_ref())?;
check_receipt_timestamps(&receipts, previous_rav.as_ref())?;

// Get the allocation id from the first receipt, return error if there are no receipts
let allocation_id = match receipts.first() {
Expand All @@ -48,7 +48,7 @@ pub fn check_and_aggregate_receipts(
};

// Check that the receipts all have the same allocation id
check_allocation_id(receipts, allocation_id)?;
check_allocation_id(&receipts, allocation_id)?;

// Check that the rav has the correct allocation id
if let Some(previous_rav) = &previous_rav {
Expand All @@ -62,8 +62,10 @@ pub fn check_and_aggregate_receipts(
}
}

let receipts = receipts.into_iter().map(Into::into).collect::<Vec<_>>();
Copy link
Contributor

Choose a reason for hiding this comment

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

No big deal but here is one place I'd like to see what type it's being coerced to 😄


// Aggregate the receipts
let rav = ReceiptAggregateVoucher::aggregate_receipts(allocation_id, receipts, previous_rav)?;
let rav = ReceiptAggregateVoucher::aggregate_receipts(&receipts, previous_rav)?;

// Sign the rav and return
Ok(EIP712SignedMessage::new(domain_separator, rav, wallet)?)
Expand Down
20 changes: 13 additions & 7 deletions tap_aggregator/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ fn aggregate_receipts_(
let res = match api_version {
TapRpcApiVersion::V0_0 => check_and_aggregate_receipts(
domain_separator,
&receipts,
receipts,
previous_rav,
wallet,
accepted_addresses,
Expand Down Expand Up @@ -202,7 +202,7 @@ impl TapAggregator for RpcImpl {

match check_and_aggregate_receipts(
&self.domain_separator,
receipts.as_slice(),
receipts,
previous_rav,
&self.wallet,
&self.accepted_addresses,
Expand Down Expand Up @@ -494,6 +494,8 @@ mod tests {
#[values(0, 1, 2)] random_seed: u64,
) {
// The keys that will be used to sign the new RAVs

use tap_core::rav::Aggregate;
let keys_main = keys();
// Extra keys to test the server's ability to accept multiple signers as input
let keys_0 = keys();
Expand Down Expand Up @@ -546,9 +548,11 @@ mod tests {

let remote_rav = res.data;

let local_rav =
ReceiptAggregateVoucher::aggregate_receipts(allocation_ids[0], &receipts, None)
.unwrap();
let local_rav = ReceiptAggregateVoucher::aggregate_receipts(
&receipts.into_iter().map(Into::into).collect::<Vec<_>>(),
None,
)
.unwrap();

assert!(remote_rav.message.allocationId == local_rav.allocationId);
assert!(remote_rav.message.timestampNs == local_rav.timestampNs);
Expand All @@ -574,6 +578,8 @@ mod tests {
#[values(0, 1, 2, 3, 4)] random_seed: u64,
) {
// The keys that will be used to sign the new RAVs

use tap_core::rav::Aggregate;
let keys_main = keys();
// Extra keys to test the server's ability to accept multiple signers as input
let keys_0 = keys();
Expand Down Expand Up @@ -614,10 +620,10 @@ mod tests {
);
}

let checked_receipt = receipts.iter().cloned().map(Into::into).collect::<Vec<_>>();
// Create previous RAV from first half of receipts locally
let prev_rav = ReceiptAggregateVoucher::aggregate_receipts(
allocation_ids[0],
&receipts[0..receipts.len() / 2],
&checked_receipt[0..checked_receipt.len() / 2],
None,
)
.unwrap();
Expand Down
2 changes: 2 additions & 0 deletions tap_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ criterion = { version = "0.5", features = ["async_std"] }
rstest.workspace = true
insta.workspace = true
serde_json.workspace = true
tap_core = { path = ".", features = ["test"] }


[features]
default = ["in_memory"]
test = []
in_memory = []

[[bench]]
Expand Down
11 changes: 7 additions & 4 deletions tap_core/benches/timeline_aggretion_protocol_benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ use std::str::FromStr;
use alloy::{dyn_abi::Eip712Domain, primitives::Address, signers::local::PrivateKeySigner};
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use tap_core::{
rav::ReceiptAggregateVoucher, receipt::Receipt, signed_message::EIP712SignedMessage,
rav::{Aggregate, ReceiptAggregateVoucher},
Copy link
Contributor

Choose a reason for hiding this comment

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

Are these benchmarks used?

receipt::Receipt,
signed_message::EIP712SignedMessage,
tap_eip712_domain,
};

Expand Down Expand Up @@ -66,15 +68,16 @@ pub fn criterion_benchmark(c: &mut Criterion) {

for log_number_of_receipts in 10..30 {
let receipts = (0..2 ^ log_number_of_receipts)
.map(|_| create_and_sign_receipt(&domain_seperator, allocation_id, value, &wallet))
.map(|_| {
create_and_sign_receipt(&domain_seperator, allocation_id, value, &wallet).into()
})
.collect::<Vec<_>>();

rav_group.bench_function(
format!("Create RAV w/ 2^{} receipt's", log_number_of_receipts),
|b| {
b.iter(|| {
ReceiptAggregateVoucher::aggregate_receipts(
black_box(allocation_id),
black_box(&receipts),
black_box(None),
)
Expand All @@ -84,7 +87,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {

let signed_rav = EIP712SignedMessage::new(
&domain_seperator,
ReceiptAggregateVoucher::aggregate_receipts(allocation_id, &receipts, None).unwrap(),
ReceiptAggregateVoucher::aggregate_receipts(&receipts, None).unwrap(),
&wallet,
)
.unwrap();
Expand Down
6 changes: 3 additions & 3 deletions tap_core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::result::Result as StdResult;
use alloy::primitives::{Address, SignatureError};
use thiserror::Error as ThisError;

use crate::{rav::ReceiptAggregateVoucher, receipt::ReceiptError};
use crate::receipt::ReceiptError;

/// Error type for the TAP protocol
#[derive(ThisError, Debug)]
Expand Down Expand Up @@ -38,8 +38,8 @@ pub enum Error {
/// Error when the received RAV does not match the expected RAV
#[error("Received RAV does not match expexted RAV")]
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
#[error("Received RAV does not match expexted RAV")]
#[error("Received RAV does not match expected RAV")]

InvalidReceivedRAV {
received_rav: ReceiptAggregateVoucher,
expected_rav: ReceiptAggregateVoucher,
received_rav: String,
expected_rav: String,
Comment on lines -41 to +42
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems strange! This is to allow for basically any generic message? Why not use a newtype?

},
/// Generic error from the adapter
#[error("Error from adapter.\n Caused by: {source_error}")]
Expand Down
24 changes: 12 additions & 12 deletions tap_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ mod tap_tests {
use rstest::*;

use crate::{
rav::ReceiptAggregateVoucher, receipt::Receipt, signed_message::EIP712SignedMessage,
rav::{Aggregate, ReceiptAggregateVoucher},
receipt::Receipt,
signed_message::EIP712SignedMessage,
tap_eip712_domain,
};

Expand Down Expand Up @@ -102,6 +104,7 @@ mod tap_tests {
#[case] values: Vec<u128>,
) {
// Create receipts

let mut receipts = Vec::new();
for value in values {
receipts.push(
Expand All @@ -110,14 +113,14 @@ mod tap_tests {
Receipt::new(allocation_ids[0], value).unwrap(),
&keys.0,
)
.unwrap(),
.unwrap()
.into(),
);
}

// Skipping receipts validation in this test, aggregate_receipts assumes receipts are valid.

let rav = ReceiptAggregateVoucher::aggregate_receipts(allocation_ids[0], &receipts, None)
.unwrap();
let rav = ReceiptAggregateVoucher::aggregate_receipts(&receipts, None).unwrap();
let signed_rav = EIP712SignedMessage::new(&domain_separator, rav, &keys.0).unwrap();
assert!(signed_rav.recover_signer(&domain_separator).unwrap() == keys.1);
}
Expand All @@ -141,23 +144,20 @@ mod tap_tests {
Receipt::new(allocation_ids[0], value).unwrap(),
&keys.0,
)
.unwrap(),
.unwrap()
.into(),
);
}

// Create previous RAV from first half of receipts
let prev_rav = ReceiptAggregateVoucher::aggregate_receipts(
allocation_ids[0],
&receipts[0..receipts.len() / 2],
None,
)
.unwrap();
let prev_rav =
ReceiptAggregateVoucher::aggregate_receipts(&receipts[0..receipts.len() / 2], None)
.unwrap();
let signed_prev_rav =
EIP712SignedMessage::new(&domain_separator, prev_rav, &keys.0).unwrap();

// Create new RAV from last half of receipts and prev_rav
let rav = ReceiptAggregateVoucher::aggregate_receipts(
allocation_ids[0],
&receipts[receipts.len() / 2..receipts.len()],
Some(signed_prev_rav),
)
Expand Down
47 changes: 4 additions & 43 deletions tap_core/src/manager/adapters/escrow.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
// Copyright 2023-, Semiotic AI, Inc.
// SPDX-License-Identifier: Apache-2.0

use alloy::{dyn_abi::Eip712Domain, primitives::Address};
use alloy::{dyn_abi::Eip712Domain, primitives::Address, sol_types::SolStruct};
use async_trait::async_trait;

use crate::{
rav::SignedRAV,
receipt::{state::AwaitingReserve, ReceiptError, ReceiptResult, ReceiptWithState},
Error,
};
use crate::{signed_message::EIP712SignedMessage, Error};

/// Manages the escrow operations
///
Expand All @@ -25,50 +21,15 @@ pub trait EscrowHandler: Send + Sync {
/// Errors of this type are returned to the user when an operation fails.
type AdapterError: std::error::Error + std::fmt::Debug + Send + Sync + 'static;

/// Retrieves the local accounting amount of available escrow for a specified sender.
async fn get_available_escrow(&self, sender_id: Address) -> Result<u128, Self::AdapterError>;

/// Deducts a specified value from the local accounting of available escrow for a specified sender.
async fn subtract_escrow(
&self,
sender_id: Address,
value: u128,
) -> Result<(), Self::AdapterError>;

/// Verifies the signer of the receipt
///
/// Used by [`Self::check_rav_signature`] to verify the signer of the receipt
async fn verify_signer(&self, signer_address: Address) -> Result<bool, Self::AdapterError>;

/// Checks and reserves escrow for the received receipt
async fn check_and_reserve_escrow(
&self,
received_receipt: &ReceiptWithState<AwaitingReserve>,
domain_separator: &Eip712Domain,
) -> ReceiptResult<()> {
let signed_receipt = &received_receipt.signed_receipt;
let receipt_signer_address =
signed_receipt
.recover_signer(domain_separator)
.map_err(|err| ReceiptError::InvalidSignature {
source_error_message: err.to_string(),
})?;

if self
.subtract_escrow(receipt_signer_address, signed_receipt.message.value)
.await
.is_err()
{
return Err(ReceiptError::SubtractEscrowFailed);
}

Ok(())
}

/// Checks the signature of the RAV
async fn check_rav_signature(
async fn check_rav_signature<R: SolStruct + Sync>(
&self,
signed_rav: &SignedRAV,
signed_rav: &EIP712SignedMessage<R>,
domain_separator: &Eip712Domain,
) -> Result<(), Error> {
let recovered_address = signed_rav.recover_signer(domain_separator)?;
Expand Down
17 changes: 12 additions & 5 deletions tap_core/src/manager/adapters/rav.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// Copyright 2023-, Semiotic AI, Inc.
// SPDX-License-Identifier: Apache-2.0

use alloy::sol_types::SolStruct;
use async_trait::async_trait;

use crate::rav::SignedRAV;
use crate::signed_message::EIP712SignedMessage;

/// Stores the latest RAV in the storage.
///
Expand All @@ -12,7 +13,10 @@ use crate::rav::SignedRAV;
/// For example code see [crate::manager::context::memory::RAVStorage]

#[async_trait]
pub trait RAVStore {
pub trait RAVStore<T>
where
T: SolStruct,
{
/// Defines the user-specified error type.
///
/// This error type should implement the `Error` and `Debug` traits from
Expand All @@ -25,7 +29,7 @@ pub trait RAVStore {
/// This method should be implemented to store the most recent validated
/// `SignedRAV` into your chosen storage system. Any errors that occur
/// during this process should be captured and returned as an `AdapterError`.
async fn update_last_rav(&self, rav: SignedRAV) -> Result<(), Self::AdapterError>;
async fn update_last_rav(&self, rav: EIP712SignedMessage<T>) -> Result<(), Self::AdapterError>;
}

/// Reads the RAV from storage
Expand All @@ -35,7 +39,10 @@ pub trait RAVStore {
/// For example code see [crate::manager::context::memory::RAVStorage]

#[async_trait]
pub trait RAVRead {
pub trait RAVRead<T>
where
T: SolStruct,
{
/// Defines the user-specified error type.
///
/// This error type should implement the `Error` and `Debug` traits from
Expand All @@ -46,5 +53,5 @@ pub trait RAVRead {
/// Retrieves the latest `SignedRAV` from the storage.
///
/// If no `SignedRAV` is available, this method should return `None`.
async fn last_rav(&self) -> Result<Option<SignedRAV>, Self::AdapterError>;
async fn last_rav(&self) -> Result<Option<EIP712SignedMessage<T>>, Self::AdapterError>;
}
Loading
Loading