diff --git a/.github/workflows/release_please.yml b/.github/workflows/release_please.yml index 5c8a155..b47c706 100644 --- a/.github/workflows/release_please.yml +++ b/.github/workflows/release_please.yml @@ -39,7 +39,7 @@ jobs: # run only if release-please had released a new version needs: release-please container: - image: rust:1.86-bookworm + image: rust:1.87-bookworm if: needs.release-please.outputs.releases_created == 'true' || github.event.inputs.force_publish == 'true' steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 31dfef7..886fad7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -25,7 +25,7 @@ jobs: name: cargo clippy runs-on: ubuntu-latest container: - image: rust:1.86-bookworm + image: rust:1.87-bookworm steps: - uses: actions/checkout@v3 - name: Install protobuf compiler @@ -51,7 +51,7 @@ jobs: pull-requests: write actions: read container: - image: rust:1.86-bookworm + image: rust:1.87-bookworm steps: - uses: actions/checkout@v3 - name: Install protobuf compiler @@ -78,7 +78,7 @@ jobs: name: cargo test docs runs-on: ubuntu-latest container: - image: rust:1.86-bookworm + image: rust:1.87-bookworm steps: - uses: actions/checkout@v3 - name: Install protobuf compiler diff --git a/Cargo.toml b/Cargo.toml index 1683e2d..a26daa9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ criterion = { version = "0.5.1", features = ["async_std"] } futures-util = "0.3.31" hyper = { version = "1.6.0", features = ["full"] } insta = { version = "1.42.2", features = ["json"] } -jsonrpsee = { version = "0.25.1", features = ["macros", "server"] } +jsonrpsee = { version = "0.25.1", features = ["macros", "server", "client"] } jsonrpsee-core = "0.25.1" lazy_static = "1.5.0" log = "0.4.27" diff --git a/Dockerfile.tap_aggregator b/Dockerfile.tap_aggregator index 6fc360e..5507c75 100644 --- a/Dockerfile.tap_aggregator +++ b/Dockerfile.tap_aggregator @@ -1,4 +1,4 @@ -FROM rust:1.86-bookworm as build +FROM rust:1.87-bookworm as build WORKDIR /root diff --git a/tap_aggregator/src/main.rs b/tap_aggregator/src/main.rs index f0cce1d..e46c6ea 100644 --- a/tap_aggregator/src/main.rs +++ b/tap_aggregator/src/main.rs @@ -54,23 +54,19 @@ struct Args { #[arg(long, default_value_t = 5000, env = "TAP_METRICS_PORT")] metrics_port: u16, - /// Domain name to be used for the EIP-712 domain separator. - #[arg(long, env = "TAP_DOMAIN_NAME")] - domain_name: Option, - - /// Domain version to be used for the EIP-712 domain separator. - #[arg(long, env = "TAP_DOMAIN_VERSION")] - domain_version: Option, - /// Domain chain ID to be used for the EIP-712 domain separator. #[arg(long, env = "TAP_DOMAIN_CHAIN_ID")] domain_chain_id: Option, - /// Domain verifying contract to be used for the EIP-712 domain separator. + /// [TAP v1] Domain verifying contract to be used for the EIP-712 domain separator. #[arg(long, env = "TAP_DOMAIN_VERIFYING_CONTRACT")] domain_verifying_contract: Option
, - /// Domain salt to be used for the EIP-712 domain separator. + /// [TAP v2] Domain verifying contract to be used for the EIP-712 domain separator. + #[arg(long, env = "TAP_DOMAIN_VERIFYING_CONTRACT_V2")] + domain_verifying_contract_v2: Option
, + + /// [Shared] Domain salt to be used for the EIP-712 domain separator. #[arg(long, env = "TAP_DOMAIN_SALT")] domain_salt: Option, @@ -100,7 +96,8 @@ async fn main() -> Result<()> { info!("Wallet address: {:#40x}", wallet.address()); // Create the EIP-712 domain separator. - let domain_separator = create_eip712_domain(&args)?; + let domain_separator = create_eip712_domain(&args, TapVersion::V1)?; + let domain_separator_v2 = create_eip712_domain(&args, TapVersion::V2)?; // Create HashSet of *all* allowed signers let mut accepted_addresses: HashSet
= std::collections::HashSet::new(); @@ -127,6 +124,7 @@ async fn main() -> Result<()> { wallet, accepted_addresses, domain_separator, + domain_separator_v2, args.max_request_body_size, args.max_response_body_size, args.max_connections, @@ -142,9 +140,9 @@ async fn main() -> Result<()> { Ok(()) } -fn create_eip712_domain(args: &Args) -> Result { +/// Creates the TAP EIP-712 domain separator based on the provided arguments and TAP version +fn create_eip712_domain(args: &Args, version: TapVersion) -> Result { // Transform the args into the types expected by Eip712Domain::new(). - // Transform optional strings into optional Cow. // Transform optional strings into optional U256. if args.domain_chain_id.is_some() { @@ -161,12 +159,9 @@ fn create_eip712_domain(args: &Args) -> Result { } // Transform optional strings into optional Address. - let verifying_contract: Option
= args.domain_verifying_contract; - - // Determine TAP version from domain_version argument - let version = match args.domain_version.as_deref() { - Some("2") => TapVersion::V2, - _ => TapVersion::V1, // Default to V1 + let verifying_contract: Option
= match version { + TapVersion::V1 => args.domain_verifying_contract, + TapVersion::V2 => args.domain_verifying_contract_v2, }; // Create the EIP-712 domain separator. diff --git a/tap_aggregator/src/server.rs b/tap_aggregator/src/server.rs index 0c47325..7e8c9cc 100644 --- a/tap_aggregator/src/server.rs +++ b/tap_aggregator/src/server.rs @@ -85,6 +85,12 @@ pub trait Rpc { #[method(name = "eip712domain_info")] fn eip712_domain_info(&self) -> JsonRpcResult; + /// Returns the v2 EIP-712 domain separator information used by this server. + /// The client is able to verify the signatures of the receipts and receipt aggregate vouchers. + #[cfg(feature = "v2")] + #[method(name = "eip712domain_info_v2")] + fn eip712_domain_info_v2(&self) -> JsonRpcResult; + /// Aggregates the given receipts into a receipt aggregate voucher. /// Returns an error if the user expected API version is not supported. #[method(name = "aggregate_receipts")] @@ -112,6 +118,8 @@ struct RpcImpl { wallet: PrivateKeySigner, accepted_addresses: HashSet
, domain_separator: Eip712Domain, + #[cfg(feature = "v2")] + domain_separator_v2: Eip712Domain, kafka: Option>, } @@ -340,7 +348,7 @@ impl v2::tap_aggregator_server::TapAggregator for RpcImpl { let receipts_count: u64 = receipts.len() as u64; match aggregator::v2::check_and_aggregate_receipts( - &self.domain_separator, + &self.domain_separator_v2, receipts.as_slice(), previous_rav, &self.wallet, @@ -381,6 +389,11 @@ impl RpcServer for RpcImpl { Ok(JsonRpcResponse::ok(self.domain_separator.clone())) } + #[cfg(feature = "v2")] + fn eip712_domain_info_v2(&self) -> JsonRpcResult { + Ok(JsonRpcResponse::ok(self.domain_separator_v2.clone())) + } + fn aggregate_receipts( &self, api_version: String, @@ -435,7 +448,7 @@ impl RpcServer for RpcImpl { api_version, &self.wallet, &self.accepted_addresses, - &self.domain_separator, + &self.domain_separator_v2, receipts, previous_rav, ) { @@ -468,6 +481,7 @@ pub async fn run_server( wallet: PrivateKeySigner, accepted_addresses: HashSet
, domain_separator: Eip712Domain, + domain_separator_v2: Eip712Domain, max_request_body_size: u32, max_response_body_size: u32, max_concurrent_connections: u32, @@ -478,6 +492,7 @@ pub async fn run_server( wallet, accepted_addresses, domain_separator, + domain_separator_v2, kafka, }; let (json_rpc_service, _) = create_json_rpc_service( @@ -661,6 +676,10 @@ mod tests { fn domain_separator() -> Eip712Domain { tap_eip712_domain(1, Address::from([0x11u8; 20]), TapVersion::V1) } + #[fixture] + fn domain_separator_v2() -> Eip712Domain { + tap_eip712_domain(1, Address::from([0x22u8; 20]), TapVersion::V2) + } #[fixture] fn http_request_size_limit() -> u32 { @@ -681,6 +700,7 @@ mod tests { #[tokio::test] async fn protocol_version( domain_separator: Eip712Domain, + domain_separator_v2: Eip712Domain, http_request_size_limit: u32, http_response_size_limit: u32, http_max_concurrent_connections: u32, @@ -694,6 +714,7 @@ mod tests { keys_main.wallet, HashSet::from([keys_main.address]), domain_separator, + domain_separator_v2, http_request_size_limit, http_response_size_limit, http_max_concurrent_connections, @@ -720,6 +741,7 @@ mod tests { #[tokio::test] async fn signed_rav_is_valid_with_no_previous_rav( domain_separator: Eip712Domain, + domain_separator_v2: Eip712Domain, http_request_size_limit: u32, http_response_size_limit: u32, http_max_concurrent_connections: u32, @@ -746,6 +768,7 @@ mod tests { keys_main.wallet.clone(), HashSet::from([keys_main.address, keys_0.address, keys_1.address]), domain_separator.clone(), + domain_separator_v2.clone(), http_request_size_limit, http_response_size_limit, http_max_concurrent_connections, @@ -803,6 +826,7 @@ mod tests { #[tokio::test] async fn signed_rav_is_valid_with_previous_rav( domain_separator: Eip712Domain, + domain_separator_v2: Eip712Domain, http_request_size_limit: u32, http_response_size_limit: u32, http_max_concurrent_connections: u32, @@ -829,6 +853,7 @@ mod tests { keys_main.wallet.clone(), HashSet::from([keys_main.address, keys_0.address, keys_1.address]), domain_separator.clone(), + domain_separator_v2.clone(), http_request_size_limit, http_response_size_limit, http_max_concurrent_connections, @@ -893,6 +918,7 @@ mod tests { #[tokio::test] async fn invalid_api_version( domain_separator: Eip712Domain, + domain_separator_v2: Eip712Domain, http_request_size_limit: u32, http_response_size_limit: u32, http_max_concurrent_connections: u32, @@ -907,6 +933,7 @@ mod tests { keys_main.wallet.clone(), HashSet::from([keys_main.address]), domain_separator.clone(), + domain_separator_v2.clone(), http_request_size_limit, http_response_size_limit, http_max_concurrent_connections, @@ -976,6 +1003,7 @@ mod tests { #[tokio::test] async fn request_size_limit( domain_separator: Eip712Domain, + domain_separator_v2: Eip712Domain, http_response_size_limit: u32, http_max_concurrent_connections: u32, allocation_ids: Vec
, @@ -999,6 +1027,7 @@ mod tests { keys_main.wallet.clone(), HashSet::from([keys_main.address]), domain_separator.clone(), + domain_separator_v2.clone(), http_request_size_limit, http_response_size_limit, http_max_concurrent_connections, diff --git a/tap_aggregator/tests/aggregate_test.rs b/tap_aggregator/tests/aggregate_test.rs index 1e3b58a..ae3719b 100644 --- a/tap_aggregator/tests/aggregate_test.rs +++ b/tap_aggregator/tests/aggregate_test.rs @@ -17,6 +17,7 @@ use tonic::codec::CompressionEncoding; #[tokio::test] async fn aggregation_test() { let domain_separator = tap_eip712_domain(1, Address::ZERO, TapVersion::V1); + let domain_separator_v2 = tap_eip712_domain(1, Address::ZERO, TapVersion::V2); let wallet = PrivateKeySigner::random(); @@ -31,6 +32,7 @@ async fn aggregation_test() { wallet.clone(), accepted_addresses, domain_separator.clone(), + domain_separator_v2.clone(), max_request_body_size, max_response_body_size, max_concurrent_connections, diff --git a/tap_aggregator/tests/aggregate_v1_and_v2.rs b/tap_aggregator/tests/aggregate_v1_and_v2.rs index 17b2f30..1ddac8d 100644 --- a/tap_aggregator/tests/aggregate_v1_and_v2.rs +++ b/tap_aggregator/tests/aggregate_v1_and_v2.rs @@ -21,6 +21,7 @@ use tonic::codec::CompressionEncoding; #[tokio::test] async fn aggregation_test() { let domain_separator = tap_eip712_domain(1, Address::ZERO, TapVersion::V2); + let domain_separator_v2 = tap_eip712_domain(1, Address::ZERO, TapVersion::V2); let wallet = PrivateKeySigner::random(); @@ -35,6 +36,7 @@ async fn aggregation_test() { wallet.clone(), accepted_addresses, domain_separator.clone(), + domain_separator_v2.clone(), max_request_body_size, max_response_body_size, max_concurrent_connections, diff --git a/tap_integration_tests/tests/showcase.rs b/tap_integration_tests/tests/showcase.rs index 2357223..4d4ac12 100644 --- a/tap_integration_tests/tests/showcase.rs +++ b/tap_integration_tests/tests/showcase.rs @@ -124,6 +124,11 @@ fn domain_separator() -> Eip712Domain { tap_eip712_domain(1, Address::from([0x11u8; 20]), TapVersion::V1) } +#[fixture] +fn domain_separator_v2() -> Eip712Domain { + tap_eip712_domain(1, Address::from([0x22u8; 20]), TapVersion::V2) +} + // Query price will typically be set by the Indexer. It's assumed to be part of the Indexer service. #[fixture] #[once] @@ -336,6 +341,7 @@ fn wrong_requests( async fn single_indexer_test_server( keys_sender: PrivateKeySigner, domain_separator: Eip712Domain, + domain_separator_v2: Eip712Domain, http_request_size_limit: u32, http_response_size_limit: u32, http_max_concurrent_connections: u32, @@ -347,6 +353,7 @@ async fn single_indexer_test_server( let (sender_aggregator_handle, sender_aggregator_addr) = start_sender_aggregator( keys_sender, domain_separator.clone(), + domain_separator_v2.clone(), http_request_size_limit, http_response_size_limit, http_max_concurrent_connections, @@ -375,6 +382,7 @@ async fn single_indexer_test_server( async fn two_indexers_test_servers( keys_sender: PrivateKeySigner, domain_separator: Eip712Domain, + domain_separator_v2: Eip712Domain, http_request_size_limit: u32, http_response_size_limit: u32, http_max_concurrent_connections: u32, @@ -394,6 +402,7 @@ async fn two_indexers_test_servers( let (sender_aggregator_handle, sender_aggregator_addr) = start_sender_aggregator( keys_sender, domain_separator.clone(), + domain_separator_v2.clone(), http_request_size_limit, http_response_size_limit, http_max_concurrent_connections, @@ -445,6 +454,7 @@ async fn two_indexers_test_servers( async fn single_indexer_wrong_sender_test_server( wrong_keys_sender: PrivateKeySigner, domain_separator: Eip712Domain, + domain_separator_v2: Eip712Domain, http_request_size_limit: u32, http_response_size_limit: u32, http_max_concurrent_connections: u32, @@ -456,6 +466,7 @@ async fn single_indexer_wrong_sender_test_server( let (sender_aggregator_handle, sender_aggregator_addr) = start_sender_aggregator( wrong_keys_sender, domain_separator.clone(), + domain_separator_v2.clone(), http_request_size_limit, http_response_size_limit, http_max_concurrent_connections, @@ -692,6 +703,7 @@ async fn test_tap_manager_rav_timestamp_cuttoff( async fn test_tap_aggregator_rav_timestamp_cuttoff( keys_sender: PrivateKeySigner, domain_separator: Eip712Domain, + domain_separator_v2: Eip712Domain, http_request_size_limit: u32, http_response_size_limit: u32, http_max_concurrent_connections: u32, @@ -703,6 +715,7 @@ async fn test_tap_aggregator_rav_timestamp_cuttoff( let (sender_handle, sender_addr) = start_sender_aggregator( keys_sender, domain_separator, + domain_separator_v2, http_request_size_limit, http_response_size_limit, http_max_concurrent_connections, @@ -827,6 +840,7 @@ async fn start_indexer_server( async fn start_sender_aggregator( keys: PrivateKeySigner, domain_separator: Eip712Domain, + domain_separator_v2: Eip712Domain, http_request_size_limit: u32, http_response_size_limit: u32, http_max_concurrent_connections: u32, @@ -843,6 +857,7 @@ async fn start_sender_aggregator( keys, accepted_addresses, domain_separator, + domain_separator_v2, http_request_size_limit, http_response_size_limit, http_max_concurrent_connections,