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
|
||||
}
|
||||
|
||||
// Delegate to the common execution logic
|
||||
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)
|
||||
// 2. Get share data - either from user input (delegate) or from database (persistent)
|
||||
var shareData []byte
|
||||
var keyShareForUpdate *entities.PartyKeyShare
|
||||
var originalThresholdN int // Original total parties from keygen
|
||||
var err error
|
||||
|
||||
// Persistent party: load from database
|
||||
// If KeygenSessionID is provided, use it to load the specific share
|
||||
// Otherwise, use the most recent share (fallback for backward compatibility)
|
||||
if sessionInfo.KeygenSessionID != uuid.Nil {
|
||||
// Load the specific share for this keygen session
|
||||
keyShareForUpdate, err = uc.keyShareRepo.FindBySessionAndParty(ctx, sessionInfo.KeygenSessionID, partyID)
|
||||
if len(input.UserShareData) > 0 {
|
||||
// Delegate party: use share provided by user
|
||||
shareData, err = uc.cryptoService.DecryptShare(input.UserShareData, input.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
|
||||
return nil, err
|
||||
}
|
||||
logger.Info("Using specific keyshare by keygen_session_id",
|
||||
zap.String("party_id", partyID),
|
||||
zap.String("keygen_session_id", sessionInfo.KeygenSessionID.String()))
|
||||
// For delegate party, get threshold info from session
|
||||
originalThresholdN = sessionInfo.ThresholdN
|
||||
logger.Info("Using user-provided share (delegate party)",
|
||||
zap.String("party_id", input.PartyID),
|
||||
zap.String("session_id", input.SessionID.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, partyID)
|
||||
if err != nil || len(keyShares) == 0 {
|
||||
return nil, ErrKeyShareNotFound
|
||||
// Persistent party: load from database
|
||||
// If KeygenSessionID is provided, use it to load the specific share
|
||||
// Otherwise, use the most recent share (fallback for backward compatibility)
|
||||
if sessionInfo.KeygenSessionID != uuid.Nil {
|
||||
// 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
|
||||
originalThresholdN = keyShareForUpdate.ThresholdN
|
||||
// Get original threshold_n from keygen
|
||||
originalThresholdN = keyShareForUpdate.ThresholdN
|
||||
|
||||
// Decrypt share data
|
||||
shareData, err = uc.cryptoService.DecryptShare(keyShareForUpdate.ShareData, partyID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// Decrypt share data
|
||||
shareData, err = uc.cryptoService.DecryptShare(keyShareForUpdate.ShareData, input.PartyID)
|
||||
if err != nil {
|
||||
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
|
||||
var selfIndex int
|
||||
partyIndexMap := make(map[string]int)
|
||||
for _, p := range sessionInfo.Participants {
|
||||
partyIndexMap[p.PartyID] = p.PartyIndex
|
||||
if p.PartyID == partyID {
|
||||
if p.PartyID == input.PartyID {
|
||||
selfIndex = p.PartyIndex
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -185,19 +185,22 @@ func (uc *ParticipateSigningUseCase) executeWithSessionInfo(
|
|||
// before others have subscribed to the session
|
||||
expectedParties := len(sessionInfo.Participants)
|
||||
logger.Info("Waiting for all parties to subscribe",
|
||||
zap.String("session_id", sessionID.String()),
|
||||
zap.String("party_id", partyID),
|
||||
zap.String("session_id", input.SessionID.String()),
|
||||
zap.String("party_id", input.PartyID),
|
||||
zap.Int("expected_parties", expectedParties))
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
|
||||
// Use message hash from session
|
||||
messageHash := sessionInfo.MessageHash
|
||||
// Use message hash from session if not provided
|
||||
messageHash := input.MessageHash
|
||||
if len(messageHash) == 0 {
|
||||
messageHash = sessionInfo.MessageHash
|
||||
}
|
||||
|
||||
// 6. Run TSS Signing protocol
|
||||
signature, r, s, err := uc.runSigningProtocol(
|
||||
ctx,
|
||||
sessionID,
|
||||
partyID,
|
||||
input.SessionID,
|
||||
input.PartyID,
|
||||
selfIndex,
|
||||
sessionInfo.Participants,
|
||||
sessionInfo.ThresholdT,
|
||||
|
|
@ -220,6 +223,123 @@ func (uc *ParticipateSigningUseCase) executeWithSessionInfo(
|
|||
}
|
||||
|
||||
// 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 {
|
||||
logger.Error("failed to report signing completion", zap.Error(err))
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue