fix(co-sign): pass complete parties list to joinSession

Problem: Participants joining early only got incomplete participant list
from other_parties (only those who had joined), causing partyIndex mismatch.

Solution:
- Add parties field to SessionInfo (from validateInviteCode response)
- Pass parties to joinSession call from frontend
- Backend joinSession uses params.parties (complete list) instead of
  result.other_parties (incomplete list)
- Add debug logging to track participant list state

Now all participants have the complete parties list with correct partyIndex.

🤖 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-31 04:34:48 -08:00
parent 8193549aba
commit e284a46e83
3 changed files with 80 additions and 27 deletions

View File

@ -821,22 +821,44 @@ async function handleCoSignStart(event: {
// 标记签名开始 // 标记签名开始
signInProgressSessionId = event.sessionId; signInProgressSessionId = event.sessionId;
// 从 event.selectedParties 更新参与者列表(类似 keygen 的 handleSessionStart // 打印当前 activeCoSignSession.participants 状态
// 这确保我们使用的是实际加入会话的参与者,而不是预设的列表 console.log('[CO-SIGN] Current activeCoSignSession.participants before update:',
activeCoSignSession.participants.map(p => ({
partyId: p.partyId.substring(0, 8),
partyIndex: p.partyIndex,
}))
);
console.log('[CO-SIGN] event.selectedParties:', event.selectedParties?.map(id => id.substring(0, 8)));
// 从 event.selectedParties 更新参与者列表
// 优先使用 activeCoSignSession.participants 中的 partyIndex来自 signingParties 或 other_parties
if (event.selectedParties && event.selectedParties.length > 0) { if (event.selectedParties && event.selectedParties.length > 0) {
const myPartyId = grpcClient?.getPartyId(); const myPartyId = grpcClient?.getPartyId();
const updatedParticipants: Array<{ partyId: string; partyIndex: number; name: string }> = []; const updatedParticipants: Array<{ partyId: string; partyIndex: number; name: string }> = [];
event.selectedParties.forEach((partyId, index) => { event.selectedParties.forEach((partyId) => {
// 查找已有的参与者信息 // 查找已有的参与者信息
const existingParticipant = activeCoSignSession?.participants.find(p => p.partyId === partyId); const existingParticipant = activeCoSignSession?.participants.find(p => p.partyId === partyId);
updatedParticipants.push({ if (existingParticipant) {
partyId: partyId, // 使用已有的 partyIndex
partyIndex: existingParticipant?.partyIndex ?? (index + 1), updatedParticipants.push({
name: partyId === myPartyId ? '我' : (existingParticipant?.name || `参与方 ${index + 1}`), partyId: partyId,
}); partyIndex: existingParticipant.partyIndex,
name: partyId === myPartyId ? '我' : existingParticipant.name,
});
} else {
// 找不到已有信息,这不应该发生 - 记录警告
console.warn(`[CO-SIGN] WARNING: Party ${partyId.substring(0, 8)} not found in activeCoSignSession.participants!`);
// 不使用 fallback index直接跳过这会导致参与者数量不足签名会失败
// 这样可以更早发现问题
}
}); });
// 检查参与者数量是否符合预期
if (updatedParticipants.length !== event.selectedParties.length) {
console.error(`[CO-SIGN] ERROR: Participant count mismatch! Expected ${event.selectedParties.length}, got ${updatedParticipants.length}`);
}
// 按 partyIndex 排序 // 按 partyIndex 排序
updatedParticipants.sort((a, b) => a.partyIndex - b.partyIndex); updatedParticipants.sort((a, b) => a.partyIndex - b.partyIndex);
@ -1651,15 +1673,17 @@ function setupIpcHandlers() {
if (joinResult?.success) { if (joinResult?.success) {
// 设置活跃的 Co-Sign 会话信息 // 设置活跃的 Co-Sign 会话信息
// 注意:这里只初始化发起者自己,其他参与者会在 session_started 事件中从 selectedParties 更新 // 使用 signingParties 初始化完整的参与者列表(包含正确的 partyIndex
const signParticipants: Array<{ partyId: string; partyIndex: number; name: string }> = []; const signParticipants: Array<{ partyId: string; partyIndex: number; name: string }> = signingParties.map(p => ({
partyId: p.party_id,
partyIndex: p.party_index,
name: p.party_id === partyId ? (params.initiatorName || '发起者') : `参与方 ${p.party_index + 1}`,
}));
// 添加发起方 console.log('[CO-SIGN] Initiator signParticipants (from signingParties):', signParticipants.map(p => ({
signParticipants.push({ partyId: p.partyId.substring(0, 8),
partyId: partyId, partyIndex: p.partyIndex,
partyIndex: joinResult.party_index, })));
name: params.initiatorName || '发起者',
});
activeCoSignSession = { activeCoSignSession = {
sessionId: result.session_id, sessionId: result.session_id,
@ -1768,6 +1792,7 @@ function setupIpcHandlers() {
walletName?: string; walletName?: string;
messageHash: string; messageHash: string;
threshold: { t: number; n: number }; threshold: { t: number; n: number };
parties?: Array<{ party_id: string; party_index: number }>;
}) => { }) => {
try { try {
const partyId = grpcClient?.getPartyId(); const partyId = grpcClient?.getPartyId();
@ -1786,18 +1811,37 @@ function setupIpcHandlers() {
const result = await grpcClient?.joinSession(params.sessionId, partyId, params.joinToken); const result = await grpcClient?.joinSession(params.sessionId, partyId, params.joinToken);
if (result?.success) { if (result?.success) {
// 设置活跃的 Co-Sign 会话 // 设置活跃的 Co-Sign 会话
const participants: Array<{ partyId: string; partyIndex: number; name: string }> = result.other_parties?.map((p: { party_id: string; party_index: number }, idx: number) => ({ // 优先使用 params.parties来自 validateInviteCode包含所有预期参与者
partyId: p.party_id, // 而不是 result.other_parties只包含已加入的参与者
partyIndex: p.party_index, let participants: Array<{ partyId: string; partyIndex: number; name: string }>;
name: `参与方 ${idx + 1}`,
})) || [];
// 添加自己 if (params.parties && params.parties.length > 0) {
participants.push({ // 使用完整的 parties 列表
partyId: partyId, participants = params.parties.map(p => ({
partyIndex: result.party_index, partyId: p.party_id,
name: '我', partyIndex: p.party_index,
}); name: p.party_id === partyId ? '我' : `参与方 ${p.party_index + 1}`,
}));
console.log('[CO-SIGN] Participant using params.parties (complete list):', participants.map(p => ({
partyId: p.partyId.substring(0, 8),
partyIndex: p.partyIndex,
})));
} else {
// Fallback: 使用 other_parties + 自己(可能不完整)
console.warn('[CO-SIGN] WARNING: params.parties not available, using other_parties (may be incomplete)');
participants = result.other_parties?.map((p: { party_id: string; party_index: number }, idx: number) => ({
partyId: p.party_id,
partyIndex: p.party_index,
name: `参与方 ${idx + 1}`,
})) || [];
// 添加自己
participants.push({
partyId: partyId,
partyIndex: result.party_index,
name: '我',
});
}
// 按 partyIndex 排序 // 按 partyIndex 排序
participants.sort((a, b) => a.partyIndex - b.partyIndex); participants.sort((a, b) => a.partyIndex - b.partyIndex);

View File

@ -10,6 +10,11 @@ interface Share {
threshold: { t: number; n: number }; threshold: { t: number; n: number };
} }
interface SignPartyInfo {
party_id: string;
party_index: number;
}
interface SessionInfo { interface SessionInfo {
sessionId: string; sessionId: string;
keygenSessionId: string; keygenSessionId: string;
@ -18,6 +23,7 @@ interface SessionInfo {
threshold: { t: number; n: number }; threshold: { t: number; n: number };
status: string; status: string;
currentParticipants: number; currentParticipants: number;
parties?: SignPartyInfo[];
} }
interface ValidateResult { interface ValidateResult {
@ -202,6 +208,7 @@ export default function CoSignJoin() {
walletName: sessionInfo.walletName, walletName: sessionInfo.walletName,
messageHash: sessionInfo.messageHash, messageHash: sessionInfo.messageHash,
threshold: sessionInfo.threshold, threshold: sessionInfo.threshold,
parties: sessionInfo.parties,
}); });
try { try {
@ -213,6 +220,7 @@ export default function CoSignJoin() {
walletName: sessionInfo.walletName, walletName: sessionInfo.walletName,
messageHash: sessionInfo.messageHash, messageHash: sessionInfo.messageHash,
threshold: sessionInfo.threshold, threshold: sessionInfo.threshold,
parties: sessionInfo.parties,
}); });
console.log('[CoSignJoin] joinSession result:', result); console.log('[CoSignJoin] joinSession result:', result);

View File

@ -456,6 +456,7 @@ interface JoinCoSignSessionParams {
walletName?: string; walletName?: string;
messageHash: string; messageHash: string;
threshold: { t: number; n: number }; threshold: { t: number; n: number };
parties?: Array<{ party_id: string; party_index: number }>;
} }
interface JoinCoSignSessionResult { interface JoinCoSignSessionResult {