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

Improve Client creation and build performance #341

Merged
merged 9 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.xmtp.android.library

import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import kotlinx.coroutines.runBlocking
Expand All @@ -12,6 +13,7 @@ import org.xmtp.android.library.messages.PrivateKeyBuilder
import org.xmtp.android.library.messages.walletAddress
import uniffi.xmtpv3.GenericException
import java.security.SecureRandom
import java.util.Date
import java.util.concurrent.CompletableFuture
import java.util.concurrent.TimeUnit

Expand Down Expand Up @@ -474,4 +476,62 @@ class ClientTest {
}
}
}

@Test
fun testCreatesADevClientPerformance() {
val key = SecureRandom().generateSeed(32)
val context = InstrumentationRegistry.getInstrumentation().targetContext
val fakeWallet = PrivateKeyBuilder()
val start = Date()
val client = runBlocking {
Client().create(
account = fakeWallet,
options = ClientOptions(
ClientOptions.Api(XMTPEnvironment.DEV, true),
appContext = context,
dbEncryptionKey = key
)
)
}
val end = Date()
val time1 = end.time - start.time
Log.d("PERF", "Created a client in ${time1 / 1000.0}s")

val start2 = Date()
val buildClient1 = runBlocking {
Client().build(
fakeWallet.address,
options = ClientOptions(
ClientOptions.Api(XMTPEnvironment.DEV, true),
appContext = context,
dbEncryptionKey = key
)
)
}
val end2 = Date()
val time2 = end2.time - start2.time
Log.d("PERF", "Built a client in ${time2 / 1000.0}s")

val start3 = Date()
val buildClient2 = runBlocking {
Client().build(
fakeWallet.address,
options = ClientOptions(
ClientOptions.Api(XMTPEnvironment.DEV, true),
appContext = context,
dbEncryptionKey = key
),
inboxId = client.inboxId
)
}
val end3 = Date()
val time3 = end3.time - start3.time
Log.d("PERF", "Built a client with inboxId in ${time3 / 1000.0}s")

assert(time2 < time1)
assert(time3 < time1)
assert(time3 < time2)
assertEquals(client.inboxId, buildClient1.inboxId)
assertEquals(client.inboxId, buildClient2.inboxId)
}
}
9 changes: 5 additions & 4 deletions library/src/main/java/org/xmtp/android/library/Client.kt
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,14 @@ class Client() {
address: String,
clientOptions: ClientOptions,
signingKey: SigningKey? = null,
inboxId: String? = null
): Client {
val accountAddress = address.lowercase()
val inboxId = getOrCreateInboxId(clientOptions.api, accountAddress)
val recoveredInboxId = inboxId ?: getOrCreateInboxId(clientOptions.api, accountAddress)

val (ffiClient, dbPath) = createFfiClient(
accountAddress,
inboxId,
recoveredInboxId,
clientOptions,
signingKey,
clientOptions.appContext,
Expand Down Expand Up @@ -139,9 +140,10 @@ class Client() {
suspend fun build(
address: String,
options: ClientOptions,
inboxId: String? = null
): Client {
return try {
initializeV3Client(address, options)
initializeV3Client(address, options, inboxId = inboxId)
} catch (e: Exception) {
throw XMTPException("Error creating V3 client: ${e.message}", e)
}
Expand Down Expand Up @@ -188,7 +190,6 @@ class Client() {
?: throw XMTPException("No signer passed but signer was required.")
ffiClient.registerIdentity(signatureRequest)
}

return Pair(ffiClient, dbPath)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,14 @@ class PrivateKeyBuilder : SigningKey {
)
val signatureKey = KeyUtil.getSignatureBytes(signatureData)

return SignatureOuterClass.Signature.newBuilder().also {
val sign = SignatureOuterClass.Signature.newBuilder().also {
it.ecdsaCompact = it.ecdsaCompact.toBuilder().also { builder ->
builder.bytes = signatureKey.take(64).toByteArray().toByteString()
builder.recovery = signatureKey[64].toInt()
}.build()
}.build()

return sign
}

override suspend fun sign(message: String): SignatureOuterClass.Signature {
Expand Down
Loading