From 5891a428039ba25ddf90410f44ff56bb39100205 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 17 Oct 2024 11:06:40 -0700 Subject: [PATCH 1/7] add a v2 conversation database --- .../down.sql | 1 + .../2024-10-17-173334_create_v2_conversations/up.sql | 6 ++++++ xmtp_mls/src/storage/encrypted_store/schema.rs | 12 +++++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/down.sql create mode 100644 xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/up.sql diff --git a/xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/down.sql b/xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/down.sql new file mode 100644 index 000000000..aad32fb5b --- /dev/null +++ b/xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS "v2_conversations"; diff --git a/xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/up.sql b/xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/up.sql new file mode 100644 index 000000000..041b982bb --- /dev/null +++ b/xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/up.sql @@ -0,0 +1,6 @@ +CREATE TABLE v2_conversations ( + topic TEXT NOT NULL PRIMARY KEY, + created_at_ns BIGINT NOT NULL, + peer_address INTEGER NOT NULL, + envelope_bytes BLOB NOT NULL +); diff --git a/xmtp_mls/src/storage/encrypted_store/schema.rs b/xmtp_mls/src/storage/encrypted_store/schema.rs index d6a7b85f7..17325c9e8 100644 --- a/xmtp_mls/src/storage/encrypted_store/schema.rs +++ b/xmtp_mls/src/storage/encrypted_store/schema.rs @@ -53,8 +53,8 @@ diesel::table! { purpose -> Integer, added_by_inbox_id -> Text, welcome_id -> Nullable, - rotated_at_ns -> BigInt, dm_inbox_id -> Nullable, + rotated_at_ns -> BigInt, } } @@ -107,6 +107,15 @@ diesel::table! { } } +diesel::table! { + v2_conversations (topic) { + topic -> Text, + created_at_ns -> BigInt, + peer_address -> Integer, + envelope_bytes -> Binary, + } +} + diesel::joinable!(group_intents -> groups (group_id)); diesel::joinable!(group_messages -> groups (group_id)); @@ -122,4 +131,5 @@ diesel::allow_tables_to_appear_in_same_query!( openmls_key_store, openmls_key_value, refresh_state, + v2_conversations, ); From c7fe6990c7cf73d3144ca1fa8069ef5eda56d296 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 17 Oct 2024 12:20:11 -0700 Subject: [PATCH 2/7] add the v2 conversation database --- .../up.sql | 2 +- .../src/storage/encrypted_store/schema.rs | 2 +- .../encrypted_store/v2_conversation.rs | 145 ++++++++++++++++++ 3 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 xmtp_mls/src/storage/encrypted_store/v2_conversation.rs diff --git a/xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/up.sql b/xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/up.sql index 041b982bb..05296fbeb 100644 --- a/xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/up.sql +++ b/xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/up.sql @@ -1,6 +1,6 @@ CREATE TABLE v2_conversations ( topic TEXT NOT NULL PRIMARY KEY, created_at_ns BIGINT NOT NULL, - peer_address INTEGER NOT NULL, + peer_address TEXT NOT NULL, envelope_bytes BLOB NOT NULL ); diff --git a/xmtp_mls/src/storage/encrypted_store/schema.rs b/xmtp_mls/src/storage/encrypted_store/schema.rs index 17325c9e8..2e83c9ed0 100644 --- a/xmtp_mls/src/storage/encrypted_store/schema.rs +++ b/xmtp_mls/src/storage/encrypted_store/schema.rs @@ -111,7 +111,7 @@ diesel::table! { v2_conversations (topic) { topic -> Text, created_at_ns -> BigInt, - peer_address -> Integer, + peer_address -> Text, envelope_bytes -> Binary, } } diff --git a/xmtp_mls/src/storage/encrypted_store/v2_conversation.rs b/xmtp_mls/src/storage/encrypted_store/v2_conversation.rs new file mode 100644 index 000000000..9080d95e7 --- /dev/null +++ b/xmtp_mls/src/storage/encrypted_store/v2_conversation.rs @@ -0,0 +1,145 @@ +use crate::{impl_store, storage::StorageError}; + +use super::Sqlite; +use super::{ + db_connection::DbConnection, + schema::consent_records::{self, dsl}, +}; +use diesel::{ + backend::Backend, + deserialize::{self, FromSql, FromSqlRow}, + expression::AsExpression, + prelude::*, + serialize::{self, IsNull, Output, ToSql}, + sql_types::Integer, + upsert::excluded, +}; +use serde::{Deserialize, Serialize}; + +/// StoredV2Conversation holds a serialized ConsentRecord +#[derive(Insertable, Queryable, Debug, Clone, PartialEq, Eq)] +#[diesel(table_name = v2_conversations)] +#[diesel(primary_key(topic))] +pub struct StoredV2Conversation { + pub topic: String, + pub peer_address: String, + pub envelope_bytes: Vec, + pub created_at_ns: i64, +} + +impl StoredV2Conversation { + pub fn new(topic: String, peer_address: String, envelope_bytes: Vec, created_at_ns: i64) -> Self { + Self { + topic, + peer_address, + envelope_bytes, + created_at_ns + } + } +} + +impl_store!(StoredV2Conversation, v2_conversations); + +impl DbConnection { + /// Returns a v2_conversation + pub fn get_v2_conversation( + &self, + peer_address: String, + ) -> Result, StorageError> { + Ok(self.raw_query(|conn| -> diesel::QueryResult<_> { + dsl::v2_conversations + .filter(dsl::peer_address.eq(peer_address)) + .first(conn) + .optional() + })?) + } + + /// Returns all the v2_conversations + pub fn get_v2_conversations( + &self, + ) -> Result, StorageError> { + Ok(self.raw_query(|conn| -> diesel::QueryResult<_> { + dsl::v2_conversations + })?) + } + + /// Insert v2_conversations + pub fn insert_or_replace_v2_conversation(&self, v2_conversation: StoredV2Conversation) -> Result { + tracing::info!("Trying to insert v2 conversation"); + let stored_v2_conversation = self.raw_query(|conn| { + let maybe_inserted_conversation: Option = diesel::insert_into(dsl::v2_conversations) + .values(&v2_conversation) + .on_conflict_do_nothing() + .get_result(conn) + .optional()?; + + if maybe_inserted_conversation.is_none() { + let existing_conversation: StoredV2Conversation = dsl::v2_conversations.find(v2_conversation.id).first(conn)?; + if existing_conversation.welcome_id == v2_conversation.welcome_id { + tracing::info!("V2 Conversation invite already exists"); + // Error so OpenMLS db transaction are rolled back on duplicate welcomes + return Err(StorageError::Duplicate(DuplicateItem::WelcomeId( + existing_group.welcome_id, + ))); + } else { + tracing::info!("V2 Conversation already exists"); + return Ok(existing_group); + } + } else { + tracing::info!("V2 Conversation is inserted"); + } + + match maybe_inserted_conversation { + Some(v2_conversation) => Ok(v2_conversation), + None => Ok(dsl::v2_conversations.find(v2_conversation.id).first(conn)?), + } + })?; + + Ok(stored_v2_conversation) + } +} + +#[cfg(test)] +mod tests { + use crate::storage::encrypted_store::tests::with_connection; + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + + use super::*; + + // fn generate_consent_record( + // entity_type: ConsentType, + // state: ConsentState, + // entity: String, + // ) -> StoredConsentRecord { + // StoredConsentRecord { + // entity_type, + // state, + // entity, + // } + // } + + // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + // #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + // async fn insert_and_read() { + // with_connection(|conn| { + // let inbox_id = "inbox_1"; + // let consent_record = generate_consent_record( + // ConsentType::InboxId, + // ConsentState::Denied, + // inbox_id.to_string(), + // ); + // let consent_record_entity = consent_record.entity.clone(); + + // conn.insert_or_replace_consent_records(vec![consent_record]) + // .expect("should store without error"); + + // let consent_record = conn + // .get_consent_record(inbox_id.to_owned(), ConsentType::InboxId) + // .expect("query should work"); + + // assert_eq!(consent_record.unwrap().entity, consent_record_entity); + // }) + // .await; + // } +} From 585d6aab0036edb2c6a536f4cb2e70f68aa59349 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 17 Oct 2024 12:26:41 -0700 Subject: [PATCH 3/7] replace id with topic --- .../src/storage/encrypted_store/v2_conversation.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/xmtp_mls/src/storage/encrypted_store/v2_conversation.rs b/xmtp_mls/src/storage/encrypted_store/v2_conversation.rs index 9080d95e7..8f6be413b 100644 --- a/xmtp_mls/src/storage/encrypted_store/v2_conversation.rs +++ b/xmtp_mls/src/storage/encrypted_store/v2_conversation.rs @@ -74,16 +74,16 @@ impl DbConnection { .optional()?; if maybe_inserted_conversation.is_none() { - let existing_conversation: StoredV2Conversation = dsl::v2_conversations.find(v2_conversation.id).first(conn)?; - if existing_conversation.welcome_id == v2_conversation.welcome_id { + let existing_conversation: StoredV2Conversation = dsl::v2_conversations.find(v2_conversation.topic).first(conn)?; + if existing_conversation.topic == v2_conversation.topic { tracing::info!("V2 Conversation invite already exists"); // Error so OpenMLS db transaction are rolled back on duplicate welcomes return Err(StorageError::Duplicate(DuplicateItem::WelcomeId( - existing_group.welcome_id, + existing_conversation.topic, ))); } else { tracing::info!("V2 Conversation already exists"); - return Ok(existing_group); + return Ok(existing_conversation); } } else { tracing::info!("V2 Conversation is inserted"); @@ -91,7 +91,7 @@ impl DbConnection { match maybe_inserted_conversation { Some(v2_conversation) => Ok(v2_conversation), - None => Ok(dsl::v2_conversations.find(v2_conversation.id).first(conn)?), + None => Ok(dsl::v2_conversations.find(v2_conversation.topic).first(conn)?), } })?; From 76b3ef13270612afe05c32ea499e429b2322dc56 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 17 Oct 2024 12:28:29 -0700 Subject: [PATCH 4/7] maybe fix the issue? --- xmtp_mls/src/storage/encrypted_store/schema.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmtp_mls/src/storage/encrypted_store/schema.rs b/xmtp_mls/src/storage/encrypted_store/schema.rs index 2e83c9ed0..17b64519c 100644 --- a/xmtp_mls/src/storage/encrypted_store/schema.rs +++ b/xmtp_mls/src/storage/encrypted_store/schema.rs @@ -53,8 +53,8 @@ diesel::table! { purpose -> Integer, added_by_inbox_id -> Text, welcome_id -> Nullable, - dm_inbox_id -> Nullable, rotated_at_ns -> BigInt, + dm_inbox_id -> Nullable, } } From 68e94fc9fb5ebfd89aed4dfb0d7d0ad53b275373 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 17 Oct 2024 12:39:07 -0700 Subject: [PATCH 5/7] add index --- .../2024-10-17-173334_create_v2_conversations/down.sql | 1 + .../migrations/2024-10-17-173334_create_v2_conversations/up.sql | 2 ++ 2 files changed, 3 insertions(+) diff --git a/xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/down.sql b/xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/down.sql index aad32fb5b..525c11f3e 100644 --- a/xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/down.sql +++ b/xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/down.sql @@ -1 +1,2 @@ DROP TABLE IF EXISTS "v2_conversations"; +DROP INDEX idx_peer_address; diff --git a/xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/up.sql b/xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/up.sql index 05296fbeb..b7b8c6361 100644 --- a/xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/up.sql +++ b/xmtp_mls/migrations/2024-10-17-173334_create_v2_conversations/up.sql @@ -4,3 +4,5 @@ CREATE TABLE v2_conversations ( peer_address TEXT NOT NULL, envelope_bytes BLOB NOT NULL ); + +CREATE INDEX idx_peer_address ON v2_conversations (peer_address); From 6083d3360970c8704b8717cb180345e79f5a3dde Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 17 Oct 2024 12:50:47 -0700 Subject: [PATCH 6/7] add a test --- .../encrypted_store/v2_conversation.rs | 80 +++++++++++-------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/xmtp_mls/src/storage/encrypted_store/v2_conversation.rs b/xmtp_mls/src/storage/encrypted_store/v2_conversation.rs index 8f6be413b..4ca110e73 100644 --- a/xmtp_mls/src/storage/encrypted_store/v2_conversation.rs +++ b/xmtp_mls/src/storage/encrypted_store/v2_conversation.rs @@ -1,3 +1,5 @@ +//! The V2 Conversation database table. Stored information surrounding v2 conversations. + use crate::{impl_store, storage::StorageError}; use super::Sqlite; @@ -107,39 +109,47 @@ mod tests { use super::*; - // fn generate_consent_record( - // entity_type: ConsentType, - // state: ConsentState, - // entity: String, - // ) -> StoredConsentRecord { - // StoredConsentRecord { - // entity_type, - // state, - // entity, - // } - // } - - // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - // #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] - // async fn insert_and_read() { - // with_connection(|conn| { - // let inbox_id = "inbox_1"; - // let consent_record = generate_consent_record( - // ConsentType::InboxId, - // ConsentState::Denied, - // inbox_id.to_string(), - // ); - // let consent_record_entity = consent_record.entity.clone(); - - // conn.insert_or_replace_consent_records(vec![consent_record]) - // .expect("should store without error"); - - // let consent_record = conn - // .get_consent_record(inbox_id.to_owned(), ConsentType::InboxId) - // .expect("query should work"); - - // assert_eq!(consent_record.unwrap().entity, consent_record_entity); - // }) - // .await; - // } + fn generate_v2_conversation( + topic: String, + peer_address: String, + envelope_bytes: Vec, + created_at_ns: i64, + ) -> StoredV2Conversation { + StoredV2Conversation { + topic, + peer_address, + envelope_bytes, + created_at_ns + } + } + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn insert_and_read() { + with_connection(|conn| { + let peer_address = "example_peer_address"; + let v2_conversation = generate_v2_conversation( + "example_topic", + peer_address, + vec![1, 2, 3], + now_ns() + ); + let v2_conversation_entity = v2_conversation.entity.clone(); + + conn.insert_or_replace_v2_conversation(vec![v2_conversation_entity]) + .expect("should store without error"); + + let v2_conversations = conn + .get_v2_conversations() + .expect("query should work"); + + let v2_conversation = conn + .get_v2_conversation(peer_address) + .expect("query should work"); + + assert_eq!(v2_conversation.unwrap().entity, v2_conversation_entity); + assert_eq!(v2_conversations.unwrap().first().entity, v2_conversation_entity); + }) + .await; + } } From 38d8cb5fcc5e9429d9762209df65cea2e9fa8935 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 17 Oct 2024 12:54:28 -0700 Subject: [PATCH 7/7] small update --- xmtp_mls/src/storage/encrypted_store/v2_conversation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmtp_mls/src/storage/encrypted_store/v2_conversation.rs b/xmtp_mls/src/storage/encrypted_store/v2_conversation.rs index 4ca110e73..6b589e721 100644 --- a/xmtp_mls/src/storage/encrypted_store/v2_conversation.rs +++ b/xmtp_mls/src/storage/encrypted_store/v2_conversation.rs @@ -61,7 +61,7 @@ impl DbConnection { &self, ) -> Result, StorageError> { Ok(self.raw_query(|conn| -> diesel::QueryResult<_> { - dsl::v2_conversations + dsl::v2_conversations.load(conn) })?) }