fix(service-party-android): 修复导入钱包签名时 'party not registered' 错误
导入的钱包份额携带原始 keygen partyId,与设备自身 partyId 不同。 签名时用原始 partyId 订阅 session events,但该 ID 未在 message-router 注册,导致服务端返回 FAILED_PRECONDITION。 修复:签名前将导入份额的 partyId 也注册到 message-router(带 3 次重试), 注册失败则中断签名流程并提示用户;断线重连时自动恢复双 partyId 注册; 签名结束后清理额外注册。 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
fe6c1b3fce
commit
1f434f32fb
|
|
@ -97,6 +97,11 @@ class GrpcClient @Inject constructor() {
|
|||
private var registeredPartyId: String? = null
|
||||
private var registeredPartyRole: String? = null
|
||||
|
||||
// Additional signing party registration (for imported/restored shares)
|
||||
// When signing with a restored wallet, the signing partyId differs from the device partyId
|
||||
// and must also be registered with the message-router
|
||||
private var registeredSigningPartyId: String? = null
|
||||
|
||||
// Heartbeat state
|
||||
private var heartbeatJob: Job? = null
|
||||
private val heartbeatFailCount = AtomicInteger(0)
|
||||
|
|
@ -460,6 +465,17 @@ class GrpcClient @Inject constructor() {
|
|||
Log.e(TAG, "Re-registration failed: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
// Also re-register the signing partyId if active (for imported/restored shares)
|
||||
val signingId = registeredSigningPartyId
|
||||
if (signingId != null && signingId != partyId) {
|
||||
Log.d(TAG, "Re-registering signing party: $signingId")
|
||||
try {
|
||||
registerPartyInternal(signingId, "temporary", "1.0.0")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Re-registration of signing party failed: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -651,6 +667,29 @@ class GrpcClient @Inject constructor() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an additional signing partyId with the message-router.
|
||||
* Used when signing with imported/restored shares where the signing partyId
|
||||
* differs from the device's own partyId. Does not overwrite the device registration.
|
||||
*/
|
||||
suspend fun registerSigningParty(signingPartyId: String): Result<Boolean> = withContext(Dispatchers.IO) {
|
||||
if (signingPartyId == registeredPartyId) {
|
||||
// Same as device partyId, already registered
|
||||
return@withContext Result.success(true)
|
||||
}
|
||||
Log.d(TAG, "Registering signing partyId: $signingPartyId (device partyId: $registeredPartyId)")
|
||||
registeredSigningPartyId = signingPartyId
|
||||
registerPartyInternal(signingPartyId, "temporary", "1.0.0")
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the additional signing party registration.
|
||||
* Called when signing completes or fails.
|
||||
*/
|
||||
fun clearSigningPartyRegistration() {
|
||||
registeredSigningPartyId = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Join a session
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -388,12 +388,34 @@ class TssRepository @Inject constructor(
|
|||
* CRITICAL: For signing with restored wallets, this should be the original
|
||||
* partyId from keygen (shareEntity.partyId).
|
||||
*/
|
||||
private fun ensureSessionEventSubscriptionActive(signingPartyId: String? = null) {
|
||||
private suspend fun ensureSessionEventSubscriptionActive(signingPartyId: String? = null) {
|
||||
// Check if the session event job is still active
|
||||
val isActive = sessionEventJob?.isActive == true
|
||||
val effectivePartyId = signingPartyId ?: currentSessionEventPartyId ?: partyId
|
||||
android.util.Log.d("TssRepository", "Checking session event subscription: isActive=$isActive, effectivePartyId=$effectivePartyId")
|
||||
|
||||
// If subscribing with a different partyId (imported/restored share),
|
||||
// register it with the message-router first to avoid "party not registered" error.
|
||||
// Retry up to 3 times to handle transient network issues.
|
||||
if (effectivePartyId != partyId) {
|
||||
var registered = false
|
||||
for (attempt in 1..3) {
|
||||
android.util.Log.d("TssRepository", "Registering signing partyId before subscribing: $effectivePartyId (attempt $attempt/3)")
|
||||
val regResult = grpcClient.registerSigningParty(effectivePartyId)
|
||||
if (regResult.isSuccess) {
|
||||
registered = true
|
||||
break
|
||||
}
|
||||
android.util.Log.e("TssRepository", "Failed to register signing partyId (attempt $attempt/3): ${regResult.exceptionOrNull()?.message}")
|
||||
if (attempt < 3) {
|
||||
kotlinx.coroutines.delay(1000L * attempt)
|
||||
}
|
||||
}
|
||||
if (!registered) {
|
||||
throw Exception("无法注册签名方 $effectivePartyId,请检查网络连接后重试")
|
||||
}
|
||||
}
|
||||
|
||||
if (!isActive) {
|
||||
android.util.Log.w("TssRepository", "Session event subscription is not active, restarting...")
|
||||
startSessionEventSubscription(signingPartyId)
|
||||
|
|
@ -1427,6 +1449,7 @@ class TssRepository @Inject constructor(
|
|||
pendingSessionId = null // Clear pending session ID on completion
|
||||
messageCollectionJob?.cancel()
|
||||
currentSigningPartyId = null // Clear after signing completes
|
||||
grpcClient.clearSigningPartyRegistration()
|
||||
|
||||
android.util.Log.d("TssRepository", "Sign as joiner completed: signature=${result.signature.take(20)}...")
|
||||
|
||||
|
|
@ -1438,6 +1461,7 @@ class TssRepository @Inject constructor(
|
|||
_sessionStatus.value = SessionStatus.FAILED
|
||||
pendingSessionId = null // Clear pending session ID on failure
|
||||
currentSigningPartyId = null // Clear on failure too
|
||||
grpcClient.clearSigningPartyRegistration()
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
|
|
@ -1734,6 +1758,7 @@ class TssRepository @Inject constructor(
|
|||
_sessionStatus.value = SessionStatus.COMPLETED
|
||||
messageCollectionJob?.cancel()
|
||||
currentSigningPartyId = null // Clear after signing completes
|
||||
grpcClient.clearSigningPartyRegistration()
|
||||
|
||||
Result.success(result)
|
||||
|
||||
|
|
@ -1741,6 +1766,7 @@ class TssRepository @Inject constructor(
|
|||
android.util.Log.e("TssRepository", "Join sign session failed", e)
|
||||
_sessionStatus.value = SessionStatus.FAILED
|
||||
currentSigningPartyId = null // Clear on failure too
|
||||
grpcClient.clearSigningPartyRegistration()
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
|
|
@ -2764,10 +2790,12 @@ class TssRepository @Inject constructor(
|
|||
_sessionStatus.value = SessionStatus.COMPLETED
|
||||
messageCollectionJob?.cancel()
|
||||
currentSigningPartyId = null // Clear after signing completes
|
||||
grpcClient.clearSigningPartyRegistration()
|
||||
|
||||
Result.success(result)
|
||||
} catch (e: Exception) {
|
||||
_sessionStatus.value = SessionStatus.FAILED
|
||||
grpcClient.clearSigningPartyRegistration()
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue