From 2534068f70c148f1f3893dbd2b5d957d26da7754 Mon Sep 17 00:00:00 2001 From: hailin Date: Fri, 16 Jan 2026 07:31:13 -0800 Subject: [PATCH] fix(mining): remove duplicate burn mechanism from mining-service Mining-service incorrectly implemented its own burn mechanism (10-year cycle) which was not in the requirements. Per requirements, only trading-service should handle per-minute burn (4756.47/minute). Removed: - BlackHoleRepository and all burn-related methods - executeBurn() from mining distribution service - Burn stats from admin API and queries - Burn progress UI from mining admin web Co-Authored-By: Claude Opus 4.5 --- .../src/api/controllers/admin.controller.ts | 8 -- .../queries/get-mining-stats.query.ts | 13 +- .../services/mining-distribution.service.ts | 49 +------- .../services/mining-calculator.service.ts | 42 +------ .../infrastructure/infrastructure.module.ts | 3 - .../repositories/black-hole.repository.ts | 111 ------------------ .../src/app/(dashboard)/configs/page.tsx | 20 ---- .../src/features/configs/api/configs.api.ts | 5 - 8 files changed, 7 insertions(+), 244 deletions(-) delete mode 100644 backend/services/mining-service/src/infrastructure/persistence/repositories/black-hole.repository.ts diff --git a/backend/services/mining-service/src/api/controllers/admin.controller.ts b/backend/services/mining-service/src/api/controllers/admin.controller.ts index ddf313dd..f7c12ffa 100644 --- a/backend/services/mining-service/src/api/controllers/admin.controller.ts +++ b/backend/services/mining-service/src/api/controllers/admin.controller.ts @@ -49,7 +49,6 @@ export class AdminController { @ApiOperation({ summary: '获取挖矿系统状态' }) async getStatus() { const config = await this.prisma.miningConfig.findFirst(); - const blackHole = await this.prisma.blackHole.findFirst(); const accountCount = await this.prisma.miningAccount.count(); // 用户有效算力 @@ -75,13 +74,6 @@ export class AdminController { currentEra: config?.currentEra || 0, remainingDistribution: config?.remainingDistribution?.toString() || '0', secondDistribution: config?.secondDistribution?.toString() || '0', - blackHole: blackHole - ? { - totalBurned: blackHole.totalBurned.toString(), - targetBurn: blackHole.targetBurn.toString(), - remainingBurn: blackHole.remainingBurn.toString(), - } - : null, accountCount, // 用户有效算力 totalContribution: userContribution._sum.totalContribution?.toString() || '0', diff --git a/backend/services/mining-service/src/application/queries/get-mining-stats.query.ts b/backend/services/mining-service/src/application/queries/get-mining-stats.query.ts index f83c2c73..0f47409b 100644 --- a/backend/services/mining-service/src/application/queries/get-mining-stats.query.ts +++ b/backend/services/mining-service/src/application/queries/get-mining-stats.query.ts @@ -1,7 +1,6 @@ import { Injectable } from '@nestjs/common'; import { MiningAccountRepository } from '../../infrastructure/persistence/repositories/mining-account.repository'; import { MiningConfigRepository } from '../../infrastructure/persistence/repositories/mining-config.repository'; -import { BlackHoleRepository } from '../../infrastructure/persistence/repositories/black-hole.repository'; import { PriceSnapshotRepository } from '../../infrastructure/persistence/repositories/price-snapshot.repository'; import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service'; @@ -23,11 +22,6 @@ export interface MiningStatsDto { participantCount: number; totalMined: string; - // 销毁信息 - burnTarget: string; - totalBurned: string; - remainingBurn: string; - // 价格信息 currentPrice: string; priceChangePercent24h: number | null; @@ -45,16 +39,14 @@ export class GetMiningStatsQuery { constructor( private readonly accountRepository: MiningAccountRepository, private readonly configRepository: MiningConfigRepository, - private readonly blackHoleRepository: BlackHoleRepository, private readonly priceRepository: PriceSnapshotRepository, private readonly prisma: PrismaService, ) {} async execute(): Promise { - const [config, blackHole, latestPrice, price24hAgo, totalMined, participantCount, totalContribution] = + const [config, latestPrice, price24hAgo, totalMined, participantCount, totalContribution] = await Promise.all([ this.configRepository.getConfig(), - this.blackHoleRepository.getBlackHole(), this.priceRepository.getLatestSnapshot(), this.get24hAgoPrice(), this.getTotalMined(), @@ -83,9 +75,6 @@ export class GetMiningStatsQuery { totalContribution: totalContribution.toString(), participantCount, totalMined: totalMined.toString(), - burnTarget: blackHole?.targetBurn.toString() || '0', - totalBurned: blackHole?.totalBurned.toString() || '0', - remainingBurn: blackHole?.remainingBurn.toString() || '0', currentPrice: latestPrice?.price.toString() || '1', priceChangePercent24h, }; diff --git a/backend/services/mining-service/src/application/services/mining-distribution.service.ts b/backend/services/mining-service/src/application/services/mining-distribution.service.ts index 4dbaca3f..f763f164 100644 --- a/backend/services/mining-service/src/application/services/mining-distribution.service.ts +++ b/backend/services/mining-service/src/application/services/mining-distribution.service.ts @@ -2,7 +2,6 @@ import { Injectable, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { MiningAccountRepository } from '../../infrastructure/persistence/repositories/mining-account.repository'; import { MiningConfigRepository } from '../../infrastructure/persistence/repositories/mining-config.repository'; -import { BlackHoleRepository } from '../../infrastructure/persistence/repositories/black-hole.repository'; import { PriceSnapshotRepository } from '../../infrastructure/persistence/repositories/price-snapshot.repository'; import { OutboxRepository } from '../../infrastructure/persistence/repositories/outbox.repository'; import { SystemMiningAccountRepository } from '../../infrastructure/persistence/repositories/system-mining-account.repository'; @@ -15,11 +14,13 @@ import Decimal from 'decimal.js'; /** * 挖矿分配服务 - * 负责每秒执行挖矿分配和销毁 + * 负责每秒执行挖矿分配 * * 策略: * - 每秒:计算并更新账户余额 * - 每分钟:写入汇总的MiningRecord记录 + * + * 注意:销毁机制由 trading-service 负责,mining-service 不再执行销毁 */ @Injectable() export class MiningDistributionService { @@ -31,7 +32,6 @@ export class MiningDistributionService { constructor( private readonly miningAccountRepository: MiningAccountRepository, private readonly miningConfigRepository: MiningConfigRepository, - private readonly blackHoleRepository: BlackHoleRepository, private readonly priceSnapshotRepository: PriceSnapshotRepository, private readonly outboxRepository: OutboxRepository, private readonly systemMiningAccountRepository: SystemMiningAccountRepository, @@ -196,9 +196,6 @@ export class MiningDistributionService { await this.writePendingMinuteRecords(currentMinute); } - // 执行销毁 - const burnAmount = await this.executeBurn(currentSecond); - // 更新配置 const newRemaining = config.remainingDistribution.subtract(totalDistributed); await this.miningConfigRepository.updateRemainingDistribution(newRemaining); @@ -272,8 +269,6 @@ export class MiningDistributionService { await this.writeMinuteRecords(currentMinute); } - await this.executeBurn(currentSecond); - const newRemaining = config.remainingDistribution.subtract(totalDistributed); await this.miningConfigRepository.updateRemainingDistribution(newRemaining); @@ -628,44 +623,6 @@ export class MiningDistributionService { } } - /** - * 执行销毁 - */ - private async executeBurn(burnSecond: Date): Promise { - const blackHole = await this.blackHoleRepository.getBlackHole(); - if (!blackHole) { - return ShareAmount.zero(); - } - - if (blackHole.remainingBurn.isZero()) { - return ShareAmount.zero(); - } - - const config = await this.miningConfigRepository.getConfig(); - if (!config) { - return ShareAmount.zero(); - } - - // 计算剩余销毁秒数(10年) - const totalBurnSeconds = 10 * 365 * 24 * 60 * 60; - const remainingSeconds = this.calculator.calculateRemainingSeconds( - config.activatedAt || new Date(), - totalBurnSeconds, - ); - - const burnAmount = this.calculator.calculateSecondBurn( - blackHole.targetBurn, - blackHole.totalBurned, - remainingSeconds, - ); - - if (!burnAmount.isZero()) { - await this.blackHoleRepository.recordBurn(burnSecond, burnAmount); - } - - return burnAmount; - } - /** * 获取当前秒(向下取整,去掉毫秒) */ diff --git a/backend/services/mining-service/src/domain/services/mining-calculator.service.ts b/backend/services/mining-service/src/domain/services/mining-calculator.service.ts index b6b64881..6b0cf2e6 100644 --- a/backend/services/mining-service/src/domain/services/mining-calculator.service.ts +++ b/backend/services/mining-service/src/domain/services/mining-calculator.service.ts @@ -4,6 +4,8 @@ import { Price } from '../value-objects/price.vo'; /** * 挖矿计算领域服务 + * + * 注意:销毁机制由 trading-service 负责,mining-service 不再执行销毁计算 */ export class MiningCalculatorService { // 总积分股数量: 100.02亿 (SHARE_POOL_A: 100亿 + SHARE_POOL_B: 200万) @@ -12,9 +14,6 @@ export class MiningCalculatorService { // 初始分配池: 200M static readonly INITIAL_DISTRIBUTION_POOL = new ShareAmount('200000000'); - // 目标销毁量: 10B - static readonly BURN_TARGET = new ShareAmount('10000000000'); - // 减半周期: 2年(秒) static readonly HALVING_PERIOD_SECONDS = 2 * 365 * 24 * 60 * 60; // 63,072,000秒 @@ -49,30 +48,10 @@ export class MiningCalculatorService { return secondDistribution.multiply(ratio); } - /** - * 计算每秒销毁量 - * secondBurn = (burnTarget - currentBurned) / remainingSeconds - */ - calculateSecondBurn( - burnTarget: ShareAmount, - currentBurned: ShareAmount, - remainingSeconds: number, - ): ShareAmount { - if (remainingSeconds <= 0) { - return ShareAmount.zero(); - } - - const remaining = burnTarget.subtract(currentBurned); - if (remaining.isZero()) { - return ShareAmount.zero(); - } - - return remaining.divide(remainingSeconds); - } - /** * 计算价格 * price = sharePool / (totalShares - blackHole - circulationPool) + * blackHole 数据从 trading-service 获取 */ calculatePrice( sharePool: ShareAmount, @@ -87,21 +66,6 @@ export class MiningCalculatorService { ); } - /** - * 计算理论价格(假设只有黑洞,用于验证销毁机制) - */ - calculateTheoreticalPrice( - sharePool: ShareAmount, - blackHole: ShareAmount, - ): Price { - return Price.calculate( - sharePool, - MiningCalculatorService.TOTAL_SHARES, - blackHole, - ShareAmount.zero(), - ); - } - /** * 计算剩余挖矿秒数 */ diff --git a/backend/services/mining-service/src/infrastructure/infrastructure.module.ts b/backend/services/mining-service/src/infrastructure/infrastructure.module.ts index 383c37e8..2c121f80 100644 --- a/backend/services/mining-service/src/infrastructure/infrastructure.module.ts +++ b/backend/services/mining-service/src/infrastructure/infrastructure.module.ts @@ -4,7 +4,6 @@ import { ClientsModule, Transport } from '@nestjs/microservices'; import { PrismaModule } from './persistence/prisma/prisma.module'; import { MiningAccountRepository } from './persistence/repositories/mining-account.repository'; import { MiningConfigRepository } from './persistence/repositories/mining-config.repository'; -import { BlackHoleRepository } from './persistence/repositories/black-hole.repository'; import { PriceSnapshotRepository } from './persistence/repositories/price-snapshot.repository'; import { OutboxRepository } from './persistence/repositories/outbox.repository'; import { SystemMiningAccountRepository } from './persistence/repositories/system-mining-account.repository'; @@ -40,7 +39,6 @@ import { KafkaProducerService } from './kafka/kafka-producer.service'; providers: [ MiningAccountRepository, MiningConfigRepository, - BlackHoleRepository, PriceSnapshotRepository, OutboxRepository, SystemMiningAccountRepository, @@ -60,7 +58,6 @@ import { KafkaProducerService } from './kafka/kafka-producer.service'; exports: [ MiningAccountRepository, MiningConfigRepository, - BlackHoleRepository, PriceSnapshotRepository, OutboxRepository, SystemMiningAccountRepository, diff --git a/backend/services/mining-service/src/infrastructure/persistence/repositories/black-hole.repository.ts b/backend/services/mining-service/src/infrastructure/persistence/repositories/black-hole.repository.ts deleted file mode 100644 index d77d6f2d..00000000 --- a/backend/services/mining-service/src/infrastructure/persistence/repositories/black-hole.repository.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { PrismaService } from '../prisma/prisma.service'; -import { ShareAmount } from '../../../domain/value-objects/share-amount.vo'; - -export interface BlackHoleEntity { - id: string; - totalBurned: ShareAmount; - targetBurn: ShareAmount; - remainingBurn: ShareAmount; - lastBurnMinute: Date | null; -} - -export interface BurnRecordEntity { - id: string; - blackHoleId: string; - burnMinute: Date; - burnAmount: ShareAmount; - remainingTarget: ShareAmount; -} - -@Injectable() -export class BlackHoleRepository { - constructor(private readonly prisma: PrismaService) {} - - async getBlackHole(): Promise { - const record = await this.prisma.blackHole.findFirst(); - if (!record) { - return null; - } - return this.toDomain(record); - } - - async initializeBlackHole(targetBurn: ShareAmount): Promise { - const existing = await this.prisma.blackHole.findFirst(); - if (existing) { - return; - } - - await this.prisma.blackHole.create({ - data: { - totalBurned: 0, - targetBurn: targetBurn.value, - remainingBurn: targetBurn.value, - }, - }); - } - - async recordBurn(burnMinute: Date, burnAmount: ShareAmount): Promise { - const blackHole = await this.prisma.blackHole.findFirst(); - if (!blackHole) { - throw new Error('Black hole not initialized'); - } - - const newTotalBurned = new ShareAmount(blackHole.totalBurned).add(burnAmount); - const newRemainingBurn = new ShareAmount(blackHole.targetBurn).subtract(newTotalBurned); - - await this.prisma.$transaction([ - this.prisma.blackHole.update({ - where: { id: blackHole.id }, - data: { - totalBurned: newTotalBurned.value, - remainingBurn: newRemainingBurn.value, - lastBurnMinute: burnMinute, - }, - }), - this.prisma.burnRecord.create({ - data: { - blackHoleId: blackHole.id, - burnMinute, - burnAmount: burnAmount.value, - remainingTarget: newRemainingBurn.value, - }, - }), - ]); - } - - async getBurnRecords(page: number, pageSize: number): Promise<{ - data: BurnRecordEntity[]; - total: number; - }> { - const [records, total] = await Promise.all([ - this.prisma.burnRecord.findMany({ - orderBy: { burnMinute: 'desc' }, - skip: (page - 1) * pageSize, - take: pageSize, - }), - this.prisma.burnRecord.count(), - ]); - - return { - data: records.map((r) => ({ - id: r.id, - blackHoleId: r.blackHoleId, - burnMinute: r.burnMinute, - burnAmount: new ShareAmount(r.burnAmount), - remainingTarget: new ShareAmount(r.remainingTarget), - })), - total, - }; - } - - private toDomain(record: any): BlackHoleEntity { - return { - id: record.id, - totalBurned: new ShareAmount(record.totalBurned), - targetBurn: new ShareAmount(record.targetBurn), - remainingBurn: new ShareAmount(record.remainingBurn), - lastBurnMinute: record.lastBurnMinute, - }; - } -} diff --git a/frontend/mining-admin-web/src/app/(dashboard)/configs/page.tsx b/frontend/mining-admin-web/src/app/(dashboard)/configs/page.tsx index c970dab0..233b91fd 100644 --- a/frontend/mining-admin-web/src/app/(dashboard)/configs/page.tsx +++ b/frontend/mining-admin-web/src/app/(dashboard)/configs/page.tsx @@ -134,26 +134,6 @@ export default function ConfigsPage() { - {miningStatus.blackHole && ( -
-

黑洞燃烧进度

-
-
-

已燃烧

-

{formatNumber(miningStatus.blackHole.totalBurned)}

-
-
-

目标

-

{formatNumber(miningStatus.blackHole.targetBurn)}

-
-
-

剩余

-

{formatNumber(miningStatus.blackHole.remainingBurn)}

-
-
-
- )} - {/* 算力同步状态提示 */} {miningStatus.contributionSyncStatus && !miningStatus.contributionSyncStatus.isSynced && (
diff --git a/frontend/mining-admin-web/src/features/configs/api/configs.api.ts b/frontend/mining-admin-web/src/features/configs/api/configs.api.ts index a9ef021d..95c7143c 100644 --- a/frontend/mining-admin-web/src/features/configs/api/configs.api.ts +++ b/frontend/mining-admin-web/src/features/configs/api/configs.api.ts @@ -14,11 +14,6 @@ export interface MiningStatus { currentEra: number; remainingDistribution: string; secondDistribution: string; - blackHole?: { - totalBurned: string; - targetBurn: string; - remainingBurn: string; - }; accountCount: number; totalContribution: string; contributionSyncStatus?: ContributionSyncStatus;