From 7d414613efbc35685917cb5ebb14440aa0801633 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 6 Aug 2024 18:18:12 -0600 Subject: [PATCH 1/5] When a new installation is added the members list becomes incorrect (#937) * lock stuff * reproduce the member list issue in test * Fix missing members due to cache inconsistency (#944) Depends on https://github.com/xmtp/libxmtp/pull/937 We currently write the association state cache whenever we compute an association state from scratch. Also, whenever we read an association state, we check the cache, and if it's not there, we go ahead and re-compute it. However, there are two codepaths that behave a little differently, causing us to underreport the members in a group: 1. One codepath computes incremental updates to an existing state, and does not update the cache. 2. One codepath batch reads multiple association states from the cache, and silently omits anything it doesn't find rather than re-computing it. I've done a few things in this PR: 1. When computing incremental updates, make sure we also write to the cache 2. When batch reading from the cache, bake in a hard assumption that the cache will be up-to-date, and throw errors if we don't find what we expect 3. Some small improvements to our logging --------- Co-authored-by: Richard Hua --- bindings_ffi/src/logger.rs | 2 +- bindings_ffi/src/mls.rs | 81 ++++++++++++++++++- .../up.sql | 2 + .../2024-05-15-145138_new_schema/up.sql | 2 + xmtp_mls/src/api/identity.rs | 1 + xmtp_mls/src/groups/group_membership.rs | 1 + xmtp_mls/src/groups/members.rs | 19 ++++- xmtp_mls/src/identity_updates.rs | 38 ++++++++- .../encrypted_store/association_state.rs | 31 +++++-- xmtp_mls/src/storage/encrypted_store/mod.rs | 2 +- 10 files changed, 160 insertions(+), 19 deletions(-) diff --git a/bindings_ffi/src/logger.rs b/bindings_ffi/src/logger.rs index 7f5c45f9d..c3dd68922 100644 --- a/bindings_ffi/src/logger.rs +++ b/bindings_ffi/src/logger.rs @@ -20,7 +20,7 @@ impl log::Log for RustLogger { self.logger.lock().expect("Logger mutex is poisoned!").log( record.level() as u32, record.level().to_string(), - format!("[libxmtp] {}", record.args()), + format!("[libxmtp][t:{}] {}", thread_id::get(), record.args()), ); } } diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 39fea18f6..d13cc477d 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -1507,6 +1507,10 @@ mod tests { } impl LocalWalletInboxOwner { + pub fn with_wallet(wallet: xmtp_cryptography::utils::LocalWallet) -> Self { + Self { wallet } + } + pub fn new() -> Self { Self { wallet: xmtp_cryptography::utils::LocalWallet::new(&mut rng()), @@ -1532,7 +1536,7 @@ mod tests { impl FfiLogger for MockLogger { fn log(&self, _level: u32, level_label: String, message: String) { - println!("[{}][t:{}]: {}", level_label, thread_id::get(), message) + println!("[{}]{}", level_label, message) } } @@ -1607,8 +1611,11 @@ mod tests { client.register_identity(signature_request).await.unwrap(); } - async fn new_test_client() -> Arc { - let ffi_inbox_owner = LocalWalletInboxOwner::new(); + /// Create a new test client with a given wallet. + async fn new_test_client_with_wallet( + wallet: xmtp_cryptography::utils::LocalWallet, + ) -> Arc { + let ffi_inbox_owner = LocalWalletInboxOwner::with_wallet(wallet); let nonce = 1; let inbox_id = generate_inbox_id(&ffi_inbox_owner.get_address(), &nonce); @@ -1626,10 +1633,16 @@ mod tests { ) .await .unwrap(); + register_client(&ffi_inbox_owner, &client).await; client } + async fn new_test_client() -> Arc { + let wallet = xmtp_cryptography::utils::LocalWallet::new(&mut rng()); + new_test_client_with_wallet(wallet).await + } + #[tokio::test] async fn get_inbox_id() { let client = new_test_client().await; @@ -2228,6 +2241,68 @@ mod tests { ); } + #[tokio::test(flavor = "multi_thread", worker_threads = 5)] + async fn test_create_new_installation_without_breaking_group() { + let wallet1_key = &mut rng(); + let wallet1 = xmtp_cryptography::utils::LocalWallet::new(wallet1_key); + let wallet2_key = &mut rng(); + let wallet2 = xmtp_cryptography::utils::LocalWallet::new(wallet2_key); + + // Create clients + let client1 = new_test_client_with_wallet(wallet1).await; + let client2 = new_test_client_with_wallet(wallet2.clone()).await; + // Create a new group with client1 including wallet2 + + let group = client1 + .conversations() + .create_group( + vec![client2.account_address.clone()], + FfiCreateGroupOptions::default(), + ) + .await + .unwrap(); + + // Sync groups + client1.conversations().sync().await.unwrap(); + client2.conversations().sync().await.unwrap(); + + // Find groups for both clients + let client1_group = client1.group(group.id()).unwrap(); + let client2_group = client2.group(group.id()).unwrap(); + + // Sync both groups + client1_group.sync().await.unwrap(); + client2_group.sync().await.unwrap(); + + // Assert both clients see 2 members + let client1_members = client1_group.list_members().unwrap(); + assert_eq!(client1_members.len(), 2); + + let client2_members = client2_group.list_members().unwrap(); + assert_eq!(client2_members.len(), 2); + + // Drop and delete local database for client2 + client2.release_db_connection().unwrap(); + + // Recreate client2 (new installation) + let client2 = new_test_client_with_wallet(wallet2).await; + + // Send a message that will break the group + client1_group + .send("This message will break the group".as_bytes().to_vec()) + .await + .unwrap(); + + // Assert client1 still sees 2 members + let client1_members = client1_group.list_members().unwrap(); + assert_eq!(client1_members.len(), 2); + + client2.conversations().sync().await.unwrap(); + let client2_group = client2.group(group.id()).unwrap(); + let client2_members = client2_group.list_members().unwrap(); + assert_eq!(client2_members.len(), 2); + } + #[tokio::test(flavor = "multi_thread", worker_threads = 5)] async fn test_can_send_messages_when_epochs_behind() { let alix = new_test_client().await; diff --git a/xmtp_mls/migrations/2024-05-11-004236_cache_association_state/up.sql b/xmtp_mls/migrations/2024-05-11-004236_cache_association_state/up.sql index ab63aba77..825bd9a1e 100644 --- a/xmtp_mls/migrations/2024-05-11-004236_cache_association_state/up.sql +++ b/xmtp_mls/migrations/2024-05-11-004236_cache_association_state/up.sql @@ -1,3 +1,5 @@ +-- Caches the computed association state at a given sequence ID in an inbox log, +-- so that we don't need to replay the whole log. CREATE TABLE association_state ( "inbox_id" TEXT NOT NULL, "sequence_id" BIGINT NOT NULL, diff --git a/xmtp_mls/migrations/2024-05-15-145138_new_schema/up.sql b/xmtp_mls/migrations/2024-05-15-145138_new_schema/up.sql index 4c0cb3a57..8b4030ab3 100644 --- a/xmtp_mls/migrations/2024-05-15-145138_new_schema/up.sql +++ b/xmtp_mls/migrations/2024-05-15-145138_new_schema/up.sql @@ -87,6 +87,8 @@ CREATE TABLE group_intents( CREATE INDEX group_intents_group_id_state ON group_intents(group_id, state); +-- Caches the identity update payload at a given sequence ID, so that API calls +-- don't need to be repeated. CREATE TABLE identity_updates( -- The inbox_id the update refers to "inbox_id" text NOT NULL, diff --git a/xmtp_mls/src/api/identity.rs b/xmtp_mls/src/api/identity.rs index cfb685392..dbf3a1e62 100644 --- a/xmtp_mls/src/api/identity.rs +++ b/xmtp_mls/src/api/identity.rs @@ -17,6 +17,7 @@ use xmtp_proto::xmtp::identity::api::v1::{ const GET_IDENTITY_UPDATES_CHUNK_SIZE: usize = 50; +#[derive(Debug)] /// A filter for querying identity updates. `sequence_id` is the starting sequence, and only later updates will be returned. pub struct GetIdentityUpdatesV2Filter { pub inbox_id: InboxId, diff --git a/xmtp_mls/src/groups/group_membership.rs b/xmtp_mls/src/groups/group_membership.rs index e14a5ea23..a614a7ea2 100644 --- a/xmtp_mls/src/groups/group_membership.rs +++ b/xmtp_mls/src/groups/group_membership.rs @@ -105,6 +105,7 @@ impl From<&GroupMembership> for Vec { } } +#[derive(Debug)] pub struct MembershipDiff<'inbox_id> { pub added_inboxes: Vec<&'inbox_id String>, pub removed_inboxes: Vec<&'inbox_id String>, diff --git a/xmtp_mls/src/groups/members.rs b/xmtp_mls/src/groups/members.rs index 4e9b073db..c25172bbb 100644 --- a/xmtp_mls/src/groups/members.rs +++ b/xmtp_mls/src/groups/members.rs @@ -40,14 +40,25 @@ impl MlsGroup { .members .into_iter() .map(|(inbox_id, sequence_id)| (inbox_id, sequence_id as i64)) + .filter(|(_, sequence_id)| *sequence_id != 0) // Skip the initial state .collect::>(); let conn = provider.conn_ref(); - let association_state_map = StoredAssociationState::batch_read_from_cache(conn, requests)?; + let association_states = + StoredAssociationState::batch_read_from_cache(conn, requests.clone())?; let mutable_metadata = self.mutable_metadata()?; - // TODO: Figure out what to do with missing members from the local DB. Do we go to the network? Load from identity updates? - // Right now I am just omitting them - let members = association_state_map + if association_states.len() != requests.len() { + // Cache miss - not expected to happen because: + // 1. We don't allow updates to the group metadata unless we have already validated the association state + // 2. When validating the association state, we must have written it to the cache + log::error!( + "Failed to load all members for group - metadata: {:?}, computed members: {:?}", + requests, + association_states + ); + return Err(GroupError::InvalidGroupMembership); + } + let members = association_states .into_iter() .map(|association_state| { let inbox_id_str = association_state.inbox_id().to_string(); diff --git a/xmtp_mls/src/identity_updates.rs b/xmtp_mls/src/identity_updates.rs index dc8432fc9..14a4cd44a 100644 --- a/xmtp_mls/src/identity_updates.rs +++ b/xmtp_mls/src/identity_updates.rs @@ -109,7 +109,6 @@ where if let Some(association_state) = StoredAssociationState::read_from_cache(conn, inbox_id.to_string(), last_sequence_id)? { - log::debug!("Loaded association state from cache"); return Ok(association_state); } @@ -125,7 +124,6 @@ where last_sequence_id, association_state.clone(), )?; - log::debug!("Wrote association state to cache"); Ok(association_state) } @@ -137,6 +135,12 @@ where starting_sequence_id: Option, ending_sequence_id: Option, ) -> Result { + log::debug!( + "Computing diff for {:?} from {:?} to {:?}", + inbox_id.as_ref(), + starting_sequence_id, + ending_sequence_id + ); if starting_sequence_id.is_none() { return Ok(self .get_association_state(conn, inbox_id.as_ref(), ending_sequence_id) @@ -148,8 +152,23 @@ where .get_association_state(conn, inbox_id.as_ref(), starting_sequence_id) .await?; - let incremental_updates = conn - .get_identity_updates(inbox_id, starting_sequence_id, ending_sequence_id)? + let incremental_updates = + conn.get_identity_updates(inbox_id.as_ref(), starting_sequence_id, ending_sequence_id)?; + + let last_sequence_id = incremental_updates.last().map(|update| update.sequence_id); + if ending_sequence_id.is_some() + && last_sequence_id.is_some() + && last_sequence_id != ending_sequence_id + { + log::error!( + "Did not find the expected last sequence id. Expected: {:?}, Found: {:?}", + ending_sequence_id, + last_sequence_id + ); + return Err(AssociationError::MissingIdentityUpdate.into()); + } + + let incremental_updates = incremental_updates .into_iter() .map(|update| update.try_into()) .collect::, AssociationError>>()?; @@ -159,6 +178,16 @@ where final_state = apply_update(final_state, update).await?; } + log::debug!("Final state at {:?}: {:?}", last_sequence_id, final_state); + if last_sequence_id.is_some() { + StoredAssociationState::write_to_cache( + conn, + inbox_id.as_ref().to_string(), + last_sequence_id.unwrap(), + final_state.clone(), + )?; + } + Ok(initial_state.diff(&final_state)) } @@ -335,6 +364,7 @@ pub async fn load_identity_updates( if inbox_ids.is_empty() { return Ok(HashMap::new()); } + log::debug!("Fetching identity updates for: {:?}", inbox_ids); let existing_sequence_ids = conn.get_latest_sequence_id(&inbox_ids)?; let filters: Vec = inbox_ids diff --git a/xmtp_mls/src/storage/encrypted_store/association_state.rs b/xmtp_mls/src/storage/encrypted_store/association_state.rs index 9ff51cca1..210009853 100644 --- a/xmtp_mls/src/storage/encrypted_store/association_state.rs +++ b/xmtp_mls/src/storage/encrypted_store/association_state.rs @@ -40,12 +40,22 @@ impl StoredAssociationState { state: AssociationState, ) -> Result<(), StorageError> { let state_proto: AssociationStateProto = state.into(); - StoredAssociationState { - inbox_id, + let result = StoredAssociationState { + inbox_id: inbox_id.clone(), sequence_id, state: state_proto.encode_to_vec(), } - .store_or_ignore(conn) + .store_or_ignore(conn); + + if result.is_ok() { + log::debug!( + "Wrote association state to cache: {} {}", + inbox_id, + sequence_id + ); + } + + result } pub fn read_from_cache( @@ -56,7 +66,7 @@ impl StoredAssociationState { let stored_state: Option = conn.fetch(&(inbox_id.to_string(), sequence_id))?; - stored_state + let result = stored_state .map(|stored_state| { stored_state .try_into() @@ -66,14 +76,23 @@ impl StoredAssociationState { )) }) }) - .transpose() + .transpose(); + + if result.is_ok() && result.as_ref().unwrap().is_some() { + log::debug!( + "Loaded association state from cache: {} {}", + inbox_id, + sequence_id + ); + } + + result } pub fn batch_read_from_cache( conn: &DbConnection, identifiers: Vec<(InboxId, i64)>, ) -> Result, StorageError> { - // If no identifier provided, return empty hash map if identifiers.is_empty() { return Ok(vec![]); } diff --git a/xmtp_mls/src/storage/encrypted_store/mod.rs b/xmtp_mls/src/storage/encrypted_store/mod.rs index 2b3eb7138..3242c5b32 100644 --- a/xmtp_mls/src/storage/encrypted_store/mod.rs +++ b/xmtp_mls/src/storage/encrypted_store/mod.rs @@ -184,7 +184,7 @@ impl EncryptedMessageStore { .as_ref() .ok_or(StorageError::PoolNeedsConnection)?; - log::info!( + log::debug!( "Pulling connection from pool, idle_connections={}, total_connections={}", pool.state().idle_connections, pool.state().connections From 340b0b68c9cd3b720e4b443d9f31b1fbc1e3cbf8 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Wed, 7 Aug 2024 10:24:24 -0700 Subject: [PATCH 2/5] Abort if retry fails (#945) * Abort if retry fails * Add error message * Add test --- xmtp_mls/src/groups/mod.rs | 53 ++++++++++++++++++++- xmtp_mls/src/groups/sync.rs | 13 ++++- xmtp_mls/src/storage/encrypted_store/mod.rs | 2 +- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 1fbcd10c7..388f2c045 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -1199,6 +1199,7 @@ fn build_group_join_config() -> MlsGroupJoinConfig { #[cfg(test)] mod tests { + use diesel::connection::SimpleConnection; use openmls::prelude::{tls_codec::Serialize, Member, MlsGroup as OpenMlsGroup}; use prost::Message; use std::sync::Arc; @@ -1229,7 +1230,7 @@ mod tests { use super::{ intents::{Installation, SendWelcomesAction}, - MlsGroup, + GroupError, MlsGroup, }; async fn receive_group_invite(client: &Client) -> MlsGroup @@ -2754,4 +2755,54 @@ mod tests { ] ); } + + #[tokio::test(flavor = "multi_thread")] + async fn process_messages_abort_on_retryable_error() { + let alix = ClientBuilder::new_test_client(&generate_local_wallet()).await; + let bo = ClientBuilder::new_test_client(&generate_local_wallet()).await; + + let alix_group = alix + .create_group(None, GroupMetadataOptions::default()) + .unwrap(); + + alix_group + .add_members_by_inbox_id(&alix, vec![bo.inbox_id()]) + .await + .unwrap(); + + // Create two commits + alix_group + .update_group_name(&alix, "foo".to_string()) + .await + .unwrap(); + alix_group + .update_group_name(&alix, "bar".to_string()) + .await + .unwrap(); + + let bo_group = receive_group_invite(&bo).await; + // Get the group messages before we lock the DB, simulating an error that happens + // in the middle of a sync instead of the beginning + let bo_messages = bo + .query_group_messages(&bo_group.group_id, &bo.store().conn().unwrap()) + .await + .unwrap(); + + let conn_1 = bo.store().conn().unwrap(); + let mut conn_2 = bo.store().raw_conn().unwrap(); + + // Begin an exclusive transaction on a second connection to lock the database + conn_2.batch_execute("BEGIN EXCLUSIVE").unwrap(); + let process_result = bo_group.process_messages(bo_messages, conn_1, &bo).await; + if let Some(GroupError::ReceiveErrors(errors)) = process_result.err() { + assert_eq!(errors.len(), 1); + assert!(errors + .first() + .unwrap() + .to_string() + .contains("database is locked")); + } else { + panic!("Expected error") + } + } } diff --git a/xmtp_mls/src/groups/sync.rs b/xmtp_mls/src/groups/sync.rs index 42fa69604..3e4686fac 100644 --- a/xmtp_mls/src/groups/sync.rs +++ b/xmtp_mls/src/groups/sync.rs @@ -28,7 +28,7 @@ use crate::{ hpke::{encrypt_welcome, HpkeError}, identity::parse_credential, identity_updates::load_identity_updates, - retry::Retry, + retry::{Retry, RetryableError}, retry_async, storage::{ db_connection::DbConnection, @@ -692,7 +692,18 @@ impl MlsGroup { }) ); if let Err(e) = result { + let is_retryable = e.is_retryable(); + let error_message = e.to_string(); receive_errors.push(e); + // If the error is retryable we cannot move on to the next message + // otherwise you can get into a forked group state. + if is_retryable { + log::error!( + "Aborting message processing for retryable error: {}", + error_message + ); + break; + } } } diff --git a/xmtp_mls/src/storage/encrypted_store/mod.rs b/xmtp_mls/src/storage/encrypted_store/mod.rs index 3242c5b32..6c5251a5f 100644 --- a/xmtp_mls/src/storage/encrypted_store/mod.rs +++ b/xmtp_mls/src/storage/encrypted_store/mod.rs @@ -175,7 +175,7 @@ impl EncryptedMessageStore { Ok(()) } - fn raw_conn( + pub(crate) fn raw_conn( &self, ) -> Result>, StorageError> { let pool_guard = self.pool.read(); From 67ecf50949d29d388b490cdfdbac34d74bef2d3f Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 8 Aug 2024 19:19:34 -0400 Subject: [PATCH 3/5] skip empty key packages (#950) skip empty keypackages to ensure TLS Deserialization does not fail --- xmtp_mls/src/api/mls.rs | 49 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/xmtp_mls/src/api/mls.rs b/xmtp_mls/src/api/mls.rs index eaf3af6b4..7520eb403 100644 --- a/xmtp_mls/src/api/mls.rs +++ b/xmtp_mls/src/api/mls.rs @@ -236,11 +236,19 @@ where .key_packages .into_iter() .enumerate() - .map(|(idx, key_package)| { - ( + .filter_map(|(idx, key_package)| { + if key_package.key_package_tls_serialized.is_empty() { + log::warn!( + "installation key 0x{} has empty key package", + hex::encode(&installation_keys[idx]) + ); + return None; + } + + Some(( installation_keys[idx].to_vec(), key_package.key_package_tls_serialized, - ) + )) }) .collect(); @@ -683,4 +691,39 @@ pub mod tests { .unwrap(); assert_eq!(result.len(), 50); } + + #[tokio::test] + async fn test_fetch_key_packages_skips_empty() { + let mut mock_api = MockApiClient::new(); + let installation_keys: Vec> = vec![vec![1, 2, 3], vec![4, 5, 6], vec![1, 1, 1]]; + mock_api.expect_fetch_key_packages().returning(move |_| { + Ok(FetchKeyPackagesResponse { + key_packages: vec![ + KeyPackage { + key_package_tls_serialized: vec![7, 8, 9], + }, + KeyPackage { + key_package_tls_serialized: vec![], + }, + KeyPackage { + key_package_tls_serialized: vec![10, 11, 12], + }, + ], + }) + }); + let wrapper = ApiClientWrapper::new(mock_api, Retry::default()); + let result = wrapper + .fetch_key_packages(installation_keys.clone()) + .await + .unwrap(); + assert_eq!(result.len(), 2); + + for (k, v) in result { + if k.eq(&installation_keys[0]) { + assert_eq!(v, vec![7, 8, 9]); + } else { + assert_eq!(v, vec![10, 11, 12]); + } + } + } } From 5acd067cb79ab8c65af297d4e8c2d22400de2b1a Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 13 Aug 2024 11:55:52 -0600 Subject: [PATCH 4/5] Revert "skip empty key packages (#950)" (#954) This reverts commit 67ecf50949d29d388b490cdfdbac34d74bef2d3f. --- xmtp_mls/src/api/mls.rs | 49 +++-------------------------------------- 1 file changed, 3 insertions(+), 46 deletions(-) diff --git a/xmtp_mls/src/api/mls.rs b/xmtp_mls/src/api/mls.rs index 7520eb403..eaf3af6b4 100644 --- a/xmtp_mls/src/api/mls.rs +++ b/xmtp_mls/src/api/mls.rs @@ -236,19 +236,11 @@ where .key_packages .into_iter() .enumerate() - .filter_map(|(idx, key_package)| { - if key_package.key_package_tls_serialized.is_empty() { - log::warn!( - "installation key 0x{} has empty key package", - hex::encode(&installation_keys[idx]) - ); - return None; - } - - Some(( + .map(|(idx, key_package)| { + ( installation_keys[idx].to_vec(), key_package.key_package_tls_serialized, - )) + ) }) .collect(); @@ -691,39 +683,4 @@ pub mod tests { .unwrap(); assert_eq!(result.len(), 50); } - - #[tokio::test] - async fn test_fetch_key_packages_skips_empty() { - let mut mock_api = MockApiClient::new(); - let installation_keys: Vec> = vec![vec![1, 2, 3], vec![4, 5, 6], vec![1, 1, 1]]; - mock_api.expect_fetch_key_packages().returning(move |_| { - Ok(FetchKeyPackagesResponse { - key_packages: vec![ - KeyPackage { - key_package_tls_serialized: vec![7, 8, 9], - }, - KeyPackage { - key_package_tls_serialized: vec![], - }, - KeyPackage { - key_package_tls_serialized: vec![10, 11, 12], - }, - ], - }) - }); - let wrapper = ApiClientWrapper::new(mock_api, Retry::default()); - let result = wrapper - .fetch_key_packages(installation_keys.clone()) - .await - .unwrap(); - assert_eq!(result.len(), 2); - - for (k, v) in result { - if k.eq(&installation_keys[0]) { - assert_eq!(v, vec![7, 8, 9]); - } else { - assert_eq!(v, vec![10, 11, 12]); - } - } - } } From 44924a2ec217d9fe7756108f32810205b338a8cb Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Tue, 13 Aug 2024 15:54:52 -0400 Subject: [PATCH 5/5] Add HTTP gRPC crate (#949) * Rename to xmtp_api_http * Update deps * Fix settings * Add streaming fns to HTTP client * Allow using `http-api` feature flag to switch client * add github CI workflow for http * remove `tokio::spawn` in stream_all_messages by using async_stream * make all Mutex's parking_lot * update dependencies in xmtp_api_grpc * remove unused dependencies in xmtp_api_grpc --------- Co-authored-by: Ry Racherbaumer --- .github/workflows/lint-workspace.yaml | 8 +- .github/workflows/test-http-api.yml | 40 + .github/workflows/test-workspace.yml | 8 - .vscode/settings.json | 37 +- Cargo.lock | 1035 ++++++++--------- Cargo.toml | 16 +- bindings_ffi/Cargo.lock | 215 +--- bindings_ffi/Cargo.toml | 1 + bindings_ffi/src/logger.rs | 6 +- bindings_node/Cargo.lock | 197 +--- bindings_node/Cargo.toml | 6 +- bindings_wasm/Cargo.toml | 17 +- bindings_wasm/package-lock.json | 8 +- bindings_wasm/package.json | 7 +- bindings_wasm/rustfmt.toml | 2 + bindings_wasm/src/lib.rs | 25 +- bindings_wasm/src/mls_client.rs | 274 +++++ bindings_wasm/tests/node.rs | 21 - bindings_wasm/tests/web.rs | 97 +- mls_validation_service/Cargo.toml | 2 +- xmtp_api_grpc/Cargo.toml | 14 +- xmtp_api_grpc_gateway/Cargo.lock | 140 ++- xmtp_api_http/Cargo.toml | 28 + xmtp_api_http/src/constants.rs | 24 + xmtp_api_http/src/lib.rs | 309 +++++ xmtp_api_http/src/util.rs | 102 ++ xmtp_id/Cargo.toml | 6 +- xmtp_id/src/lib.rs | 4 +- xmtp_mls/Cargo.toml | 14 +- xmtp_mls/benches/group_limit.rs | 5 +- xmtp_mls/src/api/test_utils.rs | 19 +- xmtp_mls/src/builder.rs | 30 +- xmtp_mls/src/groups/subscriptions.rs | 88 +- xmtp_mls/src/groups/sync.rs | 1 - xmtp_mls/src/identity.rs | 9 +- xmtp_mls/src/lib.rs | 27 +- xmtp_mls/src/owner/evm_owner.rs | 4 +- .../storage/encrypted_store/db_connection.rs | 12 +- xmtp_mls/src/subscriptions.rs | 185 ++- xmtp_mls/src/utils/bench.rs | 4 +- xmtp_mls/src/utils/test.rs | 79 +- xmtp_proto/Cargo.toml | 6 +- 42 files changed, 1832 insertions(+), 1300 deletions(-) create mode 100644 .github/workflows/test-http-api.yml create mode 100644 bindings_wasm/rustfmt.toml create mode 100644 bindings_wasm/src/mls_client.rs delete mode 100644 bindings_wasm/tests/node.rs create mode 100644 xmtp_api_http/Cargo.toml create mode 100644 xmtp_api_http/src/constants.rs create mode 100644 xmtp_api_http/src/lib.rs create mode 100644 xmtp_api_http/src/util.rs diff --git a/.github/workflows/lint-workspace.yaml b/.github/workflows/lint-workspace.yaml index a92a1079b..de69824e8 100644 --- a/.github/workflows/lint-workspace.yaml +++ b/.github/workflows/lint-workspace.yaml @@ -1,15 +1,14 @@ name: Lint Workspace - on: push: branches: - main - pull_request: paths: - ".github/workflows/lint.yaml" - "mls_validation_service/**" - "xmtp_api_grpc/**" + - "xmtp_api_http/**" - "xmtp_cryptography/**" - "xmtp_id/**" - "xmtp_mls/**" @@ -19,7 +18,6 @@ on: - "Cargo.lock" - "rust-toolchain" - "rustfmt.toml" - jobs: lint: name: Lint @@ -27,18 +25,14 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - - name: Update rust toolchains run: rustup update - - name: Cache uses: Swatinem/rust-cache@v2 with: workspaces: | . - - name: Run clippy and fail on warnings run: cargo clippy --all-features --all-targets --no-deps -- -Dwarnings - - name: Run format check run: cargo fmt --check diff --git a/.github/workflows/test-http-api.yml b/.github/workflows/test-http-api.yml new file mode 100644 index 000000000..360408735 --- /dev/null +++ b/.github/workflows/test-http-api.yml @@ -0,0 +1,40 @@ +name: Test workspace with HTTP +on: + push: + branches: + - main + pull_request: + # only run tests when related changes are made + paths: + - ".github/workflows/test-workspace.yml" + - "dev/**" + - "mls_validation_service/**" + - "xmtp_api_http/**" + - "xmtp_cryptography/**" + - "xmtp_id/**" + - "xmtp_mls/**" + - "xmtp_proto/**" + - "xmtp_v2/**" + - "Cargo.toml" + - "Cargo.lock" + - "rust-toolchain" +jobs: + test: + name: Test + runs-on: warp-ubuntu-latest-x64-16x + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Update rust toolchains + run: rustup update + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + - name: Cache + uses: Swatinem/rust-cache@v2 + with: + workspaces: | + . + - name: Start Docker containers + run: dev/up + - name: Run cargo test on main workspace + run: cargo test --workspace --exclude xmtp_api_grpc --features http-api -- --test-threads=2 diff --git a/.github/workflows/test-workspace.yml b/.github/workflows/test-workspace.yml index df73a80b4..17428fe37 100644 --- a/.github/workflows/test-workspace.yml +++ b/.github/workflows/test-workspace.yml @@ -1,10 +1,8 @@ name: Test Workspace - on: push: branches: - main - pull_request: # only run tests when related changes are made paths: @@ -20,7 +18,6 @@ on: - "Cargo.toml" - "Cargo.lock" - "rust-toolchain" - jobs: test: name: Test @@ -28,21 +25,16 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - - name: Update rust toolchains run: rustup update - - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 - - name: Cache uses: Swatinem/rust-cache@v2 with: workspaces: | . - - name: Start Docker containers run: dev/up - - name: Run cargo test on main workspace run: cargo test -- --test-threads=2 diff --git a/.vscode/settings.json b/.vscode/settings.json index 4f17ce193..34f9ee388 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,25 +1,20 @@ { - "rust-analyzer": { - "cargo": { - "sysroot": "discover" - }, - "linkedProjects": [ - "bindings_ffi/Cargo.toml", - "bindings_node/Cargo.toml", - "examples/cli/Cargo.toml", - "xmtp_api_grpc_gateway/Cargo.toml" - ], - "procMacro": { - "enable": true, - "attributes.enable": true, - "ignored": { - "async-trait": ["async_trait"], - "napi-derive": ["napi"], - "async-recursion": ["async_recursion"], - "ctor": ["ctor"], - "tokio": ["test"] - } - } + "rust-analyzer.cargo.sysroot": "discover", + "rust-analyzer.linkedProjects": [ + "bindings_ffi/Cargo.toml", + "bindings_node/Cargo.toml", + "bindings_wasm/Cargo.toml", + "examples/cli/Cargo.toml" + ], + "rust-analyzer.procMacro.enable": true, + "rust-analyzer.procMacro.attributes.enable": true, + "rust-analyzer.procMacro.ignored": { + "async-trait": ["async_trait"], + "napi-derive": ["napi"], + "async-recursion": ["async_recursion"], + "ctor": ["ctor"], + "tokio": ["test"], + "async-stream": ["stream", "try_stream"] }, "[toml]": { "editor.defaultFormatter": "tamasfe.even-better-toml" diff --git a/Cargo.lock b/Cargo.lock index f54a2ff83..f2c3a428a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,9 +14,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -103,9 +103,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -118,33 +118,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.3" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -158,9 +158,9 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" [[package]] name = "arrayvec" @@ -225,18 +225,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -264,7 +264,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -286,7 +286,7 @@ dependencies = [ "futures-util", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.28", + "hyper 0.14.30", "itoa", "matchit", "memchr", @@ -295,7 +295,7 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", - "sync_wrapper", + "sync_wrapper 0.1.2", "tower", "tower-layer", "tower-service", @@ -320,9 +320,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", @@ -407,9 +407,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bitvec" @@ -471,9 +471,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" dependencies = [ "serde", ] @@ -539,13 +539,12 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.98" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "504bdec147f2cc13c8b57ed9401fd8a147cc66b67ad5cb241394244f2c947549" dependencies = [ "jobserver", "libc", - "once_cell", ] [[package]] @@ -589,7 +588,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -632,9 +631,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "c937d4061031a6d0c8da4b9a4f98a172fc2976dfb1c19213a9cf7d0d3c837e36" dependencies = [ "clap_builder", "clap_derive", @@ -642,9 +641,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "85379ba512b21a328adf887e85f7742d12e96eb31f3ef077df4ffc26b506ffed" dependencies = [ "anstream", "anstyle", @@ -654,21 +653,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "coins-bip32" @@ -724,9 +723,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "colored" @@ -763,9 +762,9 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.11.4" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ff96486ccc291d36a958107caf2c0af8c78c0af7d31ae2f35ce055130de1a6" +checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" dependencies = [ "cfg-if", "cpufeatures", @@ -941,7 +940,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -955,16 +954,15 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.1.2" +version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", - "platforms", "rustc_version", "subtle", "zeroize", @@ -978,14 +976,14 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "darling" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", @@ -993,27 +991,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "darling_macro" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -1054,13 +1052,13 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] @@ -1077,15 +1075,15 @@ dependencies = [ [[package]] name = "diesel_derives" -version = "2.2.0" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6fdd83d5947068817016e939596d246e5367279453f2a3433287894f2f2996" +checksum = "d6ff2be1e7312c858b2ef974f5c7089833ae57b5311b334b30923af58e5718d8" dependencies = [ "diesel_table_macro_syntax", "dsl_auto_type", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -1105,15 +1103,9 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" dependencies = [ - "syn 2.0.66", + "syn 2.0.72", ] -[[package]] -name = "difflib" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" - [[package]] name = "digest" version = "0.9.0" @@ -1185,23 +1177,23 @@ checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" [[package]] name = "dsl_auto_type" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab32c18ea6760d951659768a3e35ea72fc1ba0916d665a88dfe048b2a41e543f" +checksum = "c5d9abe6314103864cc2d8901b7ae224e0ab1a103a0a416661b4097b0779b607" dependencies = [ "darling", "either", "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "dunce" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "ecdsa" @@ -1257,9 +1249,9 @@ dependencies = [ [[package]] name = "either" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "elliptic-curve" @@ -1345,17 +1337,27 @@ dependencies = [ "zeroize", ] +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", + "regex", +] + [[package]] name = "env_logger" -version = "0.10.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" dependencies = [ + "anstream", + "anstyle", + "env_filter", "humantime", - "is-terminal", "log", - "regex", - "termcolor", ] [[package]] @@ -1513,14 +1515,14 @@ dependencies = [ "ethers-core", "ethers-etherscan", "eyre", - "prettyplease 0.2.20", + "prettyplease", "proc-macro2", "quote", "regex", "reqwest 0.11.27", "serde", "serde_json", - "syn 2.0.66", + "syn 2.0.72", "toml", "walkdir", ] @@ -1538,7 +1540,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -1564,7 +1566,7 @@ dependencies = [ "serde", "serde_json", "strum", - "syn 2.0.66", + "syn 2.0.72", "tempfile", "thiserror", "tiny-keccak", @@ -1787,23 +1789,14 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" dependencies = [ "crc32fast", "miniz_oxide", ] -[[package]] -name = "float-cmp" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" -dependencies = [ - "num-traits", -] - [[package]] name = "flume" version = "0.11.0" @@ -1934,7 +1927,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -2022,9 +2015,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "glob" @@ -2078,7 +2071,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.6", + "indexmap 2.3.0", "slab", "tokio", "tokio-util", @@ -2097,7 +2090,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.2.6", + "indexmap 2.3.0", "slab", "tokio", "tokio-util", @@ -2309,9 +2302,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http 1.1.0", @@ -2319,22 +2312,22 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", - "futures-core", + "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" @@ -2350,9 +2343,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.28" +version = "0.14.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" dependencies = [ "bytes", "futures-channel", @@ -2374,17 +2367,18 @@ dependencies = [ [[package]] name = "hyper" -version = "1.3.1" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ "bytes", "futures-channel", "futures-util", "h2 0.4.5", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "httparse", + "httpdate", "itoa", "pin-project-lite", "smallvec", @@ -2400,19 +2394,36 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper 0.14.28", + "hyper 0.14.30", "rustls 0.21.12", "tokio", "tokio-rustls 0.24.1", ] +[[package]] +name = "hyper-rustls" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.4.1", + "hyper-util", + "rustls 0.23.12", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.0", + "tower-service", +] + [[package]] name = "hyper-timeout" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper 0.14.28", + "hyper 0.14.30", "pin-project-lite", "tokio", "tokio-io-timeout", @@ -2426,7 +2437,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.3.1", + "hyper 1.4.1", "hyper-util", "native-tls", "tokio", @@ -2436,16 +2447,16 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d8d52be92d09acc2e01dddb7fde3ad983fc6489c7db4837e605bc3fca4cb63e" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", - "http-body 1.0.0", - "hyper 1.3.1", + "http-body 1.0.1", + "hyper 1.4.1", "pin-project-lite", "socket2", "tokio", @@ -2549,9 +2560,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -2607,9 +2618,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "isolang" @@ -2655,9 +2666,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] @@ -2744,7 +2755,7 @@ dependencies = [ "lalrpop-util", "petgraph", "regex", - "regex-syntax 0.8.3", + "regex-syntax 0.8.4", "string_cache", "term", "tiny-keccak", @@ -2758,14 +2769,14 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ - "regex-automata 0.4.6", + "regex-automata 0.4.7", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" @@ -2785,7 +2796,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", ] @@ -2867,9 +2878,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" dependencies = [ "serde", "value-bag", @@ -2902,9 +2913,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "migrations_internals" @@ -2935,9 +2946,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ "mime", "unicase", @@ -2945,22 +2956,23 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" dependencies = [ + "hermit-abi", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2979,7 +2991,7 @@ dependencies = [ "openmls_basic_credential", "openmls_rust_crypto", "openmls_traits", - "prost 0.12.6", + "prost", "rand", "serde", "sha2 0.10.8", @@ -2994,14 +3006,13 @@ dependencies = [ [[package]] name = "mockall" -version = "0.11.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c84490118f2ee2d74570d114f3d0493cbf02790df303d2707606c3e14e07c96" +checksum = "d4c28b3fb6d753d28c20e826cd46ee611fda1cf3cde03a443a974043247c065a" dependencies = [ "cfg-if", "downcast", "fragile", - "lazy_static", "mockall_derive", "predicates", "predicates-tree", @@ -3009,26 +3020,31 @@ dependencies = [ [[package]] name = "mockall_derive" -version = "0.11.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" +checksum = "341014e7f530314e9a1fdbc7400b244efea7122662c96bfa248c31da5bfb2020" dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] name = "mockito" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f6e023aa5bdf392aa06c78e4a4e6d498baab5138d0c993503350ebbc37bf1e" +checksum = "09b34bd91b9e5c5b06338d392463e1318d683cf82ec3d3af4014609be6e2108d" dependencies = [ "assert-json-diff", + "bytes", "colored", - "futures-core", - "hyper 0.14.28", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-util", "log", "rand", "regex", @@ -3062,12 +3078,6 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" -[[package]] -name = "multimap" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" - [[package]] name = "nanorand" version = "0.7.0" @@ -3079,11 +3089,10 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" dependencies = [ - "lazy_static", "libc", "log", "openssl", @@ -3101,12 +3110,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" -[[package]] -name = "normalize-line-endings" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" - [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -3119,9 +3122,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", @@ -3164,23 +3167,23 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -3191,9 +3194,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.32.2" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ "memchr", ] @@ -3206,9 +3209,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "opaque-debug" @@ -3325,7 +3328,7 @@ dependencies = [ "quote", "rstest", "rstest_reuse", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -3339,11 +3342,11 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.64" +version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "cfg-if", "foreign-types", "libc", @@ -3360,7 +3363,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -3371,18 +3374,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.3.0+3.3.0" +version = "300.3.1+3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eba8804a1c5765b18c4b3f907e6897ebabeedebc9830e1a0046c4a4cf44663e1" +checksum = "7259953d42a81bf137fbbd73bd30a8e1914d6dce43c2b90ed575783a22608b91" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.102" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", @@ -3471,7 +3474,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -3491,16 +3494,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" -[[package]] -name = "pbjson" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048f9ac93c1eab514f9470c4bc8d97ca2a0a236b84f45cc19d69a59fc11467f6" -dependencies = [ - "base64 0.13.1", - "serde", -] - [[package]] name = "pbjson" version = "0.6.0" @@ -3511,18 +3504,6 @@ dependencies = [ "serde", ] -[[package]] -name = "pbjson-build" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbb7b706f2afc610f3853550cdbbf6372fd324824a087806bd4480ea4996e24" -dependencies = [ - "heck 0.4.1", - "itertools 0.10.5", - "prost 0.11.9", - "prost-types 0.11.9", -] - [[package]] name = "pbjson-build" version = "0.6.2" @@ -3531,23 +3512,8 @@ checksum = "2580e33f2292d34be285c5bc3dba5259542b083cfad6037b6d70345f24dcb735" dependencies = [ "heck 0.4.1", "itertools 0.11.0", - "prost 0.12.6", - "prost-types 0.12.6", -] - -[[package]] -name = "pbjson-types" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a88c8d87f99a4ac14325e7a4c24af190fca261956e3b82dd7ed67e77e6c7043" -dependencies = [ - "bytes", - "chrono", - "pbjson 0.5.1", - "pbjson-build 0.5.1", - "prost 0.11.9", - "prost-build 0.11.9", - "serde", + "prost", + "prost-types", ] [[package]] @@ -3558,10 +3524,10 @@ checksum = "18f596653ba4ac51bdecbb4ef6773bc7f56042dc13927910de1684ad3d32aa12" dependencies = [ "bytes", "chrono", - "pbjson 0.6.0", - "pbjson-build 0.6.2", - "prost 0.12.6", - "prost-build 0.12.6", + "pbjson", + "pbjson-build", + "prost", + "prost-build", "serde", ] @@ -3618,7 +3584,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.2.6", + "indexmap 2.3.0", ] [[package]] @@ -3661,7 +3627,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -3699,7 +3665,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -3740,12 +3706,6 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" -[[package]] -name = "platforms" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" - [[package]] name = "plotters" version = "0.3.6" @@ -3799,9 +3759,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" [[package]] name = "powerfmt" @@ -3811,9 +3771,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "precomputed-hash" @@ -3823,44 +3786,30 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "predicates" -version = "2.1.5" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" +checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" dependencies = [ - "difflib", - "float-cmp", - "itertools 0.10.5", - "normalize-line-endings", + "anstyle", "predicates-core", - "regex", ] [[package]] name = "predicates-core" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" +checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" [[package]] name = "predicates-tree" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" dependencies = [ "predicates-core", "termtree", ] -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - [[package]] name = "prettyplease" version = "0.2.20" @@ -3868,7 +3817,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -3905,39 +3854,29 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.83" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "lazy_static", "num-traits", "rand", "rand_chacha", "rand_xorshift", - "regex-syntax 0.8.3", + "regex-syntax 0.8.4", "unarray", ] -[[package]] -name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes", - "prost-derive 0.11.9", -] - [[package]] name = "prost" version = "0.12.6" @@ -3945,29 +3884,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes", - "prost-derive 0.12.6", -] - -[[package]] -name = "prost-build" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" -dependencies = [ - "bytes", - "heck 0.4.1", - "itertools 0.10.5", - "lazy_static", - "log", - "multimap 0.8.3", - "petgraph", - "prettyplease 0.1.25", - "prost 0.11.9", - "prost-types 0.11.9", - "regex", - "syn 1.0.109", - "tempfile", - "which", + "prost-derive", ] [[package]] @@ -3980,30 +3897,17 @@ dependencies = [ "heck 0.5.0", "itertools 0.12.1", "log", - "multimap 0.10.0", + "multimap", "once_cell", "petgraph", - "prettyplease 0.2.20", - "prost 0.12.6", - "prost-types 0.12.6", + "prettyplease", + "prost", + "prost-types", "regex", - "syn 2.0.66", + "syn 2.0.72", "tempfile", ] -[[package]] -name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools 0.10.5", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "prost-derive" version = "0.12.6" @@ -4014,16 +3918,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.66", -] - -[[package]] -name = "prost-types" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" -dependencies = [ - "prost 0.11.9", + "syn 2.0.72", ] [[package]] @@ -4032,7 +3927,7 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" dependencies = [ - "prost 0.12.6", + "prost", ] [[package]] @@ -4122,11 +4017,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] @@ -4142,14 +4037,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.4" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.6", - "regex-syntax 0.8.3", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -4163,13 +4058,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.3", + "regex-syntax 0.8.4", ] [[package]] @@ -4180,9 +4075,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "reqwest" @@ -4198,8 +4093,8 @@ dependencies = [ "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.28", - "hyper-rustls", + "hyper 0.14.30", + "hyper-rustls 0.24.2", "ipnet", "js-sys", "log", @@ -4212,7 +4107,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "system-configuration", "tokio", "tokio-rustls 0.24.1", @@ -4227,9 +4122,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" dependencies = [ "base64 0.22.1", "bytes", @@ -4238,9 +4133,10 @@ dependencies = [ "futures-util", "h2 0.4.5", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", - "hyper 1.3.1", + "hyper 1.4.1", + "hyper-rustls 0.27.2", "hyper-tls", "hyper-util", "ipnet", @@ -4251,11 +4147,11 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile 2.1.2", + "rustls-pemfile 2.1.3", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.1", "system-configuration", "tokio", "tokio-native-tls", @@ -4416,7 +4312,7 @@ version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -4444,19 +4340,32 @@ dependencies = [ "log", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.4", + "rustls-webpki 0.102.6", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls" +version = "0.23.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki 0.102.6", "subtle", "zeroize", ] [[package]] name = "rustls-native-certs" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +checksum = "a88d6d420651b496bdd98684116959239430022a115c1240e6c3993be0b15fba" dependencies = [ "openssl-probe", - "rustls-pemfile 2.1.2", + "rustls-pemfile 2.1.3", "rustls-pki-types", "schannel", "security-framework", @@ -4473,9 +4382,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" dependencies = [ "base64 0.22.1", "rustls-pki-types", @@ -4483,19 +4392,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" - -[[package]] -name = "rustls-webpki" -version = "0.100.3" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6a5fc258f1c1276dfe3016516945546e2d5383911efc0fc4f1cdc5df3a4ae3" -dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", -] +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-webpki" @@ -4509,9 +4408,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.4" +version = "0.102.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" dependencies = [ "ring 0.17.8", "rustls-pki-types", @@ -4654,11 +4553,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -4667,9 +4566,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" dependencies = [ "core-foundation-sys", "libc", @@ -4698,22 +4597,22 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.202" +version = "1.0.205" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +checksum = "e33aedb1a7135da52b7c21791455563facbbcc43d0f0f66165b42c21b3dfb150" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.202" +version = "1.0.205" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +checksum = "692d6f5ac90220161d6774db30c662202721e64aed9058d2c394f451261420c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -4727,20 +4626,21 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] @@ -4832,9 +4732,9 @@ dependencies = [ [[package]] name = "similar" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640" +checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" [[package]] name = "simple_asn1" @@ -4877,7 +4777,7 @@ checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -4966,31 +4866,31 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", "rustversion", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sval" @@ -5103,9 +5003,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.66" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", @@ -5118,6 +5018,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + [[package]] name = "system-configuration" version = "0.5.1" @@ -5147,14 +5053,15 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.10.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5168,15 +5075,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - [[package]] name = "termtree" version = "0.4.1" @@ -5185,22 +5083,22 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -5275,9 +5173,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -5302,7 +5200,7 @@ dependencies = [ [[package]] name = "tls_codec" version = "0.4.2-pre.1" -source = "git+https://github.com/rustcrypto/formats#6c42217ec681a073bfbdfffd78588306f9063de2" +source = "git+https://github.com/rustcrypto/formats#6456b48674e0646b4628adb075c82a290d3160b9" dependencies = [ "serde", "tls_codec_derive 0.4.1 (git+https://github.com/rustcrypto/formats)", @@ -5317,36 +5215,36 @@ checksum = "8d9ef545650e79f30233c0003bcc2504d7efac6dad25fca40744de773fe2049c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "tls_codec_derive" version = "0.4.1" -source = "git+https://github.com/rustcrypto/formats#6c42217ec681a073bfbdfffd78588306f9063de2" +source = "git+https://github.com/rustcrypto/formats#6456b48674e0646b4628adb075c82a290d3160b9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "tokio" -version = "1.37.0" +version = "1.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "tracing", + "windows-sys 0.52.0", ] [[package]] @@ -5361,13 +5259,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -5401,6 +5299,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls 0.23.12", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.15" @@ -5455,21 +5364,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.13" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.13", + "toml_edit 0.22.20", ] [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] @@ -5480,22 +5389,22 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.3.0", "toml_datetime", "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.22.13" +version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.3.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.8", + "winnow 0.6.18", ] [[package]] @@ -5512,13 +5421,13 @@ dependencies = [ "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.28", + "hyper 0.14.30", "hyper-timeout", "percent-encoding", "pin-project", - "prost 0.12.6", + "prost", "rustls-native-certs", - "rustls-pemfile 2.1.2", + "rustls-pemfile 2.1.3", "rustls-pki-types", "tokio", "tokio-rustls 0.25.0", @@ -5527,7 +5436,7 @@ dependencies = [ "tower-layer", "tower-service", "tracing", - "webpki-roots 0.26.1", + "webpki-roots 0.26.3", ] [[package]] @@ -5582,7 +5491,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -5647,11 +5556,10 @@ dependencies = [ [[package]] name = "tracing-test" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a2c0ff408fe918a94c428a3f2ad04e4afd5c95bbc08fcf868eff750c15728a4" +checksum = "557b891436fe0d5e0e363427fc7f217abf9ccd510d5136549847bdcbcd011d68" dependencies = [ - "lazy_static", "tracing-core", "tracing-subscriber", "tracing-test-macro", @@ -5659,13 +5567,12 @@ dependencies = [ [[package]] name = "tracing-test-macro" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258bc1c4f8e2e73a977812ab339d503e6feeb92700f6d07a6de4d321522d5c08" +checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ - "lazy_static", "quote", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] @@ -5775,9 +5682,9 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" @@ -5809,9 +5716,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -5826,9 +5733,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" @@ -5842,9 +5749,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom", ] @@ -5899,9 +5806,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" @@ -5933,7 +5840,7 @@ dependencies = [ "futures-util", "headers", "http 0.2.12", - "hyper 0.14.28", + "hyper 0.14.30", "log", "mime", "mime_guess", @@ -5980,7 +5887,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", "wasm-bindgen-shared", ] @@ -6014,7 +5921,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6047,7 +5954,7 @@ checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -6073,15 +5980,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" -dependencies = [ - "rustls-webpki 0.100.3", -] - [[package]] name = "webpki-roots" version = "0.25.4" @@ -6090,25 +5988,13 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.1" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" dependencies = [ "rustls-pki-types", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - [[package]] name = "winapi" version = "0.3.9" @@ -6127,11 +6013,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -6146,7 +6032,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -6164,7 +6050,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -6184,18 +6079,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -6206,9 +6101,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -6218,9 +6113,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -6230,15 +6125,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -6248,9 +6143,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -6260,9 +6155,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -6272,9 +6167,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -6284,9 +6179,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" @@ -6299,9 +6194,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.8" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] @@ -6371,26 +6266,41 @@ name = "xmtp_api_grpc" version = "0.1.0" dependencies = [ "async-stream", - "base64 0.21.7", + "base64 0.22.1", "futures", "hex", - "http-body 0.4.6", - "hyper 0.14.28", "log", - "pbjson 0.5.1", - "pbjson-types 0.5.1", - "prost 0.12.6", + "pbjson", + "pbjson-types", + "prost", "serde", "tokio", "tonic", - "tower", "tracing", - "uuid 1.8.0", - "webpki-roots 0.23.1", + "uuid 1.10.0", "xmtp_proto", "xmtp_v2", ] +[[package]] +name = "xmtp_api_http" +version = "0.1.0" +dependencies = [ + "async-stream", + "async-trait", + "bytes", + "futures", + "log", + "reqwest 0.12.5", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "xmtp_proto", +] + [[package]] name = "xmtp_cli" version = "0.1.0" @@ -6403,7 +6313,7 @@ dependencies = [ "hex", "kv-log-macro", "log", - "prost 0.12.6", + "prost", "serde", "serde_json", "thiserror", @@ -6448,6 +6358,7 @@ dependencies = [ "ed25519", "ed25519-dalek", "ethers", + "ethers-core", "futures", "hex", "log", @@ -6455,7 +6366,7 @@ dependencies = [ "openmls_basic_credential", "openmls_rust_crypto", "openmls_traits", - "prost 0.12.6", + "prost", "rand", "regex", "rustc-hex", @@ -6474,10 +6385,10 @@ dependencies = [ name = "xmtp_mls" version = "0.1.0" dependencies = [ - "aes", "aes-gcm", "anyhow", "async-barrier", + "async-stream", "async-trait", "bincode", "chrono", @@ -6502,9 +6413,9 @@ dependencies = [ "openmls_rust_crypto", "openmls_traits", "parking_lot", - "prost 0.12.6", + "prost", "rand", - "reqwest 0.12.4", + "reqwest 0.12.5", "ring 0.17.8", "serde", "serde_json", @@ -6522,6 +6433,7 @@ dependencies = [ "tracing-subscriber", "tracing-test", "xmtp_api_grpc", + "xmtp_api_http", "xmtp_cryptography", "xmtp_id", "xmtp_proto", @@ -6537,10 +6449,10 @@ dependencies = [ "futures-core", "openmls", "openmls_basic_credential", - "pbjson 0.6.0", - "pbjson-types 0.6.0", - "prost 0.12.6", - "prost-types 0.12.6", + "pbjson", + "pbjson-types", + "prost", + "prost-types", "serde", "tonic", ] @@ -6552,7 +6464,7 @@ dependencies = [ "base64 0.21.7", "libsecp256k1", "once_cell", - "prost 0.12.6", + "prost", "rand", "xmtp_proto", "xmtp_v2", @@ -6581,11 +6493,32 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] @@ -6598,7 +6531,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -6642,9 +6575,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.10+zstd.1.5.6" +version = "2.0.13+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index 822b063b9..9ad24599a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "mls_validation_service", "xmtp_cryptography", "xmtp_api_grpc", + "xmtp_api_http", "xmtp_proto", "xmtp_user_preferences", "xmtp_v2", @@ -35,13 +36,11 @@ ethers-core = "2.0.4" futures = "0.3.30" futures-core = "0.3.30" hex = "0.4.3" -log = { version = "0.4", features = ["release_max_level_debug"] } +log = { version = "0.4" } openmls = { git = "https://github.com/xmtp/openmls", rev = "9cb3207", default-features = false } openmls_basic_credential = { git = "https://github.com/xmtp/openmls", rev = "9cb3207" } openmls_rust_crypto = { git = "https://github.com/xmtp/openmls", rev = "9cb3207" } openmls_traits = { git = "https://github.com/xmtp/openmls", rev = "9cb3207" } -prost = "^0.12" -prost-types = "^0.12" rand = "0.8.5" regex = "1.10.4" rustc-hex = "2.1.0" @@ -50,11 +49,16 @@ serde_json = "1.0" sha2 = "0.10.8" thiserror = "1.0" tls_codec = "0.4.0" -tokio = { version = "1.35.1", features = ["macros"] } -tonic = "^0.11" -tracing = { version = "0.1", features = ["release_max_level_debug"] } +tokio = { version = "1.35.1", default-features = false } +async-stream = "0.3" +tracing = { version = "0.1" } tracing-subscriber = "0.3" url = "2.5.0" +tonic = "^0.11" +prost = "^0.12" +prost-types = "^0.12" +pbjson = "0.6.0" +pbjson-types = "0.6.0" # Internal Crate Dependencies xmtp_cryptography = { path = "xmtp_cryptography" } diff --git a/bindings_ffi/Cargo.lock b/bindings_ffi/Cargo.lock index 9d9afb5aa..04299c077 100644 --- a/bindings_ffi/Cargo.lock +++ b/bindings_ffi/Cargo.lock @@ -1404,7 +1404,7 @@ dependencies = [ "ethers-core", "ethers-etherscan", "eyre", - "prettyplease 0.2.16", + "prettyplease", "proc-macro2", "quote", "regex", @@ -3095,16 +3095,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" -[[package]] -name = "pbjson" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048f9ac93c1eab514f9470c4bc8d97ca2a0a236b84f45cc19d69a59fc11467f6" -dependencies = [ - "base64 0.13.1", - "serde", -] - [[package]] name = "pbjson" version = "0.6.0" @@ -3115,18 +3105,6 @@ dependencies = [ "serde", ] -[[package]] -name = "pbjson-build" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbb7b706f2afc610f3853550cdbbf6372fd324824a087806bd4480ea4996e24" -dependencies = [ - "heck 0.4.1", - "itertools 0.10.5", - "prost 0.11.9", - "prost-types 0.11.9", -] - [[package]] name = "pbjson-build" version = "0.6.2" @@ -3135,23 +3113,8 @@ checksum = "2580e33f2292d34be285c5bc3dba5259542b083cfad6037b6d70345f24dcb735" dependencies = [ "heck 0.4.1", "itertools 0.11.0", - "prost 0.12.3", - "prost-types 0.12.3", -] - -[[package]] -name = "pbjson-types" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a88c8d87f99a4ac14325e7a4c24af190fca261956e3b82dd7ed67e77e6c7043" -dependencies = [ - "bytes", - "chrono", - "pbjson 0.5.1", - "pbjson-build 0.5.1", - "prost 0.11.9", - "prost-build 0.11.9", - "serde", + "prost", + "prost-types", ] [[package]] @@ -3162,10 +3125,10 @@ checksum = "18f596653ba4ac51bdecbb4ef6773bc7f56042dc13927910de1684ad3d32aa12" dependencies = [ "bytes", "chrono", - "pbjson 0.6.0", - "pbjson-build 0.6.2", - "prost 0.12.3", - "prost-build 0.12.3", + "pbjson", + "pbjson-build", + "prost", + "prost-build", "serde", ] @@ -3397,16 +3360,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - [[package]] name = "prettyplease" version = "0.2.16" @@ -3519,86 +3472,40 @@ dependencies = [ [[package]] name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes", - "prost-derive 0.11.9", -] - -[[package]] -name = "prost" -version = "0.12.3" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes", - "prost-derive 0.12.3", -] - -[[package]] -name = "prost-build" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" -dependencies = [ - "bytes", - "heck 0.4.1", - "itertools 0.10.5", - "lazy_static", - "log", - "multimap", - "petgraph", - "prettyplease 0.1.25", - "prost 0.11.9", - "prost-types 0.11.9", - "regex", - "syn 1.0.109", - "tempfile", - "which", + "prost-derive", ] [[package]] name = "prost-build" -version = "0.12.3" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" +checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" dependencies = [ "bytes", - "heck 0.4.1", + "heck 0.5.0", "itertools 0.11.0", "log", "multimap", "once_cell", "petgraph", - "prettyplease 0.2.16", - "prost 0.12.3", - "prost-types 0.12.3", + "prettyplease", + "prost", + "prost-types", "regex", "syn 2.0.48", "tempfile", - "which", ] [[package]] name = "prost-derive" -version = "0.11.9" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools 0.10.5", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "prost-derive" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", "itertools 0.11.0", @@ -3609,20 +3516,11 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" -dependencies = [ - "prost 0.11.9", -] - -[[package]] -name = "prost-types" -version = "0.12.3" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" +checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" dependencies = [ - "prost 0.12.3", + "prost", ] [[package]] @@ -4032,9 +3930,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.2" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" dependencies = [ "log", "ring 0.17.8", @@ -4082,16 +3980,6 @@ version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ede67b28608b4c60685c7d54122d4400d90f62b40caee7700e700380a390fa8" -[[package]] -name = "rustls-webpki" -version = "0.100.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6a5fc258f1c1276dfe3016516945546e2d5383911efc0fc4f1cdc5df3a4ae3" -dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", -] - [[package]] name = "rustls-webpki" version = "0.101.7" @@ -4849,6 +4737,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", + "tracing", "windows-sys 0.48.0", ] @@ -4899,7 +4788,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" dependencies = [ - "rustls 0.22.2", + "rustls 0.22.4", "rustls-pki-types", "tokio", ] @@ -5041,7 +4930,7 @@ dependencies = [ "hyper-timeout", "percent-encoding", "pin-project", - "prost 0.12.3", + "prost", "rustls-native-certs", "rustls-pemfile 2.1.0", "rustls-pki-types", @@ -5093,7 +4982,6 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -5599,15 +5487,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" -dependencies = [ - "rustls-webpki 0.100.3", -] - [[package]] name = "webpki-roots" version = "0.25.3" @@ -5632,18 +5511,6 @@ dependencies = [ "nom", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - [[package]] name = "winapi" version = "0.3.9" @@ -5890,21 +5757,17 @@ name = "xmtp_api_grpc" version = "0.1.0" dependencies = [ "async-stream", - "base64 0.21.7", + "base64 0.22.1", "futures", "hex", - "http-body 0.4.6", - "hyper 0.14.28", "log", - "pbjson 0.5.1", - "pbjson-types 0.5.1", - "prost 0.12.3", + "pbjson", + "pbjson-types", + "prost", "serde", "tokio", "tonic", - "tower", "tracing", - "webpki-roots 0.23.1", "xmtp_proto", "xmtp_v2", ] @@ -5938,6 +5801,7 @@ dependencies = [ "ed25519", "ed25519-dalek", "ethers", + "ethers-core", "futures", "hex", "log", @@ -5945,7 +5809,7 @@ dependencies = [ "openmls_basic_credential", "openmls_rust_crypto", "openmls_traits", - "prost 0.12.3", + "prost", "rand", "regex", "rustc-hex", @@ -5963,8 +5827,8 @@ dependencies = [ name = "xmtp_mls" version = "0.1.0" dependencies = [ - "aes", "aes-gcm", + "async-stream", "async-trait", "bincode", "chrono", @@ -5982,7 +5846,7 @@ dependencies = [ "openmls_rust_crypto", "openmls_traits", "parking_lot", - "prost 0.12.3", + "prost", "rand", "reqwest 0.12.4", "ring 0.17.8", @@ -6011,10 +5875,10 @@ dependencies = [ "futures-core", "openmls", "openmls_basic_credential", - "pbjson 0.6.0", - "pbjson-types 0.6.0", - "prost 0.12.3", - "prost-types 0.12.3", + "pbjson", + "pbjson-types", + "prost", + "prost-types", "serde", "tonic", ] @@ -6025,7 +5889,7 @@ version = "0.1.0" dependencies = [ "base64 0.21.7", "once_cell", - "prost 0.12.3", + "prost", "xmtp_proto", "xmtp_v2", ] @@ -6056,6 +5920,7 @@ dependencies = [ "ethers-core", "futures", "log", + "parking_lot", "tempfile", "thiserror", "thread-id", diff --git a/bindings_ffi/Cargo.toml b/bindings_ffi/Cargo.toml index d7cba6126..6ef49dbb0 100644 --- a/bindings_ffi/Cargo.toml +++ b/bindings_ffi/Cargo.toml @@ -22,6 +22,7 @@ xmtp_mls = { path = "../xmtp_mls", features = ["grpc", "native"] } xmtp_proto = { path = "../xmtp_proto", features = ["proto_full", "grpc"] } xmtp_user_preferences = { path = "../xmtp_user_preferences" } xmtp_v2 = { path = "../xmtp_v2" } +parking_lot = "0.12.3" tracing-subscriber = { version = "0.3", features = ["env-filter"] } # NOTE: A regression in openssl-sys exists where libatomic is dynamically linked diff --git a/bindings_ffi/src/logger.rs b/bindings_ffi/src/logger.rs index c3dd68922..5e9d0c623 100644 --- a/bindings_ffi/src/logger.rs +++ b/bindings_ffi/src/logger.rs @@ -6,7 +6,7 @@ pub trait FfiLogger: Send + Sync { } struct RustLogger { - logger: std::sync::Mutex>, + logger: parking_lot::Mutex>, } impl log::Log for RustLogger { @@ -17,7 +17,7 @@ impl log::Log for RustLogger { fn log(&self, record: &Record) { if self.enabled(record.metadata()) { // TODO handle errors - self.logger.lock().expect("Logger mutex is poisoned!").log( + self.logger.lock().log( record.level() as u32, record.level().to_string(), format!("[libxmtp][t:{}] {}", thread_id::get(), record.args()), @@ -33,7 +33,7 @@ pub fn init_logger(logger: Box) { // TODO handle errors LOGGER_INIT.call_once(|| { let logger = RustLogger { - logger: std::sync::Mutex::new(logger), + logger: parking_lot::Mutex::new(logger), }; log::set_boxed_logger(Box::new(logger)) .map(|()| log::set_max_level(LevelFilter::Info)) diff --git a/bindings_node/Cargo.lock b/bindings_node/Cargo.lock index da46c7974..caa5d48cc 100644 --- a/bindings_node/Cargo.lock +++ b/bindings_node/Cargo.lock @@ -304,7 +304,7 @@ dependencies = [ "napi", "napi-build", "napi-derive", - "prost 0.12.6", + "prost", "rand", "tokio", "tonic", @@ -1244,7 +1244,7 @@ dependencies = [ "ethers-core", "ethers-etherscan", "eyre", - "prettyplease 0.2.20", + "prettyplease", "proc-macro2", "quote", "regex", @@ -2474,12 +2474,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - [[package]] name = "multimap" version = "0.10.0" @@ -2923,16 +2917,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" -[[package]] -name = "pbjson" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048f9ac93c1eab514f9470c4bc8d97ca2a0a236b84f45cc19d69a59fc11467f6" -dependencies = [ - "base64 0.13.1", - "serde", -] - [[package]] name = "pbjson" version = "0.6.0" @@ -2943,18 +2927,6 @@ dependencies = [ "serde", ] -[[package]] -name = "pbjson-build" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbb7b706f2afc610f3853550cdbbf6372fd324824a087806bd4480ea4996e24" -dependencies = [ - "heck 0.4.1", - "itertools 0.10.5", - "prost 0.11.9", - "prost-types 0.11.9", -] - [[package]] name = "pbjson-build" version = "0.6.2" @@ -2963,23 +2935,8 @@ checksum = "2580e33f2292d34be285c5bc3dba5259542b083cfad6037b6d70345f24dcb735" dependencies = [ "heck 0.4.1", "itertools 0.11.0", - "prost 0.12.6", - "prost-types 0.12.6", -] - -[[package]] -name = "pbjson-types" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a88c8d87f99a4ac14325e7a4c24af190fca261956e3b82dd7ed67e77e6c7043" -dependencies = [ - "bytes", - "chrono", - "pbjson 0.5.1", - "pbjson-build 0.5.1", - "prost 0.11.9", - "prost-build 0.11.9", - "serde", + "prost", + "prost-types", ] [[package]] @@ -2990,10 +2947,10 @@ checksum = "18f596653ba4ac51bdecbb4ef6773bc7f56042dc13927910de1684ad3d32aa12" dependencies = [ "bytes", "chrono", - "pbjson 0.6.0", - "pbjson-build 0.6.2", - "prost 0.12.6", - "prost-build 0.12.6", + "pbjson", + "pbjson-build", + "prost", + "prost-build", "serde", ] @@ -3219,16 +3176,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - [[package]] name = "prettyplease" version = "0.2.20" @@ -3296,16 +3243,6 @@ dependencies = [ "unarray", ] -[[package]] -name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes", - "prost-derive 0.11.9", -] - [[package]] name = "prost" version = "0.12.6" @@ -3313,29 +3250,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes", - "prost-derive 0.12.6", -] - -[[package]] -name = "prost-build" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" -dependencies = [ - "bytes", - "heck 0.4.1", - "itertools 0.10.5", - "lazy_static", - "log", - "multimap 0.8.3", - "petgraph", - "prettyplease 0.1.25", - "prost 0.11.9", - "prost-types 0.11.9", - "regex", - "syn 1.0.109", - "tempfile", - "which", + "prost-derive", ] [[package]] @@ -3348,30 +3263,17 @@ dependencies = [ "heck 0.5.0", "itertools 0.12.1", "log", - "multimap 0.10.0", + "multimap", "once_cell", "petgraph", - "prettyplease 0.2.20", - "prost 0.12.6", - "prost-types 0.12.6", + "prettyplease", + "prost", + "prost-types", "regex", "syn 2.0.64", "tempfile", ] -[[package]] -name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools 0.10.5", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "prost-derive" version = "0.12.6" @@ -3385,22 +3287,13 @@ dependencies = [ "syn 2.0.64", ] -[[package]] -name = "prost-types" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" -dependencies = [ - "prost 0.11.9", -] - [[package]] name = "prost-types" version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" dependencies = [ - "prost 0.12.6", + "prost", ] [[package]] @@ -3840,16 +3733,6 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" -[[package]] -name = "rustls-webpki" -version = "0.100.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6a5fc258f1c1276dfe3016516945546e2d5383911efc0fc4f1cdc5df3a4ae3" -dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", -] - [[package]] name = "rustls-webpki" version = "0.101.7" @@ -4525,6 +4408,7 @@ dependencies = [ "pin-project-lite", "socket2", "tokio-macros", + "tracing", "windows-sys 0.48.0", ] @@ -4683,7 +4567,7 @@ dependencies = [ "hyper-timeout", "percent-encoding", "pin-project", - "prost 0.12.6", + "prost", "rustls-native-certs", "rustls-pemfile 2.1.2", "rustls-pki-types", @@ -4735,7 +4619,6 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -5054,15 +4937,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" -dependencies = [ - "rustls-webpki 0.100.3", -] - [[package]] name = "webpki-roots" version = "0.25.4" @@ -5078,18 +4952,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - [[package]] name = "winapi" version = "0.3.9" @@ -5352,21 +5214,17 @@ name = "xmtp_api_grpc" version = "0.1.0" dependencies = [ "async-stream", - "base64 0.21.7", + "base64 0.22.1", "futures", "hex", - "http-body 0.4.6", - "hyper 0.14.28", "log", - "pbjson 0.5.1", - "pbjson-types 0.5.1", - "prost 0.12.6", + "pbjson", + "pbjson-types", + "prost", "serde", "tokio", "tonic", - "tower", "tracing", - "webpki-roots 0.23.1", "xmtp_proto", "xmtp_v2", ] @@ -5400,6 +5258,7 @@ dependencies = [ "ed25519", "ed25519-dalek", "ethers", + "ethers-core", "futures", "hex", "log", @@ -5407,7 +5266,7 @@ dependencies = [ "openmls_basic_credential", "openmls_rust_crypto", "openmls_traits", - "prost 0.12.6", + "prost", "rand", "regex", "rustc-hex", @@ -5425,8 +5284,8 @@ dependencies = [ name = "xmtp_mls" version = "0.1.0" dependencies = [ - "aes", "aes-gcm", + "async-stream", "async-trait", "bincode", "chrono", @@ -5444,7 +5303,7 @@ dependencies = [ "openmls_rust_crypto", "openmls_traits", "parking_lot", - "prost 0.12.6", + "prost", "rand", "reqwest 0.12.4", "ring 0.17.8", @@ -5473,10 +5332,10 @@ dependencies = [ "futures-core", "openmls", "openmls_basic_credential", - "pbjson 0.6.0", - "pbjson-types 0.6.0", - "prost 0.12.6", - "prost-types 0.12.6", + "pbjson", + "pbjson-types", + "prost", + "prost-types", "serde", "tonic", ] diff --git a/bindings_node/Cargo.toml b/bindings_node/Cargo.toml index c31c75cd8..23711717c 100644 --- a/bindings_node/Cargo.toml +++ b/bindings_node/Cargo.toml @@ -10,6 +10,7 @@ crate-type = ["cdylib"] # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix futures = "0.3.30" hex = "0.4.3" +log = { version = "0.4", features = ["release_max_level_debug"] } napi = { version = "2.12.2", default-features = false, features = [ "napi4", "napi6", @@ -17,15 +18,14 @@ napi = { version = "2.12.2", default-features = false, features = [ ] } napi-derive = "2.12.2" prost = "^0.12" +rand = "0.8.5" tokio = { version = "1.35.1", features = ["macros", "rt-multi-thread", "time"] } tonic = { version = "^0.11", features = ["tls"] } xmtp_api_grpc = { path = "../xmtp_api_grpc" } xmtp_cryptography = { path = "../xmtp_cryptography" } +xmtp_id = { path = "../xmtp_id" } xmtp_mls = { path = "../xmtp_mls", features = ["grpc", "native"] } xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } -xmtp_id = { path = "../xmtp_id" } -rand = "0.8.5" -log = { version = "0.4", features = ["release_max_level_debug"] } [build-dependencies] napi-build = "2.0.1" diff --git a/bindings_wasm/Cargo.toml b/bindings_wasm/Cargo.toml index 01be1d6b2..eeb652421 100644 --- a/bindings_wasm/Cargo.toml +++ b/bindings_wasm/Cargo.toml @@ -2,28 +2,23 @@ edition = "2021" name = "bindings_wasm" version = "0.1.0" -description = "WASM bindings for the libXMTP rust library" -repository = "https://github.com/xmtp/libxmtp" -license = "MIT" [lib] crate-type = ["cdylib", "rlib"] [dependencies] -async-trait = "0.1.68" -getrandom = { version = "0.2", features = ["js"] } -hex = "0.4" js-sys = "0.3" -prost = { version = "^0.12", features = ["prost-derive"] } -prost-types = "^0.12" +serde = { version = "1.0", features = ["derive"] } +serde-wasm-bindgen = "0.6.5" wasm-bindgen = "0.2.91" wasm-bindgen-futures = "0.4.41" -xmtp_api_grpc_gateway = { path = "../xmtp_api_grpc_gateway" } -xmtp_cryptography = { path = "../xmtp_cryptography", features = ["ws"] } +xmtp_api_http = { path = "../xmtp_api_http" } +xmtp_cryptography = { path = "../xmtp_cryptography" } +xmtp_id = { path = "../xmtp_id" } +xmtp_mls = { path = "../xmtp_mls", features = [] } xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } [dev-dependencies] -uuid = { version = "1.3.1", features = ["v4"] } wasm-bindgen-test = "0.3.41" [profile.release] diff --git a/bindings_wasm/package-lock.json b/bindings_wasm/package-lock.json index 46f479037..1dcd55649 100644 --- a/bindings_wasm/package-lock.json +++ b/bindings_wasm/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.0", "license": "MIT", "devDependencies": { - "wasm-pack": "^0.12.1" + "wasm-pack": "^0.13.0" }, "engines": { "node": ">=18" @@ -264,9 +264,9 @@ } }, "node_modules/wasm-pack": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/wasm-pack/-/wasm-pack-0.12.1.tgz", - "integrity": "sha512-dIyKWUumPFsGohdndZjDXRFaokUT/kQS+SavbbiXVAvA/eN4riX5QNdB6AhXQx37zNxluxQkuixZUgJ8adKjOg==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/wasm-pack/-/wasm-pack-0.13.0.tgz", + "integrity": "sha512-AmboGZEnZoIcVCzSlkLEmNFEqJN+IwgshJ5S7pi30uNUTce4LvWkifQzsQRxnWj47G8gkqZxlyGlyQplsnIS7w==", "dev": true, "hasInstallScript": true, "dependencies": { diff --git a/bindings_wasm/package.json b/bindings_wasm/package.json index 5fe210718..90ef91975 100644 --- a/bindings_wasm/package.json +++ b/bindings_wasm/package.json @@ -24,10 +24,11 @@ }, "scripts": { "build": "npm run clean && npm run build:node && npm run clean:gitignore", - "build:node": "wasm-pack build --target nodejs --no-pack --release --out-dir ./dist/node", + "build:node": "wasm-pack build --target web --no-pack --release --out-dir ./dist", "clean": "rm -rf ./dist", "clean:gitignore": "rm -f ./dist/**/.gitignore", - "prepublishOnly": "npm run build" + "prepublishOnly": "npm run build", + "test": "wasm-pack test --chrome --headless" }, "files": [ "./dist/**/*" @@ -49,6 +50,6 @@ "registry": "https://registry.npmjs.org/" }, "devDependencies": { - "wasm-pack": "^0.12.1" + "wasm-pack": "^0.13.0" } } diff --git a/bindings_wasm/rustfmt.toml b/bindings_wasm/rustfmt.toml new file mode 100644 index 000000000..2bc17ab9a --- /dev/null +++ b/bindings_wasm/rustfmt.toml @@ -0,0 +1,2 @@ +edition = "2021" +tab_spaces = 2 diff --git a/bindings_wasm/src/lib.rs b/bindings_wasm/src/lib.rs index 374800493..9e31f7a45 100644 --- a/bindings_wasm/src/lib.rs +++ b/bindings_wasm/src/lib.rs @@ -1,24 +1 @@ -use wasm_bindgen::prelude::{wasm_bindgen, JsError}; -use xmtp_api_grpc_gateway::XmtpGrpcGatewayClient; - -#[wasm_bindgen] -pub struct WasmXmtpClient { - api: XmtpGrpcGatewayClient, - // inbox_owner: WasmInboxOwner, -} - -impl WasmXmtpClient { - pub fn api(&self) -> &XmtpGrpcGatewayClient { - &self.api - } -} - -#[wasm_bindgen] -impl WasmXmtpClient { - #[wasm_bindgen(constructor)] - pub fn create_client(host_url: String) -> Result { - Ok(WasmXmtpClient { - api: XmtpGrpcGatewayClient::new(host_url), - }) - } -} +pub mod mls_client; diff --git a/bindings_wasm/src/mls_client.rs b/bindings_wasm/src/mls_client.rs new file mode 100644 index 000000000..2afad6c74 --- /dev/null +++ b/bindings_wasm/src/mls_client.rs @@ -0,0 +1,274 @@ +use js_sys::Uint8Array; +use std::collections::HashMap; +use std::sync::Arc; +use wasm_bindgen::prelude::{wasm_bindgen, JsError}; +use wasm_bindgen::JsValue; +use xmtp_api_http::XmtpHttpApiClient; +use xmtp_cryptography::signature::ed25519_public_key_to_address; +use xmtp_id::associations::generate_inbox_id as xmtp_id_generate_inbox_id; +use xmtp_id::associations::{ + AccountId, MemberIdentifier, RecoverableEcdsaSignature, Signature, SmartContractWalletSignature, +}; +use xmtp_mls::api::ApiClientWrapper; +use xmtp_mls::builder::ClientBuilder; +use xmtp_mls::identity::IdentityStrategy; +use xmtp_mls::retry::Retry; +use xmtp_mls::storage::{EncryptedMessageStore, EncryptionKey, StorageOption}; +use xmtp_mls::Client as MlsClient; + +pub type RustXmtpClient = MlsClient; + +#[wasm_bindgen] +pub struct WasmClient { + account_address: String, + inner_client: Arc, + signatures: HashMap>, +} + +#[wasm_bindgen] +pub async fn create_client( + host: String, + inbox_id: String, + account_address: String, + encryption_key: Option, + history_sync_url: Option, +) -> Result { + let api_client = XmtpHttpApiClient::new(host.clone()).unwrap(); + + let storage_option = StorageOption::Ephemeral; + let store = match encryption_key { + Some(key) => { + let key: Vec = key.to_vec(); + let key: EncryptionKey = key + .try_into() + .map_err(|_| JsError::new("Malformed 32 byte encryption key"))?; + EncryptedMessageStore::new(storage_option, key) + .map_err(|_| JsError::new("Error creating encrypted message store"))? + } + None => EncryptedMessageStore::new_unencrypted(storage_option) + .map_err(|_| JsError::new("Error creating unencrypted message store"))?, + }; + + let identity_strategy = IdentityStrategy::CreateIfNotFound( + inbox_id.clone(), + account_address.clone().to_lowercase(), + // this is a temporary solution + 1, + None, + ); + + let xmtp_client = match history_sync_url { + Some(url) => ClientBuilder::new(identity_strategy) + .api_client(api_client) + .store(store) + .history_sync_url(&url) + .build() + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?, + None => ClientBuilder::new(identity_strategy) + .api_client(api_client) + .store(store) + .build() + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?, + }; + + Ok(WasmClient { + account_address, + inner_client: Arc::new(xmtp_client), + signatures: HashMap::new(), + }) +} + +#[wasm_bindgen] +pub async fn get_inbox_id_for_address( + host: String, + account_address: String, +) -> Result, JsError> { + let account_address = account_address.to_lowercase(); + let api_client = ApiClientWrapper::new( + XmtpHttpApiClient::new(host.clone()).unwrap(), + Retry::default(), + ); + + let results = api_client + .get_inbox_ids(vec![account_address.clone()]) + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + + Ok(results.get(&account_address).cloned()) +} + +#[wasm_bindgen] +pub fn generate_inbox_id(account_address: String) -> String { + let account_address = account_address.to_lowercase(); + // ensure that the nonce is always 1 for now since this will only be used for the + // create_client function above, which also has a hard-coded nonce of 1 + xmtp_id_generate_inbox_id(&account_address, &1) +} + +#[wasm_bindgen] +impl WasmClient { + #[wasm_bindgen(getter)] + pub fn account_address(&self) -> String { + self.account_address.clone() + } + + #[wasm_bindgen(getter)] + pub fn inbox_id(&self) -> String { + self.inner_client.inbox_id() + } + + #[wasm_bindgen(getter)] + pub fn is_registered(&self) -> bool { + self.inner_client.identity().signature_request().is_none() + } + + #[wasm_bindgen(getter)] + pub fn installation_id(&self) -> String { + ed25519_public_key_to_address(self.inner_client.installation_public_key().as_slice()) + } + + #[wasm_bindgen] + pub async fn can_message(&self, account_addresses: Vec) -> Result { + let results: HashMap = self + .inner_client + .can_message(account_addresses) + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + + Ok(serde_wasm_bindgen::to_value(&results)?) + } + + #[wasm_bindgen] + pub fn add_ecdsa_signature(&mut self, signature_bytes: Uint8Array) -> Result<(), JsError> { + if self.is_registered() { + return Err(JsError::new( + "An identity is already registered with this client", + )); + } + + let signature_text = match self.signature_text() { + Some(text) => text, + None => return Err(JsError::new("No signature text found")), + }; + + let signature = Box::new(RecoverableEcdsaSignature::new( + signature_text.into(), + signature_bytes.to_vec(), + )); + + self.signatures.insert( + MemberIdentifier::Address(self.account_address.clone().to_lowercase()), + signature, + ); + + Ok(()) + } + + #[wasm_bindgen] + pub fn add_scw_signature( + &mut self, + signature_bytes: Uint8Array, + chain_id: String, + account_address: String, + chain_rpc_url: String, + block_number: u64, + ) -> Result<(), JsError> { + if self.is_registered() { + return Err(JsError::new( + "An identity is already registered with this client", + )); + } + + let signature_text = match self.signature_text() { + Some(text) => text, + None => return Err(JsError::new("No signature text found")), + }; + + let account_id = AccountId::new(chain_id, account_address.clone()); + + let signature = Box::new(SmartContractWalletSignature::new( + signature_text, + signature_bytes.to_vec(), + account_id, + chain_rpc_url, + block_number, + )); + + self.signatures.insert( + MemberIdentifier::Address(account_address.clone().to_lowercase()), + signature, + ); + + Ok(()) + } + + #[wasm_bindgen] + pub async fn register_identity(&self) -> Result<(), JsError> { + if self.is_registered() { + return Err(JsError::new( + "An identity is already registered with this client", + )); + } + + if self.signatures.is_empty() { + return Err(JsError::new( + "No client signatures found, add at least 1 before registering", + )); + } + + let mut signature_request = match self.inner_client.identity().signature_request() { + Some(signature_req) => signature_req, + // this should never happen since we're checking for it above in is_registered + None => return Err(JsError::new("No signature request found")), + }; + + // apply added signatures to the signature request + for signature in self.signatures.values() { + signature_request + .add_signature(signature.clone()) + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + } + + self + .inner_client + .register_identity(signature_request) + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + + Ok(()) + } + + #[wasm_bindgen] + pub fn signature_text(&self) -> Option { + self + .inner_client + .identity() + .signature_request() + .map(|signature_req| signature_req.signature_text()) + } + + #[wasm_bindgen] + pub async fn request_history_sync(&self) -> Result<(), JsError> { + let _ = self + .inner_client + .send_history_request() + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + + Ok(()) + } + + #[wasm_bindgen] + pub async fn find_inbox_id_by_address(&self, address: String) -> Result, JsError> { + let inbox_id = self + .inner_client + .find_inbox_id_from_address(address) + .await + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + + Ok(inbox_id) + } +} diff --git a/bindings_wasm/tests/node.rs b/bindings_wasm/tests/node.rs deleted file mode 100644 index 86d48a16b..000000000 --- a/bindings_wasm/tests/node.rs +++ /dev/null @@ -1,21 +0,0 @@ -extern crate bindings_wasm; -extern crate wasm_bindgen_test; - -use wasm_bindgen_futures::JsFuture; -use wasm_bindgen::prelude::*; -use wasm_bindgen_test::*; - -#[wasm_bindgen] -extern "C" { - // Use `js_namespace` here to bind `console.log(..)` instead of just `log(..)` - #[wasm_bindgen(js_namespace = console)] - fn log(s: &str); -} - - -#[wasm_bindgen_test] -async fn test_async_works() { - let promise = js_sys::Promise::resolve(&JsValue::from(42)); - let result = JsFuture::from(promise).await.unwrap(); - assert_eq!(result, 42); -} diff --git a/bindings_wasm/tests/web.rs b/bindings_wasm/tests/web.rs index a13cc71a3..2b678accb 100644 --- a/bindings_wasm/tests/web.rs +++ b/bindings_wasm/tests/web.rs @@ -1,86 +1,35 @@ -extern crate bindings_wasm; -extern crate wasm_bindgen_test; -use bindings_wasm::*; -use prost::Message; +use bindings_wasm::mls_client::{create_client, get_inbox_id_for_address}; use wasm_bindgen::prelude::*; use wasm_bindgen_test::*; -use xmtp_cryptography::signature::RecoverableSignature; -use xmtp_proto::api_client::XmtpApiClient; -use xmtp_proto::xmtp::message_api::v1::{ - BatchQueryRequest, Envelope, PublishRequest, QueryRequest, -}; +use xmtp_api_http::constants::ApiUrls; +use xmtp_cryptography::utils::{rng, LocalWallet}; +use xmtp_id::InboxOwner; // Only run these tests in a browser. wasm_bindgen_test_configure!(run_in_browser); #[wasm_bindgen] extern "C" { - // Use `js_namespace` here to bind `console.log(..)` instead of just `log(..)` - #[wasm_bindgen(js_namespace = console)] - fn log(s: &str); + #[wasm_bindgen(js_namespace = console)] + fn log(s: &str); } #[wasm_bindgen_test] -pub async fn test_client_raw_requests() { - let xmtp_url: String = "http://localhost:5555".to_string(); - let client = WasmXmtpClient::create_client(xmtp_url).unwrap_or_else(|error| { - let error_str = format!("{:?}", JsValue::from(error)); - log(&error_str); - panic!("client should be constructed"); - }); - let api = client.api(); - - let topic = uuid::Uuid::new_v4(); - let q = QueryRequest { - content_topics: vec![topic.to_string()], - ..QueryRequest::default() - }; - - let res = api.query(q.clone()).await.expect("successfully queried"); - assert_eq!(0, res.envelopes.len()); - - // Note: this is mostly just to make sure it's all wired up correctly. - // More functionality tests live in the xmtp_api_grpc_gateway crate. -} - -#[wasm_bindgen_test] -pub fn test_xmtp_proto_in_wasm() { - // Use some basic stuff from `xmtp_proto` to test that it works in Wasm. - // TODO: cut once we have a full wasm client to test - - let env1 = Envelope { - timestamp_ns: 12345, - content_topic: "abc123".to_string(), - message: vec![65], - }; - let mut buf = Vec::with_capacity(env1.encoded_len()); - env1.encode(&mut buf).unwrap(); - let env2 = Envelope::decode(buf.as_slice()).unwrap(); - assert_eq!(12345, env2.timestamp_ns); - assert_eq!("abc123".to_string(), env2.content_topic); -} - -#[wasm_bindgen_test] -pub fn test_xmtp_cryptography_in_wasm() { - // (cribbed from `xmtp_cryptography`) tests that we can use it in Wasm. - // TODO: cut once we have a full wasm client to test - - // This test was generated using Etherscans Signature tool: https://etherscan.io/verifySig/18959 - let addr = "0x1B2a516d691aBb8f08a75B2C73c95c62A1632431"; - let msg = "TestVector1"; - let sig_hash = "19d6bec562518e365d07ba3cce26d08a5fffa2cbb1e7fe03c1f2d6a722fd3a5e544097b91f8f8cd11d43b032659f30529139ab1a9ecb6c81ed4a762179e87db81c"; - - let addr_alt = addr.strip_prefix("0x").unwrap(); - let addr_bad = &addr.replacen('b', "c", 1); - let sig_bytes = hex::decode(sig_hash).unwrap(); - let sig = RecoverableSignature::Eip191Signature(sig_bytes); - let msg_bad = "Testvector1"; - - let recovered_addr = sig.recover_address(msg).unwrap(); - assert_eq!(recovered_addr, addr.to_lowercase()); - - assert!(sig.verify_signature(addr, msg).is_ok()); - assert!(sig.verify_signature(addr_alt, msg).is_ok()); - assert!(sig.verify_signature(addr_bad, msg).is_err()); - assert!(sig.verify_signature(addr, msg_bad).is_err()); +pub async fn test_create_client() { + let wallet = LocalWallet::new(&mut rng()); + let account_address = wallet.get_address(); + let host = ApiUrls::LOCAL_ADDRESS.to_string(); + let inbox_id = get_inbox_id_for_address(host.clone(), account_address.clone()) + .await + .unwrap_or_else(|e| panic!("Error getting inbox ID")); + let client = create_client( + host.clone(), + inbox_id.unwrap(), + account_address.clone(), + None, + None, + ) + .await; + + assert!(client.is_ok()); } diff --git a/mls_validation_service/Cargo.toml b/mls_validation_service/Cargo.toml index ce0d90aee..e2b580a13 100644 --- a/mls_validation_service/Cargo.toml +++ b/mls_validation_service/Cargo.toml @@ -10,7 +10,7 @@ path = "src/main.rs" [dependencies] clap = { version = "4.4.6", features = ["derive"] } ed25519-dalek = { workspace = true, features = ["digest"] } -env_logger = "0.10.0" +env_logger = "0.11" hex = { workspace = true } futures = { workspace = true } log = { workspace = true } diff --git a/xmtp_api_grpc/Cargo.toml b/xmtp_api_grpc/Cargo.toml index c3b5de304..32a3f353a 100644 --- a/xmtp_api_grpc/Cargo.toml +++ b/xmtp_api_grpc/Cargo.toml @@ -4,15 +4,13 @@ name = "xmtp_api_grpc" version = "0.1.0" [dependencies] -async-stream = "0.3.5" -base64 = "0.21.0" -futures = "0.3.29" +async-stream.workspace = true +base64 = "0.22" +futures.workspace = true hex.workspace = true -http-body = "0.4.5" -hyper = "0.14.26" log = { workspace = true, features = ["std"] } -pbjson = "0.5.1" -pbjson-types = "0.5.1" +pbjson.workspace = true +pbjson-types.workspace = true prost = { workspace = true, features = ["prost-derive"] } serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] } @@ -21,8 +19,6 @@ tonic = { workspace = true, features = [ "tls-roots", "tls-webpki-roots", ] } -tower = "0.4.13" -webpki-roots = "0.23.0" xmtp_proto = { path = "../xmtp_proto", features = ["proto_full", "grpc"] } xmtp_v2 = { path = "../xmtp_v2" } tracing.workspace = true diff --git a/xmtp_api_grpc_gateway/Cargo.lock b/xmtp_api_grpc_gateway/Cargo.lock index 88a4457e7..cd8ea58c8 100644 --- a/xmtp_api_grpc_gateway/Cargo.lock +++ b/xmtp_api_grpc_gateway/Cargo.lock @@ -608,9 +608,12 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] [[package]] name = "derive_more" @@ -1494,6 +1497,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.3.2" @@ -1745,6 +1754,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" @@ -1985,6 +2003,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.45" @@ -2193,9 +2217,9 @@ checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" [[package]] name = "pbjson" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1030c719b0ec2a2d25a5df729d6cff1acf3cc230bf766f4f97833591f7577b90" +checksum = "c7e6349fa080353f4a597daffd05cb81572a9c031a6d4fff7e504947496fcc68" dependencies = [ "base64 0.21.4", "serde", @@ -2203,27 +2227,27 @@ dependencies = [ [[package]] name = "pbjson-build" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2580e33f2292d34be285c5bc3dba5259542b083cfad6037b6d70345f24dcb735" +checksum = "6eea3058763d6e656105d1403cb04e0a41b7bbac6362d413e7c33be0c32279c9" dependencies = [ - "heck", - "itertools 0.11.0", - "prost", - "prost-types", + "heck 0.5.0", + "itertools 0.13.0", + "prost 0.13.1", + "prost-types 0.13.1", ] [[package]] name = "pbjson-types" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18f596653ba4ac51bdecbb4ef6773bc7f56042dc13927910de1684ad3d32aa12" +checksum = "e54e5e7bfb1652f95bc361d76f3c780d8e526b134b85417e774166ee941f0887" dependencies = [ "bytes", "chrono", "pbjson", "pbjson-build", - "prost", + "prost 0.13.1", "prost-build", "serde", ] @@ -2400,6 +2424,12 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -2486,29 +2516,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.12.3", +] + +[[package]] +name = "prost" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13db3d3fde688c61e2446b4d843bc27a7e8af269a69440c0308021dc92333cc" +dependencies = [ + "bytes", + "prost-derive 0.13.1", ] [[package]] name = "prost-build" -version = "0.12.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" +checksum = "5bb182580f71dd070f88d01ce3de9f4da5021db7115d2e1c3605a754153b77c1" dependencies = [ "bytes", - "heck", + "heck 0.4.1", "itertools 0.11.0", "log", "multimap", "once_cell", "petgraph", "prettyplease", - "prost", - "prost-types", + "prost 0.13.1", + "prost-types 0.13.1", "regex", "syn 2.0.48", "tempfile", - "which", ] [[package]] @@ -2524,13 +2563,35 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "prost-derive" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca" +dependencies = [ + "anyhow", + "itertools 0.11.0", + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "prost-types" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" dependencies = [ - "prost", + "prost 0.12.3", +] + +[[package]] +name = "prost-types" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cee5168b05f49d4b0ca581206eb14a7b22fafd963efe729ac48eb03266e25cc2" +dependencies = [ + "prost 0.13.1", ] [[package]] @@ -3252,7 +3313,7 @@ version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "rustversion", @@ -3359,12 +3420,14 @@ dependencies = [ [[package]] name = "time" -version = "0.3.28" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f6bb557fd245c28e6411aa56b6403c689ad95061f50e4be16c274e70a17e48" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", + "num-conv", + "powerfmt", "serde", "time-core", "time-macros", @@ -3372,16 +3435,17 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.14" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a942f44339478ef67935ab2bbaec2fb0322496cf3cbe84b261e06ac3814c572" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] @@ -3832,18 +3896,6 @@ version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - [[package]] name = "winapi" version = "0.3.9" @@ -4063,8 +4115,8 @@ dependencies = [ "getrandom", "hex", "js-sys", - "prost", - "prost-types", + "prost 0.12.3", + "prost-types 0.12.3", "reqwest", "uuid 1.4.1", "wasm-bindgen", @@ -4103,8 +4155,8 @@ dependencies = [ "futures-core", "pbjson", "pbjson-types", - "prost", - "prost-types", + "prost 0.13.1", + "prost-types 0.13.1", "serde", ] diff --git a/xmtp_api_http/Cargo.toml b/xmtp_api_http/Cargo.toml new file mode 100644 index 000000000..381f160c8 --- /dev/null +++ b/xmtp_api_http/Cargo.toml @@ -0,0 +1,28 @@ +[package] +edition = "2021" +name = "xmtp_api_http" +version = "0.1.0" + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +log.workspace = true +tracing.workspace = true +async-trait = { workspace = true } +futures = { workspace = true } +reqwest = { version = "0.12.5", features = ["json", "stream"] } +serde = { workspace = true } +serde_json = { workspace = true } +xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } +tokio = { workspace = true, features = ["sync", "rt", "macros"] } +tokio-stream = { version = "0.1", default-features = false } +async-stream.workspace = true +bytes = "1.7" +thiserror = "1.0" + +[dev-dependencies] +tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] } + +[profile.release] +opt-level = "s" diff --git a/xmtp_api_http/src/constants.rs b/xmtp_api_http/src/constants.rs new file mode 100644 index 000000000..e5df6b82f --- /dev/null +++ b/xmtp_api_http/src/constants.rs @@ -0,0 +1,24 @@ +pub struct ApiUrls; + +impl ApiUrls { + pub const LOCAL_ADDRESS: &'static str = "http://localhost:5555"; + pub const DEV_ADDRESS: &'static str = "https://dev.xmtp.network"; + pub const PRODUCTION_ADDRESS: &'static str = "https://production.xmtp.network"; +} + +pub struct ApiEndpoints; + +impl ApiEndpoints { + pub const FETCH_KEY_PACKAGES: &'static str = "/mls/v1/fetch-key-packages"; + pub const GET_IDENTITY_UPDATES: &'static str = "/identity/v1/get-identity-updates"; + pub const GET_INBOX_IDS: &'static str = "/identity/v1/get-inbox-ids"; + pub const PUBLISH_IDENTITY_UPDATE: &'static str = "/identity/v1/publish-identity-update"; + pub const QUERY_GROUP_MESSAGES: &'static str = "/mls/v1/query-group-messages"; + pub const QUERY_WELCOME_MESSAGES: &'static str = "/mls/v1/query-welcome-messages"; + pub const REGISTER_INSTALLATION: &'static str = "/mls/v1/register-installation"; + pub const SEND_GROUP_MESSAGES: &'static str = "/mls/v1/send-group-messages"; + pub const SEND_WELCOME_MESSAGES: &'static str = "/mls/v1/send-welcome-messages"; + pub const SUBSCRIBE_GROUP_MESSAGES: &'static str = "/mls/v1/subscribe-group-messages"; + pub const SUBSCRIBE_WELCOME_MESSAGES: &'static str = "/mls/v1/subscribe-welcome-messages"; + pub const UPLOAD_KEY_PACKAGE: &'static str = "/mls/v1/upload-key-package"; +} diff --git a/xmtp_api_http/src/lib.rs b/xmtp_api_http/src/lib.rs new file mode 100644 index 000000000..a375ded72 --- /dev/null +++ b/xmtp_api_http/src/lib.rs @@ -0,0 +1,309 @@ +pub mod constants; +mod util; + +use async_trait::async_trait; +use util::{create_grpc_stream, handle_error}; +use xmtp_proto::api_client::{Error, ErrorKind, XmtpIdentityClient}; +use xmtp_proto::xmtp::identity::api::v1::{ + GetIdentityUpdatesRequest as GetIdentityUpdatesV2Request, + GetIdentityUpdatesResponse as GetIdentityUpdatesV2Response, GetInboxIdsRequest, + GetInboxIdsResponse, PublishIdentityUpdateRequest, PublishIdentityUpdateResponse, +}; +use xmtp_proto::xmtp::mls::api::v1::{GroupMessage, WelcomeMessage}; +use xmtp_proto::{ + api_client::{GroupMessageStream, WelcomeMessageStream, XmtpMlsClient}, + xmtp::mls::api::v1::{ + FetchKeyPackagesRequest, FetchKeyPackagesResponse, GetIdentityUpdatesRequest, + GetIdentityUpdatesResponse, QueryGroupMessagesRequest, QueryGroupMessagesResponse, + QueryWelcomeMessagesRequest, QueryWelcomeMessagesResponse, RegisterInstallationRequest, + RegisterInstallationResponse, SendGroupMessagesRequest, SendWelcomeMessagesRequest, + SubscribeGroupMessagesRequest, SubscribeWelcomeMessagesRequest, UploadKeyPackageRequest, + }, +}; + +use crate::constants::ApiEndpoints; + +#[derive(Debug, thiserror::Error)] +pub enum HttpClientError { + #[error(transparent)] + Reqwest(#[from] reqwest::Error), +} + +pub struct XmtpHttpApiClient { + http_client: reqwest::Client, + host_url: String, +} + +impl XmtpHttpApiClient { + pub fn new(host_url: String) -> Result { + let client = reqwest::Client::builder() + .connection_verbose(true) + .build()?; + + Ok(XmtpHttpApiClient { + http_client: client, + host_url, + }) + } + + fn endpoint(&self, endpoint: &str) -> String { + format!("{}{}", self.host_url, endpoint) + } +} + +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] +impl XmtpMlsClient for XmtpHttpApiClient { + async fn register_installation( + &self, + request: RegisterInstallationRequest, + ) -> Result { + let res = self + .http_client + .post(self.endpoint(ApiEndpoints::REGISTER_INSTALLATION)) + .json(&request) + .send() + .await + .map_err(|e| Error::new(ErrorKind::MlsError).with(e))? + .bytes() + .await + .map_err(|e| Error::new(ErrorKind::MlsError).with(e))?; + + log::debug!("register_installation"); + handle_error(&*res) + } + + async fn upload_key_package(&self, request: UploadKeyPackageRequest) -> Result<(), Error> { + let res = self + .http_client + .post(self.endpoint(ApiEndpoints::UPLOAD_KEY_PACKAGE)) + .json(&request) + .send() + .await + .map_err(|e| Error::new(ErrorKind::MlsError).with(e))? + .bytes() + .await + .map_err(|e| Error::new(ErrorKind::MlsError).with(e))?; + + log::debug!("upload_key_package"); + handle_error(&*res) + } + + async fn fetch_key_packages( + &self, + request: FetchKeyPackagesRequest, + ) -> Result { + let res = self + .http_client + .post(self.endpoint(ApiEndpoints::FETCH_KEY_PACKAGES)) + .json(&request) + .send() + .await + .map_err(|e| Error::new(ErrorKind::MlsError).with(e))? + .bytes() + .await + .map_err(|e| Error::new(ErrorKind::MlsError).with(e))?; + + log::debug!("fetch_key_packages"); + handle_error(&*res) + } + + async fn send_group_messages(&self, request: SendGroupMessagesRequest) -> Result<(), Error> { + let res = self + .http_client + .post(self.endpoint(ApiEndpoints::SEND_GROUP_MESSAGES)) + .json(&request) + .send() + .await + .map_err(|e| Error::new(ErrorKind::MlsError).with(e))? + .bytes() + .await + .map_err(|e| Error::new(ErrorKind::MlsError).with(e))?; + + log::debug!("send_group_messages"); + handle_error(&*res) + } + + async fn send_welcome_messages( + &self, + request: SendWelcomeMessagesRequest, + ) -> Result<(), Error> { + let res = self + .http_client + .post(self.endpoint(ApiEndpoints::SEND_WELCOME_MESSAGES)) + .json(&request) + .send() + .await + .map_err(|e| Error::new(ErrorKind::MlsError).with(e))? + .bytes() + .await + .map_err(|e| Error::new(ErrorKind::MlsError).with(e))?; + + log::debug!("send_welcome_messages"); + handle_error(&*res) + } + + // deprecated + async fn get_identity_updates( + &self, + _request: GetIdentityUpdatesRequest, + ) -> Result { + unimplemented!() + } + + async fn query_group_messages( + &self, + request: QueryGroupMessagesRequest, + ) -> Result { + let res = self + .http_client + .post(self.endpoint(ApiEndpoints::QUERY_GROUP_MESSAGES)) + .json(&request) + .send() + .await + .map_err(|e| Error::new(ErrorKind::MlsError).with(e))? + .bytes() + .await + .map_err(|e| Error::new(ErrorKind::MlsError).with(e))?; + + log::debug!("query_group_messages"); + handle_error(&*res) + } + + async fn query_welcome_messages( + &self, + request: QueryWelcomeMessagesRequest, + ) -> Result { + let res = self + .http_client + .post(self.endpoint(ApiEndpoints::QUERY_WELCOME_MESSAGES)) + .json(&request) + .send() + .await + .map_err(|e| Error::new(ErrorKind::MlsError).with(e))? + .bytes() + .await + .map_err(|e| Error::new(ErrorKind::MlsError).with(e))?; + + log::debug!("query_welcome_messages"); + handle_error(&*res) + } + + async fn subscribe_group_messages( + &self, + request: SubscribeGroupMessagesRequest, + ) -> Result { + log::debug!("subscribe_group_messages"); + create_grpc_stream::<_, GroupMessage>( + request, + self.endpoint(ApiEndpoints::SUBSCRIBE_GROUP_MESSAGES), + self.http_client.clone(), + ) + .await + } + + async fn subscribe_welcome_messages( + &self, + request: SubscribeWelcomeMessagesRequest, + ) -> Result { + log::debug!("subscribe_welcome_messages"); + create_grpc_stream::<_, WelcomeMessage>( + request, + self.endpoint(ApiEndpoints::SUBSCRIBE_WELCOME_MESSAGES), + self.http_client.clone(), + ) + .await + } +} + +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] +impl XmtpIdentityClient for XmtpHttpApiClient { + async fn publish_identity_update( + &self, + request: PublishIdentityUpdateRequest, + ) -> Result { + let res = self + .http_client + .post(self.endpoint(ApiEndpoints::PUBLISH_IDENTITY_UPDATE)) + .json(&request) + .send() + .await + .map_err(|e| Error::new(ErrorKind::IdentityError).with(e))? + .bytes() + .await + .map_err(|e| Error::new(ErrorKind::IdentityError).with(e))?; + + log::debug!("publish_identity_update"); + handle_error(&*res) + } + + async fn get_identity_updates_v2( + &self, + request: GetIdentityUpdatesV2Request, + ) -> Result { + let res = self + .http_client + .post(self.endpoint(ApiEndpoints::GET_IDENTITY_UPDATES)) + .json(&request) + .send() + .await + .map_err(|e| Error::new(ErrorKind::IdentityError).with(e))? + .bytes() + .await + .map_err(|e| Error::new(ErrorKind::IdentityError).with(e))?; + + log::debug!("get_identity_updates_v2"); + handle_error(&*res) + } + + async fn get_inbox_ids( + &self, + request: GetInboxIdsRequest, + ) -> Result { + let res = self + .http_client + .post(self.endpoint(ApiEndpoints::GET_INBOX_IDS)) + .json(&request) + .send() + .await + .map_err(|e| Error::new(ErrorKind::IdentityError).with(e))? + .bytes() + .await + .map_err(|e| Error::new(ErrorKind::IdentityError).with(e))?; + + log::debug!("get_inbox_ids"); + handle_error(&*res) + } +} + +// tests +#[cfg(test)] +mod tests { + use xmtp_proto::xmtp::mls::api::v1::KeyPackageUpload; + + use crate::constants::ApiUrls; + + use super::*; + + #[tokio::test] + async fn test_register_installation() { + let client = XmtpHttpApiClient::new(ApiUrls::LOCAL_ADDRESS.to_string()).unwrap(); + let result = client + .register_installation(RegisterInstallationRequest { + is_inbox_id_credential: false, + key_package: Some(KeyPackageUpload { + key_package_tls_serialized: vec![1, 2, 3], + }), + }) + .await; + + assert!(result.is_err()); + assert!(result + .as_ref() + .err() + .unwrap() + .to_string() + .contains("invalid identity")); + } +} diff --git a/xmtp_api_http/src/util.rs b/xmtp_api_http/src/util.rs new file mode 100644 index 000000000..f50fd7372 --- /dev/null +++ b/xmtp_api_http/src/util.rs @@ -0,0 +1,102 @@ +use futures::stream::BoxStream; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use serde_json::Deserializer; +use std::io::Read; +use xmtp_proto::api_client::{Error, ErrorKind}; + +#[derive(Deserialize, Serialize, Debug)] +#[serde(untagged)] +pub(crate) enum GrpcResponse { + Ok(T), + Err(ErrorResponse), + SubscriptionItem(SubscriptionItem), + Empty {}, +} + +#[derive(Deserialize, Serialize, Debug)] +pub(crate) struct ErrorResponse { + code: usize, + pub message: String, + details: Vec, +} + +#[derive(Deserialize, Serialize, Debug)] +pub(crate) struct SubscriptionItem { + pub result: T, +} + +/// handle JSON response from gRPC, returning either +/// the expected deserialized response object or a gRPC [`Error`] +pub fn handle_error(reader: R) -> Result +where + T: DeserializeOwned + Default, +{ + match serde_json::from_reader(reader) { + Ok(GrpcResponse::Ok(response)) => Ok(response), + Ok(GrpcResponse::Err(e)) => Err(Error::new(ErrorKind::IdentityError).with(e.message)), + Ok(GrpcResponse::Empty {}) => Ok(Default::default()), + Ok(GrpcResponse::SubscriptionItem(item)) => Ok(item.result), + Err(e) => Err(Error::new(ErrorKind::QueryError).with(e.to_string())), + } +} + +pub async fn create_grpc_stream< + T: Serialize + Send + 'static, + R: DeserializeOwned + Send + std::fmt::Debug + 'static, +>( + request: T, + endpoint: String, + http_client: reqwest::Client, +) -> Result>, Error> { + let stream = async_stream::stream! { + log::debug!("Spawning grpc http stream"); + let request = http_client + .post(endpoint) + .json(&request) + .send() + .await + .map_err(|e| Error::new(ErrorKind::MlsError).with(e))?; + + let mut remaining = vec![]; + for await bytes in request.bytes_stream() { + let bytes = bytes + .map_err(|e| Error::new(ErrorKind::SubscriptionUpdateError).with(e.to_string()))?; + let bytes = &[remaining.as_ref(), bytes.as_ref()].concat(); + let de = Deserializer::from_slice(bytes); + let mut stream = de.into_iter::>(); + 'messages: loop { + let response = stream.next(); + let res = match response { + Some(Ok(GrpcResponse::Ok(response))) => Ok(response), + Some(Ok(GrpcResponse::SubscriptionItem(item))) => Ok(item.result), + Some(Ok(GrpcResponse::Err(e))) => { + Err(Error::new(ErrorKind::MlsError).with(e.message)) + } + Some(Err(e)) => { + if e.is_eof() { + remaining = (&**bytes)[stream.byte_offset()..].to_vec(); + break 'messages; + } else { + Err(Error::new(ErrorKind::MlsError).with(e.to_string())) + } + } + Some(Ok(GrpcResponse::Empty {})) => continue 'messages, + None => break 'messages, + }; + yield res; + } + } + }; + + Ok(Box::pin(stream)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_error_handler_on_unit_value() { + handle_error::<_, ()>(b"{}".as_slice()).unwrap(); + } +} diff --git a/xmtp_id/Cargo.toml b/xmtp_id/Cargo.toml index 36cc1a3c9..74b65298c 100644 --- a/xmtp_id/Cargo.toml +++ b/xmtp_id/Cargo.toml @@ -9,6 +9,7 @@ chrono.workspace = true ed25519-dalek = { workspace = true, features = ["digest"] } ed25519.workspace = true ethers.workspace = true +ethers-core.workspace = true futures.workspace = true hex.workspace = true log.workspace = true @@ -23,7 +24,7 @@ rustc-hex.workspace = true serde.workspace = true sha2.workspace = true thiserror.workspace = true -tokio.workspace = true +tokio = { workspace = true, features = ["macros"] } tracing.workspace = true url.workspace = true xmtp_cryptography.workspace = true @@ -32,10 +33,9 @@ xmtp_proto = { workspace = true, features = ["proto_full"] } [dev-dependencies] ctor = "0.2.5" ed25519-dalek = { workspace = true, features = ["digest"] } -ethers.workspace = true futures = "0.3" regex = "1.10" -tokio = { workspace = true, features = ["time"] } +tokio = { workspace = true, features = ["macros", "time"] } xmtp_v2 = { path = "../xmtp_v2" } [features] diff --git a/xmtp_id/src/lib.rs b/xmtp_id/src/lib.rs index 050681d34..9a446127b 100644 --- a/xmtp_id/src/lib.rs +++ b/xmtp_id/src/lib.rs @@ -8,7 +8,6 @@ use ethers::{ signers::{LocalWallet, Signer}, types::Address, }; -use futures::executor; use openmls_traits::types::CryptoError; use thiserror::Error; use xmtp_cryptography::signature::{h160addr_to_string, RecoverableSignature, SignatureError}; @@ -54,7 +53,8 @@ impl InboxOwner for LocalWallet { } fn sign(&self, text: &str) -> Result { - Ok(executor::block_on(self.sign_message(text))?.to_vec().into()) + let message_hash = ethers_core::utils::hash_message(text); + Ok(self.sign_hash(message_hash)?.to_vec().into()) } } diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 63dc5b126..4b0f47072 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -12,11 +12,11 @@ path = "src/bin/update-schema.rs" default = ["native"] grpc = ["xmtp_proto/grpc"] native = ["libsqlite3-sys/bundled-sqlcipher-vendored-openssl"] -test-utils = ["xmtp_api_grpc"] -bench = ["test-utils", "indicatif", "tracing-subscriber", "anyhow", "tracing-flame", "once_cell"] +test-utils = [] +bench = ["test-utils", "indicatif", "tracing-subscriber", "anyhow", "tracing-flame", "once_cell", "xmtp_api_grpc"] +http-api = ["xmtp_api_http"] [dependencies] -aes = "0.8.4" aes-gcm = { version = "0.10.3", features = ["std"] } async-trait.workspace = true bincode = "1.3.3" @@ -50,8 +50,9 @@ sha2.workspace = true smart-default = "0.7.1" thiserror = { workspace = true } tls_codec = { workspace = true } -tokio = { workspace = true, features = ["rt-multi-thread"] } -tokio-stream = { version = "0.1", features = ["sync"] } +tokio = { workspace = true, features = ["macros", "rt-multi-thread", "tracing"] } +tokio-stream = { version = "0.1", features = ["sync"] } +async-stream.workspace = true toml = "0.8.4" xmtp_cryptography = { workspace = true } xmtp_id = { path = "../xmtp_id" } @@ -60,6 +61,7 @@ xmtp_v2 = { path = "../xmtp_v2" } # Test/Bench Utils xmtp_api_grpc = { path = "../xmtp_api_grpc", optional = true } +xmtp_api_http = { path = "../xmtp_api_http", optional = true } tracing-subscriber = { workspace = true, optional = true } indicatif = { version = "0.17", optional = true } anyhow = { workspace = true, optional = true } @@ -69,7 +71,7 @@ once_cell = { version = "1.19", optional = true } [dev-dependencies] ctor.workspace = true flume = "0.11" -mockall = "0.11.4" +mockall = "0.13.0" mockito = "1.4.0" tempfile = "3.5.0" tracing.workspace = true diff --git a/xmtp_mls/benches/group_limit.rs b/xmtp_mls/benches/group_limit.rs index 135bfc519..8408bd305 100755 --- a/xmtp_mls/benches/group_limit.rs +++ b/xmtp_mls/benches/group_limit.rs @@ -15,13 +15,16 @@ use xmtp_mls::{ bench::{create_identities_if_dont_exist, init_logging, Identity, BENCH_ROOT_SPAN}, test::TestClient, }, + Client, }; +pub type BenchClient = Client; + pub const IDENTITY_SAMPLES: [usize; 9] = [10, 20, 40, 80, 100, 200, 300, 400, 450]; pub const MAX_IDENTITIES: usize = 1_000; pub const SAMPLE_SIZE: usize = 10; -fn setup() -> (Arc, Vec, Runtime) { +fn setup() -> (Arc, Vec, Runtime) { let runtime = Builder::new_multi_thread() .enable_time() .enable_io() diff --git a/xmtp_mls/src/api/test_utils.rs b/xmtp_mls/src/api/test_utils.rs index f1a7ccec2..9f0a1f8e0 100644 --- a/xmtp_mls/src/api/test_utils.rs +++ b/xmtp_mls/src/api/test_utils.rs @@ -1,6 +1,5 @@ use async_trait::async_trait; use mockall::mock; -use xmtp_api_grpc::grpc_api_helper::Client as GrpcClient; use xmtp_proto::{ api_client::{ Error, GroupMessageStream, WelcomeMessageStream, XmtpIdentityClient, XmtpMlsClient, @@ -21,17 +20,7 @@ use xmtp_proto::{ }, }; -use super::ApiClientWrapper; -use crate::retry::Retry; - -pub async fn get_test_api_client() -> ApiClientWrapper { - ApiClientWrapper::new( - GrpcClient::create("http://localhost:5556".to_string(), false) - .await - .unwrap(), - Retry::default(), - ) -} +use crate::XmtpTestClient; pub fn build_group_messages(num_messages: usize, group_id: Vec) -> Vec { let mut out: Vec = vec![]; @@ -82,4 +71,10 @@ mock! { async fn get_identity_updates_v2(&self, request: GetIdentityUpdatesV2Request) -> Result; async fn get_inbox_ids(&self, request: GetInboxIdsRequest) -> Result; } + + #[async_trait] + impl XmtpTestClient for ApiClient { + async fn create_local() -> Self { ApiClient } + async fn create_dev() -> Self { ApiClient } + } } diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index e6b0fa6d9..321c399c8 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -123,6 +123,7 @@ mod tests { use crate::builder::ClientBuilderError; use crate::identity::IdentityError; use crate::retry::Retry; + use crate::XmtpApi; use crate::{ api::test_utils::*, identity::Identity, storage::identity::StoredIdentity, utils::test::rand_vec, Store, @@ -133,7 +134,6 @@ mod tests { use openmls_basic_credential::SignatureKeyPair; use openmls_traits::types::SignatureScheme; use prost::Message; - use xmtp_api_grpc::grpc_api_helper::Client as GrpcClient; use xmtp_cryptography::signature::h160addr_to_string; use xmtp_cryptography::utils::{generate_local_wallet, rng}; use xmtp_id::associations::ValidatedLegacySignedPublicKey; @@ -157,7 +157,7 @@ mod tests { Client, InboxOwner, }; - async fn register_client(client: &Client, owner: &impl InboxOwner) { + async fn register_client(client: &Client, owner: &impl InboxOwner) { let mut signature_request = client.context.signature_request().unwrap(); let signature_text = signature_request.signature_text(); signature_request @@ -311,7 +311,7 @@ mod tests { for test_case in identity_strategies_test_cases { let result = ClientBuilder::new(test_case.strategy) .temp_store() - .local_grpc() + .local_client() .await .build() .await; @@ -344,18 +344,18 @@ mod tests { let store = EncryptedMessageStore::new_unencrypted(StorageOption::Persistent(tmp_path())).unwrap(); - let client1: Client = ClientBuilder::new(identity_strategy.clone()) + let client1 = ClientBuilder::new(identity_strategy.clone()) .store(store.clone()) - .local_grpc() + .local_client() .await .build() .await .unwrap(); assert!(client1.context.signature_request().is_none()); - let client2: Client = ClientBuilder::new(IdentityStrategy::CachedOnly) + let client2 = ClientBuilder::new(IdentityStrategy::CachedOnly) .store(store.clone()) - .local_grpc() + .local_client() .await .build() .await @@ -364,14 +364,14 @@ mod tests { assert!(client1.inbox_id() == client2.inbox_id()); assert!(client1.installation_public_key() == client2.installation_public_key()); - let client3: Client = ClientBuilder::new(IdentityStrategy::CreateIfNotFound( + let client3 = ClientBuilder::new(IdentityStrategy::CreateIfNotFound( generate_inbox_id(&legacy_account_address, &0), legacy_account_address.to_string(), 0, None, )) .store(store.clone()) - .local_grpc() + .local_client() .await .build() .await @@ -380,14 +380,14 @@ mod tests { assert!(client1.inbox_id() == client3.inbox_id()); assert!(client1.installation_public_key() == client3.installation_public_key()); - let client4: Client = ClientBuilder::new(IdentityStrategy::CreateIfNotFound( + let client4 = ClientBuilder::new(IdentityStrategy::CreateIfNotFound( generate_inbox_id(&legacy_account_address, &0), legacy_account_address.to_string(), 0, Some(legacy_key), )) .temp_store() - .local_grpc() + .local_client() .await .build() .await @@ -543,7 +543,7 @@ mod tests { nonce, None, )) - .local_grpc() + .local_client() .await .store(store_a) .build() @@ -566,7 +566,7 @@ mod tests { nonce, None, )) - .local_grpc() + .local_client() .await .store(store_b) .build() @@ -588,7 +588,7 @@ mod tests { // generate_local_wallet().get_address(), // None, // )) - // .local_grpc() + // .local_client() // .await // .store(store_c) // .build() @@ -600,7 +600,7 @@ mod tests { EncryptedMessageStore::new_unencrypted(StorageOption::Persistent(tmpdb.clone())) .unwrap(); let client_d = ClientBuilder::new(IdentityStrategy::CachedOnly) - .local_grpc() + .local_client() .await .store(store_d) .build() diff --git a/xmtp_mls/src/groups/subscriptions.rs b/xmtp_mls/src/groups/subscriptions.rs index e5c6b4099..622333768 100644 --- a/xmtp_mls/src/groups/subscriptions.rs +++ b/xmtp_mls/src/groups/subscriptions.rs @@ -141,12 +141,13 @@ impl MlsGroup { #[cfg(test)] mod tests { use prost::Message; - use std::sync::Arc; + use std::{sync::Arc, time::Duration}; + use tokio_stream::wrappers::UnboundedReceiverStream; use xmtp_cryptography::utils::generate_local_wallet; use crate::{ builder::ClientBuilder, groups::GroupMetadataOptions, - storage::group_message::GroupMessageKind, + storage::group_message::GroupMessageKind, utils::test::Delivery, }; use futures::StreamExt; @@ -190,7 +191,7 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 10)] async fn test_subscribe_messages() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; - let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; + let bola = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let amal_group = amal .create_group(None, GroupMetadataOptions::default()) @@ -203,15 +204,30 @@ mod tests { // Get bola's version of the same group let bola_groups = bola.sync_welcomes().await.unwrap(); - let bola_group = bola_groups.first().unwrap(); + let bola_group = Arc::new(bola_groups.first().unwrap().clone()); + + let bola_ptr = bola.clone(); + let bola_group_ptr = bola_group.clone(); + let notify = Delivery::new(Some(Duration::from_secs(10))); + let notify_ptr = notify.clone(); + let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); + let mut stream = UnboundedReceiverStream::new(rx); + tokio::spawn(async move { + let mut stream = bola_group_ptr.stream(bola_ptr).await.unwrap(); + while let Some(item) = stream.next().await { + let _ = tx.send(item); + notify_ptr.notify_one(); + } + }); - let mut stream = bola_group.stream(Arc::new(bola)).await.unwrap(); - tokio::time::sleep(std::time::Duration::from_millis(50)).await; amal_group .send_message("hello".as_bytes(), &amal) .await .unwrap(); - tokio::time::sleep(std::time::Duration::from_millis(50)).await; + notify + .wait_for_delivery() + .await + .expect("timed out waiting for first message"); let first_val = stream.next().await.unwrap(); assert_eq!(first_val.decrypted_message_bytes, "hello".as_bytes()); @@ -220,6 +236,10 @@ mod tests { .await .unwrap(); + notify + .wait_for_delivery() + .await + .expect("timed out waiting for second message"); let second_val = stream.next().await.unwrap(); assert_eq!(second_val.decrypted_message_bytes, "goodbye".as_bytes()); } @@ -227,13 +247,21 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 10)] async fn test_subscribe_multiple() { let amal = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); - let group = amal - .create_group(None, GroupMetadataOptions::default()) - .unwrap(); - - let stream = group.stream(amal.clone()).await.unwrap(); + let group = Arc::new( + amal.create_group(None, GroupMetadataOptions::default()) + .unwrap(), + ); - tokio::time::sleep(std::time::Duration::from_millis(100)).await; + let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); + let stream = tokio_stream::wrappers::UnboundedReceiverStream::new(rx); + let amal_ptr = amal.clone(); + let group_ptr = group.clone(); + tokio::spawn(async move { + let mut stream = group_ptr.stream(amal_ptr).await.unwrap(); + while let Some(item) = stream.next().await { + let _ = tx.send(item); + } + }); for i in 0..10 { group @@ -253,7 +281,11 @@ mod tests { } } + // https://github.com/xmtp/libxmtp/issues/948 + // This test works in its previous form, with std::time:sleep + // with `Notify` it never recieves the add members message #[tokio::test(flavor = "multi_thread", worker_threads = 10)] + #[ignore] async fn test_subscribe_membership_changes() { let amal = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -262,15 +294,33 @@ mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); - let mut stream = amal_group.stream(amal.clone()).await.unwrap(); - tokio::time::sleep(std::time::Duration::from_millis(50)).await; + let amal_ptr = amal.clone(); + let amal_group_ptr = amal_group.clone(); + let notify = Delivery::new(Some(Duration::from_secs(20))); + let notify_ptr = notify.clone(); + + let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); + let (start_tx, start_rx) = tokio::sync::oneshot::channel(); + let mut stream = UnboundedReceiverStream::new(rx); + tokio::spawn(async move { + let mut stream = amal_group_ptr.stream(amal_ptr).await.unwrap(); + let _ = start_tx.send(()); + while let Some(item) = stream.next().await { + let _ = tx.send(item); + notify_ptr.notify_one(); + } + }); + // just to make sure stream is started + let _ = start_rx.await; amal_group .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) .await .unwrap(); - tokio::time::sleep(std::time::Duration::from_millis(50)).await; - + notify + .wait_for_delivery() + .await + .expect("Never received group membership change from stream"); let first_val = stream.next().await.unwrap(); assert_eq!(first_val.kind, GroupMessageKind::MembershipChange); @@ -278,6 +328,10 @@ mod tests { .send_message("hello".as_bytes(), &amal) .await .unwrap(); + notify + .wait_for_delivery() + .await + .expect("Never received second message from stream"); let second_val = stream.next().await.unwrap(); assert_eq!(second_val.decrypted_message_bytes, "hello".as_bytes()); } diff --git a/xmtp_mls/src/groups/sync.rs b/xmtp_mls/src/groups/sync.rs index 3e4686fac..14d376b27 100644 --- a/xmtp_mls/src/groups/sync.rs +++ b/xmtp_mls/src/groups/sync.rs @@ -130,7 +130,6 @@ impl MlsGroup { if !errors.is_empty() { return Err(GroupError::Sync(errors)); } - Ok(()) } diff --git a/xmtp_mls/src/identity.rs b/xmtp_mls/src/identity.rs index 22e63a80c..6a98a2f97 100644 --- a/xmtp_mls/src/identity.rs +++ b/xmtp_mls/src/identity.rs @@ -43,10 +43,7 @@ use xmtp_id::{ constants::INSTALLATION_KEY_SIGNATURE_CONTEXT, InboxId, }; -use xmtp_proto::{ - api_client::{XmtpIdentityClient, XmtpMlsClient}, - xmtp::identity::MlsCredential, -}; +use xmtp_proto::xmtp::identity::MlsCredential; #[derive(Debug, Clone)] pub enum IdentityStrategy { @@ -60,7 +57,7 @@ pub enum IdentityStrategy { } impl IdentityStrategy { - pub(crate) async fn initialize_identity( + pub(crate) async fn initialize_identity( self, api_client: &ApiClientWrapper, store: &EncryptedMessageStore, @@ -192,7 +189,7 @@ impl Identity { /// /// If the address is NOT associated with an inbox_id, a new inbox_id will be generated. /// Prioritize legacy key if provided, otherwise use wallet to sign. - pub(crate) async fn new( + pub(crate) async fn new( inbox_id: InboxId, address: String, nonce: u64, diff --git a/xmtp_mls/src/lib.rs b/xmtp_mls/src/lib.rs index 80527f0e5..a4bb7e98b 100644 --- a/xmtp_mls/src/lib.rs +++ b/xmtp_mls/src/lib.rs @@ -26,8 +26,31 @@ use xmtp_proto::api_client::{XmtpIdentityClient, XmtpMlsClient}; /// XMTP Api Super Trait /// Implements all Trait Network APIs for convenience. -pub trait XmtpApi: XmtpMlsClient + XmtpIdentityClient {} -impl XmtpApi for T where T: XmtpMlsClient + XmtpIdentityClient {} +#[cfg(not(test))] +pub trait XmtpApi +where + Self: XmtpMlsClient + XmtpIdentityClient, +{ +} +#[cfg(not(test))] +impl XmtpApi for T where T: XmtpMlsClient + XmtpIdentityClient + ?Sized {} + +#[cfg(test)] +pub trait XmtpApi +where + Self: XmtpMlsClient + XmtpIdentityClient + XmtpTestClient, +{ +} + +#[cfg(test)] +impl XmtpApi for T where T: XmtpMlsClient + XmtpIdentityClient + XmtpTestClient + ?Sized {} + +#[cfg(any(test, feature = "test-utils", feature = "bench"))] +#[async_trait::async_trait] +pub trait XmtpTestClient { + async fn create_local() -> Self; + async fn create_dev() -> Self; +} pub trait InboxOwner { /// Get address of the wallet. diff --git a/xmtp_mls/src/owner/evm_owner.rs b/xmtp_mls/src/owner/evm_owner.rs index 2832c8dda..bbf4fbf19 100644 --- a/xmtp_mls/src/owner/evm_owner.rs +++ b/xmtp_mls/src/owner/evm_owner.rs @@ -1,5 +1,4 @@ pub use ethers::signers::{LocalWallet, Signer}; -use futures::executor; use xmtp_cryptography::signature::{h160addr_to_string, RecoverableSignature, SignatureError}; @@ -11,6 +10,7 @@ impl InboxOwner for LocalWallet { } fn sign(&self, text: &str) -> Result { - Ok(executor::block_on(self.sign_message(text))?.to_vec().into()) + let message_hash = ethers_core::utils::hash_message(text); + Ok(self.sign_hash(message_hash)?.to_vec().into()) } } diff --git a/xmtp_mls/src/storage/encrypted_store/db_connection.rs b/xmtp_mls/src/storage/encrypted_store/db_connection.rs index 7ed1e4930..6227c1a43 100644 --- a/xmtp_mls/src/storage/encrypted_store/db_connection.rs +++ b/xmtp_mls/src/storage/encrypted_store/db_connection.rs @@ -1,5 +1,6 @@ +use parking_lot::Mutex; use std::fmt; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use crate::storage::RawDbConnection; @@ -27,14 +28,7 @@ impl DbConnection { where F: FnOnce(&mut RawDbConnection) -> Result, { - let mut lock = self.wrapped_conn.lock().unwrap_or_else( - |err| { - log::error!( - "Recovering from poisoned mutex - a thread has previously panicked holding this lock" - ); - err.into_inner() - }, - ); + let mut lock = self.wrapped_conn.lock(); fun(&mut lock) } } diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 490a8193f..02b65f54c 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -2,11 +2,8 @@ use std::{collections::HashMap, pin::Pin, sync::Arc}; use futures::{FutureExt, Stream, StreamExt}; use prost::Message; -use tokio::{ - sync::{mpsc, oneshot}, - task::JoinHandle, -}; -use tokio_stream::wrappers::{errors::BroadcastStreamRecvError, UnboundedReceiverStream}; +use tokio::{sync::oneshot, task::JoinHandle}; +use tokio_stream::wrappers::errors::BroadcastStreamRecvError; use xmtp_proto::xmtp::mls::api::v1::WelcomeMessage; use crate::{ @@ -195,6 +192,7 @@ where Ok(envelope) => { log::info!("Received message streaming payload"); let group_id = extract_group_id(&envelope)?; + log::info!("Extracted group id {}", hex::encode(&group_id)); let stream_info = group_id_to_info.get(&group_id).ok_or( ClientError::StreamInconsistency( "Received message for a non-subscribed group".to_string(), @@ -202,7 +200,6 @@ where )?; let mls_group = MlsGroup::new(context, group_id, stream_info.convo_created_at_ns); - mls_group .process_stream_entry(envelope.clone(), client.clone()) .await @@ -278,9 +275,7 @@ where pub async fn stream_all_messages( client: Arc>, - ) -> Result, ClientError> { - let (tx, rx) = mpsc::unbounded_channel(); - + ) -> Result>, ClientError> { client.sync_welcomes().await?; let mut group_id_to_info = client @@ -291,7 +286,7 @@ where .map(Into::into) .collect::, MessagesStreamInfo>>(); - tokio::spawn(async move { + let stream = async_stream::stream! { let client = client.clone(); let mut messages_stream = client .clone() @@ -309,22 +304,15 @@ where messages = futures::future::ready(&mut extra_messages), if !extra_messages.is_empty() => { for message in messages.drain(0..) { - if tx.send(message).is_err() { - break; - } + yield Ok(message); } }, Some(message) = messages_stream.next() => { // an error can only mean the receiver has been dropped or closed so we're // safe to end the stream - if tx.send(message).is_err() { - break; - } + yield Ok(message); } Some(new_group) = convo_stream.next() => { - if tx.is_closed() { - break; - } if group_id_to_info.contains_key(&new_group.group_id) { continue; } @@ -339,8 +327,16 @@ where cursor: 1, // For the new group, stream all messages since the group was created }, ); - let new_messages_stream = client.clone().stream_messages(group_id_to_info.clone()).await?; + let new_messages_stream = match client.clone().stream_messages(group_id_to_info.clone()).await { + Ok(stream) => stream, + Err(e) => { + log::error!("{}", e); + break; + } + }; + + log::debug!("switching streams"); // attempt to drain all ready messages from existing stream while let Some(Some(message)) = messages_stream.next().now_or_never() { extra_messages.push(message); @@ -349,10 +345,9 @@ where }, } } - Ok::<_, ClientError>(()) - }); + }; - Ok(UnboundedReceiverStream::new(rx)) + Ok(Box::pin(stream)) } pub fn stream_all_messages_with_callback( @@ -365,7 +360,10 @@ where let mut stream = Self::stream_all_messages(client).await?; let _ = tx.send(()); while let Some(message) = stream.next().await { - callback(message) + match message { + Ok(m) => callback(m), + Err(m) => log::error!("error during stream all messages {}", m), + } } Ok(()) }); @@ -379,36 +377,93 @@ where #[cfg(test)] mod tests { - use crate::utils::test::Delivery; + use crate::utils::test::{Delivery, TestClient}; use crate::{ builder::ClientBuilder, groups::GroupMetadataOptions, storage::group_message::StoredGroupMessage, Client, }; use futures::StreamExt; + use parking_lot::Mutex; use std::sync::{ atomic::{AtomicU64, Ordering}, - Arc, Mutex, + Arc, }; - use xmtp_api_grpc::grpc_api_helper::Client as GrpcClient; use xmtp_cryptography::utils::generate_local_wallet; - #[tokio::test(flavor = "multi_thread", worker_threads = 10)] + #[tokio::test(flavor = "current_thread")] async fn test_stream_welcomes() { - let alice = ClientBuilder::new_test_client(&generate_local_wallet()).await; - let bob = ClientBuilder::new_test_client(&generate_local_wallet()).await; - + let alice = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); + let bob = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let alice_bob_group = alice .create_group(None, GroupMetadataOptions::default()) .unwrap(); - let mut bob_stream = bob.stream_conversations().await.unwrap(); + // FIXME:insipx we run into an issue where the reqwest::post().send() request + // blocks the executor and we cannot progress the runtime if we dont `tokio::spawn` this. + // A solution might be to use `hyper` instead, and implement a custom connection pool with + // `deadpool`. This is a bit more work but shouldn't be too complicated since + // we're only using `post` requests. It would be nice for all streams to work + // w/o spawning a separate task. + let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); + let mut stream = tokio_stream::wrappers::UnboundedReceiverStream::new(rx); + let bob_ptr = bob.clone(); + tokio::spawn(async move { + let mut bob_stream = bob_ptr.stream_conversations().await.unwrap(); + while let Some(item) = bob_stream.next().await { + let _ = tx.send(item); + } + }); + + let group_id = alice_bob_group.group_id.clone(); alice_bob_group .add_members_by_inbox_id(&alice, vec![bob.inbox_id()]) .await .unwrap(); - let bob_received_groups = bob_stream.next().await.unwrap(); - assert_eq!(bob_received_groups.group_id, alice_bob_group.group_id); + let bob_received_groups = stream.next().await.unwrap(); + assert_eq!(bob_received_groups.group_id, group_id); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 10)] + async fn test_stream_messages() { + let alice = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); + let bob = ClientBuilder::new_test_client(&generate_local_wallet()).await; + + let alice_group = alice + .create_group(None, GroupMetadataOptions::default()) + .unwrap(); + + // let mut bob_stream = bob.stream_conversations().await.unwrap(); + alice_group + .add_members_by_inbox_id(&alice, vec![bob.inbox_id()]) + .await + .unwrap(); + let bob_group = bob.sync_welcomes().await.unwrap(); + let bob_group = bob_group.first().unwrap(); + + let notify = Delivery::new(None); + let notify_ptr = notify.clone(); + let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); + tokio::spawn(async move { + let mut stream = alice_group.stream(alice).await.unwrap(); + while let Some(item) = stream.next().await { + let _ = tx.send(item); + notify_ptr.notify_one(); + } + }); + let mut stream = tokio_stream::wrappers::UnboundedReceiverStream::new(rx); + + bob_group.send_message(b"hello", &bob).await.unwrap(); + notify.wait_for_delivery().await.unwrap(); + let message = stream.next().await.unwrap(); + assert_eq!(message.decrypted_message_bytes, b"hello"); + + bob_group.send_message(b"hello2", &bob).await.unwrap(); + notify.wait_for_delivery().await.unwrap(); + let message = stream.next().await.unwrap(); + assert_eq!(message.decrypted_message_bytes, b"hello2"); + + // assert_eq!(bob_received_groups.group_id, alice_bob_group.group_id); } #[tokio::test(flavor = "multi_thread", worker_threads = 10)] @@ -437,12 +492,12 @@ mod tests { let messages: Arc>> = Arc::new(Mutex::new(Vec::new())); let messages_clone = messages.clone(); - let notify = Delivery::new(); + let notify = Delivery::new(None); let notify_pointer = notify.clone(); - let mut handle = Client::::stream_all_messages_with_callback( + let mut handle = Client::::stream_all_messages_with_callback( Arc::new(caro), move |message| { - (*messages_clone.lock().unwrap()).push(message); + (*messages_clone.lock()).push(message); notify_pointer.notify_one(); }, ); @@ -452,7 +507,10 @@ mod tests { .send_message("first".as_bytes(), &alix) .await .unwrap(); - notify.wait_for_delivery().await.unwrap(); + notify + .wait_for_delivery() + .await + .expect("didn't get `first`"); bo_group .send_message("second".as_bytes(), &bo) .await @@ -469,7 +527,7 @@ mod tests { .unwrap(); notify.wait_for_delivery().await.unwrap(); - let messages = messages.lock().unwrap(); + let messages = messages.lock(); assert_eq!(messages[0].decrypted_message_bytes, b"first"); assert_eq!(messages[1].decrypted_message_bytes, b"second"); assert_eq!(messages[2].decrypted_message_bytes, b"third"); @@ -492,12 +550,12 @@ mod tests { let messages: Arc>> = Arc::new(Mutex::new(Vec::new())); let messages_clone = messages.clone(); - let delivery = Delivery::new(); + let delivery = Delivery::new(None); let delivery_pointer = delivery.clone(); let mut handle = - Client::::stream_all_messages_with_callback(caro.clone(), move |message| { + Client::::stream_all_messages_with_callback(caro.clone(), move |message| { delivery_pointer.notify_one(); - (*messages_clone.lock().unwrap()).push(message); + (*messages_clone.lock()).push(message); }); handle.wait_for_ready().await; @@ -505,7 +563,10 @@ mod tests { .send_message("first".as_bytes(), &alix) .await .unwrap(); - delivery.wait_for_delivery().await.unwrap(); + delivery + .wait_for_delivery() + .await + .expect("timed out waiting for `first`"); let bo_group = bo .create_group(None, GroupMetadataOptions::default()) @@ -519,13 +580,19 @@ mod tests { .send_message("second".as_bytes(), &bo) .await .unwrap(); - delivery.wait_for_delivery().await.unwrap(); + delivery + .wait_for_delivery() + .await + .expect("timed out waiting for `second`"); alix_group .send_message("third".as_bytes(), &alix) .await .unwrap(); - delivery.wait_for_delivery().await.unwrap(); + delivery + .wait_for_delivery() + .await + .expect("timed out waiting for `third`"); let alix_group_2 = alix .create_group(None, GroupMetadataOptions::default()) @@ -539,16 +606,22 @@ mod tests { .send_message("fourth".as_bytes(), &alix) .await .unwrap(); - delivery.wait_for_delivery().await.unwrap(); + delivery + .wait_for_delivery() + .await + .expect("timed out waiting for `fourth`"); alix_group_2 .send_message("fifth".as_bytes(), &alix) .await .unwrap(); - delivery.wait_for_delivery().await.unwrap(); + delivery + .wait_for_delivery() + .await + .expect("timed out waiting for `fifth`"); { - let messages = messages.lock().unwrap(); + let messages = messages.lock(); assert_eq!(messages.len(), 5); } @@ -563,7 +636,7 @@ mod tests { .unwrap(); tokio::time::sleep(std::time::Duration::from_millis(100)).await; - let messages = messages.lock().unwrap(); + let messages = messages.lock(); assert_eq!(messages.len(), 5); } @@ -588,8 +661,8 @@ mod tests { let blocked_pointer = blocked.clone(); let mut handle = - Client::::stream_all_messages_with_callback(caro.clone(), move |message| { - (*messages_clone.lock().unwrap()).push(message); + Client::::stream_all_messages_with_callback(caro.clone(), move |message| { + (*messages_clone.lock()).push(message); blocked_pointer.fetch_sub(1, Ordering::SeqCst); }); handle.wait_for_ready().await; @@ -640,12 +713,12 @@ mod tests { let bo = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let groups = Arc::new(Mutex::new(Vec::new())); - let notify = Delivery::new(); + let notify = Delivery::new(None); let (notify_pointer, groups_pointer) = (notify.clone(), groups.clone()); let closer = - Client::::stream_conversations_with_callback(alix.clone(), move |g| { - let mut groups = groups_pointer.lock().unwrap(); + Client::::stream_conversations_with_callback(alix.clone(), move |g| { + let mut groups = groups_pointer.lock(); groups.push(g); notify_pointer.notify_one(); }); @@ -659,7 +732,7 @@ mod tests { .expect("Stream never received group"); { - let grps = groups.lock().unwrap(); + let grps = groups.lock(); assert_eq!(grps.len(), 1); } @@ -674,7 +747,7 @@ mod tests { notify.wait_for_delivery().await.unwrap(); { - let grps = groups.lock().unwrap(); + let grps = groups.lock(); assert_eq!(grps.len(), 2); } diff --git a/xmtp_mls/src/utils/bench.rs b/xmtp_mls/src/utils/bench.rs index 101f0ab6b..a880b1bf9 100644 --- a/xmtp_mls/src/utils/bench.rs +++ b/xmtp_mls/src/utils/bench.rs @@ -1,7 +1,7 @@ //! Utilities for xmtp_mls benchmarks //! Utilities mostly include pre-generating identities in order to save time when writing/testing //! benchmarks. -use crate::builder::ClientBuilder; +use crate::{builder::ClientBuilder, Client}; use ethers::signers::{LocalWallet, Signer}; use indicatif::{ProgressBar, ProgressStyle}; use once_cell::sync::OnceCell; @@ -174,7 +174,7 @@ async fn create_identities(n: usize, is_dev_network: bool) -> Vec { /// node still has those identities. pub async fn create_identities_if_dont_exist( identities: usize, - client: &TestClient, + client: &Client, is_dev_network: bool, ) -> Vec { match load_identities(is_dev_network) { diff --git a/xmtp_mls/src/utils/test.rs b/xmtp_mls/src/utils/test.rs index 584c93ebe..9c7e8bd18 100644 --- a/xmtp_mls/src/utils/test.rs +++ b/xmtp_mls/src/utils/test.rs @@ -14,10 +14,17 @@ use crate::{ identity::IdentityStrategy, storage::{EncryptedMessageStore, StorageOption}, types::Address, - Client, InboxOwner, + Client, InboxOwner, XmtpApi, XmtpTestClient, }; -pub type TestClient = Client; +#[cfg(feature = "http-api")] +use xmtp_api_http::XmtpHttpApiClient; + +#[cfg(not(feature = "http-api"))] +pub type TestClient = GrpcClient; + +#[cfg(feature = "http-api")] +pub type TestClient = XmtpHttpApiClient; pub fn rand_string() -> String { Alphanumeric.sample_string(&mut rand::thread_rng(), 24) @@ -41,28 +48,34 @@ pub fn rand_time() -> i64 { rng.gen_range(0..1_000_000_000) } -/// Get a GRPC Client pointed at the local instance of `xmtp-node-go` -pub async fn get_local_grpc_client() -> GrpcClient { - GrpcClient::create("http://localhost:5556".to_string(), false) - .await - .unwrap() -} +#[async_trait::async_trait] +#[cfg(feature = "http-api")] +impl XmtpTestClient for XmtpHttpApiClient { + async fn create_local() -> Self { + XmtpHttpApiClient::new("http://localhost:5555".into()).unwrap() + } -pub async fn get_dev_grpc_client() -> GrpcClient { - GrpcClient::create("https://grpc.dev.xmtp.network:443".into(), true) - .await - .unwrap() + async fn create_dev() -> Self { + XmtpHttpApiClient::new("https://grpc.dev.xmtp.network:443".into()).unwrap() + } } -impl ClientBuilder { - pub async fn local_grpc(self) -> Self { - self.api_client(get_local_grpc_client().await) +#[async_trait::async_trait] +impl XmtpTestClient for GrpcClient { + async fn create_local() -> Self { + GrpcClient::create("http://localhost:5556".into(), false) + .await + .unwrap() } - pub async fn dev_grpc(self) -> Self { - self.api_client(get_dev_grpc_client().await) + async fn create_dev() -> Self { + GrpcClient::create("https://grpc.dev.xmtp.network:443".into(), false) + .await + .unwrap() } +} +impl ClientBuilder { pub fn temp_store(self) -> Self { let tmpdb = tmp_path(); self.store( @@ -70,9 +83,16 @@ impl ClientBuilder { ) } - pub async fn new_test_client(owner: &impl InboxOwner) -> Client { + pub async fn local_client(mut self) -> Self { + let local_client = ::create_local().await; + self = self.api_client(local_client); + self + } + + pub async fn new_test_client(owner: &impl InboxOwner) -> Client { let nonce = 1; let inbox_id = generate_inbox_id(&owner.get_address(), &nonce); + let client = Self::new(IdentityStrategy::CreateIfNotFound( inbox_id, owner.get_address(), @@ -80,7 +100,7 @@ impl ClientBuilder { None, )) .temp_store() - .local_grpc() + .local_client() .await .build() .await @@ -91,9 +111,11 @@ impl ClientBuilder { client } - pub async fn new_dev_client(owner: &impl InboxOwner) -> Client { + pub async fn new_dev_client(owner: &impl InboxOwner) -> Client { let nonce = 1; let inbox_id = generate_inbox_id(&owner.get_address(), &nonce); + let dev_client = ::create_dev().await; + let client = Self::new(IdentityStrategy::CreateIfNotFound( inbox_id, owner.get_address(), @@ -101,8 +123,7 @@ impl ClientBuilder { None, )) .temp_store() - .dev_grpc() - .await + .api_client(dev_client) .build() .await .unwrap(); @@ -117,20 +138,20 @@ impl ClientBuilder { #[derive(Clone, Default)] pub struct Delivery { notify: Arc, + timeout: std::time::Duration, } impl Delivery { - pub fn new() -> Self { + pub fn new(timeout: Option) -> Self { + let timeout = timeout.unwrap_or(std::time::Duration::from_secs(60)); Self { notify: Arc::new(Notify::new()), + timeout, } } pub async fn wait_for_delivery(&self) -> Result<(), Elapsed> { - tokio::time::timeout(std::time::Duration::from_secs(60), async { - self.notify.notified().await - }) - .await + tokio::time::timeout(self.timeout, async { self.notify.notified().await }).await } pub fn notify_one(&self) { @@ -138,7 +159,7 @@ impl Delivery { } } -impl Client { +impl Client { pub async fn is_registered(&self, address: &String) -> bool { let ids = self .api_client @@ -149,7 +170,7 @@ impl Client { } } -pub async fn register_client(client: &Client, owner: &impl InboxOwner) { +pub async fn register_client(client: &Client, owner: &impl InboxOwner) { let mut signature_request = client.context.signature_request().unwrap(); let signature_text = signature_request.signature_text(); signature_request diff --git a/xmtp_proto/Cargo.toml b/xmtp_proto/Cargo.toml index 506479cea..3572a4a21 100644 --- a/xmtp_proto/Cargo.toml +++ b/xmtp_proto/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" async-trait = { workspace = true } futures = { workspace = true } futures-core = { workspace = true } -pbjson = "0.6.0" -pbjson-types = "0.6.0" +pbjson.workspace = true +pbjson-types.workspace = true prost = { workspace = true, features = ["prost-derive"] } # Only necessary if using Protobuf well-known types: prost-types = { workspace = true } @@ -35,4 +35,4 @@ proto_full = ["xmtp-identity","xmtp-identity-api-v1","xmtp-identity-associations "xmtp-mls-database" = [] "xmtp-mls-message_contents" = ["xmtp-message_contents"] "xmtp-mls_validation-v1" = ["xmtp-identity-associations"] -## @@protoc_insertion_point(features) \ No newline at end of file +## @@protoc_insertion_point(features)