fix(sign): fetch partyIndex from Account Service instead of local storage

- Query keygen session status to get correct party_index for signing
- Keep original design: don't save partyIndex locally during keygen
- Add parties to createSignSession response
- Make partyIndex optional in database type definitions
- Transfer.tsx: use signParties from createSignSession response

🤖 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 2025-12-30 07:31:35 -08:00
parent 454e596d40
commit b79289bc29
4 changed files with 38 additions and 23 deletions

View File

@ -574,17 +574,18 @@ func (h *CoManagedHTTPHandler) CreateSignSession(c *gin.Context) {
zap.Int("num_parties", len(resp.SelectedParties)))
c.JSON(http.StatusCreated, gin.H{
"session_id": resp.SessionID,
"keygen_session_id": req.KeygenSessionID,
"wallet_name": req.WalletName,
"invite_code": inviteCode,
"join_token": wildcardToken,
"threshold_t": req.ThresholdT,
"selected_parties": resp.SelectedParties,
"status": "waiting_for_participants",
"current_participants": 0,
"session_id": resp.SessionID,
"keygen_session_id": req.KeygenSessionID,
"wallet_name": req.WalletName,
"invite_code": inviteCode,
"join_token": wildcardToken,
"threshold_t": req.ThresholdT,
"parties": req.Parties, // 返回完整的 parties (包含 party_id 和 party_index)
"selected_parties": resp.SelectedParties,
"status": "waiting_for_participants",
"current_participants": 0,
"required_participants": len(req.Parties),
"expires_at": resp.ExpiresAt,
"expires_at": resp.ExpiresAt,
})
}

View File

@ -564,10 +564,10 @@ async function handleKeygenComplete(result: KeygenResult) {
try {
// 1. 保存 share 到本地数据库
const publicKeyHex = result.publicKey.toString('hex');
// 转换 participants 格式:保存 partyId, partyIndex, name
// 转换 participants 格式:从 { partyId, partyIndex, name } 到 { partyId, name }
// 注意partyIndex 不保存到本地,签名时需要从 Account Service 获取
const participantsForSave = activeKeygenSession.participants.map(p => ({
partyId: p.partyId,
partyIndex: p.partyIndex,
name: p.name,
}));
const saved = database.saveShare({
@ -1219,11 +1219,16 @@ function setupIpcHandlers() {
return { success: false, error: 'Share not found or incorrect password' };
}
// 解析 participants_json 获取参与方列表
const participants = JSON.parse(share.participants_json || '[]');
const parties = participants.map((p: { partyId: string; partyIndex?: number }, index: number) => ({
party_id: p.partyId,
party_index: p.partyIndex ?? index, // 优先使用保存的 partyIndex否则使用数组索引
// 从 Account Service 查询 keygen session 获取正确的 participants包含 party_index
const sessionStatus = await accountClient?.getSessionStatus(share.session_id);
if (!sessionStatus?.participants || sessionStatus.participants.length === 0) {
return { success: false, error: 'Failed to get participants from keygen session' };
}
// 使用后端返回的 participants包含正确的 party_index
const parties = sessionStatus.participants.map(p => ({
party_id: p.party_id,
party_index: p.party_index,
}));
const result = await accountClient?.createSignSession({
@ -1241,6 +1246,7 @@ function setupIpcHandlers() {
inviteCode: result?.invite_code,
expiresAt: result?.expires_at,
joinToken: result?.join_token,
parties: result?.parties, // 包含正确的 party_id 和 party_index
};
} catch (error) {
return { success: false, error: (error as Error).message };

View File

@ -339,7 +339,7 @@ export class DatabaseManager {
thresholdN: number;
publicKeyHex: string;
rawShare: string;
participants: Array<{ partyId: string; name: string }>;
participants: Array<{ partyId: string; partyIndex?: number; name: string }>;
}, password: string): ShareRecord {
if (!this.db) throw new Error('Database not initialized');

View File

@ -60,6 +60,7 @@ export default function Transfer() {
// 签名会话
const [inviteCode, setInviteCode] = useState('');
const [signSessionId, setSignSessionId] = useState('');
const [signParties, setSignParties] = useState<Array<{ party_id: string; party_index: number }>>([]);
// 错误信息
const [error, setError] = useState('');
@ -215,6 +216,7 @@ export default function Transfer() {
setInviteCode(result.inviteCode || '');
setSignSessionId(result.sessionId || '');
setSignParties(result.parties || []);
setTxHash(messageHash);
// 显示邀请码,等待用户通知其他参与方
@ -231,11 +233,17 @@ export default function Transfer() {
if (!txParams || !share || !txHash || !signSessionId) return;
try {
// 构建 participants 列表
const participants = (share.participants || []).map((p, index) => ({
partyId: p.partyId,
partyIndex: p.partyIndex ?? index, // 优先使用保存的 partyIndex
}));
// 使用创建签名会话时返回的 parties包含正确的 party_index
// 如果没有,则 fallback 到本地 share 的 participants
const participants = signParties.length > 0
? signParties.map(p => ({
partyId: p.party_id,
partyIndex: p.party_index,
}))
: (share.participants || []).map((p, index) => ({
partyId: p.partyId,
partyIndex: p.partyIndex ?? index,
}));
// 执行 TSS 签名
if (window.electronAPI) {