fix(mpc-service): 修复 MPC 会话流程,先创建会话再加入
问题:mpc-service 尝试用 identity-service 生成的 SHA256 哈希作为 joinToken 加入会话,但 session-coordinator 期望的是由它自己 CreateSession 接口生成的 JWT token。 修复: - coordinator-client.ts: 添加 createSession() 方法 - participate-keygen.handler.ts: 先创建会话获取 JWT,再加入 - participate-signing.handler.ts: 同上 - rotate-share.handler.ts: 同上(使用 keygen 类型) 流程变更: 1. CreateSession -> 获取 sessionId + JWT joinToken 2. JoinSession 使用 JWT token 加入会话 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
467206fd61
commit
e51edc2ce4
|
|
@ -163,11 +163,31 @@ export class ParticipateInKeygenHandler {
|
||||||
|
|
||||||
private async joinSession(command: ParticipateInKeygenCommand): Promise<SessionInfo> {
|
private async joinSession(command: ParticipateInKeygenCommand): Promise<SessionInfo> {
|
||||||
try {
|
try {
|
||||||
return await this.coordinatorClient.joinSession({
|
// First, create the session via coordinator to get a valid JWT token
|
||||||
sessionId: command.sessionId,
|
// The session-coordinator expects us to create a session first
|
||||||
partyId: command.partyId,
|
this.logger.log('Creating MPC session via coordinator...');
|
||||||
joinToken: command.joinToken,
|
const createResponse = await this.coordinatorClient.createSession({
|
||||||
|
sessionType: 'keygen',
|
||||||
|
thresholdN: 3, // Default 2-of-3 MPC
|
||||||
|
thresholdT: 2,
|
||||||
|
createdBy: command.partyId,
|
||||||
|
expiresIn: 600, // 10 minutes
|
||||||
});
|
});
|
||||||
|
this.logger.log(`Session created: ${createResponse.sessionId}, now joining...`);
|
||||||
|
|
||||||
|
// Now join using the valid JWT token from the coordinator
|
||||||
|
const sessionInfo = await this.coordinatorClient.joinSession({
|
||||||
|
sessionId: createResponse.sessionId,
|
||||||
|
partyId: command.partyId,
|
||||||
|
joinToken: createResponse.joinToken, // Use the JWT from createSession
|
||||||
|
});
|
||||||
|
|
||||||
|
// Return session info with the original session ID for consistency
|
||||||
|
return {
|
||||||
|
...sessionInfo,
|
||||||
|
sessionId: createResponse.sessionId,
|
||||||
|
joinToken: createResponse.joinToken,
|
||||||
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new ApplicationError(
|
throw new ApplicationError(
|
||||||
`Failed to join session: ${error.message}`,
|
`Failed to join session: ${error.message}`,
|
||||||
|
|
|
||||||
|
|
@ -167,11 +167,33 @@ export class ParticipateInSigningHandler {
|
||||||
|
|
||||||
private async joinSession(command: ParticipateInSigningCommand): Promise<SessionInfo> {
|
private async joinSession(command: ParticipateInSigningCommand): Promise<SessionInfo> {
|
||||||
try {
|
try {
|
||||||
return await this.coordinatorClient.joinSession({
|
// First, create the session via coordinator to get a valid JWT token
|
||||||
sessionId: command.sessionId,
|
this.logger.log('Creating MPC signing session via coordinator...');
|
||||||
partyId: command.partyId,
|
const createResponse = await this.coordinatorClient.createSession({
|
||||||
joinToken: command.joinToken,
|
sessionType: 'sign',
|
||||||
|
thresholdN: 3, // Default 2-of-3 MPC
|
||||||
|
thresholdT: 2,
|
||||||
|
createdBy: command.partyId,
|
||||||
|
messageHash: command.messageHash,
|
||||||
|
expiresIn: 300, // 5 minutes for signing
|
||||||
});
|
});
|
||||||
|
this.logger.log(`Signing session created: ${createResponse.sessionId}, now joining...`);
|
||||||
|
|
||||||
|
// Now join using the valid JWT token from the coordinator
|
||||||
|
const sessionInfo = await this.coordinatorClient.joinSession({
|
||||||
|
sessionId: createResponse.sessionId,
|
||||||
|
partyId: command.partyId,
|
||||||
|
joinToken: createResponse.joinToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Return session info with correct IDs and public key from command
|
||||||
|
return {
|
||||||
|
...sessionInfo,
|
||||||
|
sessionId: createResponse.sessionId,
|
||||||
|
joinToken: createResponse.joinToken,
|
||||||
|
publicKey: command.publicKey, // Preserve public key from command
|
||||||
|
messageHash: command.messageHash,
|
||||||
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new ApplicationError(
|
throw new ApplicationError(
|
||||||
`Failed to join signing session: ${error.message}`,
|
`Failed to join signing session: ${error.message}`,
|
||||||
|
|
|
||||||
|
|
@ -174,11 +174,31 @@ export class RotateShareHandler {
|
||||||
|
|
||||||
private async joinSession(command: RotateShareCommand): Promise<SessionInfo> {
|
private async joinSession(command: RotateShareCommand): Promise<SessionInfo> {
|
||||||
try {
|
try {
|
||||||
return await this.coordinatorClient.joinSession({
|
// First, create the session via coordinator to get a valid JWT token
|
||||||
sessionId: command.sessionId,
|
// Key refresh uses 'keygen' session type (coordinator doesn't have 'refresh' type)
|
||||||
partyId: command.partyId,
|
this.logger.log('Creating MPC refresh session via coordinator...');
|
||||||
joinToken: command.joinToken,
|
const createResponse = await this.coordinatorClient.createSession({
|
||||||
|
sessionType: 'keygen', // Use keygen type for key refresh
|
||||||
|
thresholdN: 3,
|
||||||
|
thresholdT: 2,
|
||||||
|
createdBy: command.partyId,
|
||||||
|
expiresIn: 600, // 10 minutes
|
||||||
});
|
});
|
||||||
|
this.logger.log(`Refresh session created: ${createResponse.sessionId}, now joining...`);
|
||||||
|
|
||||||
|
// Now join using the valid JWT token from the coordinator
|
||||||
|
const sessionInfo = await this.coordinatorClient.joinSession({
|
||||||
|
sessionId: createResponse.sessionId,
|
||||||
|
partyId: command.partyId,
|
||||||
|
joinToken: createResponse.joinToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
...sessionInfo,
|
||||||
|
sessionId: createResponse.sessionId,
|
||||||
|
joinToken: createResponse.joinToken,
|
||||||
|
publicKey: command.publicKey,
|
||||||
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new ApplicationError(
|
throw new ApplicationError(
|
||||||
`Failed to join rotation session: ${error.message}`,
|
`Failed to join rotation session: ${error.message}`,
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,32 @@
|
||||||
* MPC Coordinator Client
|
* MPC Coordinator Client
|
||||||
*
|
*
|
||||||
* Client for communicating with the external MPC Session Coordinator.
|
* Client for communicating with the external MPC Session Coordinator.
|
||||||
|
*
|
||||||
|
* Flow:
|
||||||
|
* 1. CreateSession - Creates a new MPC session and returns a JWT joinToken
|
||||||
|
* 2. JoinSession - Parties join using the JWT token
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
|
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import axios, { AxiosInstance, AxiosError } from 'axios';
|
import axios, { AxiosInstance, AxiosError } from 'axios';
|
||||||
|
|
||||||
|
export interface CreateSessionRequest {
|
||||||
|
sessionType: 'keygen' | 'sign';
|
||||||
|
thresholdN: number;
|
||||||
|
thresholdT: number;
|
||||||
|
createdBy: string;
|
||||||
|
messageHash?: string;
|
||||||
|
expiresIn?: number; // seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateSessionResponse {
|
||||||
|
sessionId: string;
|
||||||
|
joinToken: string; // JWT token for joining
|
||||||
|
status: string;
|
||||||
|
expiresAt?: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface JoinSessionRequest {
|
export interface JoinSessionRequest {
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
partyId: string;
|
partyId: string;
|
||||||
|
|
@ -22,6 +42,7 @@ export interface SessionInfo {
|
||||||
participants: Array<{ partyId: string; partyIndex: number }>;
|
participants: Array<{ partyId: string; partyIndex: number }>;
|
||||||
publicKey?: string;
|
publicKey?: string;
|
||||||
messageHash?: string;
|
messageHash?: string;
|
||||||
|
joinToken?: string; // JWT token for this session
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReportCompletionRequest {
|
export interface ReportCompletionRequest {
|
||||||
|
|
@ -89,7 +110,42 @@ export class MPCCoordinatorClient implements OnModuleInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Join an MPC session
|
* Create an MPC session
|
||||||
|
*
|
||||||
|
* This must be called first to get a valid JWT joinToken
|
||||||
|
*/
|
||||||
|
async createSession(request: CreateSessionRequest): Promise<CreateSessionResponse> {
|
||||||
|
this.logger.log(`Creating session: type=${request.sessionType}, ${request.thresholdT}-of-${request.thresholdN}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.client.post('/api/v1/sessions', {
|
||||||
|
sessionType: request.sessionType,
|
||||||
|
thresholdN: request.thresholdN,
|
||||||
|
thresholdT: request.thresholdT,
|
||||||
|
createdBy: request.createdBy,
|
||||||
|
messageHash: request.messageHash,
|
||||||
|
expiresIn: request.expiresIn || 600, // Default 10 minutes
|
||||||
|
});
|
||||||
|
|
||||||
|
this.logger.log(`Session created: ${response.data.sessionId}`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
sessionId: response.data.sessionId,
|
||||||
|
joinToken: response.data.joinToken,
|
||||||
|
status: response.data.status,
|
||||||
|
expiresAt: response.data.expiresAt,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
const message = this.getErrorMessage(error);
|
||||||
|
this.logger.error(`Failed to create session: ${message}`);
|
||||||
|
throw new Error(`Failed to create MPC session: ${message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Join an MPC session using a JWT token
|
||||||
|
*
|
||||||
|
* The joinToken must be obtained from createSession()
|
||||||
*/
|
*/
|
||||||
async joinSession(request: JoinSessionRequest): Promise<SessionInfo> {
|
async joinSession(request: JoinSessionRequest): Promise<SessionInfo> {
|
||||||
this.logger.log(`Joining session: ${request.sessionId}`);
|
this.logger.log(`Joining session: ${request.sessionId}`);
|
||||||
|
|
@ -114,6 +170,7 @@ export class MPCCoordinatorClient implements OnModuleInit {
|
||||||
})) || [],
|
})) || [],
|
||||||
publicKey: undefined,
|
publicKey: undefined,
|
||||||
messageHash: undefined,
|
messageHash: undefined,
|
||||||
|
joinToken: request.joinToken,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = this.getErrorMessage(error);
|
const message = this.getErrorMessage(error);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue