fix(android): ensure session event subscription active before creating sign session

Add ensureSessionEventSubscriptionActive() call at the start of createSignSession()
to prevent race condition where session_started event arrives before subscription
is ready. Also add debug logging for _signSessionId and pendingSignInitiatorInfo
in event callback to help diagnose sign initiator event matching issues.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-01-01 21:45:18 -08:00
parent ecd7a2a2dc
commit 0bd764e1d1
2 changed files with 28 additions and 0 deletions

View File

@ -1936,6 +1936,11 @@ class TssRepository @Inject constructor(
): Result<SignSessionResult> { ): Result<SignSessionResult> {
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {
try { try {
// CRITICAL: Ensure session event subscription is active BEFORE creating sign session
// This prevents race condition where session_started event arrives before subscription is ready
android.util.Log.d("TssRepository", "[CO-SIGN] Ensuring session event subscription is active before creating sign session")
ensureSessionEventSubscriptionActive()
// Get share record // Get share record
val shareEntity = shareRecordDao.getShareById(shareId) val shareEntity = shareRecordDao.getShareById(shareId)
?: return@withContext Result.failure(Exception("Share not found")) ?: return@withContext Result.failure(Exception("Share not found"))
@ -2145,8 +2150,15 @@ class TssRepository @Inject constructor(
?: return@withContext Result.failure(Exception("Share not found")) ?: return@withContext Result.failure(Exception("Share not found"))
android.util.Log.d("TssRepository", "[CO-SIGN] startSigning: participants=${session.participants.size}") android.util.Log.d("TssRepository", "[CO-SIGN] startSigning: participants=${session.participants.size}")
android.util.Log.d("TssRepository", "[CO-SIGN] startSigning: sessionId=$sessionId, partyId=$partyId, partyIndex=${shareEntity.partyIndex}")
android.util.Log.d("TssRepository", "[CO-SIGN] startSigning: thresholdT=${session.thresholdT}, thresholdN=${shareEntity.thresholdN}")
android.util.Log.d("TssRepository", "[CO-SIGN] startSigning: messageHash=${session.messageHash?.take(20)}...")
session.participants.forEachIndexed { idx, p ->
android.util.Log.d("TssRepository", "[CO-SIGN] startSigning: participant[$idx] = ${p.partyId.take(12)}..., index=${p.partyIndex}")
}
// Start TSS sign // Start TSS sign
android.util.Log.d("TssRepository", "[CO-SIGN] Calling tssNativeBridge.startSign...")
val startResult = tssNativeBridge.startSign( val startResult = tssNativeBridge.startSign(
sessionId = sessionId, sessionId = sessionId,
partyId = partyId, partyId = partyId,
@ -2158,10 +2170,13 @@ class TssRepository @Inject constructor(
shareData = shareEntity.encryptedShare, shareData = shareEntity.encryptedShare,
password = password password = password
) )
android.util.Log.d("TssRepository", "[CO-SIGN] tssNativeBridge.startSign returned: isSuccess=${startResult.isSuccess}")
if (startResult.isFailure) { if (startResult.isFailure) {
android.util.Log.e("TssRepository", "[CO-SIGN] startSign FAILED: ${startResult.exceptionOrNull()?.message}")
return@withContext Result.failure(startResult.exceptionOrNull()!!) return@withContext Result.failure(startResult.exceptionOrNull()!!)
} }
android.util.Log.d("TssRepository", "[CO-SIGN] startSign succeeded, starting progress collection...")
// Start collecting progress from native bridge // Start collecting progress from native bridge
startProgressCollection() startProgressCollection()

View File

@ -329,6 +329,8 @@ class MainViewModel @Inject constructor(
android.util.Log.d("MainViewModel", " _currentSessionId: ${_currentSessionId.value}") android.util.Log.d("MainViewModel", " _currentSessionId: ${_currentSessionId.value}")
android.util.Log.d("MainViewModel", " pendingJoinKeygenInfo?.sessionId: ${pendingJoinKeygenInfo?.sessionId}") android.util.Log.d("MainViewModel", " pendingJoinKeygenInfo?.sessionId: ${pendingJoinKeygenInfo?.sessionId}")
android.util.Log.d("MainViewModel", " pendingJoinSignInfo?.sessionId: ${pendingJoinSignInfo?.sessionId}") android.util.Log.d("MainViewModel", " pendingJoinSignInfo?.sessionId: ${pendingJoinSignInfo?.sessionId}")
android.util.Log.d("MainViewModel", " _signSessionId: ${_signSessionId.value}")
android.util.Log.d("MainViewModel", " pendingSignInitiatorInfo?.sessionId: ${pendingSignInitiatorInfo?.sessionId}")
when (event.eventType) { when (event.eventType) {
"session_started" -> { "session_started" -> {
@ -362,9 +364,12 @@ class MainViewModel @Inject constructor(
// Check if this is for sign initiator (TransferScreen - 发起签名) // Check if this is for sign initiator (TransferScreen - 发起签名)
val signSessionId = _signSessionId.value val signSessionId = _signSessionId.value
android.util.Log.d("MainViewModel", "Checking for sign initiator: signSessionId=$signSessionId, eventSessionId=${event.sessionId}")
if (signSessionId != null && event.sessionId == signSessionId) { if (signSessionId != null && event.sessionId == signSessionId) {
android.util.Log.d("MainViewModel", "Session started event for sign initiator, triggering sign") android.util.Log.d("MainViewModel", "Session started event for sign initiator, triggering sign")
startSignAsInitiator(event.selectedParties) startSignAsInitiator(event.selectedParties)
} else {
android.util.Log.d("MainViewModel", "NOT triggering sign initiator: signSessionId=$signSessionId, pendingSignInitiatorInfo=${pendingSignInitiatorInfo?.sessionId}")
} }
} }
"party_joined", "participant_joined" -> { "party_joined", "participant_joined" -> {
@ -1218,22 +1223,30 @@ class MainViewModel @Inject constructor(
* Start the TSS signing process * Start the TSS signing process
*/ */
private fun startSigningProcess(sessionId: String, shareId: Long, password: String) { private fun startSigningProcess(sessionId: String, shareId: Long, password: String) {
android.util.Log.d("MainViewModel", "[SIGN] startSigningProcess called: sessionId=$sessionId, shareId=$shareId")
viewModelScope.launch { viewModelScope.launch {
android.util.Log.d("MainViewModel", "[SIGN] Calling repository.startSigning...")
val startResult = repository.startSigning(sessionId, shareId, password) val startResult = repository.startSigning(sessionId, shareId, password)
android.util.Log.d("MainViewModel", "[SIGN] repository.startSigning returned: isSuccess=${startResult.isSuccess}")
if (startResult.isFailure) { if (startResult.isFailure) {
android.util.Log.e("MainViewModel", "[SIGN] startSigning FAILED: ${startResult.exceptionOrNull()?.message}")
_uiState.update { it.copy(error = startResult.exceptionOrNull()?.message) } _uiState.update { it.copy(error = startResult.exceptionOrNull()?.message) }
return@launch return@launch
} }
// Wait for signature // Wait for signature
android.util.Log.d("MainViewModel", "[SIGN] startSigning succeeded, calling waitForSignature...")
val signResult = repository.waitForSignature() val signResult = repository.waitForSignature()
android.util.Log.d("MainViewModel", "[SIGN] waitForSignature returned: isSuccess=${signResult.isSuccess}")
signResult.fold( signResult.fold(
onSuccess = { result -> onSuccess = { result ->
android.util.Log.d("MainViewModel", "[SIGN] Signature received: ${result.signature.take(20)}...")
_signature.value = result.signature _signature.value = result.signature
}, },
onFailure = { e -> onFailure = { e ->
android.util.Log.e("MainViewModel", "[SIGN] waitForSignature FAILED: ${e.message}")
_uiState.update { it.copy(error = e.message) } _uiState.update { it.copy(error = e.message) }
} }
) )