Compare commits

..

2 Commits

Author SHA1 Message Date
hailin 702fa937e8 fix(batch-mining): 修正阶段划分逻辑
- preMineDays 是该批次加入后挖矿的天数,不是差值
- 批次1的preMineDays=3 → 批次1先独挖3天
- 批次2的preMineDays=2 → 批次1+2一起挖2天
- 批次3的preMineDays=1 → 批次1+2+3一起挖1天
- 最后所有批次一起挖剩余天数

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 21:29:34 -08:00
hailin 8b8d1f7d16 Revert "fix(batch-mining): 简化计算逻辑"
This reverts commit 4dcbe38309.
2026-01-21 21:17:00 -08:00
1 changed files with 60 additions and 41 deletions

View File

@ -136,11 +136,11 @@ export class BatchMiningService {
/** /**
* *
* *
* *
* - = × 86400 * - 1311
* - = ( / ) × × * - 221+2
* - 70% = / 0.7 * - 311+2+3
* - : (1000000/365/2)*70%*74 = 70958.90411 * - 4
*/ */
async preview(items: BatchMiningItem[]): Promise<BatchMiningPreviewResult> { async preview(items: BatchMiningItem[]): Promise<BatchMiningPreviewResult> {
this.logger.log(`[preview] 开始预览批量补发, 共 ${items.length} 条数据`); this.logger.log(`[preview] 开始预览批量补发, 共 ${items.length} 条数据`);
@ -170,8 +170,7 @@ export class BatchMiningService {
} }
const secondDistribution = config.secondDistribution.value; const secondDistribution = config.secondDistribution.value;
const dailyDistribution = secondDistribution.times(SECONDS_PER_DAY); this.logger.log(`[preview] 每秒分配量: ${secondDistribution.toString()}`);
this.logger.log(`[preview] 每秒分配量: ${secondDistribution.toString()}, 每日分配量: ${dailyDistribution.toFixed(6)}`);
// 按批次分组并排序 // 按批次分组并排序
const batchGroups = this.groupByBatch(items); const batchGroups = this.groupByBatch(items);
@ -190,40 +189,61 @@ export class BatchMiningService {
this.logger.log(`[preview] 批次${batchNum}算力: ${batchTotal.toFixed(2)}`); this.logger.log(`[preview] 批次${batchNum}算力: ${batchTotal.toFixed(2)}`);
} }
// 计算用户总算力和全网算力 // 计算每个用户的算力
let totalUserContribution = new Decimal(0); const userContributions = new Map<string, Decimal>();
for (const contribution of batchContributions.values()) {
totalUserContribution = totalUserContribution.plus(contribution);
}
// 用户只占全网的70%30%是系统、运营、层级、团队),所以全网算力 = 用户算力 / 0.7
const networkContribution = totalUserContribution.dividedBy(USER_NETWORK_RATIO);
this.logger.log(`[preview] 用户总算力: ${totalUserContribution.toFixed(2)}, 全网算力(用户占70%): ${networkContribution.toFixed(2)}`);
// 获取最大总挖矿天数
let maxTotalMiningDays = 0;
for (const item of items) { for (const item of items) {
if (item.totalMiningDays && item.totalMiningDays > maxTotalMiningDays) { userContributions.set(item.accountSequence, this.calculateUserContribution(item.treeCount));
maxTotalMiningDays = item.totalMiningDays;
} }
}
this.logger.log(`[preview] 最大总挖矿天数: ${maxTotalMiningDays}`);
// 简化计算:所有用户按各自的总挖矿天数计算收益 // 定义挖矿阶段
// 用户收益 = (用户算力 / 全网算力) × 每日产出 × 天数 // 阶段1: 批次1独挖3天
// 阶段2: 批次1+2共挖2天
// 阶段3: 批次1+2+3共挖1天
// 阶段4: 所有批次共挖(剩余天数)
const phases = this.buildMiningPhases(items, sortedBatches, batchContributions);
this.logger.log(`[preview] 挖矿阶段: ${JSON.stringify(phases.map(p => ({
phase: p.phaseNumber,
days: p.daysInPhase,
batches: p.participatingBatches,
networkContribution: p.networkContribution.toFixed(2)
})))}`);
// 计算每个用户在各阶段的收益
const userAmounts = new Map<string, Decimal>(); const userAmounts = new Map<string, Decimal>();
for (const item of items) { for (const item of items) {
const userContribution = this.calculateUserContribution(item.treeCount); userAmounts.set(item.accountSequence, new Decimal(0));
const ratio = userContribution.dividedBy(networkContribution); }
const days = item.totalMiningDays || maxTotalMiningDays;
const amount = dailyDistribution.times(ratio).times(days); for (const phase of phases) {
userAmounts.set(item.accountSequence, amount); const dailyDistribution = secondDistribution.times(SECONDS_PER_DAY);
this.logger.debug(`[preview] 用户 ${item.accountSequence}: 算力=${userContribution.toFixed(2)}, 占比=${ratio.toFixed(6)}, 天数=${days}, 金额=${amount.toFixed(8)}`); const phaseDistribution = dailyDistribution.times(phase.daysInPhase);
for (const item of items) {
// 检查该用户的批次是否参与此阶段
if (phase.participatingBatches.includes(item.batch)) {
const userContribution = userContributions.get(item.accountSequence)!;
const ratio = userContribution.dividedBy(phase.networkContribution);
const phaseAmount = phaseDistribution.times(ratio);
const currentAmount = userAmounts.get(item.accountSequence)!;
userAmounts.set(item.accountSequence, currentAmount.plus(phaseAmount));
}
}
} }
// 构建返回结果 // 构建返回结果
let grandTotalAmount = new Decimal(0); let grandTotalAmount = new Decimal(0);
const batchResults: BatchMiningPreviewResult['batches'] = []; const batchResults: BatchMiningPreviewResult['batches'] = [];
// 计算累计全网算力(最终状态)
// 用户只占全网的70%30%是系统、运营、层级、团队),所以全网算力 = 用户算力 / 0.7
let totalUserContribution = new Decimal(0);
for (const contribution of batchContributions.values()) {
totalUserContribution = totalUserContribution.plus(contribution);
}
const finalNetworkContribution = totalUserContribution.dividedBy(USER_NETWORK_RATIO);
this.logger.log(`[preview] 用户总算力: ${totalUserContribution.toFixed(2)}, 全网算力(用户占70%): ${finalNetworkContribution.toFixed(2)}`);
for (const batchNum of sortedBatches) { for (const batchNum of sortedBatches) {
const batchItems = batchGroups.get(batchNum)!; const batchItems = batchGroups.get(batchNum)!;
const batchContribution = batchContributions.get(batchNum)!; const batchContribution = batchContributions.get(batchNum)!;
@ -287,14 +307,16 @@ export class BatchMiningService {
* "提前天数" * "提前天数"
* - preMineDays * - preMineDays
* - 1 preMineDays=3 123 * - 1 preMineDays=3 123
* - 2 preMineDays=2 232 * - 1 preMineDays=3 13
* - 3 preMineDays=1 341 * - 2 preMineDays=2 1+22
* - 3 preMineDays=1 1+2+31
* *
* *
* - 阶段1: 只有批次1 (1preMineDays - 2preMineDays) * - 阶段1: 只有批次1 preMineDays
* - 阶段2: 批次1+2 (2preMineDays - 3preMineDays) * - 阶段2: 批次1+2 preMineDays
* - 阶段3: 批次1+2+3 preMineDays
* - ... * - ...
* - 最后阶段: 所有批次一起挖 (totalMiningDays - ) * - 最后阶段: 所有批次一起挖 (totalMiningDays - )
*/ */
private buildMiningPhases( private buildMiningPhases(
items: BatchMiningItem[], items: BatchMiningItem[],
@ -323,8 +345,6 @@ export class BatchMiningService {
this.logger.log(`[buildMiningPhases] 各批次提前天数: ${JSON.stringify(Object.fromEntries(batchPreMineDays))}`); this.logger.log(`[buildMiningPhases] 各批次提前天数: ${JSON.stringify(Object.fromEntries(batchPreMineDays))}`);
this.logger.log(`[buildMiningPhases] 最大总挖矿天数: ${maxTotalMiningDays}`); this.logger.log(`[buildMiningPhases] 最大总挖矿天数: ${maxTotalMiningDays}`);
// 获取第一批次的提前天数
const firstBatchPreMineDays = batchPreMineDays.get(sortedBatches[0]) || 0;
if (maxTotalMiningDays <= 0) { if (maxTotalMiningDays <= 0) {
this.logger.warn('[buildMiningPhases] 总挖矿天数<=0无法计算'); this.logger.warn('[buildMiningPhases] 总挖矿天数<=0无法计算');
return phases; return phases;
@ -335,17 +355,16 @@ export class BatchMiningService {
let usedDays = 0; // 已分配的天数 let usedDays = 0; // 已分配的天数
// 按批次顺序添加阶段(提前挖矿阶段) // 按批次顺序添加阶段(提前挖矿阶段)
// 每个批次加入后,挖该批次的 preMineDays 天
for (let i = 0; i < sortedBatches.length; i++) { for (let i = 0; i < sortedBatches.length; i++) {
const currentBatch = sortedBatches[i]; const currentBatch = sortedBatches[i];
const currentPreMineDays = batchPreMineDays.get(currentBatch) || 0; const currentPreMineDays = batchPreMineDays.get(currentBatch) || 0;
const nextBatch = sortedBatches[i + 1];
const nextPreMineDays = nextBatch !== undefined ? (batchPreMineDays.get(nextBatch) || 0) : 0;
// 当前批次加入挖矿 // 当前批次加入挖矿
participatingBatches.push(currentBatch); participatingBatches.push(currentBatch);
// 计算当前阶段持续的天数 = 当前批次提前天数 - 下一批次提前天数 // 该阶段持续天数 = 当前批次的提前天数
const phaseDays = currentPreMineDays - nextPreMineDays; const phaseDays = currentPreMineDays;
if (phaseDays > 0) { if (phaseDays > 0) {
// 计算该阶段参与用户的算力 // 计算该阶段参与用户的算力