fix(session-coordinator): 支持 co_managed_keygen 动态参与者加入
问题: 通过邀请码加入共管钱包会话时报 "party not invited" 错误 原因: 外部参与者不在 party pool 中,CreateSession 时无法预先选择 修复: - join_session.go: 对于 co_managed_keygen + wildcard token,允许动态添加参与者 - create_session.go: 新增 selectPartiesByCompositionForCoManaged,跳过 TemporaryCount 选择 - report_completion.go: 使用 IsKeygen() 方法,co_managed_keygen 完成后也创建账户记录 注意: 所有修改仅对 co_managed_keygen 类型生效,不影响现有 keygen/sign 流程 🤖 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
af08f0f9c6
commit
a5ab2e8350
|
|
@ -160,8 +160,14 @@ func (uc *CreateSessionUseCase) Execute(
|
||||||
|
|
||||||
// Check if party composition is specified
|
// Check if party composition is specified
|
||||||
if req.PartyComposition != nil {
|
if req.PartyComposition != nil {
|
||||||
// Select parties based on composition requirements
|
// For co_managed_keygen, TemporaryCount represents external participants
|
||||||
selectedParties, err = uc.selectPartiesByComposition(req.PartyComposition)
|
// who will join dynamically via invite code - don't select from pool
|
||||||
|
if sessionType == entities.SessionTypeCoManagedKeygen {
|
||||||
|
selectedParties, err = uc.selectPartiesByCompositionForCoManaged(req.PartyComposition)
|
||||||
|
} else {
|
||||||
|
// Select parties based on composition requirements
|
||||||
|
selectedParties, err = uc.selectPartiesByComposition(req.PartyComposition)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warn("failed to select parties by composition, falling back to simple selection",
|
logger.Warn("failed to select parties by composition, falling back to simple selection",
|
||||||
zap.Error(err))
|
zap.Error(err))
|
||||||
|
|
@ -359,6 +365,62 @@ func (uc *CreateSessionUseCase) Execute(
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// selectPartiesByCompositionForCoManaged selects parties for co_managed_keygen sessions
|
||||||
|
// For co_managed_keygen, TemporaryCount represents external participants who will join
|
||||||
|
// dynamically via invite code - we don't select them from pool, only select persistent parties
|
||||||
|
func (uc *CreateSessionUseCase) selectPartiesByCompositionForCoManaged(composition *input.PartyComposition) ([]output.PartyEndpoint, error) {
|
||||||
|
if uc.partyPool == nil {
|
||||||
|
return nil, fmt.Errorf("party pool not configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
var allSelected []output.PartyEndpoint
|
||||||
|
|
||||||
|
// Select persistent parties (server-side parties)
|
||||||
|
if composition.PersistentCount > 0 {
|
||||||
|
persistent, err := uc.partyPool.SelectPartiesWithFilter(output.PartySelectionFilter{
|
||||||
|
Count: composition.PersistentCount,
|
||||||
|
Role: output.PartyRolePersistent,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to select persistent parties: %w", err)
|
||||||
|
}
|
||||||
|
allSelected = append(allSelected, persistent...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select delegate parties if any
|
||||||
|
if composition.DelegateCount > 0 {
|
||||||
|
delegate, err := uc.partyPool.SelectPartiesWithFilter(output.PartySelectionFilter{
|
||||||
|
Count: composition.DelegateCount,
|
||||||
|
Role: output.PartyRoleDelegate,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to select delegate parties: %w", err)
|
||||||
|
}
|
||||||
|
allSelected = append(allSelected, delegate...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: TemporaryCount is intentionally NOT selected from pool for co_managed_keygen
|
||||||
|
// External participants will join dynamically via invite code with wildcard token
|
||||||
|
if composition.TemporaryCount > 0 {
|
||||||
|
logger.Info("co_managed_keygen: TemporaryCount represents external participants, not selecting from pool",
|
||||||
|
zap.Int("temporary_count", composition.TemporaryCount),
|
||||||
|
zap.Int("persistent_selected", len(allSelected)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply custom filters if provided
|
||||||
|
for _, filter := range composition.CustomFilters {
|
||||||
|
customParties, err := uc.partyPool.SelectPartiesWithFilter(filter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to select parties with custom filter: %w", err)
|
||||||
|
}
|
||||||
|
allSelected = append(allSelected, customParties...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// For co_managed_keygen, it's OK to have no selected parties if all are external
|
||||||
|
// The session will use wildcard tokens for all participants
|
||||||
|
return allSelected, nil
|
||||||
|
}
|
||||||
|
|
||||||
// selectPartiesByComposition selects parties based on composition requirements
|
// selectPartiesByComposition selects parties based on composition requirements
|
||||||
func (uc *CreateSessionUseCase) selectPartiesByComposition(composition *input.PartyComposition) ([]output.PartyEndpoint, error) {
|
func (uc *CreateSessionUseCase) selectPartiesByComposition(composition *input.PartyComposition) ([]output.PartyEndpoint, error) {
|
||||||
if uc.partyPool == nil {
|
if uc.partyPool == nil {
|
||||||
|
|
|
||||||
|
|
@ -81,14 +81,55 @@ func (uc *JoinSessionUseCase) Execute(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Get participant (must already exist from CreateSession)
|
// 5. Get participant (must already exist from CreateSession)
|
||||||
|
// For co_managed_keygen with wildcard token, allow dynamic participant addition
|
||||||
participant, err := session.GetParticipant(partyID)
|
participant, err := session.GetParticipant(partyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Participant doesn't exist - this party was not invited to this session
|
// Check if this is a co_managed_keygen session with wildcard token
|
||||||
logger.Warn("party not found in session participants",
|
// Wildcard tokens allow any party to join dynamically
|
||||||
zap.String("session_id", session.ID.String()),
|
if session.SessionType == entities.SessionTypeCoManagedKeygen && claims.PartyID == "*" {
|
||||||
zap.String("party_id", inputData.PartyID),
|
// Dynamic participant addition for co_managed_keygen
|
||||||
zap.Int("existing_participant_count", len(session.Participants)))
|
if len(session.Participants) >= session.Threshold.N() {
|
||||||
return nil, entities.ErrPartyNotInvited
|
logger.Warn("session is full, cannot add more participants",
|
||||||
|
zap.String("session_id", session.ID.String()),
|
||||||
|
zap.String("party_id", inputData.PartyID),
|
||||||
|
zap.Int("current_participants", len(session.Participants)),
|
||||||
|
zap.Int("threshold_n", session.Threshold.N()))
|
||||||
|
return nil, entities.ErrSessionFull
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new participant with the next available index
|
||||||
|
newIndex := len(session.Participants)
|
||||||
|
participant, err = entities.NewParticipant(partyID, newIndex, inputData.DeviceInfo)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("failed to create new participant",
|
||||||
|
zap.String("session_id", session.ID.String()),
|
||||||
|
zap.String("party_id", inputData.PartyID),
|
||||||
|
zap.Error(err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add participant to session
|
||||||
|
if err := session.AddParticipant(participant); err != nil {
|
||||||
|
logger.Error("failed to add participant to session",
|
||||||
|
zap.String("session_id", session.ID.String()),
|
||||||
|
zap.String("party_id", inputData.PartyID),
|
||||||
|
zap.Error(err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("dynamically added participant to co_managed_keygen session",
|
||||||
|
zap.String("session_id", session.ID.String()),
|
||||||
|
zap.String("party_id", inputData.PartyID),
|
||||||
|
zap.Int("party_index", newIndex),
|
||||||
|
zap.Int("total_participants", len(session.Participants)))
|
||||||
|
} else {
|
||||||
|
// Participant doesn't exist - this party was not invited to this session
|
||||||
|
logger.Warn("party not found in session participants",
|
||||||
|
zap.String("session_id", session.ID.String()),
|
||||||
|
zap.String("party_id", inputData.PartyID),
|
||||||
|
zap.Int("existing_participant_count", len(session.Participants)))
|
||||||
|
return nil, entities.ErrPartyNotInvited
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Debug("participant found in session",
|
logger.Debug("participant found in session",
|
||||||
|
|
|
||||||
|
|
@ -191,8 +191,8 @@ func (uc *ReportCompletionUseCase) executeWithRetry(
|
||||||
zap.Error(err))
|
zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// For keygen sessions, automatically create account record
|
// For keygen sessions (including co_managed_keygen), automatically create account record
|
||||||
if session.SessionType == entities.SessionTypeKeygen && uc.accountService != nil {
|
if session.SessionType.IsKeygen() && uc.accountService != nil {
|
||||||
uc.createAccountFromKeygen(ctx, session)
|
uc.createAccountFromKeygen(ctx, session)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue