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;
// 从 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) {
const myPartyId = grpcClient?.getPartyId();
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);
updatedParticipants.push({
partyId: partyId,
partyIndex: existingParticipant?.partyIndex ?? (index + 1),
name: partyId === myPartyId ? '我' : (existingParticipant?.name || `参与方 ${index + 1}`),
});
if (existingParticipant) {
// 使用已有的 partyIndex
updatedParticipants.push({
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 排序
updatedParticipants.sort((a, b) => a.partyIndex - b.partyIndex);
@ -1651,15 +1673,17 @@ function setupIpcHandlers() {
if (joinResult?.success) {
// 设置活跃的 Co-Sign 会话信息
// 注意:这里只初始化发起者自己,其他参与者会在 session_started 事件中从 selectedParties 更新
const signParticipants: Array<{ partyId: string; partyIndex: number; name: string }> = [];
// 使用 signingParties 初始化完整的参与者列表(包含正确的 partyIndex
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}`,
}));
// 添加发起方
signParticipants.push({
partyId: partyId,
partyIndex: joinResult.party_index,
name: params.initiatorName || '发起者',
});
console.log('[CO-SIGN] Initiator signParticipants (from signingParties):', signParticipants.map(p => ({
partyId: p.partyId.substring(0, 8),
partyIndex: p.partyIndex,
})));
activeCoSignSession = {
sessionId: result.session_id,
@ -1768,6 +1792,7 @@ function setupIpcHandlers() {
walletName?: string;
messageHash: string;
threshold: { t: number; n: number };
parties?: Array<{ party_id: string; party_index: number }>;
}) => {
try {
const partyId = grpcClient?.getPartyId();
@ -1786,18 +1811,37 @@ function setupIpcHandlers() {
const result = await grpcClient?.joinSession(params.sessionId, partyId, params.joinToken);
if (result?.success) {
// 设置活跃的 Co-Sign 会话
const participants: Array<{ partyId: string; partyIndex: number; name: string }> = result.other_parties?.map((p: { party_id: string; party_index: number }, idx: number) => ({
partyId: p.party_id,
partyIndex: p.party_index,
name: `参与方 ${idx + 1}`,
})) || [];
// 优先使用 params.parties来自 validateInviteCode包含所有预期参与者
// 而不是 result.other_parties只包含已加入的参与者
let participants: Array<{ partyId: string; partyIndex: number; name: string }>;
// 添加自己
participants.push({
partyId: partyId,
partyIndex: result.party_index,
name: '我',
});
if (params.parties && params.parties.length > 0) {
// 使用完整的 parties 列表
participants = params.parties.map(p => ({
partyId: p.party_id,
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 排序
participants.sort((a, b) => a.partyIndex - b.partyIndex);

View File

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

View File

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