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:
parent
454e596d40
commit
b79289bc29
|
|
@ -574,17 +574,18 @@ func (h *CoManagedHTTPHandler) CreateSignSession(c *gin.Context) {
|
||||||
zap.Int("num_parties", len(resp.SelectedParties)))
|
zap.Int("num_parties", len(resp.SelectedParties)))
|
||||||
|
|
||||||
c.JSON(http.StatusCreated, gin.H{
|
c.JSON(http.StatusCreated, gin.H{
|
||||||
"session_id": resp.SessionID,
|
"session_id": resp.SessionID,
|
||||||
"keygen_session_id": req.KeygenSessionID,
|
"keygen_session_id": req.KeygenSessionID,
|
||||||
"wallet_name": req.WalletName,
|
"wallet_name": req.WalletName,
|
||||||
"invite_code": inviteCode,
|
"invite_code": inviteCode,
|
||||||
"join_token": wildcardToken,
|
"join_token": wildcardToken,
|
||||||
"threshold_t": req.ThresholdT,
|
"threshold_t": req.ThresholdT,
|
||||||
"selected_parties": resp.SelectedParties,
|
"parties": req.Parties, // 返回完整的 parties (包含 party_id 和 party_index)
|
||||||
"status": "waiting_for_participants",
|
"selected_parties": resp.SelectedParties,
|
||||||
"current_participants": 0,
|
"status": "waiting_for_participants",
|
||||||
|
"current_participants": 0,
|
||||||
"required_participants": len(req.Parties),
|
"required_participants": len(req.Parties),
|
||||||
"expires_at": resp.ExpiresAt,
|
"expires_at": resp.ExpiresAt,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -564,10 +564,10 @@ async function handleKeygenComplete(result: KeygenResult) {
|
||||||
try {
|
try {
|
||||||
// 1. 保存 share 到本地数据库
|
// 1. 保存 share 到本地数据库
|
||||||
const publicKeyHex = result.publicKey.toString('hex');
|
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 => ({
|
const participantsForSave = activeKeygenSession.participants.map(p => ({
|
||||||
partyId: p.partyId,
|
partyId: p.partyId,
|
||||||
partyIndex: p.partyIndex,
|
|
||||||
name: p.name,
|
name: p.name,
|
||||||
}));
|
}));
|
||||||
const saved = database.saveShare({
|
const saved = database.saveShare({
|
||||||
|
|
@ -1219,11 +1219,16 @@ function setupIpcHandlers() {
|
||||||
return { success: false, error: 'Share not found or incorrect password' };
|
return { success: false, error: 'Share not found or incorrect password' };
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析 participants_json 获取参与方列表
|
// 从 Account Service 查询 keygen session 获取正确的 participants(包含 party_index)
|
||||||
const participants = JSON.parse(share.participants_json || '[]');
|
const sessionStatus = await accountClient?.getSessionStatus(share.session_id);
|
||||||
const parties = participants.map((p: { partyId: string; partyIndex?: number }, index: number) => ({
|
if (!sessionStatus?.participants || sessionStatus.participants.length === 0) {
|
||||||
party_id: p.partyId,
|
return { success: false, error: 'Failed to get participants from keygen session' };
|
||||||
party_index: p.partyIndex ?? index, // 优先使用保存的 partyIndex,否则使用数组索引
|
}
|
||||||
|
|
||||||
|
// 使用后端返回的 participants(包含正确的 party_index)
|
||||||
|
const parties = sessionStatus.participants.map(p => ({
|
||||||
|
party_id: p.party_id,
|
||||||
|
party_index: p.party_index,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const result = await accountClient?.createSignSession({
|
const result = await accountClient?.createSignSession({
|
||||||
|
|
@ -1241,6 +1246,7 @@ function setupIpcHandlers() {
|
||||||
inviteCode: result?.invite_code,
|
inviteCode: result?.invite_code,
|
||||||
expiresAt: result?.expires_at,
|
expiresAt: result?.expires_at,
|
||||||
joinToken: result?.join_token,
|
joinToken: result?.join_token,
|
||||||
|
parties: result?.parties, // 包含正确的 party_id 和 party_index
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { success: false, error: (error as Error).message };
|
return { success: false, error: (error as Error).message };
|
||||||
|
|
|
||||||
|
|
@ -339,7 +339,7 @@ export class DatabaseManager {
|
||||||
thresholdN: number;
|
thresholdN: number;
|
||||||
publicKeyHex: string;
|
publicKeyHex: string;
|
||||||
rawShare: string;
|
rawShare: string;
|
||||||
participants: Array<{ partyId: string; name: string }>;
|
participants: Array<{ partyId: string; partyIndex?: number; name: string }>;
|
||||||
}, password: string): ShareRecord {
|
}, password: string): ShareRecord {
|
||||||
if (!this.db) throw new Error('Database not initialized');
|
if (!this.db) throw new Error('Database not initialized');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ export default function Transfer() {
|
||||||
// 签名会话
|
// 签名会话
|
||||||
const [inviteCode, setInviteCode] = useState('');
|
const [inviteCode, setInviteCode] = useState('');
|
||||||
const [signSessionId, setSignSessionId] = useState('');
|
const [signSessionId, setSignSessionId] = useState('');
|
||||||
|
const [signParties, setSignParties] = useState<Array<{ party_id: string; party_index: number }>>([]);
|
||||||
|
|
||||||
// 错误信息
|
// 错误信息
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
|
|
@ -215,6 +216,7 @@ export default function Transfer() {
|
||||||
|
|
||||||
setInviteCode(result.inviteCode || '');
|
setInviteCode(result.inviteCode || '');
|
||||||
setSignSessionId(result.sessionId || '');
|
setSignSessionId(result.sessionId || '');
|
||||||
|
setSignParties(result.parties || []);
|
||||||
setTxHash(messageHash);
|
setTxHash(messageHash);
|
||||||
|
|
||||||
// 显示邀请码,等待用户通知其他参与方
|
// 显示邀请码,等待用户通知其他参与方
|
||||||
|
|
@ -231,11 +233,17 @@ export default function Transfer() {
|
||||||
if (!txParams || !share || !txHash || !signSessionId) return;
|
if (!txParams || !share || !txHash || !signSessionId) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 构建 participants 列表
|
// 使用创建签名会话时返回的 parties(包含正确的 party_index)
|
||||||
const participants = (share.participants || []).map((p, index) => ({
|
// 如果没有,则 fallback 到本地 share 的 participants
|
||||||
partyId: p.partyId,
|
const participants = signParties.length > 0
|
||||||
partyIndex: p.partyIndex ?? index, // 优先使用保存的 partyIndex
|
? signParties.map(p => ({
|
||||||
}));
|
partyId: p.party_id,
|
||||||
|
partyIndex: p.party_index,
|
||||||
|
}))
|
||||||
|
: (share.participants || []).map((p, index) => ({
|
||||||
|
partyId: p.partyId,
|
||||||
|
partyIndex: p.partyIndex ?? index,
|
||||||
|
}));
|
||||||
|
|
||||||
// 执行 TSS 签名
|
// 执行 TSS 签名
|
||||||
if (window.electronAPI) {
|
if (window.electronAPI) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue