From dd183f7897b1633105335b8be17328763e2f8036 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 7 May 2025 18:47:32 +0000 Subject: [PATCH 1/4] Update utxo chart colors & add acceleration support --- .../components/block-overview-graph/utils.ts | 4 +- .../utxo-graph/utxo-graph.component.ts | 45 +++++++++++++++++-- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/components/block-overview-graph/utils.ts b/frontend/src/app/components/block-overview-graph/utils.ts index f051e9d51..94ab9b686 100644 --- a/frontend/src/app/components/block-overview-graph/utils.ts +++ b/frontend/src/app/components/block-overview-graph/utils.ts @@ -12,7 +12,7 @@ export function hexToColor(hex: string): Color { } export function colorToHex(color: Color): string { - return [color.r, color.g, color.b].map(c => Math.round(c * 255).toString(16)).join(''); + return [color.r, color.g, color.b].map(c => Math.max(0, Math.min(Math.round(c * 255), 255)).toString(16)).join(''); } export function desaturate(color: Color, amount: number): Color { @@ -35,6 +35,8 @@ export function darken(color: Color, amount: number): Color { } export function mix(color1: Color, color2: Color, amount: number): Color { + // clamp to 0-1 + amount = Math.max(0, Math.min(amount, 1)); return { r: color1.r * (1 - amount) + color2.r * amount, g: color1.g * (1 - amount) + color2.g * amount, diff --git a/frontend/src/app/components/utxo-graph/utxo-graph.component.ts b/frontend/src/app/components/utxo-graph/utxo-graph.component.ts index b712fcf87..ebcad891c 100644 --- a/frontend/src/app/components/utxo-graph/utxo-graph.component.ts +++ b/frontend/src/app/components/utxo-graph/utxo-graph.component.ts @@ -8,9 +8,12 @@ import { RelativeUrlPipe } from '@app/shared/pipes/relative-url/relative-url.pip import { renderSats } from '@app/shared/common.utils'; import { colorToHex, hexToColor, mix } from '@components/block-overview-graph/utils'; import { TimeService } from '@app/services/time.service'; +import { WebsocketService } from '@app/services/websocket.service'; +import { Acceleration } from '@interfaces/node-api.interface'; +import { defaultAuditColors } from '@components/block-overview-graph/utils'; -const newColorHex = '1bd8f4'; -const oldColorHex = '9339f4'; +const newColorHex = '1BF4AF'; +const oldColorHex = '3C39F4'; const pendingColorHex = 'eba814'; const newColor = hexToColor(newColorHex); const oldColor = hexToColor(oldColorHex); @@ -61,8 +64,10 @@ export class UtxoGraphComponent implements OnChanges, OnDestroy { @Input() widget: boolean = false; subscription: Subscription; + accelerationsSubscription: Subscription; lastUpdate: number = 0; updateInterval; + accelerationMap: Record = {}; chartOptions: EChartsOption = {}; chartInitOptions = { @@ -80,6 +85,7 @@ export class UtxoGraphComponent implements OnChanges, OnDestroy { private router: Router, private relativeUrlPipe: RelativeUrlPipe, private timeService: TimeService, + private websocketService: WebsocketService, ) { // re-render the chart every 10 seconds, to keep the age colors up to date this.updateInterval = setInterval(() => { @@ -87,6 +93,18 @@ export class UtxoGraphComponent implements OnChanges, OnDestroy { this.prepareChartOptions(this.utxos); } }, 10000); + + this.websocketService.startTrackAccelerations(); + this.accelerationsSubscription = this.stateService.liveAccelerations$.subscribe((accelerations) => { + this.accelerationMap = accelerations.reduce((acc, acceleration) => { + acc[acceleration.txid] = acceleration; + return acc; + }, {}); + + this.applyAccelerations(); + this.prepareChartOptions(this.utxos); + }); + } ngOnChanges(changes: SimpleChanges): void { @@ -95,10 +113,20 @@ export class UtxoGraphComponent implements OnChanges, OnDestroy { return; } if (changes.utxos) { + this.applyAccelerations(); this.prepareChartOptions(this.utxos); } } + applyAccelerations(): void { + for (const utxo of this.utxos) { + delete utxo.status['accelerated']; + if (this.accelerationMap[utxo.txid]) { + utxo.status['accelerated'] = true; + } + } + } + prepareChartOptions(utxos: Utxo[]): void { if (!utxos || utxos.length === 0) { return; @@ -311,7 +339,12 @@ export class UtxoGraphComponent implements OnChanges, OnDestroy {
${valueStr}
- ${utxo.status.confirmed ? 'Confirmed ' + this.timeService.calculate(utxo.status.block_time, 'since', true, 1, 'minute').text : 'Pending'} + ${utxo.status.confirmed + ? 'Confirmed ' + this.timeService.calculate(utxo.status.block_time, 'since', true, 1, 'minute').text + : utxo.status['accelerated'] + ? 'Accelerated' + : 'Pending' + } `; }, } @@ -322,7 +355,9 @@ export class UtxoGraphComponent implements OnChanges, OnDestroy { } getColor(utxo: Utxo): string { - if (utxo.status.confirmed) { + if (utxo.status['accelerated']) { + return colorToHex(defaultAuditColors.accelerated); + } else if (utxo.status.confirmed) { const age = Date.now() / 1000 - utxo.status.block_time; const oneHour = 60 * 60; const fourYears = 4 * 365 * 24 * 60 * 60; @@ -366,6 +401,8 @@ export class UtxoGraphComponent implements OnChanges, OnDestroy { this.subscription.unsubscribe(); } clearInterval(this.updateInterval); + this.websocketService.stopTrackAccelerations(); + this.accelerationsSubscription.unsubscribe(); } isMobile(): boolean { From e5082863de6b713613dea8e80d613f519fe299ff Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Thu, 8 May 2025 11:32:51 +0200 Subject: [PATCH 2/4] [mining] fix potential bug where we try to index hashrate even if there are no blocks --- backend/src/api/mining/mining.ts | 47 ++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/backend/src/api/mining/mining.ts b/backend/src/api/mining/mining.ts index 7e3ec525a..0e9dcf91a 100644 --- a/backend/src/api/mining/mining.ts +++ b/backend/src/api/mining/mining.ts @@ -256,31 +256,36 @@ class Mining { const blockStats: any = await BlocksRepository.$blockCountBetweenTimestamp( null, fromTimestamp / 1000, toTimestamp / 1000); - const lastBlockHashrate = await bitcoinClient.getNetworkHashPs(blockStats.blockCount, - blockStats.lastBlockHeight); - let pools = await PoolsRepository.$getPoolsInfoBetween(fromTimestamp / 1000, toTimestamp / 1000); - const totalBlocks = pools.reduce((acc, pool) => acc + pool.blockCount, 0); - if (totalBlocks > 0) { - pools = pools.map((pool: any) => { - pool.hashrate = (pool.blockCount / totalBlocks) * lastBlockHashrate; - pool.share = (pool.blockCount / totalBlocks); - return pool; - }); + if (blockStats.blockCount <= 0) { + logger.debug(`No block found between ${fromTimestamp / 1000} and ${toTimestamp / 1000}, skipping hashrate indexing for this period`, logger.tags.mining); + } else { + const lastBlockHashrate = await bitcoinClient.getNetworkHashPs(blockStats.blockCount, + blockStats.lastBlockHeight); - for (const pool of pools) { - hashrates.push({ - hashrateTimestamp: toTimestamp / 1000, - avgHashrate: pool['hashrate'] , - poolId: pool.poolId, - share: pool['share'], - type: 'weekly', + let pools = await PoolsRepository.$getPoolsInfoBetween(fromTimestamp / 1000, toTimestamp / 1000); + const totalBlocks = pools.reduce((acc, pool) => acc + pool.blockCount, 0); + if (totalBlocks > 0) { + pools = pools.map((pool: any) => { + pool.hashrate = (pool.blockCount / totalBlocks) * lastBlockHashrate; + pool.share = (pool.blockCount / totalBlocks); + return pool; }); - } - newlyIndexed += hashrates.length / Math.max(1, pools.length); - await HashratesRepository.$saveHashrates(hashrates); - hashrates.length = 0; + for (const pool of pools) { + hashrates.push({ + hashrateTimestamp: toTimestamp / 1000, + avgHashrate: pool['hashrate'] , + poolId: pool.poolId, + share: pool['share'], + type: 'weekly', + }); + } + + newlyIndexed += hashrates.length / Math.max(1, pools.length); + await HashratesRepository.$saveHashrates(hashrates); + hashrates.length = 0; + } } const elapsedSeconds = Math.max(1, Math.round((new Date().getTime() / 1000) - timer)); From 13b4126f9b3c43d991e7dea24312de1b7b10dc96 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Thu, 8 May 2025 12:52:32 +0200 Subject: [PATCH 3/4] [lightning] make sure channel id has valid format before caching its funding transaction --- backend/src/tasks/lightning/sync-tasks/funding-tx-fetcher.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/src/tasks/lightning/sync-tasks/funding-tx-fetcher.ts b/backend/src/tasks/lightning/sync-tasks/funding-tx-fetcher.ts index ada2a89b2..f681565d4 100644 --- a/backend/src/tasks/lightning/sync-tasks/funding-tx-fetcher.ts +++ b/backend/src/tasks/lightning/sync-tasks/funding-tx-fetcher.ts @@ -79,6 +79,10 @@ class FundingTxFetcher { } const parts = channelId.split('x'); + if (parts.length < 3) { + logger.debug(`Channel ID ${channelId} does not seem valid, should contains at least 3 parts separated by 'x'`, logger.tags.ln); + return null; + } const blockHeight = parts[0]; const txIdx = parts[1]; const outputIdx = parts[2]; From c67c2571b7a95c2b865b7dd2adefd624e045138c Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Thu, 8 May 2025 13:07:05 +0200 Subject: [PATCH 4/4] [lightning] make sure tx idx is present in block --- backend/src/tasks/lightning/sync-tasks/funding-tx-fetcher.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/src/tasks/lightning/sync-tasks/funding-tx-fetcher.ts b/backend/src/tasks/lightning/sync-tasks/funding-tx-fetcher.ts index f681565d4..d0b92f42e 100644 --- a/backend/src/tasks/lightning/sync-tasks/funding-tx-fetcher.ts +++ b/backend/src/tasks/lightning/sync-tasks/funding-tx-fetcher.ts @@ -103,6 +103,10 @@ class FundingTxFetcher { } const txid = block.tx[txIdx]; + if (!txid) { + logger.debug(`Cannot cache ${channelId} funding tx. TX index ${txIdx} does not exist in block ${block.hash ?? block.id}`, logger.tags.ln); + return null; + } const rawTx = await bitcoinClient.getRawTransaction(txid); const tx = await bitcoinClient.decodeRawTransaction(rawTx);