fix(service-party-app): checkAndTriggerKeygen 改为轮询等待
问题: - 原来 checkAndTriggerKeygen 只检查一次 - 如果首次检查时会话状态还不是 in_progress,就直接返回 - 导致 external party 永远不触发 keygen 修复: - 改为与 server-party 的 waitForAllParticipants 一致的轮询逻辑 - 2 秒轮询间隔,最多等待 5 分钟 - 持续检查直到所有参与者加入且状态正确 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
dfead071ab
commit
bd6537a2cb
|
|
@ -123,7 +123,8 @@ function cleanExpiredEventCache() {
|
|||
}
|
||||
}
|
||||
|
||||
// 检查并触发 keygen(100% 可靠方案:不依赖事件,直接检查状态)
|
||||
// 检查并触发 keygen(100% 可靠方案:轮询等待所有参与者加入)
|
||||
// 与 server-party 的 waitForAllParticipants 逻辑保持一致
|
||||
async function checkAndTriggerKeygen(sessionId: string) {
|
||||
if (!activeKeygenSession || activeKeygenSession.sessionId !== sessionId) {
|
||||
console.log('No matching active keygen session for', sessionId);
|
||||
|
|
@ -136,80 +137,98 @@ async function checkAndTriggerKeygen(sessionId: string) {
|
|||
return;
|
||||
}
|
||||
|
||||
// 从 Account 服务获取最新会话状态
|
||||
try {
|
||||
const status = await accountClient?.getSessionStatus(sessionId);
|
||||
if (!status) {
|
||||
debugLog.warn('main', 'Failed to get session status');
|
||||
const pollIntervalMs = 2000; // 2秒轮询间隔,与 server-party 保持一致
|
||||
const maxWaitMs = 5 * 60 * 1000; // 5分钟超时
|
||||
const startTime = Date.now();
|
||||
|
||||
debugLog.info('main', `Starting to poll session status for ${sessionId}`);
|
||||
|
||||
while (Date.now() - startTime < maxWaitMs) {
|
||||
// 检查会话是否仍然有效
|
||||
if (!activeKeygenSession || activeKeygenSession.sessionId !== sessionId) {
|
||||
debugLog.warn('main', 'Active keygen session changed, stopping poll');
|
||||
return;
|
||||
}
|
||||
|
||||
debugLog.info('main', `Session ${sessionId} status: ${status.status} (${status.completed_parties}/${status.total_parties} parties)`);
|
||||
|
||||
// 对于 co_managed_keygen,必须等待所有 N 个参与者加入后才能开始
|
||||
// 这与 server-party 的 waitForAllParticipants 逻辑一致
|
||||
const expectedN = status.total_parties || activeKeygenSession.threshold.n;
|
||||
const currentParticipants = status.participants?.length || 0;
|
||||
|
||||
if (currentParticipants < expectedN) {
|
||||
debugLog.debug('main', `Waiting for all participants: ${currentParticipants}/${expectedN}`);
|
||||
// 如果 TSS 已经在运行(可能被其他事件触发),停止轮询
|
||||
if (tssHandler?.getIsRunning()) {
|
||||
debugLog.info('main', 'TSS started running, stopping poll');
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果会话已经是 in_progress 或 all_joined,或者参与方已满,触发 keygen
|
||||
// 使用 status 字段判断是否可以开始
|
||||
if (status.status === 'in_progress' ||
|
||||
status.status === 'all_joined' ||
|
||||
status.status === 'waiting_for_keygen') {
|
||||
|
||||
debugLog.info('main', `All ${expectedN} participants joined, triggering keygen...`);
|
||||
|
||||
// 使用后端返回的 participants 信息(包含正确的 party_index)
|
||||
// 这解决了 co_managed_keygen 中 server-party 和 service-party-app 混合的问题
|
||||
if (status.participants && status.participants.length > 0) {
|
||||
const myPartyId = grpcClient?.getPartyId();
|
||||
const updatedParticipants: Array<{ partyId: string; partyIndex: number; name: string }> = [];
|
||||
|
||||
for (const p of status.participants) {
|
||||
// 查找已有的参与者名称
|
||||
const existing = activeKeygenSession.participants.find(ep => ep.partyId === p.party_id);
|
||||
updatedParticipants.push({
|
||||
partyId: p.party_id,
|
||||
partyIndex: p.party_index,
|
||||
name: existing?.name || (p.party_id === myPartyId ? '我' : `参与方 ${p.party_index + 1}`),
|
||||
});
|
||||
}
|
||||
|
||||
// 更新参与者列表
|
||||
activeKeygenSession.participants = updatedParticipants;
|
||||
|
||||
// 更新自己的 partyIndex
|
||||
const myInfo = updatedParticipants.find(p => p.partyId === myPartyId);
|
||||
if (myInfo) {
|
||||
activeKeygenSession.partyIndex = myInfo.partyIndex;
|
||||
}
|
||||
|
||||
debugLog.info('main', `Updated participants from server: ${JSON.stringify(updatedParticipants.map(p => ({
|
||||
partyId: p.partyId.substring(0, 8) + '...',
|
||||
partyIndex: p.partyIndex,
|
||||
})))}`);
|
||||
try {
|
||||
const status = await accountClient?.getSessionStatus(sessionId);
|
||||
if (!status) {
|
||||
debugLog.warn('main', 'Failed to get session status, will retry');
|
||||
await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
|
||||
continue;
|
||||
}
|
||||
|
||||
const selectedParties = activeKeygenSession.participants.map(p => p.partyId);
|
||||
const expectedN = status.total_parties || activeKeygenSession.threshold.n;
|
||||
const currentParticipants = status.participants?.length || 0;
|
||||
|
||||
await handleSessionStart({
|
||||
eventType: 'session_started',
|
||||
sessionId: sessionId,
|
||||
thresholdN: activeKeygenSession.threshold.n,
|
||||
thresholdT: activeKeygenSession.threshold.t,
|
||||
selectedParties: selectedParties,
|
||||
});
|
||||
} else {
|
||||
debugLog.debug('main', `Session not ready yet, status: ${status.status}`);
|
||||
debugLog.debug('main', `Session ${sessionId} status: ${status.status}, participants: ${currentParticipants}/${expectedN}`);
|
||||
|
||||
// 检查是否满足启动条件
|
||||
const hasAllParticipants = currentParticipants >= expectedN;
|
||||
const statusReady = status.status === 'in_progress' ||
|
||||
status.status === 'all_joined' ||
|
||||
status.status === 'waiting_for_keygen';
|
||||
|
||||
if (hasAllParticipants && statusReady) {
|
||||
debugLog.info('main', `All ${expectedN} participants joined (status: ${status.status}), triggering keygen...`);
|
||||
|
||||
// 使用后端返回的 participants 信息(包含正确的 party_index)
|
||||
if (status.participants && status.participants.length > 0) {
|
||||
const myPartyId = grpcClient?.getPartyId();
|
||||
const updatedParticipants: Array<{ partyId: string; partyIndex: number; name: string }> = [];
|
||||
|
||||
for (const p of status.participants) {
|
||||
const existing = activeKeygenSession.participants.find(ep => ep.partyId === p.party_id);
|
||||
updatedParticipants.push({
|
||||
partyId: p.party_id,
|
||||
partyIndex: p.party_index,
|
||||
name: existing?.name || (p.party_id === myPartyId ? '我' : `参与方 ${p.party_index + 1}`),
|
||||
});
|
||||
}
|
||||
|
||||
activeKeygenSession.participants = updatedParticipants;
|
||||
|
||||
const myInfo = updatedParticipants.find(p => p.partyId === myPartyId);
|
||||
if (myInfo) {
|
||||
activeKeygenSession.partyIndex = myInfo.partyIndex;
|
||||
}
|
||||
|
||||
debugLog.info('main', `Updated participants from server: ${JSON.stringify(updatedParticipants.map(p => ({
|
||||
partyId: p.partyId.substring(0, 8) + '...',
|
||||
partyIndex: p.partyIndex,
|
||||
})))}`);
|
||||
}
|
||||
|
||||
const selectedParties = activeKeygenSession.participants.map(p => p.partyId);
|
||||
|
||||
await handleSessionStart({
|
||||
eventType: 'session_started',
|
||||
sessionId: sessionId,
|
||||
thresholdN: activeKeygenSession.threshold.n,
|
||||
thresholdT: activeKeygenSession.threshold.t,
|
||||
selectedParties: selectedParties,
|
||||
});
|
||||
|
||||
return; // 成功触发,退出循环
|
||||
}
|
||||
|
||||
// 等待下次轮询
|
||||
await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
|
||||
|
||||
} catch (error) {
|
||||
debugLog.error('main', `Failed to check session status: ${error}, will retry`);
|
||||
await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
|
||||
}
|
||||
} catch (error) {
|
||||
debugLog.error('main', `Failed to check session status: ${error}`);
|
||||
}
|
||||
|
||||
// 超时
|
||||
debugLog.error('main', `Timeout waiting for all participants to join session ${sessionId}`);
|
||||
}
|
||||
|
||||
// 创建主窗口
|
||||
|
|
|
|||
Loading…
Reference in New Issue