邹方成 6ee627139c
Some checks failed
Build docker and publish / linux (1.24.5) (push) Failing after 40s
feat: 新增支付测试小程序与微信支付集成
feat(pay): 添加支付API基础结构
feat(miniapp): 创建支付测试小程序页面与配置
feat(wechatpay): 配置微信支付参数与证书
fix(guild): 修复成员列表查询条件
docs: 更新代码规范文档与需求文档
style: 统一前后端枚举显示与注释格式
refactor(admin): 重构用户奖励发放接口参数处理
test(title): 添加称号效果参数验证测试
2025-11-17 00:42:08 +08:00

156 lines
4.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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"
// CommitIssueRandom 为指定期生成随机承诺(包含主种子哈希、奖项根、总权重)
// 参数: issueID 期ID
// 返回: 承诺对象与错误
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
}
// GetIssueRandomCommit 获取期随机承诺(最新版本)
// 参数: issueID 期ID
// 返回: 承诺对象(可能为 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
}
// GetIssueRandomCommitHistory 获取期随机承诺历史记录
// 参数: issueID 期ID
// 返回: 承诺历史数组与错误
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
}