feat(admin): 新增管理后台前端资源文件 feat(api): 实现获取用户统计数据的API接口 - 添加获取用户道具卡数量、优惠券数量和积分余额的接口 - 实现设置默认地址和删除地址的接口 feat(service): 新增用户统计服务方法 - 实现GetUserStats方法查询用户统计数据 - 添加地址管理相关服务方法 fix(core): 修复静态资源路由问题 - 调整静态资源路由配置 - 优化404路由处理逻辑 chore: 更新前端构建配置 - 添加Windows平台构建命令 - 更新README构建说明
7.5 KiB
7.5 KiB
/Users/win/code2025/bindbox_game/docs/抽奖一致性方案/TECH_DESIGN_抽奖一致性.md
抽奖一致性与离线验证技术方案
1. 背景与目标
- 背景:当前系统具备活动/期/奖励配置与日志查询,但缺少“抽奖随机一致性与离线验证”的闭环
- 目标
- 离线验证:用户拿一份回执单 (
receipt.json) 在本地无网络环境重算并比对抽奖结果 - 不可作假:平台在抽前预承诺随机源与奖池,抽后揭示并提供签名,用户可核验
- 不可预测:一次一密、不提前泄露服务端随机,用户无法事前预测下一次结果
- 便携性:单文件验证工具,零依赖、零配置,命令行运行即可
- 离线验证:用户拿一份回执单 (
2. 总体方案
- 方案A(MVP):Commit-Reveal + HMAC-SHA256
- 服务端为每个期
issue_id预承诺高熵主种子serverSeed_master,公开SHA256(serverSeed_master)(记为serverSeedHash) - 每次抽奖派生一次性子种子:
serverSubSeed = HMAC_SHA256(serverSeed_master, encode(issueId|drawId));抽后在回执揭示serverSubSeed,不泄露主种子 - 抽奖随机:
entropy = HMAC_SHA256(serverSubSeed, encodedMessage);拒绝采样,映射到权重区间 - 权重与奖池:抽奖前对奖励配置做规范化快照并哈希承诺
itemsRoot,确保各用户池一致 - 优点:实现简单、使用标准库、双平台易构建;满足不可作假与便携校验
- 服务端为每个期
- 方案B(升级):VRF(可验证随机函数)
- 服务端用 VRF 私钥对消息生成随机与证明;用户用公钥离线验真,无需揭示任何种子
- 优点:一次一密且天然不可预测;缺点:需引入并审计成熟库,跨平台打包复杂度更高
- 方案C(审计增强):透明日志与库存状态证明
- 使用追加型透明日志的 Merkle 根约束
drawId顺序与库存变更;可提供单位级“包含/非包含证明” - 适合二期提升全局可追溯性与防“双花”
- 使用追加型透明日志的 Merkle 根约束
3. 核心数据与回执规范
- 回执字段(自包含模式)
algoVersion: 算法/编码版本roundId: 期ID(issue_id)drawId: 抽奖唯一ID(递增或全局唯一)clientId: 用户IDtimestamp: 抽奖时间戳serverSeedHash:SHA256(serverSeed_master)的十六进制/Base64serverSubSeed: 本次子种子(十六进制/Base64)clientSeed: 用户种子(可系统生成)nonce: 用户在该期内的递增计数(防重)items: 奖池快照(按id排序)[{id, name, weight, quantity_before}]itemsRoot:SHA256(canonical_items_json)weightsTotal: 权重总和(整数)selectedIndex: 选中项索引selectedItemId: 选中奖励IDrandProof: 可选,记录一次性entropy的十六进制signature: 平台签名(覆盖整份回执,推荐 ed25519)
- 双文件模式(大池可选)
- 回执移除
items,仅保留itemsRoot与weightsTotal;本地需提供pool.json,其哈希必须等于itemsRoot
- 回执移除
4. 消息编码与随机选取规范
- 编码规则(用于 HMAC 消息)
- 固定顺序:
algoVersion | roundId | drawId | clientId | clientSeed | nonce | itemsRoot | weightsTotal - 字符串:
uint32(大端)长度 + UTF-8 字节 - 整数:
uint64(大端) - 哈希:原始 32 字节
- 固定顺序:
- 随机选取(拒绝采样)
- 取
R = uint64(entropy[0:8]) - 设
W = weightsTotal,M = floor(2^64 / W) * W - 若
R >= M:以计数器扩展重新计算entropy = HMAC_SHA256(serverSubSeed, encodedMessage || counter++),直到命中 - 位置
pos = R % W;以权重累加区间定位selectedIndex
- 取
5. 有库存的验证与扣减
- 抽奖前集合:仅在“
quantity_before > 0”的奖励集合中参与权重抽取 - 两阶段(可选):
- 阶段1:类别选择(权重拒绝采样)
- 阶段2:单位选择(该类别剩余单位内均匀或约定次序)
- 事务处理(服务端)
- 扣减
ActivityRewardSettings.Quantity(乐观检查>0) - 写入
ActivityDrawLogs(抽奖记录) - 如需生成用户资产/订单,参考现有逻辑(
internal/service/user/reward_grant.go)
- 扣减
- 二期增强(Merkle证明)
- 维护稀疏 Merkle 树(键=
unitId,值=状态位),回执包含“抽前包含证明 + 抽后非包含/状态更新证明”与版本号单调
- 维护稀疏 Merkle 树(键=
6. 服务端接口与集成点
- APP端新增
POST /api/app/activities/:activity_id/issues/:issue_id/draw:执行抽奖,返回回执 JSON- 集成位置:
internal/router/router.go的 APP认证组(与用户接口相同组)
- 管理端新增
POST /api/admin/activities/:activity_id/issues/:issue_id/commit_random:生成/轮换期的随机承诺GET /api/admin/activities/:activity_id/issues/:issue_id/commit_random:查看承诺
- 现有点位复用
- 奖励配置与权重:
ListIssueRewards(internal/service/activity/rewards_list.go) - 抽奖日志查询:
ListDrawLogs(internal/api/activity/draw_logs_app.go) - 用户资产/订单:参考系统发放(
internal/service/user/reward_grant.go)
- 奖励配置与权重:
7. 随机承诺存储设计
- 新增表:
issue_random_commitments- 字段:
issue_id, algo_version, server_seed_master, server_seed_hash, items_root, weights_total, state_version, created_at - 用途:管理期的随机承诺与池快照,支持版本化(
state_version递增)
- 字段:
- 过渡方案:若不立刻加表,可用配置存储(KV/配置表/文件),但建议最终落库便于审计
8. 离线验证工具(CLI)
- 用法:
bindbox_verify.exe receipt.json(返回码0通过、1失败) - 验证步骤
- 验签:用公钥验证
signature - 验承诺:
SHA256(serverSeed_master)是否等于serverSeedHash;并校验子种子派生规则 - 验奖池:重算
itemsRoot与weightsTotal - 重算随机:按编码规范 HMAC 与拒绝采样
- 映射比对:
selectedIndex/selectedItemId是否一致
- 验签:用公钥验证
- 构建(参考已有命令)
- Windows:
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -trimpath -o build/bindbox_verify.exe ./cmd/verify - macOS(amd64/arm64):同上构建;现有参考命令见
README.md:17
- Windows:
9. 安全与公平
- 不可预测
- 每次抽奖一次一密(
serverSubSeed),不提前揭示 drawId/nonce单调递增并纳入消息编码
- 每次抽奖一次一密(
- 不可操控
- 抽前公开承诺:
serverSeedHash与itemsRoot - 回执签名覆盖所有字段;日志保留顺序与上下文
- 抽前公开承诺:
- 无偏性
- 严格使用拒绝采样;权重与数量为非负整数;总和与整型范围校验
10. 实施步骤与时间节点
- 第1周:协议固化与承诺表设计;管理端承诺接口;服务层
ExecuteDraw实现(无库存/有库存) - 第2周:APP路由与处理器接入;离线验证 CLI 首版;测试向量与集成测试
- 第3周:文档与用户指引;压测极端权重/库存;可选VRF调研与二期规划
11. 验收标准
- 抽前承诺已公开且与回执一致
- 同一回执在 Windows/macOS 离线复验结果一致
- 有库存时仅在剩余>0集合中抽取;事务扣减与日志记录完整
- 随机输出在所有构建版本中一致;拒绝采样性能达标
12. 参考与代码位置
- 构建命令(Windows):
README.md:17 - 奖励配置查询:
internal/service/activity/rewards_list.go:7 - 抽奖日志查询:
internal/api/activity/draw_logs_app.go:35、internal/service/activity/draw_logs_list.go:7 - 用户资产发放参考:
internal/service/user/reward_grant.go:136