Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fork fixes via intent filter fix #569

Merged
merged 3 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fork-fix-filter-adjustment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@xmtp/react-native-sdk": patch
---

Fix for forked groups via intent filter adjustment
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ repositories {
dependencies {
implementation project(':expo-modules-core')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
implementation "org.xmtp:android:3.0.15"
implementation "org.xmtp:android:3.0.16"
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'com.facebook.react:react-native:0.71.3'
implementation "com.daveanthonythomas.moshipack:moshipack:1.0.1"
Expand Down
14 changes: 7 additions & 7 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ PODS:
- hermes-engine/Pre-built (= 0.71.14)
- hermes-engine/Pre-built (0.71.14)
- libevent (2.1.12)
- LibXMTP (3.0.10)
- LibXMTP (3.0.12)
- MessagePacker (0.4.7)
- MMKV (2.0.0):
- MMKVCore (~> 2.0.0)
Expand Down Expand Up @@ -448,18 +448,18 @@ PODS:
- SQLCipher/standard (4.5.7):
- SQLCipher/common
- SwiftProtobuf (1.28.2)
- XMTP (3.0.16):
- XMTP (3.0.17):
- Connect-Swift (= 1.0.0)
- CryptoSwift (= 1.8.3)
- CSecp256k1 (~> 0.2)
- LibXMTP (= 3.0.10)
- LibXMTP (= 3.0.12)
- SQLCipher (= 4.5.7)
- XMTPReactNative (3.1.2):
- CSecp256k1 (~> 0.2)
- ExpoModulesCore
- MessagePacker
- SQLCipher (= 4.5.7)
- XMTP (= 3.0.16)
- XMTP (= 3.0.17)
- Yoga (1.14.0)

DEPENDENCIES:
Expand Down Expand Up @@ -711,7 +711,7 @@ SPEC CHECKSUMS:
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
hermes-engine: d7cc127932c89c53374452d6f93473f1970d8e88
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
LibXMTP: e550ccb4565023eb77f5a2eddd9d5a71cfb9d2b3
LibXMTP: 7e7607786ccc82c0230960964aa00843a5d47094
MessagePacker: ab2fe250e86ea7aedd1a9ee47a37083edd41fd02
MMKV: f7d1d5945c8765f97f39c3d121f353d46735d801
MMKVCore: c04b296010fcb1d1638f2c69405096aac12f6390
Expand Down Expand Up @@ -762,8 +762,8 @@ SPEC CHECKSUMS:
RNSVG: d00c8f91c3cbf6d476451313a18f04d220d4f396
SQLCipher: 5e6bfb47323635c8b657b1b27d25c5f1baf63bf5
SwiftProtobuf: 4dbaffec76a39a8dc5da23b40af1a5dc01a4c02d
XMTP: ce70e4a8e71db02af15bf4a0c230f5990c619281
XMTPReactNative: 00f79e4244439587ade2f7d65900e0dc9bd2634f
XMTP: 5be6a8212c789e828b6eeef9edae84a227c61f22
XMTPReactNative: 72e92330c1d9883a93c4a1be62ac4342e95dd80d
Yoga: e71803b4c1fff832ccf9b92541e00f9b873119b9

PODFILE CHECKSUM: 0e6fe50018f34e575d38dc6a1fdf1f99c9596cdd
Expand Down
272 changes: 272 additions & 0 deletions example/src/tests/groupTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
createGroups,
delayToPropogate,
} from './test-utils'
import {

Check warning on line 10 in example/src/tests/groupTests.ts

View workflow job for this annotation

GitHub Actions / lint

There should be at least one empty line between import groups
Client,
Conversation,
Group,
Expand All @@ -16,13 +16,285 @@
DecodedMessage,
ConsentRecord,
} from '../../../src/index'
import { DefaultContentTypes } from 'xmtp-react-native-sdk/lib/types/DefaultContentType'

Check warning on line 19 in example/src/tests/groupTests.ts

View workflow job for this annotation

GitHub Actions / lint

`xmtp-react-native-sdk/lib/types/DefaultContentType` import should occur before import of `./test-utils`

export const groupTests: Test[] = []
let counter = 1
function test(name: string, perform: () => Promise<boolean>) {
groupTests.push({ name: String(counter++) + '. ' + name, run: perform })
}

test('groups cannot fork', async () => {
const [alix, bo, caro] = await createClients(3)
// Create group with 3 users
const { id: groupId } = await alix.conversations.newGroup([
bo.address,
caro.address,
])

const getGroupForClient = async (client: Client) => {
// Always sync the client before getting the group
await client.conversations.sync()
const group = await client.conversations.findGroup(groupId)
assert(group !== undefined, `Group not found for ${client.address}`)
return group as Group<DefaultContentTypes>
}

const syncClientAndGroup = async (client: Client) => {
const group = await getGroupForClient(client)
await group.sync()
}

const addMemberToGroup = async (fromClient: Client, addresses: string[]) => {
await syncClientAndGroup(fromClient)
const group = await getGroupForClient(fromClient)
await group.addMembers(addresses)
await delayToPropogate(500)
}

const removeMemberFromGroup = async (
fromClient: Client,
addresses: string[]
) => {
await syncClientAndGroup(fromClient)
const group = await getGroupForClient(fromClient)
await group.removeMembers(addresses)
await delayToPropogate(500)
}

// Helper to send a message from a bunch of senders and make sure it is received by all receivers
const testMessageSending = async (senderClient: Client, receiver: Client) => {
// for (const senderClient of senders) {
const messageContent = Math.random().toString(36)
await syncClientAndGroup(senderClient)
const senderGroup = await getGroupForClient(senderClient)
await senderGroup.send(messageContent)

await delayToPropogate(500)
await senderGroup.sync()

await syncClientAndGroup(receiver)

const receiverGroupToCheck = await getGroupForClient(receiver)
await receiverGroupToCheck.sync()

const messages = await receiverGroupToCheck.messages({
direction: 'DESCENDING',
})
const lastMessage = messages[0]
// console.log(lastMessage);
console.log(
`${receiverGroupToCheck.client.address} sees ${messages.length} messages in group`
)
assert(
lastMessage !== undefined &&
lastMessage.nativeContent.text === messageContent,
`${receiverGroupToCheck.client.address} should have received the message, FORK? ${lastMessage?.nativeContent.text} !== ${messageContent}`
)
// }
}

console.log('Testing that messages sent by alix are received by bo')
await testMessageSending(alix, bo)
console.log('Alix & Bo are not forked at the beginning')

// Test adding members one by one
// console.log('Testing adding members one by one...')
const newClients = await createClients(2)

// Add back several members
console.log('Adding new members to the group...')
for (const client of newClients) {
console.log(`Adding member ${client.address}...`)
await addMemberToGroup(alix, [client.address])
}
await delayToPropogate()

await alix.conversations.sync()
await syncClientAndGroup(alix)

// NB => if we don't use Promise.all but a loop, we don't get a fork
const REMOVE_MEMBERS_IN_PARALLEL = true
if (REMOVE_MEMBERS_IN_PARALLEL) {
console.log('Removing members in parallel')

await Promise.all(
newClients.map((client) => {
console.log(`Removing member ${client.address}...`)
return removeMemberFromGroup(alix, [client.address])
})
)
} else {
console.log('Removing members one by one')

for (const client of newClients) {
console.log(`Removing member ${client.address}...`)
await removeMemberFromGroup(alix, [client.address])
}
}

await delayToPropogate(1000)

// When forked, it stays forked even if we try 5 times
// but sometimes it is not forked and works 5/5 times
let forkCount = 0
const tryCount = 5
for (let i = 0; i < tryCount; i++) {
console.log(`Checking fork status ${i+1}/${tryCount}`)

Check warning on line 143 in example/src/tests/groupTests.ts

View workflow job for this annotation

GitHub Actions / lint

Replace `+` with `·+·`
try {
await syncClientAndGroup(alix)
await syncClientAndGroup(bo)
await delayToPropogate(500)
await testMessageSending(alix, bo)
console.log('Not forked!')
} catch (e: any) {
console.log('Forked!')
console.log(e)
forkCount++
}
}

assert(forkCount === 0, `Forked ${forkCount}/${tryCount} times`)

return true
})

test('groups cannot fork short version', async () => {
const [alix, bo, new_one, new_two] = await createClients(4)
// Create group with 2 users
const alixGroup = await alix.conversations.newGroup([
bo.address,
new_one.address,
new_two.address,
])

// sync clients
await alix.conversations.sync()
await bo.conversations.sync()
const boGroup: Group<DefaultContentTypes> = (await bo.conversations.findGroup(alixGroup.id))!

Check warning on line 174 in example/src/tests/groupTests.ts

View workflow job for this annotation

GitHub Actions / lint

Replace `alixGroup.id` with `⏎····alixGroup.id⏎··`

// Remove two members in parallel
// NB => if we don't use Promise.all but a loop, we don't get a fork
console.log('*************libxmtp*********************: Removing members in parallel')

Check warning on line 178 in example/src/tests/groupTests.ts

View workflow job for this annotation

GitHub Actions / lint

Replace `'*************libxmtp*********************:·Removing·members·in·parallel'` with `⏎····'*************libxmtp*********************:·Removing·members·in·parallel'⏎··`
await Promise.all([
alixGroup.removeMembers([new_one.address]),
alixGroup.removeMembers([new_two.address])

Check warning on line 181 in example/src/tests/groupTests.ts

View workflow job for this annotation

GitHub Actions / lint

Insert `,`
])

// Helper to send a message from a bunch of senders and make sure it is received by all receivers
const testMessageSending = async (senderGroup: Group<DefaultContentTypes>, receiverGroup: Group<DefaultContentTypes>) => {

Check warning on line 185 in example/src/tests/groupTests.ts

View workflow job for this annotation

GitHub Actions / lint

Replace `senderGroup:·Group<DefaultContentTypes>,·receiverGroup:·Group<DefaultContentTypes>` with `⏎····senderGroup:·Group<DefaultContentTypes>,⏎····receiverGroup:·Group<DefaultContentTypes>⏎··`
const messageContent = Math.random().toString(36)
await senderGroup.sync()
await alixGroup.send(messageContent)

await delayToPropogate(500)
await alixGroup.sync()
await receiverGroup.sync()

const messages = await receiverGroup.messages({
direction: 'DESCENDING',
})
const lastMessage = messages[0]
console.log(
`${receiverGroup.client.address} sees ${messages.length} messages in group`
)
assert(
lastMessage !== undefined &&
lastMessage.nativeContent.text === messageContent,
`${receiverGroup.client.address} should have received the message, FORK? ${lastMessage?.nativeContent.text} !== ${messageContent}`
)
}
// When forked, it stays forked even if we try 5 times
// but sometimes it is not forked and works 5/5 times
let forkCount = 0
const tryCount = 5
for (let i = 0; i < tryCount; i++) {
console.log(`Checking fork status ${i+1}/${tryCount}`)

Check warning on line 212 in example/src/tests/groupTests.ts

View workflow job for this annotation

GitHub Actions / lint

Replace `+` with `·+·`
try {
await alixGroup.sync()
await boGroup.sync()
await delayToPropogate(500)
await testMessageSending(alixGroup, boGroup)
console.log('Not forked!')
} catch (e: any) {
console.log('Forked!')
console.log(e)
forkCount++
}
}
assert(forkCount === 0, `Forked ${forkCount}/${tryCount} times`)

return true
})

test('groups cannot fork short version - update metadata', async () => {
const [alix, bo, new_one, new_two, new_three, new_four] = await createClients(6)

Check warning on line 231 in example/src/tests/groupTests.ts

View workflow job for this annotation

GitHub Actions / lint

'new_three' is assigned a value but never used
// Create group with 2 users
const alixGroup = await alix.conversations.newGroup([
bo.address,
new_one.address,
new_two.address,
])

// sync clients
await alix.conversations.sync()
await bo.conversations.sync()
const boGroup: Group<DefaultContentTypes> = (await bo.conversations.findGroup(alixGroup.id))!

// Remove two members in parallel
// NB => if we don't use Promise.all but a loop, we don't get a fork
console.log('*************libxmtp*********************: Updating metadata in parallel')
await Promise.all([
alixGroup.updateGroupName('new name'),
alixGroup.updateGroupName('new name 2')
])

// Helper to send a message from a bunch of senders and make sure it is received by all receivers
const testMessageSending = async (senderGroup: Group<DefaultContentTypes>, receiverGroup: Group<DefaultContentTypes>) => {
const messageContent = Math.random().toString(36)
await senderGroup.sync()
await alixGroup.send(messageContent)

await delayToPropogate(500)
await alixGroup.sync()
await receiverGroup.sync()

const messages = await receiverGroup.messages({
direction: 'DESCENDING',
})
const lastMessage = messages[0]
console.log(
`${receiverGroup.client.address} sees ${messages.length} messages in group`
)
assert(
lastMessage !== undefined &&
lastMessage.nativeContent.text === messageContent,
`${receiverGroup.client.address} should have received the message, FORK? ${lastMessage?.nativeContent.text} !== ${messageContent}`
)
}
// When forked, it stays forked even if we try 5 times
// but sometimes it is not forked and works 5/5 times
let forkCount = 0
const tryCount = 5
for (let i = 0; i < tryCount; i++) {
console.log(`Checking fork status ${i+1}/${tryCount}`)
try {
await alixGroup.sync()
await boGroup.sync()
await delayToPropogate(500)
await testMessageSending(alixGroup, boGroup)
console.log('Not forked!')
} catch (e: any) {
console.log('Forked!')
console.log(e)
forkCount++
}
}
assert(forkCount === 0, `Forked ${forkCount}/${tryCount} times`)

return true
})

test('can cancel streams', async () => {
const [alix, bo] = await createClients(2)
let messageCallbacks = 0
Expand Down
2 changes: 1 addition & 1 deletion example/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6283,7 +6283,7 @@
resolved "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz"
integrity sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==

"@types/node@^20.14.9":
"@types/node@^20.15.0":
version "20.17.10"
resolved "https://registry.npmjs.org/@types/node/-/node-20.17.10.tgz#3f7166190aece19a0d1d364d75c8b0b5778c1e18"
integrity sha512-/jrvh5h6NXhEauFFexRin69nA0uHJ5gwk4iDivp/DeoEua3uwCUto6PC86IpRITBOs4+6i2I56K5x5b6WYGXHA==
Expand Down
2 changes: 1 addition & 1 deletion ios/XMTPReactNative.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Pod::Spec.new do |s|
s.source_files = "**/*.{h,m,swift}"

s.dependency "MessagePacker"
s.dependency "XMTP", "= 3.0.16"
s.dependency "XMTP", "= 3.0.17"
s.dependency 'CSecp256k1', '~> 0.2'
s.dependency "SQLCipher", "= 4.5.7"
end
Loading