package activity import ( "context" "crypto/rand" "crypto/sha256" "encoding/json" "errors" "sort" "bindbox-game/internal/repository/mysql/model" "gorm.io/gorm" ) var algoVersion = "v1-hmac-256" func (s *service) CommitIssueRandom(ctx context.Context, issueID int64) (*IssueRandomCommitment, error) { // 检查活动期数状态 issue, err := s.readDB.ActivityIssues.WithContext(ctx). Where(s.readDB.ActivityIssues.ID.Eq(issueID)). First() if err != nil { if err == gorm.ErrRecordNotFound { return nil, errors.New("活动期数不存在") } return nil, err } // 只允许在未开始状态(3)生成承诺 if issue.Status != 3 { return nil, errors.New("只能在期数未开始状态下生成随机承诺") } // 检查是否已存在承诺(防止重复生成) existing, _ := s.readDB.IssueRandomCommitments.WithContext(ctx). Where(s.readDB.IssueRandomCommitments.IssueID.Eq(issueID)). First() if existing != nil { return nil, errors.New("该期数已存在随机承诺,不可重复生成") } items, err := s.readDB.ActivityRewardSettings.WithContext(ctx). Where(s.readDB.ActivityRewardSettings.IssueID.Eq(issueID)). Order(s.readDB.ActivityRewardSettings.ID). Find() if err != nil { return nil, err } if len(items) == 0 { return nil, errors.New("该期数未配置奖励,无法生成随机承诺") } canonical := make([]ReceiptItem, 0, len(items)) var weightsTotal int64 for _, it := range items { canonical = append(canonical, ReceiptItem{ID: it.ID, Name: it.Name, Weight: it.Weight, QuantityBefore: it.Quantity}) if it.Weight > 0 && (it.Quantity == -1 || it.Quantity > 0) { weightsTotal += int64(it.Weight) } } // 检查奖池权重是否有效 if weightsTotal <= 0 { return nil, errors.New("奖池配置无效:总权重必须大于0") } sort.Slice(canonical, func(i, j int) bool { return canonical[i].ID < canonical[j].ID }) b, _ := json.Marshal(canonical) itemsRoot := sha256.Sum256(b) master := make([]byte, 32) _, _ = rand.Read(master) serverHash := sha256.Sum256(master) nextVer := int32(1) enc, _ := maskSeed(master, issueID, nextVer) rec := &model.IssueRandomCommitments{ IssueID: issueID, AlgoVersion: algoVersion, ServerSeedMaster: enc, ServerSeedHash: serverHash[:], ItemsRoot: itemsRoot[:], WeightsTotal: weightsTotal, StateVersion: nextVer, } if err := s.writeDB.IssueRandomCommitments.WithContext(ctx).Create(rec); err != nil { return nil, err } return &IssueRandomCommitment{ AlgoVersion: rec.AlgoVersion, IssueID: rec.IssueID, ServerSeedMaster: rec.ServerSeedMaster, ServerSeedHash: rec.ServerSeedHash, ItemsRoot: rec.ItemsRoot, WeightsTotal: rec.WeightsTotal, StateVersion: rec.StateVersion, }, nil } func (s *service) GetIssueRandomCommit(ctx context.Context, issueID int64) (*IssueRandomCommitment, error) { latest, err := s.readDB.IssueRandomCommitments.WithContext(ctx). Where(s.readDB.IssueRandomCommitments.IssueID.Eq(issueID)). Order(s.readDB.IssueRandomCommitments.StateVersion.Desc()). Take() if err != nil { if err == gorm.ErrRecordNotFound { return nil, nil // 没有找到记录是正常的,表示尚未生成承诺 } return nil, err } return &IssueRandomCommitment{ AlgoVersion: latest.AlgoVersion, IssueID: latest.IssueID, ServerSeedMaster: latest.ServerSeedMaster, ServerSeedHash: latest.ServerSeedHash, ItemsRoot: latest.ItemsRoot, WeightsTotal: latest.WeightsTotal, StateVersion: latest.StateVersion, }, nil } func (s *service) GetIssueRandomCommitHistory(ctx context.Context, issueID int64) ([]*IssueRandomCommitment, error) { commitments, err := s.readDB.IssueRandomCommitments.WithContext(ctx). Where(s.readDB.IssueRandomCommitments.IssueID.Eq(issueID)). Order(s.readDB.IssueRandomCommitments.StateVersion.Desc()). Find() if err != nil { if err == gorm.ErrRecordNotFound { return []*IssueRandomCommitment{}, nil // 返回空数组而不是错误 } return nil, err } result := make([]*IssueRandomCommitment, 0, len(commitments)) for _, commit := range commitments { result = append(result, &IssueRandomCommitment{ AlgoVersion: commit.AlgoVersion, IssueID: commit.IssueID, ServerSeedMaster: commit.ServerSeedMaster, ServerSeedHash: commit.ServerSeedHash, ItemsRoot: commit.ItemsRoot, WeightsTotal: commit.WeightsTotal, StateVersion: commit.StateVersion, }) } return result, nil }