Merge pull request #4887 from mempool/mononaut/local-acceleration-data
Local acceleration data
This commit is contained in:
		
						commit
						03867ada49
					
				| @ -1,12 +1,14 @@ | |||||||
| import { Application, Request, Response } from "express"; | import { Application, Request, Response } from 'express'; | ||||||
| import config from "../../config"; | import config from '../../config'; | ||||||
| import axios from "axios"; | import axios from 'axios'; | ||||||
| import logger from "../../logger"; | import logger from '../../logger'; | ||||||
|  | import mempool from '../mempool'; | ||||||
|  | import AccelerationRepository from '../../repositories/AccelerationRepository'; | ||||||
| 
 | 
 | ||||||
| class AccelerationRoutes { | class AccelerationRoutes { | ||||||
|   private tag = 'Accelerator'; |   private tag = 'Accelerator'; | ||||||
| 
 | 
 | ||||||
|   public initRoutes(app: Application) { |   public initRoutes(app: Application): void { | ||||||
|     app |     app | ||||||
|       .get(config.MEMPOOL.API_URL_PREFIX + 'services/accelerator/accelerations', this.$getAcceleratorAccelerations.bind(this)) |       .get(config.MEMPOOL.API_URL_PREFIX + 'services/accelerator/accelerations', this.$getAcceleratorAccelerations.bind(this)) | ||||||
|       .get(config.MEMPOOL.API_URL_PREFIX + 'services/accelerator/accelerations/history', this.$getAcceleratorAccelerationsHistory.bind(this)) |       .get(config.MEMPOOL.API_URL_PREFIX + 'services/accelerator/accelerations/history', this.$getAcceleratorAccelerationsHistory.bind(this)) | ||||||
| @ -15,35 +17,27 @@ class AccelerationRoutes { | |||||||
|     ; |     ; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async $getAcceleratorAccelerations(req: Request, res: Response) { |   private async $getAcceleratorAccelerations(req: Request, res: Response): Promise<void> { | ||||||
|     const url = `${config.MEMPOOL_SERVICES.API}/${req.originalUrl.replace('/api/v1/services/', '')}`; |     const accelerations = mempool.getAccelerations(); | ||||||
|     try { |     res.status(200).send(Object.values(accelerations)); | ||||||
|       const response = await axios.get(url, { responseType: 'stream', timeout: 10000 }); |  | ||||||
|       for (const key in response.headers) { |  | ||||||
|         res.setHeader(key, response.headers[key]);  |  | ||||||
|       }       |  | ||||||
|       response.data.pipe(res); |  | ||||||
|     } catch (e) { |  | ||||||
|       logger.err(`Unable to get current accelerations from ${url} in $getAcceleratorAccelerations(), ${e}`, this.tag); |  | ||||||
|       res.status(500).end(); |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async $getAcceleratorAccelerationsHistory(req: Request, res: Response) { |   private async $getAcceleratorAccelerationsHistory(req: Request, res: Response): Promise<void> { | ||||||
|     const url = `${config.MEMPOOL_SERVICES.API}/${req.originalUrl.replace('/api/v1/services/', '')}`; |     const history = await AccelerationRepository.$getAccelerationInfo(null, req.query.blockHeight ? parseInt(req.query.blockHeight as string, 10) : null); | ||||||
|     try { |     res.status(200).send(history.map(accel => ({ | ||||||
|       const response = await axios.get(url, { responseType: 'stream', timeout: 10000 }); |       txid: accel.txid, | ||||||
|       for (const key in response.headers) { |       added: accel.added, | ||||||
|         res.setHeader(key, response.headers[key]);  |       status: 'completed', | ||||||
|       }       |       effectiveFee: accel.effective_fee, | ||||||
|       response.data.pipe(res); |       effectiveVsize: accel.effective_vsize, | ||||||
|     } catch (e) { |       boostRate: accel.boost_rate, | ||||||
|       logger.err(`Unable to get acceleration history from ${url} in $getAcceleratorAccelerationsHistory(), ${e}`, this.tag); |       boostCost: accel.boost_cost, | ||||||
|       res.status(500).end(); |       blockHeight: accel.height, | ||||||
|     } |       pools: [accel.pool], | ||||||
|  |     }))); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async $getAcceleratorAccelerationsHistoryAggregated(req: Request, res: Response) { |   private async $getAcceleratorAccelerationsHistoryAggregated(req: Request, res: Response): Promise<void> { | ||||||
|     const url = `${config.MEMPOOL_SERVICES.API}/${req.originalUrl.replace('/api/v1/services/', '')}`; |     const url = `${config.MEMPOOL_SERVICES.API}/${req.originalUrl.replace('/api/v1/services/', '')}`; | ||||||
|     try { |     try { | ||||||
|       const response = await axios.get(url, { responseType: 'stream', timeout: 10000 }); |       const response = await axios.get(url, { responseType: 'stream', timeout: 10000 }); | ||||||
| @ -57,7 +51,7 @@ class AccelerationRoutes { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async $getAcceleratorAccelerationsStats(req: Request, res: Response) { |   private async $getAcceleratorAccelerationsStats(req: Request, res: Response): Promise<void> { | ||||||
|     const url = `${config.MEMPOOL_SERVICES.API}/${req.originalUrl.replace('/api/v1/services/', '')}`; |     const url = `${config.MEMPOOL_SERVICES.API}/${req.originalUrl.replace('/api/v1/services/', '')}`; | ||||||
|     try { |     try { | ||||||
|       const response = await axios.get(url, { responseType: 'stream', timeout: 10000 }); |       const response = await axios.get(url, { responseType: 'stream', timeout: 10000 }); | ||||||
|  | |||||||
| @ -29,6 +29,7 @@ import websocketHandler from './websocket-handler'; | |||||||
| import redisCache from './redis-cache'; | import redisCache from './redis-cache'; | ||||||
| import rbfCache from './rbf-cache'; | import rbfCache from './rbf-cache'; | ||||||
| import { calcBitsDifference } from './difficulty-adjustment'; | import { calcBitsDifference } from './difficulty-adjustment'; | ||||||
|  | import AccelerationRepository from '../repositories/AccelerationRepository'; | ||||||
| 
 | 
 | ||||||
| class Blocks { | class Blocks { | ||||||
|   private blocks: BlockExtended[] = []; |   private blocks: BlockExtended[] = []; | ||||||
| @ -872,6 +873,7 @@ class Blocks { | |||||||
|             await BlocksRepository.$deleteBlocksFrom(lastBlock.height - 10); |             await BlocksRepository.$deleteBlocksFrom(lastBlock.height - 10); | ||||||
|             await HashratesRepository.$deleteLastEntries(); |             await HashratesRepository.$deleteLastEntries(); | ||||||
|             await cpfpRepository.$deleteClustersFrom(lastBlock.height - 10); |             await cpfpRepository.$deleteClustersFrom(lastBlock.height - 10); | ||||||
|  |             await AccelerationRepository.$deleteAccelerationsFrom(lastBlock.height - 10); | ||||||
|             this.blocks = this.blocks.slice(0, -10); |             this.blocks = this.blocks.slice(0, -10); | ||||||
|             this.updateTimerProgress(timer, `rolled back chain divergence from ${this.currentBlockHeight}`); |             this.updateTimerProgress(timer, `rolled back chain divergence from ${this.currentBlockHeight}`); | ||||||
|             for (let i = 10; i >= 0; --i) { |             for (let i = 10; i >= 0; --i) { | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ import cpfpRepository from '../repositories/CpfpRepository'; | |||||||
| import { RowDataPacket } from 'mysql2'; | import { RowDataPacket } from 'mysql2'; | ||||||
| 
 | 
 | ||||||
| class DatabaseMigration { | class DatabaseMigration { | ||||||
|   private static currentVersion = 76; |   private static currentVersion = 77; | ||||||
|   private queryTimeout = 3600_000; |   private queryTimeout = 3600_000; | ||||||
|   private statisticsAddedIndexed = false; |   private statisticsAddedIndexed = false; | ||||||
|   private uniqueLogs: string[] = []; |   private uniqueLogs: string[] = []; | ||||||
| @ -664,6 +664,11 @@ class DatabaseMigration { | |||||||
|       await this.$executeQuery('ALTER TABLE `blocks_audits` ADD prioritized_txs JSON DEFAULT "[]"'); |       await this.$executeQuery('ALTER TABLE `blocks_audits` ADD prioritized_txs JSON DEFAULT "[]"'); | ||||||
|       await this.updateToSchemaVersion(76); |       await this.updateToSchemaVersion(76); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     if (databaseSchemaVersion < 77 && config.MEMPOOL.NETWORK === 'mainnet') { | ||||||
|  |       await this.$executeQuery('ALTER TABLE `accelerations` ADD requested datetime DEFAULT NULL'); | ||||||
|  |       await this.updateToSchemaVersion(77); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|  | |||||||
| @ -5,6 +5,9 @@ import axios from 'axios'; | |||||||
| 
 | 
 | ||||||
| export interface Acceleration { | export interface Acceleration { | ||||||
|   txid: string, |   txid: string, | ||||||
|  |   added: number, | ||||||
|  |   effectiveVsize: number, | ||||||
|  |   effectiveFee: number, | ||||||
|   feeDelta: number, |   feeDelta: number, | ||||||
|   pools: number[], |   pools: number[], | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -6,7 +6,7 @@ import { IEsploraApi } from '../api/bitcoin/esplora-api.interface'; | |||||||
| import { Common } from '../api/common'; | import { Common } from '../api/common'; | ||||||
| import config from '../config'; | import config from '../config'; | ||||||
| import blocks from '../api/blocks'; | import blocks from '../api/blocks'; | ||||||
| import accelerationApi, { Acceleration } from '../api/services/acceleration'; | import accelerationApi, { Acceleration, AccelerationHistory } from '../api/services/acceleration'; | ||||||
| import accelerationCosts from '../api/acceleration/acceleration'; | import accelerationCosts from '../api/acceleration/acceleration'; | ||||||
| import bitcoinApi from '../api/bitcoin/bitcoin-api-factory'; | import bitcoinApi from '../api/bitcoin/bitcoin-api-factory'; | ||||||
| import transactionUtils from '../api/transaction-utils'; | import transactionUtils from '../api/transaction-utils'; | ||||||
| @ -15,6 +15,7 @@ import { BlockExtended, MempoolTransactionExtended } from '../mempool.interfaces | |||||||
| export interface PublicAcceleration { | export interface PublicAcceleration { | ||||||
|   txid: string, |   txid: string, | ||||||
|   height: number, |   height: number, | ||||||
|  |   added: number, | ||||||
|   pool: { |   pool: { | ||||||
|     id: number, |     id: number, | ||||||
|     slug: string, |     slug: string, | ||||||
| @ -29,15 +30,20 @@ export interface PublicAcceleration { | |||||||
| class AccelerationRepository { | class AccelerationRepository { | ||||||
|   private bidBoostV2Activated = 831580; |   private bidBoostV2Activated = 831580; | ||||||
| 
 | 
 | ||||||
|   public async $saveAcceleration(acceleration: AccelerationInfo, block: IEsploraApi.Block, pool_id: number): Promise<void> { |   public async $saveAcceleration(acceleration: AccelerationInfo, block: IEsploraApi.Block, pool_id: number, accelerationData: Acceleration[]): Promise<void> { | ||||||
|  |     const accelerationMap: { [txid: string]: Acceleration } = {}; | ||||||
|  |     for (const acc of accelerationData) { | ||||||
|  |       accelerationMap[acc.txid] = acc; | ||||||
|  |     } | ||||||
|     try { |     try { | ||||||
|       await DB.query(` |       await DB.query(` | ||||||
|         INSERT INTO accelerations(txid, added, height, pool, effective_vsize, effective_fee, boost_rate, boost_cost) |         INSERT INTO accelerations(txid, requested, added, height, pool, effective_vsize, effective_fee, boost_rate, boost_cost) | ||||||
|         VALUE (?, FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?) |         VALUE (?, FROM_UNIXTIME(?), FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?) | ||||||
|         ON DUPLICATE KEY UPDATE |         ON DUPLICATE KEY UPDATE | ||||||
|           height = ? |           height = ? | ||||||
|       `, [
 |       `, [
 | ||||||
|         acceleration.txSummary.txid, |         acceleration.txSummary.txid, | ||||||
|  |         accelerationMap[acceleration.txSummary.txid].added, | ||||||
|         block.timestamp, |         block.timestamp, | ||||||
|         block.height, |         block.height, | ||||||
|         pool_id, |         pool_id, | ||||||
| @ -64,7 +70,7 @@ class AccelerationRepository { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     let query = ` |     let query = ` | ||||||
|       SELECT * FROM accelerations |       SELECT *, UNIX_TIMESTAMP(requested) as requested_timestamp, UNIX_TIMESTAMP(added) as block_timestamp FROM accelerations | ||||||
|       JOIN pools on pools.unique_id = accelerations.pool |       JOIN pools on pools.unique_id = accelerations.pool | ||||||
|     `;
 |     `;
 | ||||||
|     let params: any[] = []; |     let params: any[] = []; | ||||||
| @ -99,6 +105,7 @@ class AccelerationRepository { | |||||||
|         return rows.map(row => ({ |         return rows.map(row => ({ | ||||||
|           txid: row.txid, |           txid: row.txid, | ||||||
|           height: row.height, |           height: row.height, | ||||||
|  |           added: row.requested_timestamp || row.block_timestamp, | ||||||
|           pool: { |           pool: { | ||||||
|             id: row.id, |             id: row.id, | ||||||
|             slug: row.slug, |             slug: row.slug, | ||||||
| @ -202,7 +209,7 @@ class AccelerationRepository { | |||||||
|         const tx = blockTxs[acc.txid]; |         const tx = blockTxs[acc.txid]; | ||||||
|         const accelerationInfo = accelerationCosts.getAccelerationInfo(tx, boostRate, transactions); |         const accelerationInfo = accelerationCosts.getAccelerationInfo(tx, boostRate, transactions); | ||||||
|         accelerationInfo.cost = Math.max(0, Math.min(acc.feeDelta, accelerationInfo.cost)); |         accelerationInfo.cost = Math.max(0, Math.min(acc.feeDelta, accelerationInfo.cost)); | ||||||
|         this.$saveAcceleration(accelerationInfo, block, block.extras.pool.id); |         this.$saveAcceleration(accelerationInfo, block, block.extras.pool.id, successfulAccelerations); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     const lastSyncedHeight = await this.$getLastSyncedHeight(); |     const lastSyncedHeight = await this.$getLastSyncedHeight(); | ||||||
| @ -230,7 +237,7 @@ class AccelerationRepository { | |||||||
|     logger.debug(`Fetching accelerations between block ${lastSyncedHeight} and ${currentHeight}`); |     logger.debug(`Fetching accelerations between block ${lastSyncedHeight} and ${currentHeight}`); | ||||||
| 
 | 
 | ||||||
|     // Fetch accelerations from mempool.space since the last synced block;
 |     // Fetch accelerations from mempool.space since the last synced block;
 | ||||||
|     const accelerationsByBlock = {}; |     const accelerationsByBlock: {[height: number]: AccelerationHistory[]} = {}; | ||||||
|     const blockHashes = {}; |     const blockHashes = {}; | ||||||
|     let done = false; |     let done = false; | ||||||
|     let page = 1; |     let page = 1; | ||||||
| @ -297,12 +304,16 @@ class AccelerationRepository { | |||||||
|           const feeStats = Common.calcEffectiveFeeStatistics(template); |           const feeStats = Common.calcEffectiveFeeStatistics(template); | ||||||
|           boostRate = feeStats.medianFee; |           boostRate = feeStats.medianFee; | ||||||
|         } |         } | ||||||
|  |         const accelerationSummaries = accelerations.map(acc => ({ | ||||||
|  |           ...acc, | ||||||
|  |           pools: acc.pools.map(pool => pool.pool_unique_id), | ||||||
|  |         })) | ||||||
|         for (const acc of accelerations) { |         for (const acc of accelerations) { | ||||||
|           if (blockTxs[acc.txid]) { |           if (blockTxs[acc.txid]) { | ||||||
|             const tx = blockTxs[acc.txid]; |             const tx = blockTxs[acc.txid]; | ||||||
|             const accelerationInfo = accelerationCosts.getAccelerationInfo(tx, boostRate, transactions); |             const accelerationInfo = accelerationCosts.getAccelerationInfo(tx, boostRate, transactions); | ||||||
|             accelerationInfo.cost = Math.max(0, Math.min(acc.feeDelta, accelerationInfo.cost)); |             accelerationInfo.cost = Math.max(0, Math.min(acc.feeDelta, accelerationInfo.cost)); | ||||||
|             await this.$saveAcceleration(accelerationInfo, block, block.extras.pool.id); |             await this.$saveAcceleration(accelerationInfo, block, block.extras.pool.id, accelerationSummaries); | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|         await this.$setLastSyncedHeight(height); |         await this.$setLastSyncedHeight(height); | ||||||
| @ -317,6 +328,26 @@ class AccelerationRepository { | |||||||
| 
 | 
 | ||||||
|     logger.debug(`Indexing accelerations completed`); |     logger.debug(`Indexing accelerations completed`); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * Delete accelerations from the database above blockHeight | ||||||
|  |    */ | ||||||
|  |   public async $deleteAccelerationsFrom(blockHeight: number): Promise<void> { | ||||||
|  |     logger.info(`Delete newer accelerations from height ${blockHeight} from the database`); | ||||||
|  |     try { | ||||||
|  |       const currentSyncedHeight = await this.$getLastSyncedHeight(); | ||||||
|  |       if (currentSyncedHeight >= blockHeight) { | ||||||
|  |         await DB.query(` | ||||||
|  |           UPDATE state | ||||||
|  |           SET number = ? | ||||||
|  |           WHERE name = 'last_acceleration_block' | ||||||
|  |         `, [blockHeight - 1]);
 | ||||||
|  |       } | ||||||
|  |       await DB.query(`DELETE FROM accelerations where height >= ${blockHeight}`); | ||||||
|  |     } catch (e) { | ||||||
|  |       logger.err('Cannot delete indexed accelerations. Reason: ' + (e instanceof Error ? e.message : e)); | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export default new AccelerationRepository(); | export default new AccelerationRepository(); | ||||||
|  | |||||||
| @ -39,10 +39,10 @@ | |||||||
|             </td> |             </td> | ||||||
|           </ng-container> |           </ng-container> | ||||||
|           <ng-container *ngIf="!pending"> |           <ng-container *ngIf="!pending"> | ||||||
|             <td *ngIf="acceleration.feePaid" class="fee text-right"> |             <td *ngIf="acceleration.boost != null" class="fee text-right"> | ||||||
|               {{ (acceleration.boost) | number }} <span class="symbol" i18n="shared.sat|sat">sat</span> |               {{ acceleration.boost | number }} <span class="symbol" i18n="shared.sat|sat">sat</span> | ||||||
|             </td> |             </td> | ||||||
|             <td *ngIf="!acceleration.feePaid" class="fee text-right"> |             <td *ngIf="acceleration.boost == null" class="fee text-right"> | ||||||
|               ~ |               ~ | ||||||
|             </td> |             </td> | ||||||
|             <td class="block text-right"> |             <td class="block text-right"> | ||||||
|  | |||||||
| @ -58,7 +58,7 @@ export class AccelerationsListComponent implements OnInit { | |||||||
|               } |               } | ||||||
|             } |             } | ||||||
|             for (const acc of accelerations) { |             for (const acc of accelerations) { | ||||||
|               acc.boost = acc.feePaid - acc.baseFee - acc.vsizeFee; |               acc.boost = acc.boostCost != null ? acc.boostCost : (acc.feePaid - acc.baseFee - acc.vsizeFee); | ||||||
|             } |             } | ||||||
|             if (this.widget) { |             if (this.widget) { | ||||||
|               return of(accelerations.slice(0, 6)); |               return of(accelerations.slice(0, 6)); | ||||||
|  | |||||||
| @ -116,15 +116,15 @@ export class AcceleratorDashboardComponent implements OnInit { | |||||||
|       switchMap(([accelerations, blocks]) => { |       switchMap(([accelerations, blocks]) => { | ||||||
|         const blockMap = {}; |         const blockMap = {}; | ||||||
|         for (const block of blocks) { |         for (const block of blocks) { | ||||||
|           blockMap[block.id] = block; |           blockMap[block.height] = block; | ||||||
|         } |         } | ||||||
|         const accelerationsByBlock: { [ hash: string ]: Acceleration[] } = {}; |         const accelerationsByBlock: { [ height: number ]: Acceleration[] } = {}; | ||||||
|         for (const acceleration of accelerations) { |         for (const acceleration of accelerations) { | ||||||
|           if (['completed_provisional', 'failed_provisional', 'completed'].includes(acceleration.status) && acceleration.pools.includes(blockMap[acceleration.blockHash]?.extras.pool.id)) { |           if (['completed_provisional', 'failed_provisional', 'completed'].includes(acceleration.status) && acceleration.pools.includes(blockMap[acceleration.blockHeight]?.extras.pool.id)) { | ||||||
|             if (!accelerationsByBlock[acceleration.blockHash]) { |             if (!accelerationsByBlock[acceleration.blockHeight]) { | ||||||
|               accelerationsByBlock[acceleration.blockHash] = []; |               accelerationsByBlock[acceleration.blockHeight] = []; | ||||||
|             } |             } | ||||||
|             accelerationsByBlock[acceleration.blockHash].push(acceleration); |             accelerationsByBlock[acceleration.blockHeight].push(acceleration); | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|         return of(blocks.slice(0, 6).map(block => { |         return of(blocks.slice(0, 6).map(block => { | ||||||
|  | |||||||
| @ -136,7 +136,7 @@ export class BlockPreviewComponent implements OnInit, OnDestroy { | |||||||
|                   return of(transactions); |                   return of(transactions); | ||||||
|                 }) |                 }) | ||||||
|               ), |               ), | ||||||
|             this.stateService.env.ACCELERATOR === true && block.height > 819500 ? this.servicesApiService.getAccelerationHistory$({ blockHash: block.id }) : of([]) |             this.stateService.env.ACCELERATOR === true && block.height > 819500 ? this.servicesApiService.getAccelerationHistory$({ blockHeight: block.height }) : of([]) | ||||||
|           ]); |           ]); | ||||||
|         } |         } | ||||||
|       ), |       ), | ||||||
|  | |||||||
| @ -345,7 +345,7 @@ export class BlockComponent implements OnInit, OnDestroy { | |||||||
|                 return of(null); |                 return of(null); | ||||||
|               }) |               }) | ||||||
|             ), |             ), | ||||||
|           this.stateService.env.ACCELERATOR === true && block.height > 819500 ? this.servicesApiService.getAccelerationHistory$({ blockHash: block.id }) : of([]) |           this.stateService.env.ACCELERATOR === true && block.height > 819500 ? this.servicesApiService.getAccelerationHistory$({ blockHeight: block.height }) : of([]) | ||||||
|         ]); |         ]); | ||||||
|       }) |       }) | ||||||
|     ) |     ) | ||||||
|  | |||||||
| @ -98,7 +98,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { | |||||||
|   fetchCpfp$ = new Subject<string>(); |   fetchCpfp$ = new Subject<string>(); | ||||||
|   fetchRbfHistory$ = new Subject<string>(); |   fetchRbfHistory$ = new Subject<string>(); | ||||||
|   fetchCachedTx$ = new Subject<string>(); |   fetchCachedTx$ = new Subject<string>(); | ||||||
|   fetchAcceleration$ = new Subject<string>(); |   fetchAcceleration$ = new Subject<number>(); | ||||||
|   fetchMiningInfo$ = new Subject<{ hash: string, height: number, txid: string }>(); |   fetchMiningInfo$ = new Subject<{ hash: string, height: number, txid: string }>(); | ||||||
|   isCached: boolean = false; |   isCached: boolean = false; | ||||||
|   now = Date.now(); |   now = Date.now(); | ||||||
| @ -288,8 +288,8 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { | |||||||
|       tap(() => { |       tap(() => { | ||||||
|         this.accelerationInfo = null; |         this.accelerationInfo = null; | ||||||
|       }), |       }), | ||||||
|       switchMap((blockHash: string) => { |       switchMap((blockHeight: number) => { | ||||||
|         return this.servicesApiService.getAccelerationHistory$({ blockHash }); |         return this.servicesApiService.getAccelerationHistory$({ blockHeight }); | ||||||
|       }), |       }), | ||||||
|       catchError(() => { |       catchError(() => { | ||||||
|         return of(null); |         return of(null); | ||||||
| @ -297,7 +297,10 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { | |||||||
|     ).subscribe((accelerationHistory) => { |     ).subscribe((accelerationHistory) => { | ||||||
|       for (const acceleration of accelerationHistory) { |       for (const acceleration of accelerationHistory) { | ||||||
|         if (acceleration.txid === this.txId && (acceleration.status === 'completed' || acceleration.status === 'completed_provisional')) { |         if (acceleration.txid === this.txId && (acceleration.status === 'completed' || acceleration.status === 'completed_provisional')) { | ||||||
|           acceleration.acceleratedFeeRate = Math.max(acceleration.effectiveFee, acceleration.effectiveFee + acceleration.feePaid - acceleration.baseFee - acceleration.vsizeFee) / acceleration.effectiveVsize; |           const boostCost = acceleration.boostCost || (acceleration.feePaid - acceleration.baseFee - acceleration.vsizeFee); | ||||||
|  |           acceleration.acceleratedFeeRate = Math.max(acceleration.effectiveFee, acceleration.effectiveFee + boostCost) / acceleration.effectiveVsize; | ||||||
|  |           acceleration.boost = boostCost; | ||||||
|  | 
 | ||||||
|           this.accelerationInfo = acceleration; |           this.accelerationInfo = acceleration; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| @ -482,7 +485,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { | |||||||
|               this.getTransactionTime(); |               this.getTransactionTime(); | ||||||
|             } |             } | ||||||
|           } else { |           } else { | ||||||
|             this.fetchAcceleration$.next(tx.status.block_hash); |             this.fetchAcceleration$.next(tx.status.block_height); | ||||||
|             this.fetchMiningInfo$.next({ hash: tx.status.block_hash, height: tx.status.block_height, txid: tx.txid }); |             this.fetchMiningInfo$.next({ hash: tx.status.block_hash, height: tx.status.block_height, txid: tx.txid }); | ||||||
|             this.transactionTime = 0; |             this.transactionTime = 0; | ||||||
|           } |           } | ||||||
| @ -544,7 +547,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { | |||||||
|         } else { |         } else { | ||||||
|           this.audioService.playSound('magic'); |           this.audioService.playSound('magic'); | ||||||
|         } |         } | ||||||
|         this.fetchAcceleration$.next(block.id); |         this.fetchAcceleration$.next(block.height); | ||||||
|         this.fetchMiningInfo$.next({ hash: block.id, height: block.height, txid: this.tx.txid }); |         this.fetchMiningInfo$.next({ hash: block.id, height: block.height, txid: this.tx.txid }); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
|  | |||||||
| @ -396,6 +396,9 @@ export interface Acceleration { | |||||||
| 
 | 
 | ||||||
|   acceleratedFeeRate?: number; |   acceleratedFeeRate?: number; | ||||||
|   boost?: number; |   boost?: number; | ||||||
|  | 
 | ||||||
|  |   boostCost?: number; | ||||||
|  |   boostRate?: number; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface AccelerationHistoryParams { | export interface AccelerationHistoryParams { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user