Some checks failed
Build docker and publish / linux (1.24.5) (push) Failing after 39s
- 新增系统称号模板与效果配置表及相关CRUD接口 - 实现用户称号分配与抽奖效果应用逻辑 - 优化抽奖接口支持用户ID参数以应用称号效果 - 新增称号管理前端页面与分配功能 - 修复Windows时区错误与JSON字段初始化问题 - 移除无用管理接口代码并更新文档说明
75 lines
3.5 KiB
Markdown
75 lines
3.5 KiB
Markdown
# 抽奖控制策略选择与执行
|
||
|
||
## 背景与约束
|
||
|
||
* 不改变算法逻辑(承诺→HMAC+拒绝采样→验算一致),仅通过“输入/配置/时机”达到运营控制。
|
||
|
||
* 验算用户能看到的是回执中池快照与承诺哈希一致性,不能证明你在抽后操纵,只能确认抽前配置。
|
||
|
||
## 方案A:权重/库存门控(推荐)
|
||
|
||
* 做法:在承诺前将目标奖品 `weight=0` 或 `quantity=0`,前 N 次(或直到达到阈值)不进入抽取集合;到期后恢复权重/库存并重新承诺。
|
||
|
||
* 基于代码:
|
||
|
||
* 排除条件:`weight>0 && (quantity==-1 || quantity>0)` 才参与抽取(`internal/service/activity/draw_execute.go:31-35,56-58`)。
|
||
|
||
* 承诺快照:包含每个奖励的 `{id,name,weight,quantity_before}`(`internal/service/activity/random_commit.go:53-61,67-73`)。
|
||
|
||
* 优点:简单直接、无需改算法;前 N 次绝不命中;验算完全通过。
|
||
|
||
* 缺点:恢复后需生成新承诺(`state_version` 增加),不同时间段 `items_root` 不同,运维需记录策略切换。
|
||
|
||
## 方案B:承诺版本切换
|
||
|
||
* 做法:用 `state_version` 管理期的承诺版本:
|
||
|
||
* v1:不含目标奖品或其权重为 0 → 前 N 次抽使用 v1。
|
||
|
||
* v2:目标奖品恢复权重/库存 → 达到 N 后切换到 v2。
|
||
|
||
* 基于代码:承诺生成与历史查询(`internal/service/activity/random_commit.go:74-97,121-146`)。
|
||
|
||
* 优点:语义清晰、审计友好;对不同用户批次可严格区分承诺。
|
||
|
||
* 缺点:运维复杂度稍高;用户若横向对比可能看到承诺变化,但单次验算仍通过。
|
||
|
||
## 方案C:直接发放替代抽奖
|
||
|
||
* 做法:对需要“必中/避中”的个体,使用管理端发放接口 `POST /api/admin/users/:user_id/rewards/grant`(`internal/router/router.go:127`)。
|
||
|
||
* 优点:精确可控,零风险。
|
||
|
||
* 缺点:不产生抽奖回执;不适合需要“抽奖体验”的场景。
|
||
|
||
## 方案对比与推荐
|
||
|
||
* 目标“前 N 次不出现”且保留抽奖体验:优先选 **方案A(权重/库存门控)**,用 `quantity=0` 或 `weight=0` 让奖品在 N 次前不参与集合;到期后恢复并重新承诺。
|
||
|
||
* 若需批次化与清晰审计边界:选 **方案B(承诺版本切换)**,以 `state_version` 驱动切换,N 次阈值以抽奖日志计数实现运维。
|
||
|
||
* 个体定向控制:用 **方案C(直接发放)** 替代抽奖。
|
||
|
||
## 验算与用户感知
|
||
|
||
* 验算会确认:回执中的 `server_seed_hash/items_root/weights_total/selected_index/rand_proof` 与承诺一致(`internal/api/admin/verify_draw.go:50-66,104-138`)。
|
||
|
||
* 用户能“看到”:当次承诺的奖池快照与权重(若回执包含快照,管理端/APP均有:`internal/api/admin/draw_receipt.go:55-73`,`internal/api/activity/draw_app.go:28-34`)。
|
||
|
||
* 用户“感知不到”:你通过前置配置与时机实现“前 N 次不出现”的意图;只要在承诺前已固化,抽后不会被判定为操纵。
|
||
|
||
## 执行建议(不改代码)
|
||
|
||
1. 选定期次与目标奖品,设置前置配置:`quantity=0` 或 `weight=0`。
|
||
2. 生成承诺(`commit_random`)并上线;开始计数抽奖日志,达到 N 次后恢复配置并生成新承诺。
|
||
3. 记录操作与版本切换,必要时在活动规则中说明奖池/期的切换策略。
|
||
|
||
## 参考位置
|
||
|
||
* 参与判定与选取:`internal/service/activity/draw_execute.go:31-35,50-66,131-145`
|
||
|
||
* 承诺生成与版本:`internal/service/activity/random_commit.go:67-85,74-97,121-146`
|
||
|
||
* 管理端验证:`internal/api/admin/verify_draw.go:50-66,104-138`
|
||
|