From 977176f84c3c8dc235f2c1eccb16140368749d98 Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Wed, 3 Apr 2024 18:17:15 -0700 Subject: [PATCH 01/21] StagedWelcome Setup --- xmtp_mls/src/groups/mod.rs | 43 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index adcdb5e90..5c85dd305 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -960,4 +960,47 @@ mod tests { .await .is_err(),); } + + #[tokio::test] + async fn test_staged_welcome() { + println!("Begin stub_group_test"); + + // === Client Creation === + let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; + let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; + + // === Dependency Creation === + let conn = &amal.store.conn().unwrap(); + let provider = super::XmtpOpenMlsProvider::new(conn); + + // === Amal creates a group === + let amal_group = amal + .create_group(Some(PreconfiguredPolicies::GroupCreatorIsAdmin)) + .unwrap(); + + // === Amal provider === + let provider = amal.mls_provider(conn); + + // === Amal group triple (WIP) === + // TODO: Need to fulfill .add_members call site requirements + let (_queued_message, welcome, _group_info) = amal_group + .add_members(provider, &amal_signer, &[bola_kpb.key_package().clone()]) + .expect("Could not add member to group."); + + // === Amal join config (WIP) === + + // === Amal Welcome - MlsMessageIN (WIP) === + + // === Amal MlsMessageIN - into_welcome (WIP) === + + // === Stage Bola Group (WIP) === + + // === Staged Bola Group Welcome Sender (WIP) === + + // === Who Added Me Leaf Node Assertion (WIP) === + + // === Bola Group Assertion (WIP) === + + // === Amal / Bola Group Equality Assertion (WIP) === + } } From 397096b9643c1ef8530c00ee6809cc5041db4503 Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Thu, 4 Apr 2024 16:55:25 -0700 Subject: [PATCH 02/21] Create StagedWelcome & Obtain Sender Creds --- xmtp_mls/src/groups/mod.rs | 60 +++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 5c85dd305..7728afbb2 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -241,6 +241,24 @@ where let welcome = deserialize_welcome(&welcome_bytes)?; + // === Create Staged Welcome === + let join_config = build_group_join_config(); + let staged_welcome = StagedWelcome::new_from_welcome( + provider, + &join_config, + welcome.clone(), + None + ) + .expect("error created staged mls group"); + + // === Obtain address of welcome sender === + // Note: .expect will be cleaned up before exiting DRAFT + let welcome_sender = staged_welcome + .welcome_sender() + .expect("couldn't determine the sender of welcome"); + + println!("{:?}", welcome_sender.credential()); + Self::create_from_welcome(client, provider, welcome) } @@ -963,44 +981,18 @@ mod tests { #[tokio::test] async fn test_staged_welcome() { - println!("Begin stub_group_test"); - - // === Client Creation === let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; - // === Dependency Creation === - let conn = &amal.store.conn().unwrap(); - let provider = super::XmtpOpenMlsProvider::new(conn); - - // === Amal creates a group === - let amal_group = amal - .create_group(Some(PreconfiguredPolicies::GroupCreatorIsAdmin)) + let amal_group = amal.create_group(None).unwrap(); + // Add bola + amal_group + .add_members_by_installation_id(vec![bola.installation_public_key()]) + .await .unwrap(); - // === Amal provider === - let provider = amal.mls_provider(conn); - - // === Amal group triple (WIP) === - // TODO: Need to fulfill .add_members call site requirements - let (_queued_message, welcome, _group_info) = amal_group - .add_members(provider, &amal_signer, &[bola_kpb.key_package().clone()]) - .expect("Could not add member to group."); - - // === Amal join config (WIP) === - - // === Amal Welcome - MlsMessageIN (WIP) === - - // === Amal MlsMessageIN - into_welcome (WIP) === - - // === Stage Bola Group (WIP) === - - // === Staged Bola Group Welcome Sender (WIP) === - - // === Who Added Me Leaf Node Assertion (WIP) === - - // === Bola Group Assertion (WIP) === - - // === Amal / Bola Group Equality Assertion (WIP) === + // Get bola's version of the same group + let bola_groups = bola.sync_welcomes().await.unwrap(); + let bola_group = bola_groups.first().unwrap(); } } From b7d943178616f40fee9a1aa6cbb00cb1f6b240e3 Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Fri, 5 Apr 2024 13:15:33 -0700 Subject: [PATCH 03/21] =?UTF-8?q?Store=20Welcome=20Sender=E2=80=99s=20Iden?= =?UTF-8?q?tity=20on=20Group?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- xmtp_mls/src/groups/mod.rs | 51 ++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 7728afbb2..f13e3cb2e 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -9,11 +9,12 @@ pub mod validated_commit; use intents::SendMessageIntentData; use openmls::{ + credentials::BasicCredential, extensions::{Extension, Extensions, Metadata}, group::{MlsGroupCreateConfig, MlsGroupJoinConfig}, prelude::{ - CredentialWithKey, CryptoConfig, Error as TlsCodecError, GroupId, MlsGroup as OpenMlsGroup, - StagedWelcome, Welcome as MlsWelcome, WireFormatPolicy, + BasicCredentialError, CredentialWithKey, CryptoConfig, Error as TlsCodecError, GroupId, + MlsGroup as OpenMlsGroup, StagedWelcome, Welcome as MlsWelcome, WireFormatPolicy, }, }; use openmls_traits::OpenMlsProvider; @@ -119,6 +120,8 @@ pub enum GroupError { Identity(#[from] IdentityError), #[error("serialization error: {0}")] EncodeError(#[from] prost::EncodeError), + #[error("Credential error")] + CredentialError(#[from] BasicCredentialError), } impl RetryableError for GroupError { @@ -140,6 +143,7 @@ impl RetryableError for GroupError { pub struct MlsGroup<'c, ApiClient> { pub group_id: Vec, pub created_at_ns: i64, + pub host_id: Option>, client: &'c Client, } @@ -149,6 +153,7 @@ impl<'c, ApiClient> Clone for MlsGroup<'c, ApiClient> { client: self.client, group_id: self.group_id.clone(), created_at_ns: self.created_at_ns, + host_id: self.host_id.clone(), } } } @@ -163,6 +168,17 @@ where client, group_id, created_at_ns, + host_id: None, + } + } + + // Creates a new group instance with the Welcome host_id. Does not validate that the group exists in the DB + pub fn new_with_host_id(client: &'c Client, group_id: Vec, created_at_ns: i64, host_id: Option>) -> Self { + Self { + client, + group_id, + created_at_ns, + host_id, } } @@ -212,6 +228,7 @@ where client: &'c Client, provider: &XmtpOpenMlsProvider, welcome: MlsWelcome, + host_id: Option>, ) -> Result { let mls_welcome = StagedWelcome::new_from_welcome(provider, &build_group_join_config(), welcome, None)?; @@ -223,10 +240,11 @@ where let to_store = StoredGroup::new(group_id, now_ns(), GroupMembershipState::Pending); let stored_group = provider.conn().insert_or_ignore_group(to_store)?; - Ok(Self::new( + Ok(Self::new_with_host_id( client, stored_group.id, stored_group.created_at_ns, + host_id, )) } @@ -257,9 +275,10 @@ where .welcome_sender() .expect("couldn't determine the sender of welcome"); - println!("{:?}", welcome_sender.credential()); + let host_credential = BasicCredential::try_from(welcome_sender.credential())?; + let host_id = host_credential.identity().to_vec(); - Self::create_from_welcome(client, provider, welcome) + Self::create_from_welcome(client, provider, welcome, Some(host_id)) } fn into_envelope(encoded_msg: &[u8], idempotency_key: &str) -> PlaintextEnvelope { @@ -505,7 +524,10 @@ fn build_group_join_config() -> MlsGroupJoinConfig { #[cfg(test)] mod tests { - use openmls::prelude::Member; + use openmls::{ + credentials::BasicCredential, + prelude::{Credential, Member} + }; use prost::Message; use xmtp_api_grpc::grpc_api_helper::Client as GrpcClient; use xmtp_cryptography::utils::generate_local_wallet; @@ -981,6 +1003,7 @@ mod tests { #[tokio::test] async fn test_staged_welcome() { + // Create Clients let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -992,7 +1015,21 @@ mod tests { .unwrap(); // Get bola's version of the same group - let bola_groups = bola.sync_welcomes().await.unwrap(); + let bola_groups = bola + .sync_welcomes() + .await + .unwrap(); let bola_group = bola_groups.first().unwrap(); + + // Check Bola's group for the welcome host_id + let host_id: Vec = bola_group.host_id.clone().unwrap(); + let host_basic_credential = BasicCredential::new(host_id).unwrap(); + let host_credential = Credential::from(host_basic_credential); + + // Verify the welcome host_credential is equal to Amal's + assert_eq!(amal.identity + .credential() + .unwrap(), + host_credential); } } From 3257ef48af3ced816de7896ed43651efa095514b Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Fri, 5 Apr 2024 16:16:24 -0700 Subject: [PATCH 04/21] Remove Extra Constructor --- bindings_ffi/src/mls.rs | 9 +++++++++ xmtp_mls/src/client.rs | 7 +++++-- xmtp_mls/src/groups/mod.rs | 37 +++++++++++++---------------------- xmtp_mls/src/subscriptions.rs | 2 +- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 9fd6399ab..9f28c7594 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -340,6 +340,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, + None, ); group.send_message(content_bytes.as_slice()).await?; @@ -352,6 +353,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, + None, ); group.sync().await?; @@ -367,6 +369,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, + None, ); let messages: Vec = group @@ -392,6 +395,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, + None, ); let message = group.process_streamed_group_message(envelope_bytes).await?; let ffi_message = message.into(); @@ -404,6 +408,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, + None, ); let members: Vec = group @@ -425,6 +430,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, + None, ); group.add_members(account_addresses).await?; @@ -437,6 +443,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, + None, ); group.remove_members(account_addresses).await?; @@ -472,6 +479,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, + None, ); Ok(group.is_active()?) @@ -482,6 +490,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, + None, ); let metadata = group.metadata()?; diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 6972476e0..42e9e1b99 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -206,6 +206,7 @@ where ) -> Result, ClientError> { log::info!("creating group"); + // EM: Consider setting host id here as self? let group = MlsGroup::create_and_insert(self, GroupMembershipState::Allowed, permissions) .map_err(|e| ClientError::Generic(format!("group create error {}", e)))?; @@ -218,7 +219,8 @@ where let conn = &mut self.store.conn()?; let stored_group: Option = conn.fetch(&group_id)?; match stored_group { - Some(group) => Ok(MlsGroup::new(self, group.id, group.created_at_ns)), + // EM: Will neeed to update StoredGroup and pass added_by_id here.... + Some(group) => Ok(MlsGroup::new(self, group.id, group.created_at_ns, None)), None => Err(ClientError::Generic("group not found".to_string())), } } @@ -242,7 +244,8 @@ where .conn()? .find_groups(allowed_states, created_after_ns, created_before_ns, limit)? .into_iter() - .map(|stored_group| MlsGroup::new(self, stored_group.id, stored_group.created_at_ns)) + // EM: Will neeed to update StoredGroup and pass added_by_id here.... + .map(|stored_group| MlsGroup::new(self, stored_group.id, stored_group.created_at_ns, None)) .collect()) } diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index f13e3cb2e..8104fb3c5 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -143,7 +143,7 @@ impl RetryableError for GroupError { pub struct MlsGroup<'c, ApiClient> { pub group_id: Vec, pub created_at_ns: i64, - pub host_id: Option>, + pub added_by_id: Option>, client: &'c Client, } @@ -153,7 +153,7 @@ impl<'c, ApiClient> Clone for MlsGroup<'c, ApiClient> { client: self.client, group_id: self.group_id.clone(), created_at_ns: self.created_at_ns, - host_id: self.host_id.clone(), + added_by_id: self.added_by_id.clone(), } } } @@ -163,22 +163,12 @@ where ApiClient: XmtpMlsClient, { // Creates a new group instance. Does not validate that the group exists in the DB - pub fn new(client: &'c Client, group_id: Vec, created_at_ns: i64) -> Self { + pub fn new(client: &'c Client, group_id: Vec, created_at_ns: i64, added_by_id: Option>) -> Self { Self { client, group_id, created_at_ns, - host_id: None, - } - } - - // Creates a new group instance with the Welcome host_id. Does not validate that the group exists in the DB - pub fn new_with_host_id(client: &'c Client, group_id: Vec, created_at_ns: i64, host_id: Option>) -> Self { - Self { - client, - group_id, - created_at_ns, - host_id, + added_by_id, } } @@ -219,7 +209,7 @@ where let group_id = mls_group.group_id().to_vec(); let stored_group = StoredGroup::new(group_id.clone(), now_ns(), membership_state); stored_group.store(provider.conn())?; - Ok(Self::new(client, group_id, stored_group.created_at_ns)) + Ok(Self::new(client, group_id, stored_group.created_at_ns, None)) } // Create a group from a decrypted and decoded welcome message @@ -228,7 +218,7 @@ where client: &'c Client, provider: &XmtpOpenMlsProvider, welcome: MlsWelcome, - host_id: Option>, + added_by_id: Option>, ) -> Result { let mls_welcome = StagedWelcome::new_from_welcome(provider, &build_group_join_config(), welcome, None)?; @@ -240,11 +230,11 @@ where let to_store = StoredGroup::new(group_id, now_ns(), GroupMembershipState::Pending); let stored_group = provider.conn().insert_or_ignore_group(to_store)?; - Ok(Self::new_with_host_id( + Ok(Self::new( client, stored_group.id, stored_group.created_at_ns, - host_id, + added_by_id, )) } @@ -260,6 +250,7 @@ where let welcome = deserialize_welcome(&welcome_bytes)?; // === Create Staged Welcome === + // Note: .expect will be cleaned up before exiting DRAFT let join_config = build_group_join_config(); let staged_welcome = StagedWelcome::new_from_welcome( provider, @@ -271,14 +262,14 @@ where // === Obtain address of welcome sender === // Note: .expect will be cleaned up before exiting DRAFT - let welcome_sender = staged_welcome + let added_by_node = staged_welcome .welcome_sender() .expect("couldn't determine the sender of welcome"); - let host_credential = BasicCredential::try_from(welcome_sender.credential())?; - let host_id = host_credential.identity().to_vec(); + let added_by_credential = BasicCredential::try_from(added_by_node.credential())?; + let added_by_id = added_by_credential.identity().to_vec(); - Self::create_from_welcome(client, provider, welcome, Some(host_id)) + Self::create_from_welcome(client, provider, welcome, Some(added_by_id)) } fn into_envelope(encoded_msg: &[u8], idempotency_key: &str) -> PlaintextEnvelope { @@ -1022,7 +1013,7 @@ mod tests { let bola_group = bola_groups.first().unwrap(); // Check Bola's group for the welcome host_id - let host_id: Vec = bola_group.host_id.clone().unwrap(); + let host_id: Vec = bola_group.added_by_id.clone().unwrap(); let host_basic_credential = BasicCredential::new(host_id).unwrap(); let host_credential = Credential::from(host_basic_credential); diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 885927bf4..6b178e26b 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -134,7 +134,7 @@ where ), )?; // TODO update cursor - MlsGroup::new(self, group_id, stream_info.convo_created_at_ns) + MlsGroup::new(self, group_id, stream_info.convo_created_at_ns, None) .process_stream_entry(envelope) .await } From 09cca4c67c95a48d51d651117719ff9c073cc32d Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Mon, 8 Apr 2024 10:29:17 -0700 Subject: [PATCH 05/21] Use Account Address Instead of Credential --- xmtp_mls/src/groups/mod.rs | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 8104fb3c5..6ac8c8294 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -143,7 +143,7 @@ impl RetryableError for GroupError { pub struct MlsGroup<'c, ApiClient> { pub group_id: Vec, pub created_at_ns: i64, - pub added_by_id: Option>, + pub added_by_address: Option, client: &'c Client, } @@ -153,7 +153,7 @@ impl<'c, ApiClient> Clone for MlsGroup<'c, ApiClient> { client: self.client, group_id: self.group_id.clone(), created_at_ns: self.created_at_ns, - added_by_id: self.added_by_id.clone(), + added_by_address: self.added_by_address.clone(), } } } @@ -163,12 +163,12 @@ where ApiClient: XmtpMlsClient, { // Creates a new group instance. Does not validate that the group exists in the DB - pub fn new(client: &'c Client, group_id: Vec, created_at_ns: i64, added_by_id: Option>) -> Self { + pub fn new(client: &'c Client, group_id: Vec, created_at_ns: i64, added_by_address: Option) -> Self { Self { client, group_id, created_at_ns, - added_by_id, + added_by_address: added_by_address, } } @@ -218,7 +218,7 @@ where client: &'c Client, provider: &XmtpOpenMlsProvider, welcome: MlsWelcome, - added_by_id: Option>, + added_by_address: Option, ) -> Result { let mls_welcome = StagedWelcome::new_from_welcome(provider, &build_group_join_config(), welcome, None)?; @@ -234,7 +234,7 @@ where client, stored_group.id, stored_group.created_at_ns, - added_by_id, + added_by_address, )) } @@ -267,9 +267,13 @@ where .expect("couldn't determine the sender of welcome"); let added_by_credential = BasicCredential::try_from(added_by_node.credential())?; - let added_by_id = added_by_credential.identity().to_vec(); + let pub_key_bytes = added_by_node.signature_key().as_slice(); + let account_address = Identity::get_validated_account_address( + added_by_credential.identity(), + pub_key_bytes + )?; - Self::create_from_welcome(client, provider, welcome, Some(added_by_id)) + Self::create_from_welcome(client, provider, welcome, Some(account_address)) } fn into_envelope(encoded_msg: &[u8], idempotency_key: &str) -> PlaintextEnvelope { @@ -515,10 +519,7 @@ fn build_group_join_config() -> MlsGroupJoinConfig { #[cfg(test)] mod tests { - use openmls::{ - credentials::BasicCredential, - prelude::{Credential, Member} - }; + use openmls::prelude::Member; use prost::Message; use xmtp_api_grpc::grpc_api_helper::Client as GrpcClient; use xmtp_cryptography::utils::generate_local_wallet; @@ -1012,15 +1013,10 @@ mod tests { .unwrap(); let bola_group = bola_groups.first().unwrap(); - // Check Bola's group for the welcome host_id - let host_id: Vec = bola_group.added_by_id.clone().unwrap(); - let host_basic_credential = BasicCredential::new(host_id).unwrap(); - let host_credential = Credential::from(host_basic_credential); + // Check Bola's group for the added_by_address of the inviter + let added_by_address = bola_group.added_by_address.clone().unwrap(); - // Verify the welcome host_credential is equal to Amal's - assert_eq!(amal.identity - .credential() - .unwrap(), - host_credential); + // // Verify the welcome host_credential is equal to Amal's + assert_eq!(amal.account_address(), added_by_address, "The Inviter and added_by_address do not match!"); } } From 520ebe1ba3436e0b539017bff09c1113057b69e2 Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Mon, 8 Apr 2024 13:48:00 -0700 Subject: [PATCH 06/21] Update schema to use added_by_address --- .../2024-04-08-180113_group_added_by_address/down.sql | 9 +++++++++ .../2024-04-08-180113_group_added_by_address/up.sql | 2 ++ xmtp_mls/src/storage/encrypted_store/group.rs | 4 ++++ xmtp_mls/src/storage/encrypted_store/schema.rs | 1 + 4 files changed, 16 insertions(+) create mode 100644 xmtp_mls/migrations/2024-04-08-180113_group_added_by_address/down.sql create mode 100644 xmtp_mls/migrations/2024-04-08-180113_group_added_by_address/up.sql diff --git a/xmtp_mls/migrations/2024-04-08-180113_group_added_by_address/down.sql b/xmtp_mls/migrations/2024-04-08-180113_group_added_by_address/down.sql new file mode 100644 index 000000000..79eca70df --- /dev/null +++ b/xmtp_mls/migrations/2024-04-08-180113_group_added_by_address/down.sql @@ -0,0 +1,9 @@ +-- As SQLite does not support ALTER, we play this game of move, repopulate, drop. Here we recreate without the 'added_by_address' column. +BEGIN TRANSACTION; +CREATE TEMPORARY TABLE backup_group(id BLOB PRIMARY KEY NOT NULL, created_at_ns BIGINT NOT NULL, membership_state INT NOT NULL, installations_last_checked BIGINT NOT NULL, purpose INT NOT NULL DEFAULT 1); +INSERT INTO backup_group SELECT id, created_at_ns, membership_state, installations_last_checked, pupose FROM groups; +DROP TABLE groups; +CREATE TABLE groups(id BLOB PRIMARY KEY NOT NULL, created_at_ns BIGINT NOT NULL, membership_state INT NOT NULL, installations_last_checked BIGINT NOT NULL, purpose INT NOT NULL DEFAULT 1); +INSERT INTO groups SELECT id, created_at_ns, membership_state, installations_last_checked, purpose FROM backup_group; +DROP TABLE backup_group; +COMMIT; diff --git a/xmtp_mls/migrations/2024-04-08-180113_group_added_by_address/up.sql b/xmtp_mls/migrations/2024-04-08-180113_group_added_by_address/up.sql new file mode 100644 index 000000000..9d32617d6 --- /dev/null +++ b/xmtp_mls/migrations/2024-04-08-180113_group_added_by_address/up.sql @@ -0,0 +1,2 @@ +ALTER TABLE groups +ADD COLUMN added_by_address TEXT diff --git a/xmtp_mls/src/storage/encrypted_store/group.rs b/xmtp_mls/src/storage/encrypted_store/group.rs index fae5f7a03..de4a75831 100644 --- a/xmtp_mls/src/storage/encrypted_store/group.rs +++ b/xmtp_mls/src/storage/encrypted_store/group.rs @@ -34,6 +34,8 @@ pub struct StoredGroup { pub installations_last_checked: i64, /// Enum, [`Purpose`] signifies the group purpose which extends to who can access it. pub purpose: Purpose, + /// String representing the wallet address of the who added the user to a group. + pub added_by_address: Option, } impl_fetch!(StoredGroup, groups, Vec); @@ -48,6 +50,7 @@ impl StoredGroup { membership_state, installations_last_checked: 0, purpose: Purpose::Conversation, + added_by_address: None, } } @@ -63,6 +66,7 @@ impl StoredGroup { membership_state, installations_last_checked: 0, purpose: Purpose::Sync, + added_by_address: None, } } } diff --git a/xmtp_mls/src/storage/encrypted_store/schema.rs b/xmtp_mls/src/storage/encrypted_store/schema.rs index fddd657c9..e259ab2a4 100644 --- a/xmtp_mls/src/storage/encrypted_store/schema.rs +++ b/xmtp_mls/src/storage/encrypted_store/schema.rs @@ -33,6 +33,7 @@ diesel::table! { membership_state -> Integer, installations_last_checked -> BigInt, purpose -> Integer, + added_by_address -> Nullable, } } From 1519f2b133d61e8c32518a85e7cdec0fb404b42d Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Mon, 8 Apr 2024 14:02:40 -0700 Subject: [PATCH 07/21] Update StoredGroup to use added_by_address --- xmtp_mls/src/groups/mod.rs | 6 ++++-- xmtp_mls/src/storage/encrypted_store/group.rs | 6 +++--- xmtp_mls/src/storage/encrypted_store/group_intent.rs | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 6ac8c8294..d5e497368 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -207,7 +207,8 @@ where mls_group.save(provider.key_store())?; let group_id = mls_group.group_id().to_vec(); - let stored_group = StoredGroup::new(group_id.clone(), now_ns(), membership_state); + // EM: Pass in now added by address + let stored_group = StoredGroup::new(group_id.clone(), now_ns(), membership_state, None); stored_group.store(provider.conn())?; Ok(Self::new(client, group_id, stored_group.created_at_ns, None)) } @@ -227,7 +228,8 @@ where mls_group.save(provider.key_store())?; let group_id = mls_group.group_id().to_vec(); - let to_store = StoredGroup::new(group_id, now_ns(), GroupMembershipState::Pending); + // EM: Store new added_by_address here + let to_store = StoredGroup::new(group_id, now_ns(), GroupMembershipState::Pending, added_by_address.clone()); let stored_group = provider.conn().insert_or_ignore_group(to_store)?; Ok(Self::new( diff --git a/xmtp_mls/src/storage/encrypted_store/group.rs b/xmtp_mls/src/storage/encrypted_store/group.rs index de4a75831..6cbdb2585 100644 --- a/xmtp_mls/src/storage/encrypted_store/group.rs +++ b/xmtp_mls/src/storage/encrypted_store/group.rs @@ -43,14 +43,14 @@ impl_store!(StoredGroup, groups); impl StoredGroup { /// Create a new [`Purpose::Conversation`] group. This is the default type of group. - pub fn new(id: ID, created_at_ns: i64, membership_state: GroupMembershipState) -> Self { + pub fn new(id: ID, created_at_ns: i64, membership_state: GroupMembershipState, added_by_address: Option) -> Self { Self { id, created_at_ns, membership_state, installations_last_checked: 0, purpose: Purpose::Conversation, - added_by_address: None, + added_by_address, } } @@ -253,7 +253,7 @@ pub(crate) mod tests { let id = rand_vec(); let created_at_ns = now_ns(); let membership_state = state.unwrap_or(GroupMembershipState::Allowed); - StoredGroup::new(id, created_at_ns, membership_state) + StoredGroup::new(id, created_at_ns, membership_state, None) } #[test] diff --git a/xmtp_mls/src/storage/encrypted_store/group_intent.rs b/xmtp_mls/src/storage/encrypted_store/group_intent.rs index a7bf59eed..ac0bca57d 100644 --- a/xmtp_mls/src/storage/encrypted_store/group_intent.rs +++ b/xmtp_mls/src/storage/encrypted_store/group_intent.rs @@ -306,7 +306,7 @@ mod tests { }; fn insert_group(conn: &DbConnection, group_id: Vec) { - let group = StoredGroup::new(group_id, 100, GroupMembershipState::Allowed); + let group = StoredGroup::new(group_id, 100, GroupMembershipState::Allowed, None); group.store(conn).unwrap(); } From 8ebeb1a005bdbbe0f73f9ef361e4a320fea9c139 Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Mon, 8 Apr 2024 14:11:16 -0700 Subject: [PATCH 08/21] Pass in account_address during group creation --- xmtp_mls/src/client.rs | 10 +++++++--- xmtp_mls/src/groups/mod.rs | 7 +++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 42e9e1b99..25c690131 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -206,9 +206,13 @@ where ) -> Result, ClientError> { log::info!("creating group"); - // EM: Consider setting host id here as self? - let group = MlsGroup::create_and_insert(self, GroupMembershipState::Allowed, permissions) - .map_err(|e| ClientError::Generic(format!("group create error {}", e)))?; + let group = MlsGroup::create_and_insert( + self, + GroupMembershipState::Allowed, + permissions, + Some(self.account_address(), + )) + .map_err(|e| ClientError::Generic(format!("group create error {}", e)))?; Ok(group) } diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index d5e497368..9e947bd74 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -186,6 +186,7 @@ where client: &'c Client, membership_state: GroupMembershipState, permissions: Option, + added_by_address: Option, ) -> Result { let conn = client.store.conn()?; let provider = XmtpOpenMlsProvider::new(&conn); @@ -207,10 +208,9 @@ where mls_group.save(provider.key_store())?; let group_id = mls_group.group_id().to_vec(); - // EM: Pass in now added by address - let stored_group = StoredGroup::new(group_id.clone(), now_ns(), membership_state, None); + let stored_group = StoredGroup::new(group_id.clone(), now_ns(), membership_state, added_by_address.clone()); stored_group.store(provider.conn())?; - Ok(Self::new(client, group_id, stored_group.created_at_ns, None)) + Ok(Self::new(client, group_id, stored_group.created_at_ns, added_by_address)) } // Create a group from a decrypted and decoded welcome message @@ -228,7 +228,6 @@ where mls_group.save(provider.key_store())?; let group_id = mls_group.group_id().to_vec(); - // EM: Store new added_by_address here let to_store = StoredGroup::new(group_id, now_ns(), GroupMembershipState::Pending, added_by_address.clone()); let stored_group = provider.conn().insert_or_ignore_group(to_store)?; From c8c54dd666e3e6be068d35dec37ec40a97cf3afc Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Mon, 8 Apr 2024 14:38:50 -0700 Subject: [PATCH 09/21] Updated DB Fetch --- xmtp_mls/src/client.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 25c690131..07b2fb62f 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -223,8 +223,7 @@ where let conn = &mut self.store.conn()?; let stored_group: Option = conn.fetch(&group_id)?; match stored_group { - // EM: Will neeed to update StoredGroup and pass added_by_id here.... - Some(group) => Ok(MlsGroup::new(self, group.id, group.created_at_ns, None)), + Some(group) => Ok(MlsGroup::new(self, group.id, group.created_at_ns, group.added_by_address)), None => Err(ClientError::Generic("group not found".to_string())), } } @@ -248,8 +247,7 @@ where .conn()? .find_groups(allowed_states, created_after_ns, created_before_ns, limit)? .into_iter() - // EM: Will neeed to update StoredGroup and pass added_by_id here.... - .map(|stored_group| MlsGroup::new(self, stored_group.id, stored_group.created_at_ns, None)) + .map(|stored_group| MlsGroup::new(self, stored_group.id, stored_group.created_at_ns, stored_group.added_by_address)) .collect()) } From 292a24f9a0ae12b0d668d1ef63a8940e4d4cb53d Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Mon, 8 Apr 2024 16:23:13 -0700 Subject: [PATCH 10/21] E2E Who Added Me Test Including CRUD --- xmtp_mls/src/client.rs | 20 +++++++++++++++---- xmtp_mls/src/groups/mod.rs | 16 ++++++++++++--- xmtp_mls/src/storage/encrypted_store/group.rs | 7 ++++++- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 07b2fb62f..91f367374 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -210,8 +210,8 @@ where self, GroupMembershipState::Allowed, permissions, - Some(self.account_address(), - )) + Some(self.account_address()), + ) .map_err(|e| ClientError::Generic(format!("group create error {}", e)))?; Ok(group) @@ -223,7 +223,12 @@ where let conn = &mut self.store.conn()?; let stored_group: Option = conn.fetch(&group_id)?; match stored_group { - Some(group) => Ok(MlsGroup::new(self, group.id, group.created_at_ns, group.added_by_address)), + Some(group) => Ok(MlsGroup::new( + self, + group.id, + group.created_at_ns, + group.added_by_address, + )), None => Err(ClientError::Generic("group not found".to_string())), } } @@ -247,7 +252,14 @@ where .conn()? .find_groups(allowed_states, created_after_ns, created_before_ns, limit)? .into_iter() - .map(|stored_group| MlsGroup::new(self, stored_group.id, stored_group.created_at_ns, stored_group.added_by_address)) + .map(|stored_group| { + MlsGroup::new( + self, + stored_group.id, + stored_group.created_at_ns, + stored_group.added_by_address, + ) + }) .collect()) } diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 9e947bd74..2a946e2fe 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -1000,22 +1000,32 @@ mod tests { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; + // Amal creates a group let amal_group = amal.create_group(None).unwrap(); - // Add bola + + // Amal adds Bola to the group amal_group .add_members_by_installation_id(vec![bola.installation_public_key()]) .await .unwrap(); - // Get bola's version of the same group + // Bola syncs groups - this will decrypt the Welcome, identify who added Bola + // and then store that value on the group and insert into the database let bola_groups = bola .sync_welcomes() .await .unwrap(); + + // Bola gets the group id. This will be needed to fetch the group from + // the database. let bola_group = bola_groups.first().unwrap(); + let bola_group_id = bola_group.group_id.clone(); + + // Bola fetches group from the database + let bola_fetched_group = bola.group(bola_group_id).unwrap(); // Check Bola's group for the added_by_address of the inviter - let added_by_address = bola_group.added_by_address.clone().unwrap(); + let added_by_address = bola_fetched_group.added_by_address.clone().unwrap(); // // Verify the welcome host_credential is equal to Amal's assert_eq!(amal.account_address(), added_by_address, "The Inviter and added_by_address do not match!"); diff --git a/xmtp_mls/src/storage/encrypted_store/group.rs b/xmtp_mls/src/storage/encrypted_store/group.rs index 6cbdb2585..5a0a318dc 100644 --- a/xmtp_mls/src/storage/encrypted_store/group.rs +++ b/xmtp_mls/src/storage/encrypted_store/group.rs @@ -43,7 +43,12 @@ impl_store!(StoredGroup, groups); impl StoredGroup { /// Create a new [`Purpose::Conversation`] group. This is the default type of group. - pub fn new(id: ID, created_at_ns: i64, membership_state: GroupMembershipState, added_by_address: Option) -> Self { + pub fn new( + id: ID, + created_at_ns: i64, + membership_state: GroupMembershipState, + added_by_address: Option, + ) -> Self { Self { id, created_at_ns, From 0bed2424e6ad9bf2bafbdc2765e86461e17f2f11 Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Mon, 8 Apr 2024 17:25:21 -0700 Subject: [PATCH 11/21] =?UTF-8?q?Remove=20Developement=20Use=20of=20?= =?UTF-8?q?=E2=80=9CExpect=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- xmtp_mls/src/groups/mod.rs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 2a946e2fe..fca009e87 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -9,13 +9,10 @@ pub mod validated_commit; use intents::SendMessageIntentData; use openmls::{ - credentials::BasicCredential, - extensions::{Extension, Extensions, Metadata}, - group::{MlsGroupCreateConfig, MlsGroupJoinConfig}, - prelude::{ + credentials::BasicCredential, error::LibraryError, extensions::{Extension, Extensions, Metadata}, group::{MlsGroupCreateConfig, MlsGroupJoinConfig}, prelude::{ BasicCredentialError, CredentialWithKey, CryptoConfig, Error as TlsCodecError, GroupId, MlsGroup as OpenMlsGroup, StagedWelcome, Welcome as MlsWelcome, WireFormatPolicy, - }, + } }; use openmls_traits::OpenMlsProvider; use prost::Message; @@ -122,6 +119,8 @@ pub enum GroupError { EncodeError(#[from] prost::EncodeError), #[error("Credential error")] CredentialError(#[from] BasicCredentialError), + #[error("LeafNode error")] + LeafNodeError(#[from] LibraryError), } impl RetryableError for GroupError { @@ -250,22 +249,16 @@ where let welcome = deserialize_welcome(&welcome_bytes)?; - // === Create Staged Welcome === - // Note: .expect will be cleaned up before exiting DRAFT let join_config = build_group_join_config(); let staged_welcome = StagedWelcome::new_from_welcome( provider, &join_config, welcome.clone(), None - ) - .expect("error created staged mls group"); + )?; - // === Obtain address of welcome sender === - // Note: .expect will be cleaned up before exiting DRAFT let added_by_node = staged_welcome - .welcome_sender() - .expect("couldn't determine the sender of welcome"); + .welcome_sender()?; let added_by_credential = BasicCredential::try_from(added_by_node.credential())?; let pub_key_bytes = added_by_node.signature_key().as_slice(); From 76f08d0ad068b11ddbac3cf12adc5908799bdebb Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Wed, 10 Apr 2024 10:32:48 -0700 Subject: [PATCH 12/21] Update FfiGroup to use added_by_address --- bindings_ffi/src/mls.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 9f28c7594..41bf5f9a8 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -221,6 +221,7 @@ impl FfiConversations { inner_client: self.inner_client.clone(), group_id: convo.group_id, created_at_ns: convo.created_at_ns, + added_by_address: Some(self.inner_client.account_address()), }); Ok(out) @@ -237,6 +238,7 @@ impl FfiConversations { inner_client: self.inner_client.clone(), group_id: group.group_id, created_at_ns: group.created_at_ns, + added_by_address: group.added_by_address, }); Ok(out) @@ -266,6 +268,7 @@ impl FfiConversations { inner_client: self.inner_client.clone(), group_id: group.group_id, created_at_ns: group.created_at_ns, + added_by_address: group.added_by_address, }) }) .collect(); @@ -285,6 +288,7 @@ impl FfiConversations { inner_client: client.clone(), group_id: convo.group_id, created_at_ns: convo.created_at_ns, + added_by_address: convo.added_by_address, })) }, || {}, // on_close_callback @@ -318,6 +322,7 @@ pub struct FfiGroup { inner_client: Arc, group_id: Vec, created_at_ns: i64, + added_by_address: Option, } #[derive(uniffi::Record)] @@ -340,7 +345,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - None, + self.added_by_address.clone(), ); group.send_message(content_bytes.as_slice()).await?; @@ -353,7 +358,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - None, + self.added_by_address.clone(), ); group.sync().await?; @@ -361,6 +366,10 @@ impl FfiGroup { Ok(()) } + pub fn who_added_me(&self) -> Option { + self.added_by_address.clone() + } + pub fn find_messages( &self, opts: FfiListMessagesOptions, @@ -369,7 +378,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - None, + self.added_by_address.clone(), ); let messages: Vec = group @@ -395,7 +404,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - None, + self.added_by_address.clone(), ); let message = group.process_streamed_group_message(envelope_bytes).await?; let ffi_message = message.into(); @@ -408,7 +417,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - None, + self.added_by_address.clone(), ); let members: Vec = group @@ -430,7 +439,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - None, + self.added_by_address.clone(), ); group.add_members(account_addresses).await?; @@ -443,7 +452,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - None, + self.added_by_address.clone(), ); group.remove_members(account_addresses).await?; @@ -479,7 +488,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - None, + self.added_by_address.clone(), ); Ok(group.is_active()?) @@ -490,7 +499,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - None, + self.added_by_address.clone(), ); let metadata = group.metadata()?; From 9aa969d9d4eb0711b7cccbd80aae2b58df63abde Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Wed, 10 Apr 2024 11:36:31 -0700 Subject: [PATCH 13/21] Initial Bindings Test --- bindings_ffi/src/mls.rs | 195 ++++++++++++++++++++++++---------------- 1 file changed, 117 insertions(+), 78 deletions(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 41bf5f9a8..6924b5b0c 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -955,84 +955,84 @@ mod tests { ); } - #[tokio::test(flavor = "multi_thread", worker_threads = 5)] - async fn test_conversation_streaming() { - let amal = new_test_client().await; - let bola = new_test_client().await; - - let stream_callback = RustStreamCallback::new(); - - let stream = bola - .conversations() - .stream(Box::new(stream_callback.clone())) - .await - .unwrap(); - - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - - amal.conversations() - .create_group(vec![bola.account_address()], None) - .await - .unwrap(); - - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - - assert_eq!(stream_callback.message_count(), 1); - // Create another group and add bola - amal.conversations() - .create_group(vec![bola.account_address()], None) - .await - .unwrap(); - - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - assert_eq!(stream_callback.message_count(), 2); - - stream.end(); - tokio::time::sleep(tokio::time::Duration::from_millis(5)).await; - assert!(stream.is_closed()); - } - - #[tokio::test(flavor = "multi_thread", worker_threads = 5)] - async fn test_stream_all_messages() { - let alix = new_test_client().await; - let bo = new_test_client().await; - let caro = new_test_client().await; - - let alix_group = alix - .conversations() - .create_group(vec![caro.account_address()], None) - .await - .unwrap(); - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - - let stream_callback = RustStreamCallback::new(); - let stream = caro - .conversations() - .stream_all_messages(Box::new(stream_callback.clone())) - .await - .unwrap(); - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - - alix_group.send("first".as_bytes().to_vec()).await.unwrap(); - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - let bo_group = bo - .conversations() - .create_group(vec![caro.account_address()], None) - .await - .unwrap(); - tokio::time::sleep(tokio::time::Duration::from_millis(200)).await; - bo_group.send("second".as_bytes().to_vec()).await.unwrap(); - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - alix_group.send("third".as_bytes().to_vec()).await.unwrap(); - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - bo_group.send("fourth".as_bytes().to_vec()).await.unwrap(); - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - - assert_eq!(stream_callback.message_count(), 4); - stream.end(); - tokio::time::sleep(tokio::time::Duration::from_millis(5)).await; - assert!(stream.is_closed()); - } + // #[tokio::test(flavor = "multi_thread", worker_threads = 5)] + // async fn test_conversation_streaming() { + // let amal = new_test_client().await; + // let bola = new_test_client().await; + + // let stream_callback = RustStreamCallback::new(); + + // let stream = bola + // .conversations() + // .stream(Box::new(stream_callback.clone())) + // .await + // .unwrap(); + + // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + + // amal.conversations() + // .create_group(vec![bola.account_address()], None) + // .await + // .unwrap(); + + // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + + // assert_eq!(stream_callback.message_count(), 1); + // // Create another group and add bola + // amal.conversations() + // .create_group(vec![bola.account_address()], None) + // .await + // .unwrap(); + + // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + // assert_eq!(stream_callback.message_count(), 2); + + // stream.end(); + // tokio::time::sleep(tokio::time::Duration::from_millis(5)).await; + // assert!(stream.is_closed()); + // } + + // #[tokio::test(flavor = "multi_thread", worker_threads = 5)] + // async fn test_stream_all_messages() { + // let alix = new_test_client().await; + // let bo = new_test_client().await; + // let caro = new_test_client().await; + + // let alix_group = alix + // .conversations() + // .create_group(vec![caro.account_address()], None) + // .await + // .unwrap(); + // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + + // let stream_callback = RustStreamCallback::new(); + // let stream = caro + // .conversations() + // .stream_all_messages(Box::new(stream_callback.clone())) + // .await + // .unwrap(); + // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + + // alix_group.send("first".as_bytes().to_vec()).await.unwrap(); + // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + // let bo_group = bo + // .conversations() + // .create_group(vec![caro.account_address()], None) + // .await + // .unwrap(); + // tokio::time::sleep(tokio::time::Duration::from_millis(200)).await; + // bo_group.send("second".as_bytes().to_vec()).await.unwrap(); + // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + // alix_group.send("third".as_bytes().to_vec()).await.unwrap(); + // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + // bo_group.send("fourth".as_bytes().to_vec()).await.unwrap(); + // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + + // assert_eq!(stream_callback.message_count(), 4); + // stream.end(); + // tokio::time::sleep(tokio::time::Duration::from_millis(5)).await; + // assert!(stream.is_closed()); + // } #[tokio::test(flavor = "multi_thread", worker_threads = 5)] async fn test_message_streaming() { @@ -1126,4 +1126,43 @@ mod tests { tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; assert!(stream_closer.is_closed()); } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_group_who_added_me() { + // Create Clients + let amal = new_test_client().await; + let bola = new_test_client().await; + + // Amal creates a group and adds Bola to the group + amal.conversations() + .create_group(vec![bola.account_address()], None) + .await + .unwrap(); + + // Bola syncs groups - this will decrypt the Welcome, identify who added Bola + // and then store that value on the group and insert into the database + let bola_conversations = bola.conversations(); + let _ = bola_conversations.sync().await; + + // Bola gets the group id. This will be needed to fetch the group from + // the database. + let bola_groups = bola_conversations + .list( + crate::FfiListConversationsOptions { + created_after_ns: None, + created_before_ns: None, + limit: None + } + ) + .await + .unwrap(); + + let bola_group = bola_groups.first().unwrap(); + + // Check Bola's group for the added_by_address of the inviter + let added_by_address = bola_group.added_by_address.clone().unwrap(); + + // // Verify the welcome host_credential is equal to Amal's + assert_eq!(amal.account_address(), added_by_address, "The Inviter and added_by_address do not match!"); + } } From a1f58c0a426c7e71b24e45c2842463218a6462a4 Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Wed, 10 Apr 2024 14:16:22 -0700 Subject: [PATCH 14/21] Formatting Cleanup --- bindings_ffi/src/mls.rs | 180 +++++++++++++++++++------------------ xmtp_mls/src/groups/mod.rs | 69 ++++++++------ 2 files changed, 135 insertions(+), 114 deletions(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 6924b5b0c..6522b617d 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -404,7 +404,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address.clone(), + self.added_by_address.clone(), ); let message = group.process_streamed_group_message(envelope_bytes).await?; let ffi_message = message.into(); @@ -955,84 +955,84 @@ mod tests { ); } - // #[tokio::test(flavor = "multi_thread", worker_threads = 5)] - // async fn test_conversation_streaming() { - // let amal = new_test_client().await; - // let bola = new_test_client().await; - - // let stream_callback = RustStreamCallback::new(); - - // let stream = bola - // .conversations() - // .stream(Box::new(stream_callback.clone())) - // .await - // .unwrap(); - - // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - - // amal.conversations() - // .create_group(vec![bola.account_address()], None) - // .await - // .unwrap(); - - // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - - // assert_eq!(stream_callback.message_count(), 1); - // // Create another group and add bola - // amal.conversations() - // .create_group(vec![bola.account_address()], None) - // .await - // .unwrap(); - - // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - // assert_eq!(stream_callback.message_count(), 2); - - // stream.end(); - // tokio::time::sleep(tokio::time::Duration::from_millis(5)).await; - // assert!(stream.is_closed()); - // } - - // #[tokio::test(flavor = "multi_thread", worker_threads = 5)] - // async fn test_stream_all_messages() { - // let alix = new_test_client().await; - // let bo = new_test_client().await; - // let caro = new_test_client().await; - - // let alix_group = alix - // .conversations() - // .create_group(vec![caro.account_address()], None) - // .await - // .unwrap(); - // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - - // let stream_callback = RustStreamCallback::new(); - // let stream = caro - // .conversations() - // .stream_all_messages(Box::new(stream_callback.clone())) - // .await - // .unwrap(); - // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - - // alix_group.send("first".as_bytes().to_vec()).await.unwrap(); - // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - // let bo_group = bo - // .conversations() - // .create_group(vec![caro.account_address()], None) - // .await - // .unwrap(); - // tokio::time::sleep(tokio::time::Duration::from_millis(200)).await; - // bo_group.send("second".as_bytes().to_vec()).await.unwrap(); - // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - // alix_group.send("third".as_bytes().to_vec()).await.unwrap(); - // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - // bo_group.send("fourth".as_bytes().to_vec()).await.unwrap(); - // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - - // assert_eq!(stream_callback.message_count(), 4); - // stream.end(); - // tokio::time::sleep(tokio::time::Duration::from_millis(5)).await; - // assert!(stream.is_closed()); - // } + #[tokio::test(flavor = "multi_thread", worker_threads = 5)] + async fn test_conversation_streaming() { + let amal = new_test_client().await; + let bola = new_test_client().await; + + let stream_callback = RustStreamCallback::new(); + + let stream = bola + .conversations() + .stream(Box::new(stream_callback.clone())) + .await + .unwrap(); + + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + + amal.conversations() + .create_group(vec![bola.account_address()], None) + .await + .unwrap(); + + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + + assert_eq!(stream_callback.message_count(), 1); + // Create another group and add bola + amal.conversations() + .create_group(vec![bola.account_address()], None) + .await + .unwrap(); + + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + assert_eq!(stream_callback.message_count(), 2); + + stream.end(); + tokio::time::sleep(tokio::time::Duration::from_millis(5)).await; + assert!(stream.is_closed()); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 5)] + async fn test_stream_all_messages() { + let alix = new_test_client().await; + let bo = new_test_client().await; + let caro = new_test_client().await; + + let alix_group = alix + .conversations() + .create_group(vec![caro.account_address()], None) + .await + .unwrap(); + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + + let stream_callback = RustStreamCallback::new(); + let stream = caro + .conversations() + .stream_all_messages(Box::new(stream_callback.clone())) + .await + .unwrap(); + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + + alix_group.send("first".as_bytes().to_vec()).await.unwrap(); + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + let bo_group = bo + .conversations() + .create_group(vec![caro.account_address()], None) + .await + .unwrap(); + tokio::time::sleep(tokio::time::Duration::from_millis(200)).await; + bo_group.send("second".as_bytes().to_vec()).await.unwrap(); + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + alix_group.send("third".as_bytes().to_vec()).await.unwrap(); + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + bo_group.send("fourth".as_bytes().to_vec()).await.unwrap(); + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + + assert_eq!(stream_callback.message_count(), 4); + stream.end(); + tokio::time::sleep(tokio::time::Duration::from_millis(5)).await; + assert!(stream.is_closed()); + } #[tokio::test(flavor = "multi_thread", worker_threads = 5)] async fn test_message_streaming() { @@ -1147,15 +1147,13 @@ mod tests { // Bola gets the group id. This will be needed to fetch the group from // the database. let bola_groups = bola_conversations - .list( - crate::FfiListConversationsOptions { - created_after_ns: None, - created_before_ns: None, - limit: None - } - ) - .await - .unwrap(); + .list(crate::FfiListConversationsOptions { + created_after_ns: None, + created_before_ns: None, + limit: None, + }) + .await + .unwrap(); let bola_group = bola_groups.first().unwrap(); @@ -1163,6 +1161,10 @@ mod tests { let added_by_address = bola_group.added_by_address.clone().unwrap(); // // Verify the welcome host_credential is equal to Amal's - assert_eq!(amal.account_address(), added_by_address, "The Inviter and added_by_address do not match!"); + assert_eq!( + amal.account_address(), + added_by_address, + "The Inviter and added_by_address do not match!" + ); } } diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index fca009e87..247998cbd 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -9,10 +9,14 @@ pub mod validated_commit; use intents::SendMessageIntentData; use openmls::{ - credentials::BasicCredential, error::LibraryError, extensions::{Extension, Extensions, Metadata}, group::{MlsGroupCreateConfig, MlsGroupJoinConfig}, prelude::{ - BasicCredentialError, CredentialWithKey, CryptoConfig, Error as TlsCodecError, GroupId, + credentials::BasicCredential, + error::LibraryError, + extensions::{Extension, Extensions, Metadata}, + group::{MlsGroupCreateConfig, MlsGroupJoinConfig}, + prelude::{ + BasicCredentialError, CredentialWithKey, CryptoConfig, Error as TlsCodecError, GroupId, MlsGroup as OpenMlsGroup, StagedWelcome, Welcome as MlsWelcome, WireFormatPolicy, - } + }, }; use openmls_traits::OpenMlsProvider; use prost::Message; @@ -162,7 +166,12 @@ where ApiClient: XmtpMlsClient, { // Creates a new group instance. Does not validate that the group exists in the DB - pub fn new(client: &'c Client, group_id: Vec, created_at_ns: i64, added_by_address: Option) -> Self { + pub fn new( + client: &'c Client, + group_id: Vec, + created_at_ns: i64, + added_by_address: Option, + ) -> Self { Self { client, group_id, @@ -207,9 +216,20 @@ where mls_group.save(provider.key_store())?; let group_id = mls_group.group_id().to_vec(); - let stored_group = StoredGroup::new(group_id.clone(), now_ns(), membership_state, added_by_address.clone()); + let stored_group = StoredGroup::new( + group_id.clone(), + now_ns(), + membership_state, + added_by_address.clone(), + ); + stored_group.store(provider.conn())?; - Ok(Self::new(client, group_id, stored_group.created_at_ns, added_by_address)) + Ok(Self::new( + client, + group_id, + stored_group.created_at_ns, + added_by_address, + )) } // Create a group from a decrypted and decoded welcome message @@ -227,7 +247,12 @@ where mls_group.save(provider.key_store())?; let group_id = mls_group.group_id().to_vec(); - let to_store = StoredGroup::new(group_id, now_ns(), GroupMembershipState::Pending, added_by_address.clone()); + let to_store = StoredGroup::new( + group_id, + now_ns(), + GroupMembershipState::Pending, + added_by_address.clone(), + ); let stored_group = provider.conn().insert_or_ignore_group(to_store)?; Ok(Self::new( @@ -250,22 +275,15 @@ where let welcome = deserialize_welcome(&welcome_bytes)?; let join_config = build_group_join_config(); - let staged_welcome = StagedWelcome::new_from_welcome( - provider, - &join_config, - welcome.clone(), - None - )?; + let staged_welcome = + StagedWelcome::new_from_welcome(provider, &join_config, welcome.clone(), None)?; - let added_by_node = staged_welcome - .welcome_sender()?; + let added_by_node = staged_welcome.welcome_sender()?; let added_by_credential = BasicCredential::try_from(added_by_node.credential())?; let pub_key_bytes = added_by_node.signature_key().as_slice(); - let account_address = Identity::get_validated_account_address( - added_by_credential.identity(), - pub_key_bytes - )?; + let account_address = + Identity::get_validated_account_address(added_by_credential.identity(), pub_key_bytes)?; Self::create_from_welcome(client, provider, welcome, Some(account_address)) } @@ -1004,10 +1022,7 @@ mod tests { // Bola syncs groups - this will decrypt the Welcome, identify who added Bola // and then store that value on the group and insert into the database - let bola_groups = bola - .sync_welcomes() - .await - .unwrap(); + let bola_groups = bola.sync_welcomes().await.unwrap(); // Bola gets the group id. This will be needed to fetch the group from // the database. @@ -1020,7 +1035,11 @@ mod tests { // Check Bola's group for the added_by_address of the inviter let added_by_address = bola_fetched_group.added_by_address.clone().unwrap(); - // // Verify the welcome host_credential is equal to Amal's - assert_eq!(amal.account_address(), added_by_address, "The Inviter and added_by_address do not match!"); + // Verify the welcome host_credential is equal to Amal's + assert_eq!( + amal.account_address(), + added_by_address, + "The Inviter and added_by_address do not match!" + ); } } From 0f83abda09532637c422a3e4768be3ea4987f3a5 Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Wed, 10 Apr 2024 14:20:33 -0700 Subject: [PATCH 15/21] Address Linter Finding --- xmtp_mls/src/groups/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 247998cbd..04eaca535 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -176,7 +176,7 @@ where client, group_id, created_at_ns, - added_by_address: added_by_address, + added_by_address, } } From 91d850d9c9f20dca755ee8f7c7feffd29257d76d Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Thu, 11 Apr 2024 19:24:12 -0700 Subject: [PATCH 16/21] get_group_member helper on FfiXmtpClient Set FfiGroupMember on FfiGroup Clean up formatting --- bindings_ffi/src/mls.rs | 109 ++++++++++++++++++++++++++-------------- 1 file changed, 71 insertions(+), 38 deletions(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 6522b617d..d097d71d6 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -217,12 +217,12 @@ impl FfiConversations { convo.add_members(account_addresses).await?; } - let out = Arc::new(FfiGroup { - inner_client: self.inner_client.clone(), - group_id: convo.group_id, - created_at_ns: convo.created_at_ns, - added_by_address: Some(self.inner_client.account_address()), - }); + let out = Arc::new(create_ffi_group( + self.inner_client.clone(), + convo.group_id, + convo.created_at_ns, + Some(self.inner_client.account_address()), + )); Ok(out) } @@ -233,14 +233,12 @@ impl FfiConversations { ) -> Result, GenericError> { let inner = self.inner_client.as_ref(); let group = inner.process_streamed_welcome_message(envelope_bytes)?; - - let out = Arc::new(FfiGroup { - inner_client: self.inner_client.clone(), - group_id: group.group_id, - created_at_ns: group.created_at_ns, - added_by_address: group.added_by_address, - }); - + let out = Arc::new(create_ffi_group( + self.inner_client.clone(), + group.group_id, + group.created_at_ns, + group.added_by_address, + )); Ok(out) } @@ -264,12 +262,12 @@ impl FfiConversations { )? .into_iter() .map(|group| { - Arc::new(FfiGroup { - inner_client: self.inner_client.clone(), - group_id: group.group_id, - created_at_ns: group.created_at_ns, - added_by_address: group.added_by_address, - }) + Arc::new(create_ffi_group( + self.inner_client.clone(), + group.group_id, + group.created_at_ns, + group.added_by_address, + )) }) .collect(); @@ -284,12 +282,12 @@ impl FfiConversations { let stream_closer = RustXmtpClient::stream_conversations_with_callback( client.clone(), move |convo| { - callback.on_conversation(Arc::new(FfiGroup { - inner_client: client.clone(), - group_id: convo.group_id, - created_at_ns: convo.created_at_ns, - added_by_address: convo.added_by_address, - })) + callback.on_conversation(Arc::new(create_ffi_group( + client.clone(), + convo.group_id, + convo.created_at_ns, + convo.added_by_address, + ))) }, || {}, // on_close_callback )?; @@ -319,10 +317,42 @@ impl FfiConversations { #[derive(uniffi::Object)] pub struct FfiGroup { + inner_client: Arc, + group_id: Vec, + created_at_ns: i64, + added_by: Option, +} + +pub fn create_ffi_group( inner_client: Arc, group_id: Vec, created_at_ns: i64, added_by_address: Option, +) -> FfiGroup { + let group = MlsGroup::new( + inner_client.as_ref(), + group_id.clone(), + created_at_ns, + added_by_address.clone(), + ); + + let added_by: Option = match group.members() { + Ok(members) => members + .into_iter() + .map(|member| FfiGroupMember { + account_address: member.account_address, + installation_ids: member.installation_ids, + }) + .find(|member| Some(&member.account_address) == added_by_address.as_ref()), + Err(_) => None, + }; + + FfiGroup { + inner_client, + group_id, + created_at_ns, + added_by, + } } #[derive(uniffi::Record)] @@ -345,7 +375,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address.clone(), + self.added_by_address(), ); group.send_message(content_bytes.as_slice()).await?; @@ -358,7 +388,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address.clone(), + self.added_by_address(), ); group.sync().await?; @@ -366,8 +396,11 @@ impl FfiGroup { Ok(()) } - pub fn who_added_me(&self) -> Option { - self.added_by_address.clone() + pub fn added_by_address(&self) -> Option { + match &self.added_by { + Some(member) => Some(member.account_address.clone()), + None => None, + } } pub fn find_messages( @@ -378,7 +411,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address.clone(), + self.added_by_address(), ); let messages: Vec = group @@ -404,7 +437,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address.clone(), + self.added_by_address(), ); let message = group.process_streamed_group_message(envelope_bytes).await?; let ffi_message = message.into(); @@ -417,7 +450,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address.clone(), + self.added_by_address(), ); let members: Vec = group @@ -439,7 +472,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address.clone(), + self.added_by_address(), ); group.add_members(account_addresses).await?; @@ -452,7 +485,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address.clone(), + self.added_by_address(), ); group.remove_members(account_addresses).await?; @@ -488,7 +521,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address.clone(), + self.added_by_address(), ); Ok(group.is_active()?) @@ -499,7 +532,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address.clone(), + self.added_by_address(), ); let metadata = group.metadata()?; @@ -1158,7 +1191,7 @@ mod tests { let bola_group = bola_groups.first().unwrap(); // Check Bola's group for the added_by_address of the inviter - let added_by_address = bola_group.added_by_address.clone().unwrap(); + let added_by_address = bola_group.added_by_address().unwrap(); // // Verify the welcome host_credential is equal to Amal's assert_eq!( From c0871f85fe3614b731c5f1dc4adbaeda98ab9450 Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Fri, 12 Apr 2024 13:51:18 -0700 Subject: [PATCH 17/21] Address Lint Findings --- bindings_ffi/src/mls.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index d097d71d6..1ee0a13de 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -397,10 +397,7 @@ impl FfiGroup { } pub fn added_by_address(&self) -> Option { - match &self.added_by { - Some(member) => Some(member.account_address.clone()), - None => None, - } + self.added_by.as_ref().map(|member| member.account_address.clone()) } pub fn find_messages( From ee1901c5ea3ab54a5a9c799397b8280e30d18036 Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Fri, 12 Apr 2024 15:33:58 -0700 Subject: [PATCH 18/21] Fix Flakey Test --- bindings_ffi/src/mls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 1ee0a13de..979702065 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -1005,7 +1005,7 @@ mod tests { .await .unwrap(); - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + tokio::time::sleep(tokio::time::Duration::from_millis(200)).await; assert_eq!(stream_callback.message_count(), 1); // Create another group and add bola From 3fc71ca5a351d5098318e8244bed9967da620099 Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Sun, 14 Apr 2024 17:28:21 -0700 Subject: [PATCH 19/21] Revert back to added_by_address --- bindings_ffi/src/mls.rs | 113 ++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 75 deletions(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 979702065..cb8b6e329 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -216,13 +216,12 @@ impl FfiConversations { if !account_addresses.is_empty() { convo.add_members(account_addresses).await?; } - - let out = Arc::new(create_ffi_group( - self.inner_client.clone(), - convo.group_id, - convo.created_at_ns, - Some(self.inner_client.account_address()), - )); + let out = Arc::new(FfiGroup { + inner_client: self.inner_client.clone(), + group_id: convo.group_id, + created_at_ns: convo.created_at_ns, + added_by_address: Some(self.inner_client.account_address()), + }); Ok(out) } @@ -233,12 +232,12 @@ impl FfiConversations { ) -> Result, GenericError> { let inner = self.inner_client.as_ref(); let group = inner.process_streamed_welcome_message(envelope_bytes)?; - let out = Arc::new(create_ffi_group( - self.inner_client.clone(), - group.group_id, - group.created_at_ns, - group.added_by_address, - )); + let out = Arc::new(FfiGroup { + inner_client: self.inner_client.clone(), + group_id: group.group_id, + created_at_ns: group.created_at_ns, + added_by_address: group.added_by_address, + }); Ok(out) } @@ -262,12 +261,12 @@ impl FfiConversations { )? .into_iter() .map(|group| { - Arc::new(create_ffi_group( - self.inner_client.clone(), - group.group_id, - group.created_at_ns, - group.added_by_address, - )) + Arc::new(FfiGroup { + inner_client: self.inner_client.clone(), + group_id: group.group_id, + created_at_ns: group.created_at_ns, + added_by_address: group.added_by_address, + }) }) .collect(); @@ -282,12 +281,12 @@ impl FfiConversations { let stream_closer = RustXmtpClient::stream_conversations_with_callback( client.clone(), move |convo| { - callback.on_conversation(Arc::new(create_ffi_group( - client.clone(), - convo.group_id, - convo.created_at_ns, - convo.added_by_address, - ))) + callback.on_conversation(Arc::new(FfiGroup { + inner_client: client.clone(), + group_id: convo.group_id, + created_at_ns: convo.created_at_ns, + added_by_address: convo.added_by_address, + })) }, || {}, // on_close_callback )?; @@ -317,42 +316,10 @@ impl FfiConversations { #[derive(uniffi::Object)] pub struct FfiGroup { - inner_client: Arc, - group_id: Vec, - created_at_ns: i64, - added_by: Option, -} - -pub fn create_ffi_group( inner_client: Arc, group_id: Vec, created_at_ns: i64, added_by_address: Option, -) -> FfiGroup { - let group = MlsGroup::new( - inner_client.as_ref(), - group_id.clone(), - created_at_ns, - added_by_address.clone(), - ); - - let added_by: Option = match group.members() { - Ok(members) => members - .into_iter() - .map(|member| FfiGroupMember { - account_address: member.account_address, - installation_ids: member.installation_ids, - }) - .find(|member| Some(&member.account_address) == added_by_address.as_ref()), - Err(_) => None, - }; - - FfiGroup { - inner_client, - group_id, - created_at_ns, - added_by, - } } #[derive(uniffi::Record)] @@ -375,7 +342,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address(), + self.added_by_address.clone(), ); group.send_message(content_bytes.as_slice()).await?; @@ -388,7 +355,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address(), + self.added_by_address.clone(), ); group.sync().await?; @@ -396,10 +363,6 @@ impl FfiGroup { Ok(()) } - pub fn added_by_address(&self) -> Option { - self.added_by.as_ref().map(|member| member.account_address.clone()) - } - pub fn find_messages( &self, opts: FfiListMessagesOptions, @@ -408,7 +371,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address(), + self.added_by_address.clone(), ); let messages: Vec = group @@ -434,7 +397,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address(), + self.added_by_address.clone(), ); let message = group.process_streamed_group_message(envelope_bytes).await?; let ffi_message = message.into(); @@ -447,7 +410,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address(), + self.added_by_address.clone(), ); let members: Vec = group @@ -469,7 +432,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address(), + self.added_by_address.clone(), ); group.add_members(account_addresses).await?; @@ -482,7 +445,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address(), + self.added_by_address.clone(), ); group.remove_members(account_addresses).await?; @@ -518,7 +481,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address(), + self.added_by_address.clone(), ); Ok(group.is_active()?) @@ -529,7 +492,7 @@ impl FfiGroup { self.inner_client.as_ref(), self.group_id.clone(), self.created_at_ns, - self.added_by_address(), + self.added_by_address.clone(), ); let metadata = group.metadata()?; @@ -985,7 +948,7 @@ mod tests { ); } - #[tokio::test(flavor = "multi_thread", worker_threads = 5)] + #[tokio::test(flavor = "multi_thread", worker_threads = 10)] async fn test_conversation_streaming() { let amal = new_test_client().await; let bola = new_test_client().await; @@ -998,14 +961,14 @@ mod tests { .await .unwrap(); - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + tokio::time::sleep(tokio::time::Duration::from_millis(400)).await; amal.conversations() .create_group(vec![bola.account_address()], None) .await .unwrap(); - tokio::time::sleep(tokio::time::Duration::from_millis(200)).await; + tokio::time::sleep(tokio::time::Duration::from_millis(400)).await; assert_eq!(stream_callback.message_count(), 1); // Create another group and add bola @@ -1014,7 +977,7 @@ mod tests { .await .unwrap(); - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + tokio::time::sleep(tokio::time::Duration::from_millis(400)).await; assert_eq!(stream_callback.message_count(), 2); stream.end(); @@ -1188,7 +1151,7 @@ mod tests { let bola_group = bola_groups.first().unwrap(); // Check Bola's group for the added_by_address of the inviter - let added_by_address = bola_group.added_by_address().unwrap(); + let added_by_address = bola_group.added_by_address.clone().unwrap(); // // Verify the welcome host_credential is equal to Amal's assert_eq!( From a795b0f5b41853c02a3521e76b9281701440ba9c Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Sun, 14 Apr 2024 22:10:05 -0700 Subject: [PATCH 20/21] Revert Flaky Test Changes --- bindings_ffi/src/mls.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index cb8b6e329..b018ada45 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -948,7 +948,7 @@ mod tests { ); } - #[tokio::test(flavor = "multi_thread", worker_threads = 10)] + #[tokio::test(flavor = "multi_thread", worker_threads = 5)] async fn test_conversation_streaming() { let amal = new_test_client().await; let bola = new_test_client().await; @@ -961,14 +961,14 @@ mod tests { .await .unwrap(); - tokio::time::sleep(tokio::time::Duration::from_millis(400)).await; + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; amal.conversations() .create_group(vec![bola.account_address()], None) .await .unwrap(); - tokio::time::sleep(tokio::time::Duration::from_millis(400)).await; + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; assert_eq!(stream_callback.message_count(), 1); // Create another group and add bola @@ -977,7 +977,7 @@ mod tests { .await .unwrap(); - tokio::time::sleep(tokio::time::Duration::from_millis(400)).await; + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; assert_eq!(stream_callback.message_count(), 2); stream.end(); From e75d5c08d6615bb4381505feefa275c4047ddeae Mon Sep 17 00:00:00 2001 From: Ethan Mateja Date: Mon, 15 Apr 2024 12:19:01 -0700 Subject: [PATCH 21/21] Use Conversation Values --- bindings_ffi/src/mls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index b018ada45..527efc096 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -220,7 +220,7 @@ impl FfiConversations { inner_client: self.inner_client.clone(), group_id: convo.group_id, created_at_ns: convo.created_at_ns, - added_by_address: Some(self.inner_client.account_address()), + added_by_address: convo.added_by_address, }); Ok(out)