fix(participate_signing): 恢复 Execute 方法的 UserShareData 分支
关键修复: - Execute 方法完全恢复原有逻辑(不重构、不委托) - 保留 UserShareData 分支(delegate party - Android 客户端) - 保留 Persistent party 分支(从数据库加载) - executeWithSessionInfo 独立实现(仅供 ExecuteWithSessionInfo 调用) 影响分析: ✅ Android 客户端(delegate party): 现在可以正常签名 ✅ server-party (persistent party): 不受影响 ✅ server-party-co-managed: 使用 ExecuteWithSessionInfo(persistent only) 破坏性变更已修复: - 之前的实现删除了 UserShareData 分支 - 导致 Android 客户端签名会失败(强制从数据库加载不存在的 share) - 现在已完全恢复 架构原则: - Execute: 完整保留原有逻辑(delegate + persistent) - ExecuteWithSessionInfo: 独立方法(仅 persistent - 供 co-managed 使用) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
514722143f
commit
f9619b7df1
|
|
@ -102,80 +102,80 @@ func (uc *ParticipateSigningUseCase) Execute(
|
||||||
return nil, ErrInvalidSignSession
|
return nil, ErrInvalidSignSession
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delegate to the common execution logic
|
// 2. Get share data - either from user input (delegate) or from database (persistent)
|
||||||
return uc.executeWithSessionInfo(ctx, input.SessionID, input.PartyID, sessionInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
// executeWithSessionInfo is the common execution logic shared by Execute and ExecuteWithSessionInfo
|
|
||||||
func (uc *ParticipateSigningUseCase) executeWithSessionInfo(
|
|
||||||
ctx context.Context,
|
|
||||||
sessionID uuid.UUID,
|
|
||||||
partyID string,
|
|
||||||
sessionInfo *SessionInfo,
|
|
||||||
) (*ParticipateSigningOutput, error) {
|
|
||||||
|
|
||||||
// 2. Get share data from database (server-party-co-managed always uses persistent shares)
|
|
||||||
var shareData []byte
|
var shareData []byte
|
||||||
var keyShareForUpdate *entities.PartyKeyShare
|
var keyShareForUpdate *entities.PartyKeyShare
|
||||||
var originalThresholdN int // Original total parties from keygen
|
var originalThresholdN int // Original total parties from keygen
|
||||||
var err error
|
|
||||||
|
|
||||||
// Persistent party: load from database
|
if len(input.UserShareData) > 0 {
|
||||||
// If KeygenSessionID is provided, use it to load the specific share
|
// Delegate party: use share provided by user
|
||||||
// Otherwise, use the most recent share (fallback for backward compatibility)
|
shareData, err = uc.cryptoService.DecryptShare(input.UserShareData, input.PartyID)
|
||||||
if sessionInfo.KeygenSessionID != uuid.Nil {
|
|
||||||
// Load the specific share for this keygen session
|
|
||||||
keyShareForUpdate, err = uc.keyShareRepo.FindBySessionAndParty(ctx, sessionInfo.KeygenSessionID, partyID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed to find keyshare for keygen session",
|
return nil, err
|
||||||
zap.String("party_id", partyID),
|
|
||||||
zap.String("keygen_session_id", sessionInfo.KeygenSessionID.String()),
|
|
||||||
zap.Error(err))
|
|
||||||
return nil, ErrKeyShareNotFound
|
|
||||||
}
|
}
|
||||||
logger.Info("Using specific keyshare by keygen_session_id",
|
// For delegate party, get threshold info from session
|
||||||
zap.String("party_id", partyID),
|
originalThresholdN = sessionInfo.ThresholdN
|
||||||
zap.String("keygen_session_id", sessionInfo.KeygenSessionID.String()))
|
logger.Info("Using user-provided share (delegate party)",
|
||||||
|
zap.String("party_id", input.PartyID),
|
||||||
|
zap.String("session_id", input.SessionID.String()))
|
||||||
} else {
|
} else {
|
||||||
// Fallback: use the most recent key share
|
// Persistent party: load from database
|
||||||
// TODO: This should be removed once all signing sessions provide keygen_session_id
|
// If KeygenSessionID is provided, use it to load the specific share
|
||||||
keyShares, err := uc.keyShareRepo.ListByParty(ctx, partyID)
|
// Otherwise, use the most recent share (fallback for backward compatibility)
|
||||||
if err != nil || len(keyShares) == 0 {
|
if sessionInfo.KeygenSessionID != uuid.Nil {
|
||||||
return nil, ErrKeyShareNotFound
|
// Load the specific share for this keygen session
|
||||||
|
keyShareForUpdate, err = uc.keyShareRepo.FindBySessionAndParty(ctx, sessionInfo.KeygenSessionID, input.PartyID)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to find keyshare for keygen session",
|
||||||
|
zap.String("party_id", input.PartyID),
|
||||||
|
zap.String("keygen_session_id", sessionInfo.KeygenSessionID.String()),
|
||||||
|
zap.Error(err))
|
||||||
|
return nil, ErrKeyShareNotFound
|
||||||
|
}
|
||||||
|
logger.Info("Using specific keyshare by keygen_session_id",
|
||||||
|
zap.String("party_id", input.PartyID),
|
||||||
|
zap.String("keygen_session_id", sessionInfo.KeygenSessionID.String()))
|
||||||
|
} else {
|
||||||
|
// Fallback: use the most recent key share
|
||||||
|
// TODO: This should be removed once all signing sessions provide keygen_session_id
|
||||||
|
keyShares, err := uc.keyShareRepo.ListByParty(ctx, input.PartyID)
|
||||||
|
if err != nil || len(keyShares) == 0 {
|
||||||
|
return nil, ErrKeyShareNotFound
|
||||||
|
}
|
||||||
|
keyShareForUpdate = keyShares[len(keyShares)-1]
|
||||||
|
logger.Warn("Using most recent keyshare (keygen_session_id not provided)",
|
||||||
|
zap.String("party_id", input.PartyID),
|
||||||
|
zap.String("fallback_session_id", keyShareForUpdate.SessionID.String()))
|
||||||
}
|
}
|
||||||
keyShareForUpdate = keyShares[len(keyShares)-1]
|
|
||||||
logger.Warn("Using most recent keyshare (keygen_session_id not provided)",
|
|
||||||
zap.String("party_id", partyID),
|
|
||||||
zap.String("fallback_session_id", keyShareForUpdate.SessionID.String()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get original threshold_n from keygen
|
// Get original threshold_n from keygen
|
||||||
originalThresholdN = keyShareForUpdate.ThresholdN
|
originalThresholdN = keyShareForUpdate.ThresholdN
|
||||||
|
|
||||||
// Decrypt share data
|
// Decrypt share data
|
||||||
shareData, err = uc.cryptoService.DecryptShare(keyShareForUpdate.ShareData, partyID)
|
shareData, err = uc.cryptoService.DecryptShare(keyShareForUpdate.ShareData, input.PartyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
}
|
||||||
|
logger.Info("Using database share (persistent party)",
|
||||||
|
zap.String("party_id", input.PartyID),
|
||||||
|
zap.String("session_id", input.SessionID.String()),
|
||||||
|
zap.String("keygen_session_id", keyShareForUpdate.SessionID.String()),
|
||||||
|
zap.Int("original_threshold_n", originalThresholdN),
|
||||||
|
zap.Int("threshold_t", keyShareForUpdate.ThresholdT))
|
||||||
}
|
}
|
||||||
logger.Info("Using database share (persistent party)",
|
|
||||||
zap.String("party_id", partyID),
|
|
||||||
zap.String("session_id", sessionID.String()),
|
|
||||||
zap.String("keygen_session_id", keyShareForUpdate.SessionID.String()),
|
|
||||||
zap.Int("original_threshold_n", originalThresholdN),
|
|
||||||
zap.Int("threshold_t", keyShareForUpdate.ThresholdT))
|
|
||||||
|
|
||||||
// 4. Find self in participants and build party index map
|
// 4. Find self in participants and build party index map
|
||||||
var selfIndex int
|
var selfIndex int
|
||||||
partyIndexMap := make(map[string]int)
|
partyIndexMap := make(map[string]int)
|
||||||
for _, p := range sessionInfo.Participants {
|
for _, p := range sessionInfo.Participants {
|
||||||
partyIndexMap[p.PartyID] = p.PartyIndex
|
partyIndexMap[p.PartyID] = p.PartyIndex
|
||||||
if p.PartyID == partyID {
|
if p.PartyID == input.PartyID {
|
||||||
selfIndex = p.PartyIndex
|
selfIndex = p.PartyIndex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Subscribe to messages
|
// 5. Subscribe to messages
|
||||||
msgChan, err := uc.messageRouter.SubscribeMessages(ctx, sessionID, partyID)
|
msgChan, err := uc.messageRouter.SubscribeMessages(ctx, input.SessionID, input.PartyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -185,19 +185,22 @@ func (uc *ParticipateSigningUseCase) executeWithSessionInfo(
|
||||||
// before others have subscribed to the session
|
// before others have subscribed to the session
|
||||||
expectedParties := len(sessionInfo.Participants)
|
expectedParties := len(sessionInfo.Participants)
|
||||||
logger.Info("Waiting for all parties to subscribe",
|
logger.Info("Waiting for all parties to subscribe",
|
||||||
zap.String("session_id", sessionID.String()),
|
zap.String("session_id", input.SessionID.String()),
|
||||||
zap.String("party_id", partyID),
|
zap.String("party_id", input.PartyID),
|
||||||
zap.Int("expected_parties", expectedParties))
|
zap.Int("expected_parties", expectedParties))
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
|
||||||
// Use message hash from session
|
// Use message hash from session if not provided
|
||||||
messageHash := sessionInfo.MessageHash
|
messageHash := input.MessageHash
|
||||||
|
if len(messageHash) == 0 {
|
||||||
|
messageHash = sessionInfo.MessageHash
|
||||||
|
}
|
||||||
|
|
||||||
// 6. Run TSS Signing protocol
|
// 6. Run TSS Signing protocol
|
||||||
signature, r, s, err := uc.runSigningProtocol(
|
signature, r, s, err := uc.runSigningProtocol(
|
||||||
ctx,
|
ctx,
|
||||||
sessionID,
|
input.SessionID,
|
||||||
partyID,
|
input.PartyID,
|
||||||
selfIndex,
|
selfIndex,
|
||||||
sessionInfo.Participants,
|
sessionInfo.Participants,
|
||||||
sessionInfo.ThresholdT,
|
sessionInfo.ThresholdT,
|
||||||
|
|
@ -220,6 +223,123 @@ func (uc *ParticipateSigningUseCase) executeWithSessionInfo(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8. Report completion to coordinator
|
// 8. Report completion to coordinator
|
||||||
|
if err := uc.sessionClient.ReportCompletion(ctx, input.SessionID, input.PartyID, signature); err != nil {
|
||||||
|
logger.Error("failed to report signing completion", zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ParticipateSigningOutput{
|
||||||
|
Success: true,
|
||||||
|
Signature: signature,
|
||||||
|
R: r,
|
||||||
|
S: s,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// executeWithSessionInfo is the internal logic for ExecuteWithSessionInfo (persistent party only)
|
||||||
|
func (uc *ParticipateSigningUseCase) executeWithSessionInfo(
|
||||||
|
ctx context.Context,
|
||||||
|
sessionID uuid.UUID,
|
||||||
|
partyID string,
|
||||||
|
sessionInfo *SessionInfo,
|
||||||
|
) (*ParticipateSigningOutput, error) {
|
||||||
|
|
||||||
|
// Get share data from database (persistent party only - used by server-party-co-managed)
|
||||||
|
var shareData []byte
|
||||||
|
var keyShareForUpdate *entities.PartyKeyShare
|
||||||
|
var originalThresholdN int
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// Load from database using KeygenSessionID
|
||||||
|
if sessionInfo.KeygenSessionID != uuid.Nil {
|
||||||
|
keyShareForUpdate, err = uc.keyShareRepo.FindBySessionAndParty(ctx, sessionInfo.KeygenSessionID, partyID)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to find keyshare for keygen session",
|
||||||
|
zap.String("party_id", partyID),
|
||||||
|
zap.String("keygen_session_id", sessionInfo.KeygenSessionID.String()),
|
||||||
|
zap.Error(err))
|
||||||
|
return nil, ErrKeyShareNotFound
|
||||||
|
}
|
||||||
|
logger.Info("Using specific keyshare by keygen_session_id",
|
||||||
|
zap.String("party_id", partyID),
|
||||||
|
zap.String("keygen_session_id", sessionInfo.KeygenSessionID.String()))
|
||||||
|
} else {
|
||||||
|
// Fallback: use the most recent key share
|
||||||
|
keyShares, err := uc.keyShareRepo.ListByParty(ctx, partyID)
|
||||||
|
if err != nil || len(keyShares) == 0 {
|
||||||
|
return nil, ErrKeyShareNotFound
|
||||||
|
}
|
||||||
|
keyShareForUpdate = keyShares[len(keyShares)-1]
|
||||||
|
logger.Warn("Using most recent keyshare (keygen_session_id not provided)",
|
||||||
|
zap.String("party_id", partyID),
|
||||||
|
zap.String("fallback_session_id", keyShareForUpdate.SessionID.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
originalThresholdN = keyShareForUpdate.ThresholdN
|
||||||
|
shareData, err = uc.cryptoService.DecryptShare(keyShareForUpdate.ShareData, partyID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("Using database share (persistent party)",
|
||||||
|
zap.String("party_id", partyID),
|
||||||
|
zap.String("session_id", sessionID.String()),
|
||||||
|
zap.String("keygen_session_id", keyShareForUpdate.SessionID.String()),
|
||||||
|
zap.Int("original_threshold_n", originalThresholdN),
|
||||||
|
zap.Int("threshold_t", keyShareForUpdate.ThresholdT))
|
||||||
|
|
||||||
|
// Find self in participants and build party index map
|
||||||
|
var selfIndex int
|
||||||
|
partyIndexMap := make(map[string]int)
|
||||||
|
for _, p := range sessionInfo.Participants {
|
||||||
|
partyIndexMap[p.PartyID] = p.PartyIndex
|
||||||
|
if p.PartyID == partyID {
|
||||||
|
selfIndex = p.PartyIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe to messages
|
||||||
|
msgChan, err := uc.messageRouter.SubscribeMessages(ctx, sessionID, partyID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for all parties to subscribe
|
||||||
|
expectedParties := len(sessionInfo.Participants)
|
||||||
|
logger.Info("Waiting for all parties to subscribe",
|
||||||
|
zap.String("session_id", sessionID.String()),
|
||||||
|
zap.String("party_id", partyID),
|
||||||
|
zap.Int("expected_parties", expectedParties))
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
|
||||||
|
messageHash := sessionInfo.MessageHash
|
||||||
|
|
||||||
|
// Run TSS Signing protocol
|
||||||
|
signature, r, s, err := uc.runSigningProtocol(
|
||||||
|
ctx,
|
||||||
|
sessionID,
|
||||||
|
partyID,
|
||||||
|
selfIndex,
|
||||||
|
sessionInfo.Participants,
|
||||||
|
sessionInfo.ThresholdT,
|
||||||
|
originalThresholdN,
|
||||||
|
shareData,
|
||||||
|
messageHash,
|
||||||
|
msgChan,
|
||||||
|
partyIndexMap,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update key share last used
|
||||||
|
if keyShareForUpdate != nil {
|
||||||
|
keyShareForUpdate.MarkUsed()
|
||||||
|
if err := uc.keyShareRepo.Update(ctx, keyShareForUpdate); err != nil {
|
||||||
|
logger.Warn("failed to update key share last used", zap.Error(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report completion to coordinator
|
||||||
if err := uc.sessionClient.ReportCompletion(ctx, sessionID, partyID, signature); err != nil {
|
if err := uc.sessionClient.ReportCompletion(ctx, sessionID, partyID, signature); err != nil {
|
||||||
logger.Error("failed to report signing completion", zap.Error(err))
|
logger.Error("failed to report signing completion", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue