fix(contribution-service): 预种算力除数从 5 改为 10,冻结阈值同步更新
- PRE_PLANTING_PORTION_DIVISOR: 5 → 10(每份算力 = 1棵树的 1/10) - 冻结条件:totalPortions < 5 → < 10 - 解冻条件:totalPortions >= 5 → >= 10 - 同步更新所有相关注释和日志文案 注:2026-03-02 前已分配的份额算力记录(按 1/5 计算)不追溯修正。 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
2b07219046
commit
94792f56ea
|
|
@ -26,7 +26,7 @@ import { PrePlantingCdcModule } from './pre-planting/pre-planting-cdc.module';
|
||||||
InfrastructureModule,
|
InfrastructureModule,
|
||||||
ApplicationModule,
|
ApplicationModule,
|
||||||
ApiModule,
|
ApiModule,
|
||||||
PrePlantingCdcModule, // 预种计划:独立 CDC consumer、独立 Prisma schema、1/5 算力、冻结调度
|
PrePlantingCdcModule, // 预种计划:独立 CDC consumer、独立 Prisma schema、1/10 算力、冻结调度
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ export interface PrePlantingOrderSyncResult {
|
||||||
* 1. 同步预种订单到 pre_planting_synced_orders(追踪表)
|
* 1. 同步预种订单到 pre_planting_synced_orders(追踪表)
|
||||||
* 2. 当订单状态为 PAID 时,标记需要算力计算
|
* 2. 当订单状态为 PAID 时,标记需要算力计算
|
||||||
* 3. 在 synced_adoptions 中插入 marker 记录(用于 getDirectReferralAdoptedCount 正确计数)
|
* 3. 在 synced_adoptions 中插入 marker 记录(用于 getDirectReferralAdoptedCount 正确计数)
|
||||||
* 4. 事务提交后,触发 1/5 算力计算(PostCommitCallback)
|
* 4. 事务提交后,触发 1/10 算力计算(PostCommitCallback)
|
||||||
*
|
*
|
||||||
* === 对现有系统的影响 ===
|
* === 对现有系统的影响 ===
|
||||||
* - 零修改现有代码
|
* - 零修改现有代码
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,11 @@ import {
|
||||||
* [2026-02-17] 新增:每日检查预种用户的冻结/解冻条件
|
* [2026-02-17] 新增:每日检查预种用户的冻结/解冻条件
|
||||||
*
|
*
|
||||||
* === 冻结规则 ===
|
* === 冻结规则 ===
|
||||||
* - firstPurchaseAt + 1 年后,仍未满 5 份(totalPortions < 5)→ 冻结所有预种算力
|
* - firstPurchaseAt + 1 年后,仍未满 10 份(totalPortions < 10)→ 冻结所有预种算力
|
||||||
* - 冻结方式:将预种算力记录标记为 expired(is_expired=true)
|
* - 冻结方式:将预种算力记录标记为 expired(is_expired=true)
|
||||||
*
|
*
|
||||||
* === 解冻规则 ===
|
* === 解冻规则 ===
|
||||||
* - 冻结后累积满 5 份(totalPortions >= 5)→ 解冻
|
* - 冻结后累积满 10 份(totalPortions >= 10)→ 解冻
|
||||||
* - 解冻后的失效期 = 解冻日 + 2 年
|
* - 解冻后的失效期 = 解冻日 + 2 年
|
||||||
*
|
*
|
||||||
* === 正常到期(未被冻结过)===
|
* === 正常到期(未被冻结过)===
|
||||||
|
|
@ -77,7 +77,7 @@ export class PrePlantingFreezeScheduler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理冻结:查找 firstPurchaseAt + 1 年已过且未满 5 份的用户
|
* 处理冻结:查找 firstPurchaseAt + 1 年已过且未满 10 份的用户
|
||||||
*/
|
*/
|
||||||
private async processFreezes(now: Date): Promise<number> {
|
private async processFreezes(now: Date): Promise<number> {
|
||||||
const freezeDeadline = new Date(now);
|
const freezeDeadline = new Date(now);
|
||||||
|
|
@ -86,7 +86,7 @@ export class PrePlantingFreezeScheduler {
|
||||||
const candidates = await this.prePlantingPrisma.prePlantingFreezeState.findMany({
|
const candidates = await this.prePlantingPrisma.prePlantingFreezeState.findMany({
|
||||||
where: {
|
where: {
|
||||||
firstPurchaseAt: { lte: freezeDeadline },
|
firstPurchaseAt: { lte: freezeDeadline },
|
||||||
totalPortions: { lt: 5 },
|
totalPortions: { lt: 10 },
|
||||||
isFrozen: false,
|
isFrozen: false,
|
||||||
},
|
},
|
||||||
take: 100,
|
take: 100,
|
||||||
|
|
@ -122,13 +122,13 @@ export class PrePlantingFreezeScheduler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理解冻:查找已冻结但现在满 5 份的用户
|
* 处理解冻:查找已冻结但现在满 10 份的用户
|
||||||
*/
|
*/
|
||||||
private async processUnfreezes(now: Date): Promise<number> {
|
private async processUnfreezes(now: Date): Promise<number> {
|
||||||
const candidates = await this.prePlantingPrisma.prePlantingFreezeState.findMany({
|
const candidates = await this.prePlantingPrisma.prePlantingFreezeState.findMany({
|
||||||
where: {
|
where: {
|
||||||
isFrozen: true,
|
isFrozen: true,
|
||||||
totalPortions: { gte: 5 },
|
totalPortions: { gte: 10 },
|
||||||
},
|
},
|
||||||
take: 100,
|
take: 100,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -40,10 +40,11 @@ export interface PrePlantingMergeSyncResult {
|
||||||
/**
|
/**
|
||||||
* 预种算力计算服务
|
* 预种算力计算服务
|
||||||
*
|
*
|
||||||
* [2026-02-17] 新增:复用现有领域计算器,以 1/5 贡献值处理预种份额
|
* [2026-02-17] 新增:复用现有领域计算器,以 1/10 贡献值处理预种份额
|
||||||
|
* [2026-03-04] 更新:预种方案从「5份合1树」调整为「10份合1树」,每份算力从 rate/5 改为 rate/10
|
||||||
*
|
*
|
||||||
* === 核心设计 ===
|
* === 核心设计 ===
|
||||||
* - 构建虚拟 SyncedAdoption 对象(treeCount=portionCount, contributionPerTree=rate/5)
|
* - 构建虚拟 SyncedAdoption 对象(treeCount=portionCount, contributionPerTree=rate/10)
|
||||||
* - 调用现有 ContributionCalculatorService(领域服务)计算分配
|
* - 调用现有 ContributionCalculatorService(领域服务)计算分配
|
||||||
* - 结果写入现有 contribution_accounts/contribution_records 表(挖矿系统可见)
|
* - 结果写入现有 contribution_accounts/contribution_records 表(挖矿系统可见)
|
||||||
* - 使用 PRE_PLANTING_SOURCE_ID_OFFSET (10B) 偏移,避免与正常认种 ID 冲突
|
* - 使用 PRE_PLANTING_SOURCE_ID_OFFSET (10B) 偏移,避免与正常认种 ID 冲突
|
||||||
|
|
@ -103,7 +104,7 @@ export class PrePlantingContributionService {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取当日每棵树贡献值(预种份额 = 1/5)
|
// 获取当日每棵树贡献值(预种份额 = 1/10,10份合1棵树)
|
||||||
const adoptionDate = order.paidAt || order.createdAt;
|
const adoptionDate = order.paidAt || order.createdAt;
|
||||||
let contributionPerTree = new Decimal('22617');
|
let contributionPerTree = new Decimal('22617');
|
||||||
try {
|
try {
|
||||||
|
|
@ -123,7 +124,7 @@ export class PrePlantingContributionService {
|
||||||
status: 'MINING_ENABLED',
|
status: 'MINING_ENABLED',
|
||||||
selectedProvince: order.provinceCode,
|
selectedProvince: order.provinceCode,
|
||||||
selectedCity: order.cityCode,
|
selectedCity: order.cityCode,
|
||||||
contributionPerTree: contributionPerPortion, // 1/5 贡献值
|
contributionPerTree: contributionPerPortion, // 1/10 贡献值
|
||||||
sourceSequenceNum: BigInt(0),
|
sourceSequenceNum: BigInt(0),
|
||||||
syncedAt: new Date(),
|
syncedAt: new Date(),
|
||||||
contributionDistributed: false,
|
contributionDistributed: false,
|
||||||
|
|
@ -557,10 +558,11 @@ export class PrePlantingContributionService {
|
||||||
/**
|
/**
|
||||||
* 预种合成树后算力切换
|
* 预种合成树后算力切换
|
||||||
*
|
*
|
||||||
* [2026-02-28] 新增:5份预种合成1棵树,合同签署(mining_enabled_at 写入)后触发
|
* [2026-02-28] 新增:预种合成1棵树,合同签署(mining_enabled_at 写入)后触发
|
||||||
|
* [2026-03-04] 更新:合成阈值从 5份 改为 10份
|
||||||
*
|
*
|
||||||
* === 操作流程 ===
|
* === 操作流程 ===
|
||||||
* 1. 作废5份份额的算力记录(is_expired=true,remark 说明原因,已挖积分不追回)
|
* 1. 作废全部份额的算力记录(is_expired=true,remark 说明原因,已挖积分不追回)
|
||||||
* 2. 从认种人账户扣减旧个人算力(保持账户余额准确)
|
* 2. 从认种人账户扣减旧个人算力(保持账户余额准确)
|
||||||
* 3. 以1棵完整树的算力创建新记录(remark 标注合成来源)
|
* 3. 以1棵完整树的算力创建新记录(remark 标注合成来源)
|
||||||
* 4. 团队分润账户通过 saveDistributionResult 自然更新(净效果≈0,旧=新)
|
* 4. 团队分润账户通过 saveDistributionResult 自然更新(净效果≈0,旧=新)
|
||||||
|
|
@ -574,7 +576,7 @@ export class PrePlantingContributionService {
|
||||||
const { mergeNo, mergeId, accountSequence, sourceOrderNos, miningEnabledAt } = result;
|
const { mergeNo, mergeId, accountSequence, sourceOrderNos, miningEnabledAt } = result;
|
||||||
const mergeSourceAdoptionId = PRE_PLANTING_MERGE_SOURCE_ID_OFFSET + mergeId;
|
const mergeSourceAdoptionId = PRE_PLANTING_MERGE_SOURCE_ID_OFFSET + mergeId;
|
||||||
|
|
||||||
// Step 1: 查找5份源订单的追踪记录
|
// Step 1: 查找源订单的追踪记录
|
||||||
const sourceOrders = await this.prePlantingPrisma.prePlantingSyncedOrder.findMany({
|
const sourceOrders = await this.prePlantingPrisma.prePlantingSyncedOrder.findMany({
|
||||||
where: { orderNo: { in: sourceOrderNos } },
|
where: { orderNo: { in: sourceOrderNos } },
|
||||||
});
|
});
|
||||||
|
|
@ -671,7 +673,7 @@ export class PrePlantingContributionService {
|
||||||
const expireRemark =
|
const expireRemark =
|
||||||
`预种合成:本份额已合并为1棵树(${mergeNo}),算力转为树级计算,已挖积分不受影响`;
|
`预种合成:本份额已合并为1棵树(${mergeNo}),算力转为树级计算,已挖积分不受影响`;
|
||||||
const mergeRemark =
|
const mergeRemark =
|
||||||
`预种合成树:由5份份额合并(${mergeNo})算力升级为整棵树,` +
|
`预种合成树:由${sourceOrderNos.length}份份额合并(${mergeNo})算力升级为整棵树,` +
|
||||||
`源订单:${sourceOrderNos.join('、')}`;
|
`源订单:${sourceOrderNos.join('、')}`;
|
||||||
|
|
||||||
await this.unitOfWork.executeInTransaction(async () => {
|
await this.unitOfWork.executeInTransaction(async () => {
|
||||||
|
|
|
||||||
|
|
@ -17,22 +17,25 @@ export const PRE_PLANTING_SOURCE_ID_OFFSET = 10_000_000_000n;
|
||||||
/**
|
/**
|
||||||
* 预种每份的贡献值因子
|
* 预种每份的贡献值因子
|
||||||
*
|
*
|
||||||
* 每份预种 = 1棵树贡献值的 1/5
|
* 每份预种 = 1棵树贡献值的 1/10(10份合1棵树)
|
||||||
* 用法:contributionPerPortion = contributionPerTree / PRE_PLANTING_PORTION_DIVISOR
|
* 用法:contributionPerPortion = contributionPerTree / PRE_PLANTING_PORTION_DIVISOR
|
||||||
|
*
|
||||||
|
* [2026-03-04] 从 5 改为 10:预种方案从「5份合1树(3566USDT/份)」调整为「10份合1树(1887USDT/份)」
|
||||||
|
* 注意:2026-03-01 前已创建的份额算力记录(3566USDT/份,按1/5计算)不追溯修正。
|
||||||
*/
|
*/
|
||||||
export const PRE_PLANTING_PORTION_DIVISOR = 5;
|
export const PRE_PLANTING_PORTION_DIVISOR = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 预种冻结期限(从首次购买日起算,单位:年)
|
* 预种冻结期限(从首次购买日起算,单位:年)
|
||||||
*
|
*
|
||||||
* 首次购买 + 1 年后仍未满 5 份 → 所有预种算力冻结
|
* 首次购买 + 1 年后仍未满 10 份 → 所有预种算力冻结
|
||||||
*/
|
*/
|
||||||
export const PRE_PLANTING_FREEZE_PERIOD_YEARS = 1;
|
export const PRE_PLANTING_FREEZE_PERIOD_YEARS = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解冻后的算力有效期(从解冻日起算,单位:年)
|
* 解冻后的算力有效期(从解冻日起算,单位:年)
|
||||||
*
|
*
|
||||||
* 冻结后满 5 份解冻 → 算力恢复,从解冻日起算 2 年后失效
|
* 冻结后满 10 份解冻 → 算力恢复,从解冻日起算 2 年后失效
|
||||||
*/
|
*/
|
||||||
export const PRE_PLANTING_POST_UNFREEZE_VALIDITY_YEARS = 2;
|
export const PRE_PLANTING_POST_UNFREEZE_VALIDITY_YEARS = 2;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,9 @@ import { BonusClaimService } from '../application/services/bonus-claim.service';
|
||||||
* === 功能概述 ===
|
* === 功能概述 ===
|
||||||
* 1. 通过独立 CDC consumer 消费预种表变更(cdc.pre-planting.public.*)
|
* 1. 通过独立 CDC consumer 消费预种表变更(cdc.pre-planting.public.*)
|
||||||
* 2. 同步预种订单/持仓到独立追踪表(PrePlantingPrismaService)
|
* 2. 同步预种订单/持仓到独立追踪表(PrePlantingPrismaService)
|
||||||
* 3. 为每份预种订单计算 1/5 算力(复用现有领域计算器)
|
* 3. 为每份预种订单计算 1/10 算力(复用现有领域计算器,10份合1棵树)
|
||||||
* 4. 在 synced_adoptions 中插入 marker 记录(让现有 unlock 逻辑自然计入预种用户)
|
* 4. 在 synced_adoptions 中插入 marker 记录(让现有 unlock 逻辑自然计入预种用户)
|
||||||
* 5. 每日检查冻结/解冻条件(1 年未满 5 份 → 冻结;满 5 份 → 解冻 + 2 年有效期)
|
* 5. 每日检查冻结/解冻条件(1 年未满 10 份 → 冻结;满 10 份 → 解冻 + 2 年有效期)
|
||||||
*
|
*
|
||||||
* === 隔离保证 ===
|
* === 隔离保证 ===
|
||||||
* - 独立 Kafka consumer group:contribution-pre-planting-cdc(不影响现有 contribution-service-cdc-group)
|
* - 独立 Kafka consumer group:contribution-pre-planting-cdc(不影响现有 contribution-service-cdc-group)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue