diff --git a/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/presentation/viewmodel/MainViewModel.kt b/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/presentation/viewmodel/MainViewModel.kt index cdd7fbf3..c1abe192 100644 --- a/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/presentation/viewmodel/MainViewModel.kt +++ b/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/presentation/viewmodel/MainViewModel.kt @@ -373,51 +373,55 @@ class MainViewModel @Inject constructor( } } "party_joined", "participant_joined" -> { - android.util.Log.d("MainViewModel", "Processing participant_joined event...") + /** + * 【架构安全修复 - 防止参与者计数竞态条件】 + * + * 原问题:使用 current.size + 1 递增计数器存在多个风险 + * 1. 事件重放:重连后事件可能重复发送,导致参与者重复添加 + * 2. 事件乱序:网络延迟可能导致事件乱序到达,参与者编号错乱 + * 3. 状态不一致:本地计数与服务端真实参与者列表不同步 + * + * 修复方案:使用事件的 selectedParties 字段构建权威的参与者列表 + * - selectedParties 来自服务端,是参与者的唯一真实来源 + * - 根据 selectedParties.size 构建参与者列表,确保与服务端一致 + * - 防止重复添加和计数错乱 + */ + android.util.Log.d("MainViewModel", "Processing participant_joined event (selectedParties=${event.selectedParties.size})...") + + // Build participant list from authoritative server data + val participantCount = event.selectedParties.size + val participantList = List(participantCount) { index -> "参与方 ${index + 1}" } + android.util.Log.d("MainViewModel", " → Building participant list from server data: $participantList") // Update participant count for initiator's CreateWallet screen val currentSessionId = _currentSessionId.value android.util.Log.d("MainViewModel", " Checking for initiator: currentSessionId=$currentSessionId, eventSessionId=${event.sessionId}") if (currentSessionId != null && event.sessionId == currentSessionId) { - android.util.Log.d("MainViewModel", " → Matched initiator session! Updating _sessionParticipants") - _sessionParticipants.update { current -> - val newParticipant = "参与方 ${current.size + 1}" - android.util.Log.d("MainViewModel", " → Adding participant: $newParticipant, total now: ${current.size + 1}") - current + newParticipant - } + android.util.Log.d("MainViewModel", " → Matched initiator session! Updating _sessionParticipants to: $participantList") + _sessionParticipants.value = participantList } // Update participant count for keygen joiner's JoinKeygen screen val joinKeygenInfo = pendingJoinKeygenInfo android.util.Log.d("MainViewModel", " Checking for joiner: joinKeygenInfo?.sessionId=${joinKeygenInfo?.sessionId}") if (joinKeygenInfo != null && event.sessionId == joinKeygenInfo.sessionId) { - android.util.Log.d("MainViewModel", " → Matched joiner session! Updating _joinKeygenParticipants") - _joinKeygenParticipants.update { current -> - val newParticipant = "参与方 ${current.size + 1}" - current + newParticipant - } + android.util.Log.d("MainViewModel", " → Matched joiner session! Updating _joinKeygenParticipants to: $participantList") + _joinKeygenParticipants.value = participantList } // Update participant count for sign joiner's CoSign screen val joinSignInfo = pendingJoinSignInfo if (joinSignInfo != null && event.sessionId == joinSignInfo.sessionId) { - android.util.Log.d("MainViewModel", " → Matched sign joiner session! Updating _coSignParticipants") - _coSignParticipants.update { current -> - val newParticipant = "参与方 ${current.size + 1}" - current + newParticipant - } + android.util.Log.d("MainViewModel", " → Matched sign joiner session! Updating _coSignParticipants to: $participantList") + _coSignParticipants.value = participantList } // Update participant count for sign initiator's TransferScreen (SigningScreen) val signSessionId = _signSessionId.value android.util.Log.d("MainViewModel", " Checking for sign initiator: signSessionId=$signSessionId, eventSessionId=${event.sessionId}") if (signSessionId != null && event.sessionId == signSessionId) { - android.util.Log.d("MainViewModel", " → Matched sign initiator session! Updating _signParticipants") - _signParticipants.update { current -> - val newParticipant = "参与方 ${current.size + 1}" - android.util.Log.d("MainViewModel", " → Adding participant: $newParticipant, total now: ${current.size + 1}") - current + newParticipant - } + android.util.Log.d("MainViewModel", " → Matched sign initiator session! Updating _signParticipants to: $participantList") + _signParticipants.value = participantList } } "all_joined" -> {