## 问题描述 (Problem) 当用户勾选"包含服务器备份"发起2-of-3签名时,Android设备无法开始签名, 导致整个签名流程卡死。日志显示: - 服务器成功参与并发送TSS消息 ✓ - Android收到session_started事件 ✓ - 但Android未执行startSigning() ❌ ## 根本原因 (Root Cause) 典型的竞态条件: 1. Android调用createSignSessionWithOptions() API 2. 服务器立即在session_created阶段JoinSession 3. 两方都加入→session_started事件立即触发(12.383ms) 4. 但Android的result.fold回调还未完成(12.387ms才设置状态) 5. MainViewModel检查pendingSignInitiatorInfo发现为null,签名被跳过 时间窗口仅4ms,但CPU性能差异会导致100%失败率。 ## 解决方案 (Solution) 采用架构级修复,参考server-party-co-managed的PendingSessionCache模式: ### 1. TssRepository层缓存机制 (Lines ~210-223) ```kotlin // 在JoinSession成功后立即缓存签名信息 private data class PendingSignInfo( val sessionId: String, val shareId: Long, val password: String, val messageHash: String ) private var pendingSignInfo: PendingSignInfo? = null private var signingTriggered: Boolean = false ``` ### 2. 事件到达时自动触发 (Lines ~273-320) ```kotlin when (event.eventType) { "session_started" -> { // 检测到缓存的签名信息,自动触发 if (pendingSignInfo != null && !signingTriggered) { signingTriggered = true repositoryScope.launch { startSigning(...) waitForSignature() } } // 仍然通知MainViewModel(作为兜底) sessionEventCallback?.invoke(event) } } ``` ### 3. MainViewModel防重入检查 (MainViewModel.kt ~1488) ```kotlin private fun startSignAsInitiator(selectedParties: List<String>) { // 检查TssRepository是否已触发 if (repository.isSigningTriggered()) { Log.d("MainViewModel", "Signing already triggered, skipping duplicate") return } startSigningProcess(...) } ``` ## 工作流程 (Workflow) ``` createSignSessionWithOptions() ↓ 【改动】缓存pendingSignInfo (before any event) ↓ auto-join session ↓ ════ 4ms竞态窗口 ════ ↓ session_started arrives (12ms) ↓ 【改动】TssRepository检测到缓存,自动触发签名 ✓ ↓ 【改动】设置signingTriggered=true防止重复 ↓ MainViewModel.result.fold完成 (50ms) ↓ 【改动】检测已触发,跳过重复执行 ✓ ↓ 签名成功完成 ``` ## 关键修改点 (Key Changes) ### TssRepository.kt 1. 添加PendingSignInfo缓存和signingTriggered标志(Line ~210-223) 2. createSignSessionWithOptions缓存签名信息(Line ~3950-3965) 3. session_started处理器自动触发签名(Line ~273-320) 4. 导出isSigningTriggered()供ViewModel检查(Line ~399-405) ### MainViewModel.kt 1. startSignAsInitiator添加防重入检查(Line ~1488-1495) ## 向后兼容性 (Backward Compatibility) ✅ 100%向后兼容: - 保留MainViewModel原有逻辑作为fallback - 仅在includeServerBackup=true时设置缓存(其他流程不变) - 添加防重入检查,不会影响正常签名 - 普通2方签名、3方签名等流程完全不受影响 ## 验证日志 (Verification Logs) 修复后将输出: ``` [CO-SIGN-OPTIONS] Cached pendingSignInfo for sessionId=xxx [RACE-FIX] session_started arrived! Auto-triggering signing [RACE-FIX] Calling startSigning from TssRepository... [RACE-FIX] Signing already triggered, skipping duplicate from MainViewModel ``` ## 技术原则 (Technical Principles) ❌ 拒绝延时方案:CPU性能差异导致不可靠 ✅ 采用架构方案:消除竞态条件的根源,不依赖时间假设 ✅ 参考业界模式:server-party-co-managed的PendingSessionCache ✅ 纵深防御:Repository自动触发 + ViewModel兜底 + 防重入检查 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| app | ||
| contracts | ||
| gradle/wrapper | ||
| tsslib | ||
| .gitignore | ||
| IMPLEMENTATION_PLAN.md | ||
| README.md | ||
| build-apk.bat | ||
| build.gradle.kts | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| settings.gradle.kts | ||
README.md
TSS Party Android
Android 版本的 TSS (Threshold Signature Scheme) Party 应用,用于多方共管钱包的密钥生成和签名。
项目结构
service-party-android/
├── app/ # Android 应用模块
│ ├── src/main/
│ │ ├── java/com/durian/tssparty/
│ │ │ ├── data/ # 数据层
│ │ │ │ ├── local/ # 本地存储 (Room, TSS Bridge)
│ │ │ │ ├── remote/ # 远程通信 (gRPC)
│ │ │ │ └── repository/ # 数据仓库
│ │ │ ├── domain/model/ # 领域模型
│ │ │ ├── presentation/ # UI 层
│ │ │ │ ├── screens/ # Compose 屏幕
│ │ │ │ └── viewmodel/ # ViewModels
│ │ │ ├── di/ # Hilt 依赖注入
│ │ │ ├── ui/theme/ # Material Theme
│ │ │ └── util/ # 工具类
│ │ ├── proto/ # gRPC Proto 文件
│ │ └── res/ # Android 资源
│ └── libs/ # TSS 原生库 (.aar)
├── tsslib/ # Go TSS 库源码
│ ├── tsslib.go # gomobile 绑定
│ ├── go.mod
│ ├── build.sh # Linux/macOS 构建脚本
│ └── build.bat # Windows 构建脚本
└── gradle/ # Gradle Wrapper
技术栈
- UI: Jetpack Compose + Material 3
- 架构: MVVM + Repository Pattern
- 依赖注入: Hilt
- 数据库: Room
- 网络: gRPC (protobuf-lite)
- TSS 核心: Go + gomobile (BnB Chain tss-lib v2)
构建步骤
1. 构建 TSS 原生库 (可选,需要 Go 环境)
# 安装 gomobile
go install golang.org/x/mobile/cmd/gomobile@latest
gomobile init
# 构建 Android AAR
cd tsslib
./build.sh # Linux/macOS
# 或
build.bat # Windows
这将在 app/libs/ 生成 tsslib.aar。
注意: 当前版本使用 Kotlin stub 实现,无需编译 Go 库即可构建 APK。 实际运行需要真正的
tsslib.aar。
2. 构建 APK
# Debug 版本
./gradlew assembleDebug
# Release 版本 (需要签名配置)
./gradlew assembleRelease
APK 输出路径: app/build/outputs/apk/debug/app-debug.apk
功能
- 加入 Keygen 会话 - 扫描/输入邀请码,参与多方密钥生成
- 查看钱包 - 显示已创建的共管钱包列表
- 签名交易 - 使用密钥份额参与多方签名
- 设置 - 配置 Message Router 服务器地址
配置
默认服务器配置:
- Message Router:
localhost:50051 - Kava RPC:
https://evm.kava.io
与 Electron 版本的对应关系
| Electron 版本 | Android 版本 |
|---|---|
electron/main.ts |
TssNativeBridge.kt + GrpcClient.kt |
electron/preload.ts |
TssRepository.kt |
src/pages/*.tsx |
presentation/screens/*.kt |
tss-party/ (Go 子进程) |
tsslib/ (gomobile .aar) |
| sql.js | Room Database |
许可证
MIT