From 300f28aa668adc77b1c1bf67411510f8addb228e Mon Sep 17 00:00:00 2001 From: Gustavo Inacio Date: Mon, 27 Jan 2025 20:34:33 +0100 Subject: [PATCH 1/4] refactor!: new crates Signed-off-by: Gustavo Inacio --- Cargo.toml | 10 +- tap_aggregator/Cargo.toml | 13 +- tap_aggregator/src/aggregator.rs | 16 +- tap_aggregator/src/grpc.rs | 32 ++-- tap_aggregator/src/server.rs | 13 +- tap_aggregator/tests/aggregate_test.rs | 10 +- tap_core/Cargo.toml | 8 +- .../timeline_aggretion_protocol_benchmark.rs | 6 +- tap_core/src/error.rs | 4 +- tap_core/src/lib.rs | 8 +- tap_core/src/manager/context/memory.rs | 7 +- tap_core/src/manager/mod.rs | 3 +- tap_core/src/manager/tap_manager.rs | 3 +- .../src/{rav/request.rs => rav_request.rs} | 4 +- tap_core/src/receipt.rs | 4 + tap_core/src/signed_message.rs | 142 +----------------- tap_core/tests/manager_test.rs | 4 +- tap_core/tests/rav_test.rs | 4 +- tap_core/tests/receipt_test.rs | 13 +- tap_core/tests/received_receipt_test.rs | 3 +- tap_eip712_message/Cargo.toml | 15 ++ tap_eip712_message/src/lib.rs | 134 +++++++++++++++++ tap_graph/Cargo.toml | 18 +++ tap_graph/src/lib.rs | 26 ++++ {tap_core => tap_graph}/src/rav.rs | 34 ++--- .../src/receipt.rs | 7 +- tap_integration_tests/Cargo.toml | 2 +- tap_integration_tests/tests/indexer_mock.rs | 4 +- tap_integration_tests/tests/showcase.rs | 7 +- tap_receipt/Cargo.toml | 18 +++ .../src/receipt => tap_receipt/src}/checks.rs | 44 +++--- .../src/receipt => tap_receipt/src}/error.rs | 0 .../receipt/mod.rs => tap_receipt/src/lib.rs | 34 ++++- tap_receipt/src/rav.rs | 27 ++++ .../src}/received_receipt.rs | 2 +- .../src/receipt => tap_receipt/src}/state.rs | 2 +- 36 files changed, 400 insertions(+), 281 deletions(-) rename tap_core/src/{rav/request.rs => rav_request.rs} (89%) create mode 100644 tap_core/src/receipt.rs create mode 100644 tap_eip712_message/Cargo.toml create mode 100644 tap_eip712_message/src/lib.rs create mode 100644 tap_graph/Cargo.toml create mode 100644 tap_graph/src/lib.rs rename {tap_core => tap_graph}/src/rav.rs (85%) rename tap_core/src/receipt/receipt_sol.rs => tap_graph/src/receipt.rs (94%) create mode 100644 tap_receipt/Cargo.toml rename {tap_core/src/receipt => tap_receipt/src}/checks.rs (92%) rename {tap_core/src/receipt => tap_receipt/src}/error.rs (100%) rename tap_core/src/receipt/mod.rs => tap_receipt/src/lib.rs (72%) create mode 100644 tap_receipt/src/rav.rs rename {tap_core/src/receipt => tap_receipt/src}/received_receipt.rs (99%) rename {tap_core/src/receipt => tap_receipt/src}/state.rs (96%) diff --git a/Cargo.toml b/Cargo.toml index f66ac499..95a5942e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,13 @@ [workspace] resolver = "2" -members = ["tap_core", "tap_aggregator", "tap_integration_tests"] +members = [ + "tap_core", + "tap_aggregator", + "tap_integration_tests", + "tap_graph", + "tap_eip712_message", + "tap_receipt", +] [workspace.package] version = "0.1.0" @@ -18,3 +25,4 @@ rand = "0.8.5" jsonrpsee = { version = "0.24.7", features = ["macros", "server"] } insta = { version = "1.42.0", features = ["json"] } serde_json = { version = "1.0.137", features = ["raw_value"] } +thiserror = "2.0.11" diff --git a/tap_aggregator/Cargo.toml b/tap_aggregator/Cargo.toml index 223cdd5f..182698aa 100644 --- a/tap_aggregator/Cargo.toml +++ b/tap_aggregator/Cargo.toml @@ -15,12 +15,12 @@ path = "src/main.rs" alloy.workspace = true anyhow.workspace = true axum = { version = "0.7.5", features = [ - "http1", - "json", - "matched-path", - "original-uri", - "query", - "tokio", + "http1", + "json", + "matched-path", + "original-uri", + "query", + "tokio", ], default-features = false } clap = { version = "4.5.15", features = ["derive", "env"] } futures-util = "0.3.28" @@ -39,6 +39,7 @@ tokio.workspace = true tonic = { version = "0.12.3", features = ["transport", "zstd"] } tower = { version = "0.5.2", features = ["util", "steer"] } tracing-subscriber = "0.3.17" +tap_graph = { path = "../tap_graph" } [build-dependencies] tonic-build = "0.12.3" diff --git a/tap_aggregator/src/aggregator.rs b/tap_aggregator/src/aggregator.rs index c01e1805..643a214f 100644 --- a/tap_aggregator/src/aggregator.rs +++ b/tap_aggregator/src/aggregator.rs @@ -9,11 +9,8 @@ use alloy::{ }; use anyhow::{bail, Ok, Result}; use rayon::prelude::*; -use tap_core::{ - rav::ReceiptAggregateVoucher, - receipt::Receipt, - signed_message::{EIP712SignedMessage, SignatureBytes, SignatureBytesExt}, -}; +use tap_core::signed_message::{EIP712SignedMessage, SignatureBytes, SignatureBytesExt}; +use tap_graph::{Receipt, ReceiptAggregateVoucher}; pub fn check_and_aggregate_receipts( domain_separator: &Eip712Domain, @@ -137,7 +134,8 @@ mod tests { use alloy::{dyn_abi::Eip712Domain, primitives::Address, signers::local::PrivateKeySigner}; use rstest::*; - use tap_core::{receipt::Receipt, signed_message::EIP712SignedMessage, tap_eip712_domain}; + use tap_core::{signed_message::EIP712SignedMessage, tap_eip712_domain}; + use tap_graph::{Receipt, ReceiptAggregateVoucher}; use crate::aggregator; @@ -242,7 +240,7 @@ mod tests { // Create rav with max_timestamp below the receipts timestamps let rav = EIP712SignedMessage::new( &domain_separator, - tap_core::rav::ReceiptAggregateVoucher { + ReceiptAggregateVoucher { allocationId: allocation_ids[0], timestampNs: receipt_timestamp_range.clone().min().unwrap() - 1, valueAggregate: 42, @@ -256,7 +254,7 @@ mod tests { // Aggregation should fail let rav = EIP712SignedMessage::new( &domain_separator, - tap_core::rav::ReceiptAggregateVoucher { + ReceiptAggregateVoucher { allocationId: allocation_ids[0], timestampNs: receipt_timestamp_range.clone().min().unwrap(), valueAggregate: 42, @@ -270,7 +268,7 @@ mod tests { // Aggregation should fail let rav = EIP712SignedMessage::new( &domain_separator, - tap_core::rav::ReceiptAggregateVoucher { + ReceiptAggregateVoucher { allocationId: allocation_ids[0], timestampNs: receipt_timestamp_range.clone().max().unwrap() + 1, valueAggregate: 42, diff --git a/tap_aggregator/src/grpc.rs b/tap_aggregator/src/grpc.rs index 03c27ea9..2378e567 100644 --- a/tap_aggregator/src/grpc.rs +++ b/tap_aggregator/src/grpc.rs @@ -6,7 +6,7 @@ use tap_core::signed_message::EIP712SignedMessage; tonic::include_proto!("tap_aggregator.v1"); -impl TryFrom for tap_core::receipt::Receipt { +impl TryFrom for tap_graph::Receipt { type Error = anyhow::Error; fn try_from(receipt: Receipt) -> Result { Ok(Self { @@ -18,7 +18,7 @@ impl TryFrom for tap_core::receipt::Receipt { } } -impl TryFrom for tap_core::receipt::SignedReceipt { +impl TryFrom for tap_graph::SignedReceipt { type Error = anyhow::Error; fn try_from(receipt: SignedReceipt) -> Result { Ok(Self { @@ -31,8 +31,8 @@ impl TryFrom for tap_core::receipt::SignedReceipt { } } -impl From for Receipt { - fn from(value: tap_core::receipt::Receipt) -> Self { +impl From for Receipt { + fn from(value: tap_graph::Receipt) -> Self { Self { allocation_id: value.allocation_id.as_slice().to_vec(), timestamp_ns: value.timestamp_ns, @@ -42,8 +42,8 @@ impl From for Receipt { } } -impl From for SignedReceipt { - fn from(value: tap_core::receipt::SignedReceipt) -> Self { +impl From for SignedReceipt { + fn from(value: tap_graph::SignedReceipt) -> Self { Self { message: Some(value.message.into()), signature: value.signature.as_bytes().to_vec(), @@ -51,7 +51,7 @@ impl From for SignedReceipt { } } -impl TryFrom for EIP712SignedMessage { +impl TryFrom for EIP712SignedMessage { type Error = anyhow::Error; fn try_from(voucher: SignedRav) -> Result { Ok(Self { @@ -64,8 +64,8 @@ impl TryFrom for EIP712SignedMessage> for SignedRav { - fn from(voucher: EIP712SignedMessage) -> Self { +impl From> for SignedRav { + fn from(voucher: EIP712SignedMessage) -> Self { Self { signature: voucher.signature.as_bytes().to_vec(), message: Some(voucher.message.into()), @@ -73,7 +73,7 @@ impl From> for Signe } } -impl TryFrom for tap_core::rav::ReceiptAggregateVoucher { +impl TryFrom for tap_graph::ReceiptAggregateVoucher { type Error = anyhow::Error; fn try_from(voucher: ReceiptAggregateVoucher) -> Result { Ok(Self { @@ -87,8 +87,8 @@ impl TryFrom for tap_core::rav::ReceiptAggregateVoucher } } -impl From for ReceiptAggregateVoucher { - fn from(voucher: tap_core::rav::ReceiptAggregateVoucher) -> Self { +impl From for ReceiptAggregateVoucher { + fn from(voucher: tap_graph::ReceiptAggregateVoucher) -> Self { Self { allocation_id: voucher.allocationId.to_vec(), timestamp_ns: voucher.timestampNs, @@ -113,8 +113,8 @@ impl From for Uint128 { impl RavRequest { pub fn new( - receipts: Vec, - previous_rav: Option, + receipts: Vec, + previous_rav: Option, ) -> Self { Self { receipts: receipts.into_iter().map(Into::into).collect(), @@ -124,8 +124,8 @@ impl RavRequest { } impl RavResponse { - pub fn signed_rav(mut self) -> anyhow::Result { - let signed_rav: tap_core::rav::SignedRav = self + pub fn signed_rav(mut self) -> anyhow::Result { + let signed_rav: tap_graph::SignedRav = self .rav .take() .ok_or(anyhow!("Couldn't find rav"))? diff --git a/tap_aggregator/src/server.rs b/tap_aggregator/src/server.rs index ab84ce8b..46796caa 100644 --- a/tap_aggregator/src/server.rs +++ b/tap_aggregator/src/server.rs @@ -14,11 +14,8 @@ use jsonrpsee::{ use lazy_static::lazy_static; use log::info; use prometheus::{register_counter, register_int_counter, Counter, IntCounter}; -use tap_core::{ - rav::ReceiptAggregateVoucher, - receipt::{Receipt, SignedReceipt}, - signed_message::EIP712SignedMessage, -}; +use tap_core::signed_message::EIP712SignedMessage; +use tap_graph::{Receipt, ReceiptAggregateVoucher, SignedReceipt}; use tokio::{net::TcpListener, signal, task::JoinHandle}; use tonic::{codec::CompressionEncoding, service::Routes, Request, Response, Status}; use tower::{layer::util::Identity, make::Shared}; @@ -394,10 +391,8 @@ mod tests { use jsonrpsee::{core::client::ClientT, http_client::HttpClientBuilder, rpc_params}; use rand::{prelude::*, seq::SliceRandom}; use rstest::*; - use tap_core::{ - rav::ReceiptAggregateVoucher, receipt::Receipt, signed_message::EIP712SignedMessage, - tap_eip712_domain, - }; + use tap_core::{signed_message::EIP712SignedMessage, tap_eip712_domain}; + use tap_graph::{Receipt, ReceiptAggregateVoucher}; use crate::server; diff --git a/tap_aggregator/tests/aggregate_test.rs b/tap_aggregator/tests/aggregate_test.rs index 86bb23f6..bc6d0c66 100644 --- a/tap_aggregator/tests/aggregate_test.rs +++ b/tap_aggregator/tests/aggregate_test.rs @@ -10,10 +10,8 @@ use tap_aggregator::{ jsonrpsee_helpers::JsonRpcResponse, server, }; -use tap_core::{ - rav::ReceiptAggregateVoucher, receipt::Receipt, signed_message::EIP712SignedMessage, - tap_eip712_domain, -}; +use tap_core::{signed_message::EIP712SignedMessage, tap_eip712_domain}; +use tap_graph::{Receipt, ReceiptAggregateVoucher}; use tonic::codec::CompressionEncoding; #[tokio::test] @@ -64,11 +62,11 @@ async fn aggregation_test() { let rav_request = RavRequest::new(receipts.clone(), None); let res = client.aggregate_receipts(rav_request).await.unwrap(); - let signed_rav: tap_core::rav::SignedRav = res.into_inner().signed_rav().unwrap(); + let signed_rav: tap_graph::SignedRav = res.into_inner().signed_rav().unwrap(); let sender_aggregator = HttpClientBuilder::default().build(&endpoint).unwrap(); - let previous_rav: Option = None; + let previous_rav: Option = None; let response: JsonRpcResponse> = sender_aggregator .request( diff --git a/tap_core/Cargo.toml b/tap_core/Cargo.toml index 9dd8c55b..a0477031 100644 --- a/tap_core/Cargo.toml +++ b/tap_core/Cargo.toml @@ -10,12 +10,14 @@ description = "Core Timeline Aggregation Protocol library: a fast, efficient and [dependencies] alloy.workspace = true anyhow.workspace = true -anymap3 = "1.0.1" async-trait = "0.1.85" rand.workspace = true serde.workspace = true -thiserror = "2.0.11" +thiserror.workspace = true tokio.workspace = true +tap_receipt = { path = "../tap_receipt" } +tap_eip712_message = { path = "../tap_eip712_message" } +tap_graph = { path = "../tap_graph", optional = true } [dev-dependencies] criterion = { version = "0.5.1", features = ["async_std"] } @@ -25,7 +27,7 @@ serde_json.workspace = true [features] default = ["in_memory"] -in_memory = [] +in_memory = ["dep:tap_graph"] [[bench]] name = 'timeline_aggretion_protocol_benchmark' diff --git a/tap_core/benches/timeline_aggretion_protocol_benchmark.rs b/tap_core/benches/timeline_aggretion_protocol_benchmark.rs index 69052919..a2ed91ea 100644 --- a/tap_core/benches/timeline_aggretion_protocol_benchmark.rs +++ b/tap_core/benches/timeline_aggretion_protocol_benchmark.rs @@ -12,10 +12,8 @@ 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, - tap_eip712_domain, -}; +use tap_core::{signed_message::EIP712SignedMessage, tap_eip712_domain}; +use tap_graph::{Receipt, ReceiptAggregateVoucher}; pub fn create_and_sign_receipt( domain_separator: &Eip712Domain, diff --git a/tap_core/src/error.rs b/tap_core/src/error.rs index 17d5ac82..11a381c4 100644 --- a/tap_core/src/error.rs +++ b/tap_core/src/error.rs @@ -6,7 +6,7 @@ use std::result::Result as StdResult; -use alloy::primitives::{Address, SignatureError}; +use alloy::primitives::Address; use thiserror::Error as ThisError; use crate::receipt::ReceiptError; @@ -26,7 +26,7 @@ pub enum Error { /// `alloy` wallet error #[error(transparent)] - SignatureError(#[from] SignatureError), + SignatureError(#[from] tap_eip712_message::Eip712Error), /// Error when signature verification fails #[error("Expected address {expected} but received {received}")] diff --git a/tap_core/src/lib.rs b/tap_core/src/lib.rs index eb09fe67..9bf28dbc 100644 --- a/tap_core/src/lib.rs +++ b/tap_core/src/lib.rs @@ -13,7 +13,7 @@ use thiserror::Error; mod error; pub mod manager; -pub mod rav; +pub mod rav_request; pub mod receipt; pub mod signed_message; @@ -62,11 +62,9 @@ mod tap_tests { use alloy::{dyn_abi::Eip712Domain, primitives::Address, signers::local::PrivateKeySigner}; use rstest::*; + use tap_graph::{Receipt, ReceiptAggregateVoucher}; - use crate::{ - rav::ReceiptAggregateVoucher, receipt::Receipt, signed_message::EIP712SignedMessage, - tap_eip712_domain, - }; + use crate::{signed_message::EIP712SignedMessage, tap_eip712_domain}; #[fixture] fn keys() -> (PrivateKeySigner, Address) { diff --git a/tap_core/src/manager/context/memory.rs b/tap_core/src/manager/context/memory.rs index 24673b41..962c8e0f 100644 --- a/tap_core/src/manager/context/memory.rs +++ b/tap_core/src/manager/context/memory.rs @@ -14,11 +14,11 @@ use std::{ use alloy::primitives::Address; use async_trait::async_trait; +use tap_graph::{ReceiptAggregateVoucher, SignedRav, SignedReceipt}; use crate::{ manager::adapters::*, - rav::{ReceiptAggregateVoucher, SignedRav}, - receipt::{checks::StatefulTimestampCheck, state::Checking, ReceiptWithState, SignedReceipt}, + receipt::{checks::StatefulTimestampCheck, state::Checking, ReceiptWithState}, signed_message::MessageId, }; @@ -259,12 +259,13 @@ pub mod checks { }; use alloy::{dyn_abi::Eip712Domain, primitives::Address}; + use tap_graph::SignedReceipt; use crate::{ receipt::{ checks::{Check, CheckError, CheckResult, ReceiptCheck}, state::Checking, - Context, ReceiptError, ReceiptWithState, SignedReceipt, + Context, ReceiptError, ReceiptWithState, }, signed_message::MessageId, }; diff --git a/tap_core/src/manager/mod.rs b/tap_core/src/manager/mod.rs index 7d34df82..42ef6eed 100644 --- a/tap_core/src/manager/mod.rs +++ b/tap_core/src/manager/mod.rs @@ -42,7 +42,6 @@ //! ReceiptError, //! Context //! }, -//! rav::ReceiptAggregateVoucher, //! manager::{ //! Manager, //! adapters::ReceiptStore @@ -63,7 +62,7 @@ //! # #[tokio::main] //! # async fn main() { //! # use alloy::{dyn_abi::Eip712Domain, primitives::Address, signers::local::PrivateKeySigner}; -//! # use tap_core::receipt::{Receipt, SignedReceipt}; +//! # use tap_graph::{Receipt, SignedReceipt, ReceiptAggregateVoucher}; //! # use tap_core::signed_message::EIP712SignedMessage; //! # let domain_separator = Eip712Domain::default(); //! # let wallet = PrivateKeySigner::random(); diff --git a/tap_core/src/manager/tap_manager.rs b/tap_core/src/manager/tap_manager.rs index 39f0dae1..31d6899b 100644 --- a/tap_core/src/manager/tap_manager.rs +++ b/tap_core/src/manager/tap_manager.rs @@ -4,12 +4,13 @@ use std::marker::PhantomData; use alloy::{dyn_abi::Eip712Domain, sol_types::SolStruct}; +use tap_receipt::rav::Aggregate; use super::adapters::{ RavRead, RavStore, ReceiptDelete, ReceiptRead, ReceiptStore, SignatureChecker, }; use crate::{ - rav::{Aggregate, RavRequest}, + rav_request::RavRequest, receipt::{ checks::{CheckBatch, CheckList, TimestampCheck, UniqueCheck}, state::{Checked, Failed}, diff --git a/tap_core/src/rav/request.rs b/tap_core/src/rav_request.rs similarity index 89% rename from tap_core/src/rav/request.rs rename to tap_core/src/rav_request.rs index 8d23e75c..eba06924 100644 --- a/tap_core/src/rav/request.rs +++ b/tap_core/src/rav_request.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use alloy::sol_types::SolStruct; +use tap_receipt::rav::AggregationError; use crate::{ receipt::{ @@ -9,7 +10,6 @@ use crate::{ ReceiptWithState, }, signed_message::EIP712SignedMessage, - Error, }; /// Request to `tap_aggregator` to aggregate receipts into a Signed RAV. @@ -22,5 +22,5 @@ pub struct RavRequest { /// List of failed receipt used to log invalid receipts pub invalid_receipts: Vec>, /// Expected RAV to be created - pub expected_rav: Result, + pub expected_rav: Result, } diff --git a/tap_core/src/receipt.rs b/tap_core/src/receipt.rs new file mode 100644 index 00000000..6171870d --- /dev/null +++ b/tap_core/src/receipt.rs @@ -0,0 +1,4 @@ +// Copyright 2023-, Semiotic AI, Inc. +// SPDX-License-Identifier: Apache-2.0 +// +pub use ::tap_receipt::*; diff --git a/tap_core/src/signed_message.rs b/tap_core/src/signed_message.rs index f0cebec6..a886a512 100644 --- a/tap_core/src/signed_message.rs +++ b/tap_core/src/signed_message.rs @@ -1,144 +1,4 @@ // Copyright 2023-, Semiotic AI, Inc. // SPDX-License-Identifier: Apache-2.0 -//! # EIP712 message and signature -//! -//! This module contains the `EIP712SignedMessage` struct which is used to sign and verify messages -//! using EIP712 standard. -//! -//! # Example -//! ```rust -//! # use alloy::{dyn_abi::Eip712Domain, primitives::Address, signers::local::PrivateKeySigner}; -//! # let domain_separator = Eip712Domain::default(); -//! use tap_core::{ -//! signed_message::EIP712SignedMessage, -//! receipt::Receipt -//! }; -//! # let wallet = PrivateKeySigner::random(); -//! # let wallet_address = wallet.address(); -//! # let message = Receipt::new(Address::from([0x11u8; 20]), 100).unwrap(); -//! -//! let signed_message = EIP712SignedMessage::new(&domain_separator, message, &wallet).unwrap(); -//! let signer = signed_message.recover_signer(&domain_separator).unwrap(); -//! -//! assert_eq!(signer, wallet_address); -//! ``` -//! - -use alloy::{ - dyn_abi::Eip712Domain, - primitives::{Address, PrimitiveSignature as Signature}, - signers::{local::PrivateKeySigner, SignerSync}, - sol_types::SolStruct, -}; -use serde::{Deserialize, Serialize}; - -use crate::{ - receipt::{WithUniqueId, WithValueAndTimestamp}, - Result, -}; - -/// EIP712 signed message -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] -pub struct EIP712SignedMessage { - /// Message to be signed - pub message: M, - /// ECDSA Signature of eip712 hash of message - pub signature: Signature, -} - -#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct SignatureBytes([u8; 65]); - -pub trait SignatureBytesExt { - fn get_signature_bytes(&self) -> SignatureBytes; -} - -impl SignatureBytesExt for Signature { - fn get_signature_bytes(&self) -> SignatureBytes { - SignatureBytes(self.as_bytes()) - } -} - -/// Unique identifier for a message -/// -/// This is equal to the hash of the contents of a message, excluding the signature. -/// This means that two receipts signed by two different signers will have the same id. -/// -/// -/// This cannot be used as a unique identifier for a message, but can be used as a key -/// for a hashmap where the value is the message. -#[derive(Debug, Eq, PartialEq, Hash)] -pub struct MessageId(pub [u8; 32]); - -impl EIP712SignedMessage { - /// Creates a signed message with signed EIP712 hash of `message` using `signing_wallet` - pub fn new( - domain_separator: &Eip712Domain, - message: M, - signing_wallet: &PrivateKeySigner, - ) -> Result { - let recovery_message_hash = message.eip712_signing_hash(domain_separator); - - let signature = signing_wallet.sign_hash_sync(&recovery_message_hash)?; - - Ok(Self { message, signature }) - } - - /// Recovers and returns the signer of the message from the signature. - pub fn recover_signer(&self, domain_separator: &Eip712Domain) -> Result
{ - let recovery_message_hash = self.message.eip712_signing_hash(domain_separator); - let recovered_address = self - .signature - .recover_address_from_prehash(&recovery_message_hash)?; - Ok(recovered_address) - } - - /// Checks that receipts signature is valid for given verifying key, returns `Ok` if it is valid. - /// - /// # Errors - /// - /// Returns [`crate::Error::SignatureError`] if the recovered address from the - /// signature is not equal to `expected_address` - /// - pub fn verify(&self, domain_separator: &Eip712Domain, expected_address: Address) -> Result<()> { - let recovered_address = self.recover_signer(domain_separator)?; - if recovered_address != expected_address { - Err(crate::Error::VerificationFailed { - expected: expected_address, - received: recovered_address, - }) - } else { - Ok(()) - } - } - - /// Use this a simple key for testing - pub fn unique_hash(&self) -> MessageId { - MessageId(self.message.eip712_hash_struct().into()) - } -} - -impl WithUniqueId for EIP712SignedMessage -where - M: SolStruct, -{ - type Output = SignatureBytes; - - fn unique_id(&self) -> Self::Output { - self.signature.get_signature_bytes() - } -} - -impl WithValueAndTimestamp for EIP712SignedMessage -where - T: WithValueAndTimestamp + SolStruct, -{ - fn value(&self) -> u128 { - self.message.value() - } - - fn timestamp_ns(&self) -> u64 { - self.message.timestamp_ns() - } -} +pub use ::tap_eip712_message::*; diff --git a/tap_core/tests/manager_test.rs b/tap_core/tests/manager_test.rs index 7b035635..9a255712 100644 --- a/tap_core/tests/manager_test.rs +++ b/tap_core/tests/manager_test.rs @@ -23,15 +23,15 @@ use tap_core::{ }, Manager, }, - rav::ReceiptAggregateVoucher, receipt::{ checks::{Check, CheckError, CheckList, StatefulTimestampCheck}, state::Checking, - Context, Receipt, ReceiptWithState, SignedReceipt, + Context, ReceiptWithState, }, signed_message::EIP712SignedMessage, tap_eip712_domain, }; +use tap_graph::{Receipt, ReceiptAggregateVoucher, SignedReceipt}; #[fixture] fn signer() -> PrivateKeySigner { diff --git a/tap_core/tests/rav_test.rs b/tap_core/tests/rav_test.rs index ad2c58d9..1c0cadf8 100644 --- a/tap_core/tests/rav_test.rs +++ b/tap_core/tests/rav_test.rs @@ -19,11 +19,11 @@ use tap_core::{ adapters::{RavRead, RavStore}, context::memory::InMemoryContext, }, - rav::ReceiptAggregateVoucher, - receipt::{checks::StatefulTimestampCheck, Receipt}, + receipt::checks::StatefulTimestampCheck, signed_message::EIP712SignedMessage, tap_eip712_domain, }; +use tap_graph::{Receipt, ReceiptAggregateVoucher}; #[fixture] fn domain_separator() -> Eip712Domain { diff --git a/tap_core/tests/receipt_test.rs b/tap_core/tests/receipt_test.rs index 201c49bd..5b4dcf56 100644 --- a/tap_core/tests/receipt_test.rs +++ b/tap_core/tests/receipt_test.rs @@ -1,3 +1,6 @@ +// Copyright 2023-, Semiotic AI, Inc. +// SPDX-License-Identifier: Apache-2.0 + use std::{ collections::HashMap, str::FromStr, @@ -5,19 +8,15 @@ use std::{ }; use alloy::{dyn_abi::Eip712Domain, primitives::Address, signers::local::PrivateKeySigner}; -// Copyright 2023-, Semiotic AI, Inc. -// SPDX-License-Identifier: Apache-2.0 -use rand::seq::SliceRandom; -use rand::thread_rng; +use rand::{seq::SliceRandom, thread_rng}; use rstest::*; use tap_core::{ manager::{adapters::ReceiptStore, context::memory::InMemoryContext}, - receipt::{ - checks::StatefulTimestampCheck, state::Checking, Receipt, ReceiptWithState, SignedReceipt, - }, + receipt::{checks::StatefulTimestampCheck, state::Checking, ReceiptWithState}, signed_message::EIP712SignedMessage, tap_eip712_domain, }; +use tap_graph::{Receipt, SignedReceipt}; #[fixture] fn domain_separator() -> Eip712Domain { diff --git a/tap_core/tests/received_receipt_test.rs b/tap_core/tests/received_receipt_test.rs index 1bcdf9ca..86f2215f 100644 --- a/tap_core/tests/received_receipt_test.rs +++ b/tap_core/tests/received_receipt_test.rs @@ -13,11 +13,12 @@ use tap_core::{ manager::context::memory::{checks::get_full_list_of_checks, EscrowStorage, QueryAppraisals}, receipt::{ checks::{ReceiptCheck, StatefulTimestampCheck}, - Context, Receipt, ReceiptWithState, SignedReceipt, + Context, ReceiptWithState, }, signed_message::EIP712SignedMessage, tap_eip712_domain, }; +use tap_graph::{Receipt, SignedReceipt}; #[fixture] fn signer() -> PrivateKeySigner { diff --git a/tap_eip712_message/Cargo.toml b/tap_eip712_message/Cargo.toml new file mode 100644 index 00000000..69541aa2 --- /dev/null +++ b/tap_eip712_message/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "tap_eip712_message" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +alloy.workspace = true +serde.workspace = true +thiserror.workspace = true + + +[dev-dependencies] +msg = { path = "../tap_graph", package = "tap_graph" } diff --git a/tap_eip712_message/src/lib.rs b/tap_eip712_message/src/lib.rs new file mode 100644 index 00000000..f8e8dca5 --- /dev/null +++ b/tap_eip712_message/src/lib.rs @@ -0,0 +1,134 @@ +// Copyright 2023-, Semiotic AI, Inc. +// SPDX-License-Identifier: Apache-2.0 + +//! # EIP712 message and signature +//! +//! This module contains the `EIP712SignedMessage` struct which is used to sign and verify messages +//! using EIP712 standard. +//! +//! # Example +//! ```rust +//! # use alloy::{dyn_abi::Eip712Domain, primitives::Address, signers::local::PrivateKeySigner}; +//! # let domain_separator = Eip712Domain::default(); +//! use tap_eip712_message::EIP712SignedMessage; +//! # let wallet = PrivateKeySigner::random(); +//! # let wallet_address = wallet.address(); +//! # let message = msg::Receipt::new(Address::from([0x11u8; 20]), 100).unwrap(); +//! +//! let signed_message = EIP712SignedMessage::new(&domain_separator, message, &wallet).unwrap(); +//! let signer = signed_message.recover_signer(&domain_separator).unwrap(); +//! +//! assert_eq!(signer, wallet_address); +//! ``` +//! + +use alloy::{ + dyn_abi::Eip712Domain, + primitives::{Address, PrimitiveSignature as Signature}, + signers::{local::PrivateKeySigner, SignerSync}, + sol_types::SolStruct, +}; +use serde::{Deserialize, Serialize}; + +#[derive(thiserror::Error, Debug)] +pub enum Eip712Error { + /// `alloy` wallet error + #[error(transparent)] + WalletError(#[from] alloy::signers::Error), + + /// `alloy` wallet error + #[error(transparent)] + SignatureError(#[from] alloy::primitives::SignatureError), + + /// Error when signature verification fails + #[error("Expected address {expected} but received {received}")] + VerificationFailed { + expected: Address, + received: Address, + }, +} + +/// EIP712 signed message +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct EIP712SignedMessage { + /// Message to be signed + pub message: M, + /// ECDSA Signature of eip712 hash of message + pub signature: Signature, +} + +#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct SignatureBytes([u8; 65]); + +pub trait SignatureBytesExt { + fn get_signature_bytes(&self) -> SignatureBytes; +} + +impl SignatureBytesExt for Signature { + fn get_signature_bytes(&self) -> SignatureBytes { + SignatureBytes(self.as_bytes()) + } +} + +/// Unique identifier for a message +/// +/// This is equal to the hash of the contents of a message, excluding the signature. +/// This means that two receipts signed by two different signers will have the same id. +/// +/// +/// This cannot be used as a unique identifier for a message, but can be used as a key +/// for a hashmap where the value is the message. +#[derive(Debug, Eq, PartialEq, Hash)] +pub struct MessageId(pub [u8; 32]); + +impl EIP712SignedMessage { + /// Creates a signed message with signed EIP712 hash of `message` using `signing_wallet` + pub fn new( + domain_separator: &Eip712Domain, + message: M, + signing_wallet: &PrivateKeySigner, + ) -> Result { + let recovery_message_hash = message.eip712_signing_hash(domain_separator); + + let signature = signing_wallet.sign_hash_sync(&recovery_message_hash)?; + + Ok(Self { message, signature }) + } + + /// Recovers and returns the signer of the message from the signature. + pub fn recover_signer(&self, domain_separator: &Eip712Domain) -> Result { + let recovery_message_hash = self.message.eip712_signing_hash(domain_separator); + let recovered_address = self + .signature + .recover_address_from_prehash(&recovery_message_hash)?; + Ok(recovered_address) + } + + /// Checks that receipts signature is valid for given verifying key, returns `Ok` if it is valid. + /// + /// # Errors + /// + /// Returns [`crate::Error::SignatureError`] if the recovered address from the + /// signature is not equal to `expected_address` + /// + pub fn verify( + &self, + domain_separator: &Eip712Domain, + expected_address: Address, + ) -> Result<(), Eip712Error> { + let recovered_address = self.recover_signer(domain_separator)?; + if recovered_address != expected_address { + Err(Eip712Error::VerificationFailed { + expected: expected_address, + received: recovered_address, + }) + } else { + Ok(()) + } + } + + /// Use this a simple key for testing + pub fn unique_hash(&self) -> MessageId { + MessageId(self.message.eip712_hash_struct().into()) + } +} diff --git a/tap_graph/Cargo.toml b/tap_graph/Cargo.toml new file mode 100644 index 00000000..ccd90e94 --- /dev/null +++ b/tap_graph/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "tap_graph" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +alloy.workspace = true +serde.workspace = true +rand.workspace = true +thiserror.workspace = true +tap_eip712_message = { path = "../tap_eip712_message" } +tap_receipt = { path = "../tap_receipt" } + + +[dev-dependencies] +rstest.workspace = true diff --git a/tap_graph/src/lib.rs b/tap_graph/src/lib.rs new file mode 100644 index 00000000..4d9f9a2f --- /dev/null +++ b/tap_graph/src/lib.rs @@ -0,0 +1,26 @@ +// Copyright 2023-, Semiotic AI, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use std::time::{SystemTime, UNIX_EPOCH}; + +mod rav; +mod receipt; + +pub use rav::{ReceiptAggregateVoucher, SignedRav}; +pub use receipt::{Receipt, SignedReceipt}; + +#[derive(Debug, thiserror::Error)] +pub enum Error { + /// Error when Rust fails to get the current system time + #[error("Failed to get current system time: {source_error_message} ")] + InvalidSystemTime { source_error_message: String }, +} + +fn get_current_timestamp_u64_ns() -> Result { + Ok(SystemTime::now() + .duration_since(UNIX_EPOCH) + .map_err(|err| Error::InvalidSystemTime { + source_error_message: err.to_string(), + })? + .as_nanos() as u64) +} diff --git a/tap_core/src/rav.rs b/tap_graph/src/rav.rs similarity index 85% rename from tap_core/src/rav.rs rename to tap_graph/src/rav.rs index 03222393..32637b7f 100644 --- a/tap_core/src/rav.rs +++ b/tap_graph/src/rav.rs @@ -37,31 +37,21 @@ //! Rav requests should be created using the //! [`crate::manager::Manager::create_rav_request`] function. -mod request; - use std::cmp; -use alloy::{primitives::Address, sol, sol_types::SolStruct}; +use alloy::{primitives::Address, sol}; use serde::{Deserialize, Serialize}; - -use crate::{ - receipt::{state::Checked, Receipt, ReceiptWithState, SignedReceipt, WithValueAndTimestamp}, - signed_message::EIP712SignedMessage, - Error, +use tap_eip712_message::EIP712SignedMessage; +use tap_receipt::{ + rav::{Aggregate, AggregationError}, + state::Checked, + ReceiptWithState, WithValueAndTimestamp, }; +use crate::{receipt::Receipt, SignedReceipt}; + /// EIP712 signed message for ReceiptAggregateVoucher pub type SignedRav = EIP712SignedMessage; -pub use request::RavRequest; - -pub trait Aggregate: SolStruct { - /// Aggregates a batch of validated receipts with optional validated previous RAV, - /// returning a new RAV if all provided items are valid or an error if not. - fn aggregate_receipts( - receipts: &[ReceiptWithState], - previous_rav: Option>, - ) -> Result; -} sol! { /// Holds information needed for promise of payment signed with ECDSA @@ -92,7 +82,7 @@ impl ReceiptAggregateVoucher { allocation_id: Address, receipts: &[EIP712SignedMessage], previous_rav: Option>, - ) -> crate::Result { + ) -> Result { //TODO(#29): When receipts in flight struct in created check that the state // of every receipt is OK with all checks complete (relies on #28) // If there is a previous RAV get initialize values from it, otherwise get default values @@ -107,7 +97,7 @@ impl ReceiptAggregateVoucher { for receipt in receipts { value_aggregate = value_aggregate .checked_add(receipt.message.value) - .ok_or(Error::AggregateOverflow)?; + .ok_or(AggregationError::AggregateOverflow)?; timestamp_max = cmp::max(timestamp_max, receipt.message.timestamp_ns) } @@ -124,9 +114,9 @@ impl Aggregate for ReceiptAggregateVoucher { fn aggregate_receipts( receipts: &[ReceiptWithState], previous_rav: Option>, - ) -> Result { + ) -> Result { if receipts.is_empty() { - return Err(Error::NoValidReceiptsForRavRequest); + return Err(AggregationError::NoValidReceiptsForRavRequest); } let allocation_id = receipts[0].signed_receipt().message.allocation_id; let receipts = receipts diff --git a/tap_core/src/receipt/receipt_sol.rs b/tap_graph/src/receipt.rs similarity index 94% rename from tap_core/src/receipt/receipt_sol.rs rename to tap_graph/src/receipt.rs index ec2824df..136adf05 100644 --- a/tap_core/src/receipt/receipt_sol.rs +++ b/tap_graph/src/receipt.rs @@ -11,8 +11,11 @@ use alloy::{primitives::Address, sol}; use rand::{thread_rng, Rng}; use serde::{Deserialize, Serialize}; +use tap_eip712_message::EIP712SignedMessage; +use tap_receipt::WithValueAndTimestamp; -use super::WithValueAndTimestamp; +/// A signed receipt message +pub type SignedReceipt = EIP712SignedMessage; sol! { /// Holds information needed for promise of payment signed with ECDSA @@ -31,7 +34,7 @@ sol! { impl Receipt { /// Returns a receipt with provided values - pub fn new(allocation_id: Address, value: u128) -> crate::Result { + pub fn new(allocation_id: Address, value: u128) -> Result { let timestamp_ns = crate::get_current_timestamp_u64_ns()?; let nonce = thread_rng().gen::(); Ok(Self { diff --git a/tap_integration_tests/Cargo.toml b/tap_integration_tests/Cargo.toml index 1d4a6420..6be70440 100644 --- a/tap_integration_tests/Cargo.toml +++ b/tap_integration_tests/Cargo.toml @@ -17,7 +17,7 @@ tokio.workspace = true alloy.workspace = true jsonrpsee = { workspace = true, features = ["jsonrpsee-http-client"] } jsonrpsee-core = "0.24.7" - +tap_graph = { path = "../tap_graph" } [dev-dependencies] rstest.workspace = true diff --git a/tap_integration_tests/tests/indexer_mock.rs b/tap_integration_tests/tests/indexer_mock.rs index 57069858..98d86599 100644 --- a/tap_integration_tests/tests/indexer_mock.rs +++ b/tap_integration_tests/tests/indexer_mock.rs @@ -21,9 +21,9 @@ use tap_core::{ adapters::{RavRead, RavStore, ReceiptRead, ReceiptStore, SignatureChecker}, Manager, }, - rav::{ReceiptAggregateVoucher, SignedRav}, - receipt::{checks::CheckList, Context, SignedReceipt}, + receipt::{checks::CheckList, Context}, }; +use tap_graph::{ReceiptAggregateVoucher, SignedRav, SignedReceipt}; /// Rpc trait represents a JSON-RPC server that has a single async method `request`. /// This method is designed to handle incoming JSON-RPC requests. #[rpc(server)] diff --git a/tap_integration_tests/tests/showcase.rs b/tap_integration_tests/tests/showcase.rs index bc751c31..5c5eb2b0 100644 --- a/tap_integration_tests/tests/showcase.rs +++ b/tap_integration_tests/tests/showcase.rs @@ -26,14 +26,11 @@ use rstest::*; use tap_aggregator::{jsonrpsee_helpers, server as agg_server}; use tap_core::{ manager::context::memory::{checks::get_full_list_of_checks, *}, - rav::SignedRav, - receipt::{ - checks::{CheckList, StatefulTimestampCheck}, - Receipt, SignedReceipt, - }, + receipt::checks::{CheckList, StatefulTimestampCheck}, signed_message::{EIP712SignedMessage, MessageId}, tap_eip712_domain, }; +use tap_graph::{Receipt, SignedRav, SignedReceipt}; use tokio::task::JoinHandle; use crate::indexer_mock; diff --git a/tap_receipt/Cargo.toml b/tap_receipt/Cargo.toml new file mode 100644 index 00000000..ab2fadff --- /dev/null +++ b/tap_receipt/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "tap_receipt" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +alloy.workspace = true +anyhow.workspace = true +anymap3 = "1.0.1" +thiserror.workspace = true +serde.workspace = true +async-trait = "0.1.85" +tap_eip712_message = { path = "../tap_eip712_message" } + +[dev-dependencies] +tokio.workspace = true diff --git a/tap_core/src/receipt/checks.rs b/tap_receipt/src/checks.rs similarity index 92% rename from tap_core/src/receipt/checks.rs rename to tap_receipt/src/checks.rs index 7f539270..b50be069 100644 --- a/tap_core/src/receipt/checks.rs +++ b/tap_receipt/src/checks.rs @@ -10,11 +10,12 @@ //! //! ```rust //! # use std::sync::Arc; -//! use tap_core::{ -//! receipt::checks::{Check, CheckResult, ReceiptCheck}, -//! receipt::{Context, ReceiptWithState, state::Checking, SignedReceipt} +//! use tap_receipt::{ +//! checks::{Check, CheckResult, ReceiptCheck}, +//! Context, ReceiptWithState, state::Checking //! }; //! # use async_trait::async_trait; +//! # struct SignedReceipt; //! //! struct MyCheck; //! @@ -208,25 +209,36 @@ where #[cfg(test)] mod tests { - use std::{ - str::FromStr, - time::{Duration, SystemTime}, - }; + use std::time::{Duration, SystemTime}; use alloy::{ - dyn_abi::Eip712Domain, primitives::Address, signers::local::PrivateKeySigner, + dyn_abi::Eip712Domain, primitives::Address, signers::local::PrivateKeySigner, sol, sol_types::eip712_domain, }; + use tap_eip712_message::EIP712SignedMessage; use super::*; - use crate::{ - receipt::{Receipt, SignedReceipt}, - signed_message::EIP712SignedMessage, - }; + + sol! { + struct MyReceipt { + uint64 timestamp_ns; + uint128 value; + } + } + + impl WithValueAndTimestamp for MyReceipt { + fn value(&self) -> u128 { + self.value + } + + fn timestamp_ns(&self) -> u64 { + self.timestamp_ns + } + } fn create_signed_receipt_with_custom_value( value: u128, - ) -> ReceiptWithState { + ) -> ReceiptWithState> { let wallet: PrivateKeySigner = PrivateKeySigner::random(); let eip712_domain_separator: Eip712Domain = eip712_domain! { name: "TAP", @@ -243,13 +255,9 @@ mod tests { let timestamp_ns = timestamp as u64; let value: u128 = value; - let nonce: u64 = 10; let receipt = EIP712SignedMessage::new( &eip712_domain_separator, - Receipt { - allocation_id: Address::from_str("0xabababababababababababababababababababab") - .unwrap(), - nonce, + MyReceipt { timestamp_ns, value, }, diff --git a/tap_core/src/receipt/error.rs b/tap_receipt/src/error.rs similarity index 100% rename from tap_core/src/receipt/error.rs rename to tap_receipt/src/error.rs diff --git a/tap_core/src/receipt/mod.rs b/tap_receipt/src/lib.rs similarity index 72% rename from tap_core/src/receipt/mod.rs rename to tap_receipt/src/lib.rs index 48e2c5f3..6a88c87c 100644 --- a/tap_core/src/receipt/mod.rs +++ b/tap_receipt/src/lib.rs @@ -21,18 +21,14 @@ //! pub mod checks; mod error; -mod receipt_sol; +pub mod rav; mod received_receipt; pub mod state; +use alloy::sol_types::SolStruct; pub use error::ReceiptError; -pub use receipt_sol::Receipt; pub use received_receipt::ReceiptWithState; - -use crate::signed_message::EIP712SignedMessage; - -/// A signed receipt message -pub type SignedReceipt = EIP712SignedMessage; +use tap_eip712_message::{EIP712SignedMessage, SignatureBytes, SignatureBytesExt}; /// Result type for receipt pub type ReceiptResult = Result; @@ -48,3 +44,27 @@ pub trait WithUniqueId { type Output: Eq + std::hash::Hash; fn unique_id(&self) -> Self::Output; } + +impl WithValueAndTimestamp for EIP712SignedMessage +where + T: SolStruct + WithValueAndTimestamp, +{ + fn value(&self) -> u128 { + self.message.value() + } + + fn timestamp_ns(&self) -> u64 { + self.message.timestamp_ns() + } +} + +impl WithUniqueId for EIP712SignedMessage +where + T: SolStruct, +{ + type Output = SignatureBytes; + + fn unique_id(&self) -> Self::Output { + self.signature.get_signature_bytes() + } +} diff --git a/tap_receipt/src/rav.rs b/tap_receipt/src/rav.rs new file mode 100644 index 00000000..3c275779 --- /dev/null +++ b/tap_receipt/src/rav.rs @@ -0,0 +1,27 @@ +// Copyright 2023-, Semiotic AI, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use alloy::sol_types::SolStruct; +use tap_eip712_message::EIP712SignedMessage; + +use crate::{state::Checked, ReceiptWithState}; + +pub trait Aggregate: SolStruct { + /// Aggregates a batch of validated receipts with optional validated previous RAV, + /// returning a new RAV if all provided items are valid or an error if not. + fn aggregate_receipts( + receipts: &[ReceiptWithState], + previous_rav: Option>, + ) -> Result; +} + +#[derive(Debug, thiserror::Error)] +pub enum AggregationError { + /// Error when trying to aggregate receipts and the result overflows + #[error("Aggregating receipt results in overflow")] + AggregateOverflow, + + /// Error when no valid receipts are found for a RAV request + #[error("Failed to produce rav request, no valid receipts")] + NoValidReceiptsForRavRequest, +} diff --git a/tap_core/src/receipt/received_receipt.rs b/tap_receipt/src/received_receipt.rs similarity index 99% rename from tap_core/src/receipt/received_receipt.rs rename to tap_receipt/src/received_receipt.rs index f1870785..4ee41421 100644 --- a/tap_core/src/receipt/received_receipt.rs +++ b/tap_receipt/src/received_receipt.rs @@ -14,7 +14,7 @@ //! their progress through various checks and stages of inclusion in RAV requests and received RAVs. use super::{checks::CheckError, Context, ReceiptError, ReceiptResult}; -use crate::receipt::{ +use crate::{ checks::ReceiptCheck, state::{Checked, Checking, Failed, ReceiptState}, }; diff --git a/tap_core/src/receipt/state.rs b/tap_receipt/src/state.rs similarity index 96% rename from tap_core/src/receipt/state.rs rename to tap_receipt/src/state.rs index 78f1f3de..3ddff162 100644 --- a/tap_core/src/receipt/state.rs +++ b/tap_receipt/src/state.rs @@ -7,7 +7,7 @@ //! state of a receipt. //! The `ReceiptState` trait represents the different states a receipt can be in. -use crate::receipt::ReceiptError; +use crate::ReceiptError; /// Checking state represents a receipt that is currently being checked. #[derive(Debug, Clone)] From c70bec1a8d6ac65cc1d8163cbff9b8127a521880 Mon Sep 17 00:00:00 2001 From: Gustavo Inacio Date: Tue, 28 Jan 2025 09:52:22 +0100 Subject: [PATCH 2/4] docs: fix typo Signed-off-by: Gustavo Inacio --- tap_eip712_message/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tap_eip712_message/src/lib.rs b/tap_eip712_message/src/lib.rs index f8e8dca5..40bb237b 100644 --- a/tap_eip712_message/src/lib.rs +++ b/tap_eip712_message/src/lib.rs @@ -127,7 +127,7 @@ impl EIP712SignedMessage { } } - /// Use this a simple key for testing + /// Use this as a simple key for testing pub fn unique_hash(&self) -> MessageId { MessageId(self.message.eip712_hash_struct().into()) } From 7024558069989494ebcc9249ed9da9e5b9783b12 Mon Sep 17 00:00:00 2001 From: Gustavo Inacio Date: Tue, 28 Jan 2025 10:48:41 +0100 Subject: [PATCH 3/4] ci: update release-please publish packages Signed-off-by: Gustavo Inacio --- release-please-config.json | 3 +++ tap_aggregator/Cargo.toml | 2 +- tap_core/Cargo.toml | 6 +++--- tap_eip712_message/Cargo.toml | 3 ++- tap_graph/Cargo.toml | 7 ++++--- tap_receipt/Cargo.toml | 5 +++-- 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/release-please-config.json b/release-please-config.json index c0b75c95..7e02b5c8 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -4,6 +4,9 @@ "draft": false, "packages": { "tap_core": {}, + "tap_graph": {}, + "tap_eip712_message": {}, + "tap_receipt": {}, "tap_aggregator": { "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": true, diff --git a/tap_aggregator/Cargo.toml b/tap_aggregator/Cargo.toml index 182698aa..ce1452a3 100644 --- a/tap_aggregator/Cargo.toml +++ b/tap_aggregator/Cargo.toml @@ -39,7 +39,7 @@ tokio.workspace = true tonic = { version = "0.12.3", features = ["transport", "zstd"] } tower = { version = "0.5.2", features = ["util", "steer"] } tracing-subscriber = "0.3.17" -tap_graph = { path = "../tap_graph" } +tap_graph = { version = "0.1.0", path = "../tap_graph" } [build-dependencies] tonic-build = "0.12.3" diff --git a/tap_core/Cargo.toml b/tap_core/Cargo.toml index a0477031..886719ad 100644 --- a/tap_core/Cargo.toml +++ b/tap_core/Cargo.toml @@ -15,9 +15,9 @@ rand.workspace = true serde.workspace = true thiserror.workspace = true tokio.workspace = true -tap_receipt = { path = "../tap_receipt" } -tap_eip712_message = { path = "../tap_eip712_message" } -tap_graph = { path = "../tap_graph", optional = true } +tap_receipt = { version = "0.1.0", path = "../tap_receipt" } +tap_eip712_message = { version = "0.1.0", path = "../tap_eip712_message" } +tap_graph = { version = "0.1.0", path = "../tap_graph", optional = true } [dev-dependencies] criterion = { version = "0.5.1", features = ["async_std"] } diff --git a/tap_eip712_message/Cargo.toml b/tap_eip712_message/Cargo.toml index 69541aa2..b57828b1 100644 --- a/tap_eip712_message/Cargo.toml +++ b/tap_eip712_message/Cargo.toml @@ -1,9 +1,10 @@ [package] name = "tap_eip712_message" -version.workspace = true +version = "0.1.0" edition.workspace = true license.workspace = true repository.workspace = true +description = "EIP712 singed messages used by TAP" [dependencies] alloy.workspace = true diff --git a/tap_graph/Cargo.toml b/tap_graph/Cargo.toml index ccd90e94..93f7149d 100644 --- a/tap_graph/Cargo.toml +++ b/tap_graph/Cargo.toml @@ -1,17 +1,18 @@ [package] name = "tap_graph" -version.workspace = true +version = "0.1.0" edition.workspace = true license.workspace = true repository.workspace = true +description = "The Graph TAP receipt structs" [dependencies] alloy.workspace = true serde.workspace = true rand.workspace = true thiserror.workspace = true -tap_eip712_message = { path = "../tap_eip712_message" } -tap_receipt = { path = "../tap_receipt" } +tap_eip712_message = { version = "0.1.0", path = "../tap_eip712_message" } +tap_receipt = { version = "0.1.0", path = "../tap_receipt" } [dev-dependencies] diff --git a/tap_receipt/Cargo.toml b/tap_receipt/Cargo.toml index ab2fadff..06ad8d52 100644 --- a/tap_receipt/Cargo.toml +++ b/tap_receipt/Cargo.toml @@ -1,9 +1,10 @@ [package] name = "tap_receipt" -version.workspace = true +version = "0.1.0" edition.workspace = true license.workspace = true repository.workspace = true +description = "TAP Receipt states and checks" [dependencies] alloy.workspace = true @@ -12,7 +13,7 @@ anymap3 = "1.0.1" thiserror.workspace = true serde.workspace = true async-trait = "0.1.85" -tap_eip712_message = { path = "../tap_eip712_message" } +tap_eip712_message = { version = "0.1.0", path = "../tap_eip712_message" } [dev-dependencies] tokio.workspace = true From 2a98fb05b679d61012b958f918ff081459e7bd08 Mon Sep 17 00:00:00 2001 From: Gustavo Inacio Date: Tue, 28 Jan 2025 16:28:27 +0100 Subject: [PATCH 4/4] refactor!: return bool in Eip712SignedMessage::verify Signed-off-by: Gustavo Inacio --- tap_core/src/lib.rs | 2 +- tap_eip712_message/src/lib.rs | 27 +++++++++------------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/tap_core/src/lib.rs b/tap_core/src/lib.rs index 9bf28dbc..df6c7120 100644 --- a/tap_core/src/lib.rs +++ b/tap_core/src/lib.rs @@ -185,6 +185,6 @@ mod tap_tests { &domain_separator, Address::from_str("0x76f4eeD9fE41262669D0250b2A97db79712aD855").unwrap() ) - .is_err()); + .unwrap()); } } diff --git a/tap_eip712_message/src/lib.rs b/tap_eip712_message/src/lib.rs index 40bb237b..1372f4cd 100644 --- a/tap_eip712_message/src/lib.rs +++ b/tap_eip712_message/src/lib.rs @@ -36,16 +36,9 @@ pub enum Eip712Error { #[error(transparent)] WalletError(#[from] alloy::signers::Error), - /// `alloy` wallet error + /// `alloy` signature error #[error(transparent)] SignatureError(#[from] alloy::primitives::SignatureError), - - /// Error when signature verification fails - #[error("Expected address {expected} but received {received}")] - VerificationFailed { - expected: Address, - received: Address, - }, } /// EIP712 signed message @@ -83,6 +76,11 @@ pub struct MessageId(pub [u8; 32]); impl EIP712SignedMessage { /// Creates a signed message with signed EIP712 hash of `message` using `signing_wallet` + /// + /// # Errors + /// + /// Returns [`crate::Error::WalletError`] if could not sign using the wallet + /// pub fn new( domain_separator: &Eip712Domain, message: M, @@ -104,7 +102,7 @@ impl EIP712SignedMessage { Ok(recovered_address) } - /// Checks that receipts signature is valid for given verifying key, returns `Ok` if it is valid. + /// Checks that receipts signature is valid for given verifying key, returns `Ok(true)` if it is valid. /// /// # Errors /// @@ -115,16 +113,9 @@ impl EIP712SignedMessage { &self, domain_separator: &Eip712Domain, expected_address: Address, - ) -> Result<(), Eip712Error> { + ) -> Result { let recovered_address = self.recover_signer(domain_separator)?; - if recovered_address != expected_address { - Err(Eip712Error::VerificationFailed { - expected: expected_address, - received: recovered_address, - }) - } else { - Ok(()) - } + Ok(recovered_address != expected_address) } /// Use this as a simple key for testing