Merge branch 'master' into master
This commit is contained in:
		
						commit
						9ca41a7608
					
				| @ -68,7 +68,8 @@ | |||||||
|     "DATABASE": "mempool", |     "DATABASE": "mempool", | ||||||
|     "USERNAME": "mempool", |     "USERNAME": "mempool", | ||||||
|     "PASSWORD": "mempool", |     "PASSWORD": "mempool", | ||||||
|     "TIMEOUT": 180000 |     "TIMEOUT": 180000, | ||||||
|  |     "PID_DIR": "" | ||||||
|   }, |   }, | ||||||
|   "SYSLOG": { |   "SYSLOG": { | ||||||
|     "ENABLED": true, |     "ENABLED": true, | ||||||
|  | |||||||
| @ -69,6 +69,7 @@ | |||||||
|     "DATABASE": "__DATABASE_DATABASE__", |     "DATABASE": "__DATABASE_DATABASE__", | ||||||
|     "USERNAME": "__DATABASE_USERNAME__", |     "USERNAME": "__DATABASE_USERNAME__", | ||||||
|     "PASSWORD": "__DATABASE_PASSWORD__", |     "PASSWORD": "__DATABASE_PASSWORD__", | ||||||
|  |     "PID_DIR": "__DATABASE_PID_FILE__", | ||||||
|     "TIMEOUT": 3000 |     "TIMEOUT": 3000 | ||||||
|   }, |   }, | ||||||
|   "SYSLOG": { |   "SYSLOG": { | ||||||
|  | |||||||
| @ -84,6 +84,7 @@ describe('Mempool Backend Config', () => { | |||||||
|         USERNAME: 'mempool', |         USERNAME: 'mempool', | ||||||
|         PASSWORD: 'mempool', |         PASSWORD: 'mempool', | ||||||
|         TIMEOUT: 180000, |         TIMEOUT: 180000, | ||||||
|  |         PID_DIR: '' | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|       expect(config.SYSLOG).toStrictEqual({ |       expect(config.SYSLOG).toStrictEqual({ | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ import cpfpRepository from '../repositories/CpfpRepository'; | |||||||
| import { RowDataPacket } from 'mysql2'; | import { RowDataPacket } from 'mysql2'; | ||||||
| 
 | 
 | ||||||
| class DatabaseMigration { | class DatabaseMigration { | ||||||
|   private static currentVersion = 65; |   private static currentVersion = 66; | ||||||
|   private queryTimeout = 3600_000; |   private queryTimeout = 3600_000; | ||||||
|   private statisticsAddedIndexed = false; |   private statisticsAddedIndexed = false; | ||||||
|   private uniqueLogs: string[] = []; |   private uniqueLogs: string[] = []; | ||||||
| @ -553,6 +553,11 @@ class DatabaseMigration { | |||||||
|       await this.$executeQuery('ALTER TABLE `blocks_audits` ADD accelerated_txs JSON DEFAULT "[]"'); |       await this.$executeQuery('ALTER TABLE `blocks_audits` ADD accelerated_txs JSON DEFAULT "[]"'); | ||||||
|       await this.updateToSchemaVersion(65); |       await this.updateToSchemaVersion(65); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     if (databaseSchemaVersion < 66) { | ||||||
|  |       await this.$executeQuery('ALTER TABLE `statistics` ADD min_fee FLOAT UNSIGNED DEFAULT NULL'); | ||||||
|  |       await this.updateToSchemaVersion(66); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ class StatisticsApi { | |||||||
|               mempool_byte_weight, |               mempool_byte_weight, | ||||||
|               fee_data, |               fee_data, | ||||||
|               total_fee, |               total_fee, | ||||||
|  |               min_fee, | ||||||
|               vsize_1, |               vsize_1, | ||||||
|               vsize_2, |               vsize_2, | ||||||
|               vsize_3, |               vsize_3, | ||||||
| @ -54,7 +55,7 @@ class StatisticsApi { | |||||||
|               vsize_1800, |               vsize_1800, | ||||||
|               vsize_2000 |               vsize_2000 | ||||||
|             ) |             ) | ||||||
|             VALUES (NOW(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |             VALUES (NOW(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)`;
 |                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)`;
 | ||||||
|       const [result]: any = await DB.query(query); |       const [result]: any = await DB.query(query); | ||||||
|       return result.insertId; |       return result.insertId; | ||||||
| @ -73,6 +74,7 @@ class StatisticsApi { | |||||||
|               mempool_byte_weight, |               mempool_byte_weight, | ||||||
|               fee_data, |               fee_data, | ||||||
|               total_fee, |               total_fee, | ||||||
|  |               min_fee, | ||||||
|               vsize_1, |               vsize_1, | ||||||
|               vsize_2, |               vsize_2, | ||||||
|               vsize_3, |               vsize_3, | ||||||
| @ -112,7 +114,7 @@ class StatisticsApi { | |||||||
|               vsize_1800, |               vsize_1800, | ||||||
|               vsize_2000 |               vsize_2000 | ||||||
|             ) |             ) | ||||||
|             VALUES (${statistics.added}, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, |             VALUES (${statistics.added}, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, | ||||||
|                ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
 |                ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
 | ||||||
| 
 | 
 | ||||||
|       const params: (string | number)[] = [ |       const params: (string | number)[] = [ | ||||||
| @ -122,6 +124,7 @@ class StatisticsApi { | |||||||
|         statistics.mempool_byte_weight, |         statistics.mempool_byte_weight, | ||||||
|         statistics.fee_data, |         statistics.fee_data, | ||||||
|         statistics.total_fee, |         statistics.total_fee, | ||||||
|  |         statistics.min_fee, | ||||||
|         statistics.vsize_1, |         statistics.vsize_1, | ||||||
|         statistics.vsize_2, |         statistics.vsize_2, | ||||||
|         statistics.vsize_3, |         statistics.vsize_3, | ||||||
| @ -173,6 +176,7 @@ class StatisticsApi { | |||||||
|       UNIX_TIMESTAMP(added) as added, |       UNIX_TIMESTAMP(added) as added, | ||||||
|       CAST(avg(unconfirmed_transactions) as DOUBLE) as unconfirmed_transactions, |       CAST(avg(unconfirmed_transactions) as DOUBLE) as unconfirmed_transactions, | ||||||
|       CAST(avg(vbytes_per_second) as DOUBLE) as vbytes_per_second, |       CAST(avg(vbytes_per_second) as DOUBLE) as vbytes_per_second, | ||||||
|  |       CAST(avg(min_fee) as DOUBLE) as min_fee, | ||||||
|       CAST(avg(vsize_1) as DOUBLE) as vsize_1, |       CAST(avg(vsize_1) as DOUBLE) as vsize_1, | ||||||
|       CAST(avg(vsize_2) as DOUBLE) as vsize_2, |       CAST(avg(vsize_2) as DOUBLE) as vsize_2, | ||||||
|       CAST(avg(vsize_3) as DOUBLE) as vsize_3, |       CAST(avg(vsize_3) as DOUBLE) as vsize_3, | ||||||
| @ -222,6 +226,7 @@ class StatisticsApi { | |||||||
|       UNIX_TIMESTAMP(added) as added, |       UNIX_TIMESTAMP(added) as added, | ||||||
|       CAST(avg(unconfirmed_transactions) as DOUBLE) as unconfirmed_transactions, |       CAST(avg(unconfirmed_transactions) as DOUBLE) as unconfirmed_transactions, | ||||||
|       CAST(avg(vbytes_per_second) as DOUBLE) as vbytes_per_second, |       CAST(avg(vbytes_per_second) as DOUBLE) as vbytes_per_second, | ||||||
|  |       CAST(avg(min_fee) as DOUBLE) as min_fee, | ||||||
|       vsize_1, |       vsize_1, | ||||||
|       vsize_2, |       vsize_2, | ||||||
|       vsize_3, |       vsize_3, | ||||||
| @ -407,6 +412,7 @@ class StatisticsApi { | |||||||
|         vbytes_per_second: s.vbytes_per_second, |         vbytes_per_second: s.vbytes_per_second, | ||||||
|         mempool_byte_weight: s.mempool_byte_weight, |         mempool_byte_weight: s.mempool_byte_weight, | ||||||
|         total_fee: s.total_fee, |         total_fee: s.total_fee, | ||||||
|  |         min_fee: s.min_fee, | ||||||
|         vsizes: [ |         vsizes: [ | ||||||
|           s.vsize_1, |           s.vsize_1, | ||||||
|           s.vsize_2, |           s.vsize_2, | ||||||
|  | |||||||
| @ -89,6 +89,9 @@ class Statistics { | |||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  |     // get minFee and convert to sats/vb
 | ||||||
|  |     const minFee = memPool.getMempoolInfo().mempoolminfee * 100000; | ||||||
|  | 
 | ||||||
|     try { |     try { | ||||||
|       const insertId = await statisticsApi.$create({ |       const insertId = await statisticsApi.$create({ | ||||||
|         added: 'NOW()', |         added: 'NOW()', | ||||||
| @ -98,6 +101,7 @@ class Statistics { | |||||||
|         mempool_byte_weight: totalWeight, |         mempool_byte_weight: totalWeight, | ||||||
|         total_fee: totalFee, |         total_fee: totalFee, | ||||||
|         fee_data: '', |         fee_data: '', | ||||||
|  |         min_fee: minFee, | ||||||
|         vsize_1: weightVsizeFees['1'] || 0, |         vsize_1: weightVsizeFees['1'] || 0, | ||||||
|         vsize_2: weightVsizeFees['2'] || 0, |         vsize_2: weightVsizeFees['2'] || 0, | ||||||
|         vsize_3: weightVsizeFees['3'] || 0, |         vsize_3: weightVsizeFees['3'] || 0, | ||||||
|  | |||||||
| @ -93,6 +93,7 @@ interface IConfig { | |||||||
|     USERNAME: string; |     USERNAME: string; | ||||||
|     PASSWORD: string; |     PASSWORD: string; | ||||||
|     TIMEOUT: number; |     TIMEOUT: number; | ||||||
|  |     PID_DIR: string; | ||||||
|   }; |   }; | ||||||
|   SYSLOG: { |   SYSLOG: { | ||||||
|     ENABLED: boolean; |     ENABLED: boolean; | ||||||
| @ -219,6 +220,7 @@ const defaults: IConfig = { | |||||||
|     'USERNAME': 'mempool', |     'USERNAME': 'mempool', | ||||||
|     'PASSWORD': 'mempool', |     'PASSWORD': 'mempool', | ||||||
|     'TIMEOUT': 180000, |     'TIMEOUT': 180000, | ||||||
|  |     'PID_DIR': '', | ||||||
|   }, |   }, | ||||||
|   'SYSLOG': { |   'SYSLOG': { | ||||||
|     'ENABLED': true, |     'ENABLED': true, | ||||||
|  | |||||||
| @ -1,3 +1,5 @@ | |||||||
|  | import * as fs from 'fs'; | ||||||
|  | import path from 'path'; | ||||||
| import config from './config'; | import config from './config'; | ||||||
| import { createPool, Pool, PoolConnection } from 'mysql2/promise'; | import { createPool, Pool, PoolConnection } from 'mysql2/promise'; | ||||||
| import logger from './logger'; | import logger from './logger'; | ||||||
| @ -101,6 +103,33 @@ import { FieldPacket, OkPacket, PoolOptions, ResultSetHeader, RowDataPacket } fr | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   public getPidLock(): boolean { | ||||||
|  |     const filePath = path.join(config.DATABASE.PID_DIR || __dirname, `/mempool-${config.DATABASE.DATABASE}.pid`); | ||||||
|  |     if (fs.existsSync(filePath)) { | ||||||
|  |       const pid = fs.readFileSync(filePath).toString(); | ||||||
|  |       if (pid !== `${process.pid}`) { | ||||||
|  |         const msg = `Already running on PID ${pid} (or pid file '${filePath}' is stale)`; | ||||||
|  |         logger.err(msg); | ||||||
|  |         throw new Error(msg); | ||||||
|  |       } else { | ||||||
|  |         return true; | ||||||
|  |       } | ||||||
|  |     } else { | ||||||
|  |       fs.writeFileSync(filePath, `${process.pid}`); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public releasePidLock(): void { | ||||||
|  |     const filePath = path.join(config.DATABASE.PID_DIR || __dirname, `/mempool-${config.DATABASE.DATABASE}.pid`); | ||||||
|  |     if (fs.existsSync(filePath)) { | ||||||
|  |       const pid = fs.readFileSync(filePath).toString(); | ||||||
|  |       if (pid === `${process.pid}`) { | ||||||
|  |         fs.unlinkSync(filePath); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   private async getPool(): Promise<Pool> { |   private async getPool(): Promise<Pool> { | ||||||
|     if (this.pool === null) { |     if (this.pool === null) { | ||||||
|       this.pool = createPool(this.poolConfig); |       this.pool = createPool(this.poolConfig); | ||||||
|  | |||||||
| @ -91,11 +91,18 @@ class Server { | |||||||
|   async startServer(worker = false): Promise<void> { |   async startServer(worker = false): Promise<void> { | ||||||
|     logger.notice(`Starting Mempool Server${worker ? ' (worker)' : ''}... (${backendInfo.getShortCommitHash()})`); |     logger.notice(`Starting Mempool Server${worker ? ' (worker)' : ''}... (${backendInfo.getShortCommitHash()})`); | ||||||
| 
 | 
 | ||||||
|  |     // Register cleanup listeners for exit events
 | ||||||
|  |     ['exit', 'SIGINT', 'SIGTERM', 'SIGUSR1', 'SIGUSR2', 'uncaughtException', 'unhandledRejection'].forEach(event => { | ||||||
|  |       process.on(event, () => { this.onExit(event); }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|     if (config.MEMPOOL.BACKEND === 'esplora') { |     if (config.MEMPOOL.BACKEND === 'esplora') { | ||||||
|       bitcoinApi.startHealthChecks(); |       bitcoinApi.startHealthChecks(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (config.DATABASE.ENABLED) { |     if (config.DATABASE.ENABLED) { | ||||||
|  |       DB.getPidLock(); | ||||||
|  | 
 | ||||||
|       await DB.checkDbConnection(); |       await DB.checkDbConnection(); | ||||||
|       try { |       try { | ||||||
|         if (process.env.npm_config_reindex_blocks === 'true') { // Re-index requests
 |         if (process.env.npm_config_reindex_blocks === 'true') { // Re-index requests
 | ||||||
| @ -306,6 +313,15 @@ class Server { | |||||||
|       this.lastHeapLogTime = now; |       this.lastHeapLogTime = now; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   onExit(exitEvent): void { | ||||||
|  |     if (config.DATABASE.ENABLED) { | ||||||
|  |       DB.releasePidLock(); | ||||||
|  |     } | ||||||
|  |     process.exit(0); | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| ((): Server => new Server())(); | ((): Server => new Server())(); | ||||||
|  | |||||||
| @ -300,6 +300,7 @@ export interface Statistic { | |||||||
|   total_fee: number; |   total_fee: number; | ||||||
|   mempool_byte_weight: number; |   mempool_byte_weight: number; | ||||||
|   fee_data: string; |   fee_data: string; | ||||||
|  |   min_fee: number; | ||||||
| 
 | 
 | ||||||
|   vsize_1: number; |   vsize_1: number; | ||||||
|   vsize_2: number; |   vsize_2: number; | ||||||
| @ -346,6 +347,7 @@ export interface OptimizedStatistic { | |||||||
|   vbytes_per_second: number; |   vbytes_per_second: number; | ||||||
|   total_fee: number; |   total_fee: number; | ||||||
|   mempool_byte_weight: number; |   mempool_byte_weight: number; | ||||||
|  |   min_fee: number; | ||||||
|   vsizes: number[]; |   vsizes: number[]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -69,7 +69,8 @@ | |||||||
|     "DATABASE": "__DATABASE_DATABASE__", |     "DATABASE": "__DATABASE_DATABASE__", | ||||||
|     "USERNAME": "__DATABASE_USERNAME__", |     "USERNAME": "__DATABASE_USERNAME__", | ||||||
|     "PASSWORD": "__DATABASE_PASSWORD__", |     "PASSWORD": "__DATABASE_PASSWORD__", | ||||||
|     "TIMEOUT": __DATABASE_TIMEOUT__ |     "TIMEOUT": __DATABASE_TIMEOUT__, | ||||||
|  |     "PID_DIR": "__DATABASE_PID_DIR__", | ||||||
|   }, |   }, | ||||||
|   "SYSLOG": { |   "SYSLOG": { | ||||||
|     "ENABLED": __SYSLOG_ENABLED__, |     "ENABLED": __SYSLOG_ENABLED__, | ||||||
|  | |||||||
| @ -71,6 +71,7 @@ __DATABASE_DATABASE__=${DATABASE_DATABASE:=mempool} | |||||||
| __DATABASE_USERNAME__=${DATABASE_USERNAME:=mempool} | __DATABASE_USERNAME__=${DATABASE_USERNAME:=mempool} | ||||||
| __DATABASE_PASSWORD__=${DATABASE_PASSWORD:=mempool} | __DATABASE_PASSWORD__=${DATABASE_PASSWORD:=mempool} | ||||||
| __DATABASE_TIMEOUT__=${DATABASE_TIMEOUT:=180000} | __DATABASE_TIMEOUT__=${DATABASE_TIMEOUT:=180000} | ||||||
|  | __DATABASE_PID_DIR__=${DATABASE_PID_DIR:=""} | ||||||
| 
 | 
 | ||||||
| # SYSLOG | # SYSLOG | ||||||
| __SYSLOG_ENABLED__=${SYSLOG_ENABLED:=false} | __SYSLOG_ENABLED__=${SYSLOG_ENABLED:=false} | ||||||
| @ -209,6 +210,7 @@ sed -i "s!__DATABASE_DATABASE__!${__DATABASE_DATABASE__}!g" mempool-config.json | |||||||
| sed -i "s!__DATABASE_USERNAME__!${__DATABASE_USERNAME__}!g" mempool-config.json | sed -i "s!__DATABASE_USERNAME__!${__DATABASE_USERNAME__}!g" mempool-config.json | ||||||
| sed -i "s!__DATABASE_PASSWORD__!${__DATABASE_PASSWORD__}!g" mempool-config.json | sed -i "s!__DATABASE_PASSWORD__!${__DATABASE_PASSWORD__}!g" mempool-config.json | ||||||
| sed -i "s!__DATABASE_TIMEOUT__!${__DATABASE_TIMEOUT__}!g" mempool-config.json | sed -i "s!__DATABASE_TIMEOUT__!${__DATABASE_TIMEOUT__}!g" mempool-config.json | ||||||
|  | sed -i "s!__DATABASE_PID_DIR__!${__DATABASE_PID_DIR__}!g" mempool-config.json | ||||||
| 
 | 
 | ||||||
| sed -i "s!__SYSLOG_ENABLED__!${__SYSLOG_ENABLED__}!g" mempool-config.json | sed -i "s!__SYSLOG_ENABLED__!${__SYSLOG_ENABLED__}!g" mempool-config.json | ||||||
| sed -i "s!__SYSLOG_HOST__!${__SYSLOG_HOST__}!g" mempool-config.json | sed -i "s!__SYSLOG_HOST__!${__SYSLOG_HOST__}!g" mempool-config.json | ||||||
|  | |||||||
| @ -37,6 +37,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges, On | |||||||
|   }; |   }; | ||||||
|   windowPreference: string; |   windowPreference: string; | ||||||
|   chartInstance: any = undefined; |   chartInstance: any = undefined; | ||||||
|  |   MA: number[][] = []; | ||||||
|   weightMode: boolean = false; |   weightMode: boolean = false; | ||||||
|   rateUnitSub: Subscription; |   rateUnitSub: Subscription; | ||||||
| 
 | 
 | ||||||
| @ -62,6 +63,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges, On | |||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     this.windowPreference = this.windowPreferenceOverride ? this.windowPreferenceOverride : this.storageService.getValue('graphWindowPreference'); |     this.windowPreference = this.windowPreferenceOverride ? this.windowPreferenceOverride : this.storageService.getValue('graphWindowPreference'); | ||||||
|  |     this.MA = this.calculateMA(this.data.series[0]); | ||||||
|     this.mountChart(); |     this.mountChart(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -72,7 +74,101 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges, On | |||||||
|     this.isLoading = false; |     this.isLoading = false; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   /// calculate the moving average of maData
 | ||||||
|  |   calculateMA(maData): number[][] { | ||||||
|  |     //update const variables that are not changed
 | ||||||
|  |     const ma: number[][] = []; | ||||||
|  |     let sum = 0; | ||||||
|  |     let i = 0; | ||||||
|  |     const len = maData.length; | ||||||
|  | 
 | ||||||
|  |     //Adjust window length based on the length of the data
 | ||||||
|  |     //5% appeared as a good amount from tests
 | ||||||
|  |     //TODO: make this a text box in the UI
 | ||||||
|  |     const maWindowLen = Math.ceil(len * 0.05); | ||||||
|  | 
 | ||||||
|  |     //calculate the center of the moving average window
 | ||||||
|  |     const center = Math.floor(maWindowLen / 2); | ||||||
|  | 
 | ||||||
|  |     //calculate the centered moving average
 | ||||||
|  |     for (i = center; i < len - center; i++) { | ||||||
|  |       sum = 0; | ||||||
|  |       //build out ma as we loop through the data
 | ||||||
|  |       ma[i] = []; | ||||||
|  |       ma[i].push(maData[i][0]); | ||||||
|  |       for (let j = i - center; j <= i + center; j++) { | ||||||
|  |         sum += maData[j][1]; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       ma[i].push(sum / maWindowLen); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //return the moving average array
 | ||||||
|  |     return ma; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   mountChart(): void { |   mountChart(): void { | ||||||
|  |     //create an array for the echart series
 | ||||||
|  |     //similar to how it is done in mempool-graph.component.ts
 | ||||||
|  |     const seriesGraph = []; | ||||||
|  |     seriesGraph.push({ | ||||||
|  |       zlevel: 0, | ||||||
|  |       name: 'data', | ||||||
|  |       data: this.data.series[0], | ||||||
|  |       type: 'line', | ||||||
|  |       smooth: false, | ||||||
|  |       showSymbol: false, | ||||||
|  |       symbol: 'none', | ||||||
|  |       lineStyle: { | ||||||
|  |         width: 3, | ||||||
|  |       }, | ||||||
|  |       markLine: { | ||||||
|  |         silent: true, | ||||||
|  |         symbol: 'none', | ||||||
|  |         lineStyle: { | ||||||
|  |           color: '#fff', | ||||||
|  |           opacity: 1, | ||||||
|  |           width: 2, | ||||||
|  |         }, | ||||||
|  |         data: [{ | ||||||
|  |           yAxis: 1667, | ||||||
|  |           label: { | ||||||
|  |             show: false, | ||||||
|  |             color: '#ffffff', | ||||||
|  |           } | ||||||
|  |         }], | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       zlevel: 0, | ||||||
|  |       name: 'MA', | ||||||
|  |       data: this.MA, | ||||||
|  |       type: 'line', | ||||||
|  |       smooth: false, | ||||||
|  |       showSymbol: false, | ||||||
|  |       symbol: 'none', | ||||||
|  |       lineStyle: { | ||||||
|  |         width: 1, | ||||||
|  |         color: "white", | ||||||
|  |       }, | ||||||
|  |       markLine: { | ||||||
|  |         silent: true, | ||||||
|  |         symbol: 'none', | ||||||
|  |         lineStyle: { | ||||||
|  |           color: '#fff', | ||||||
|  |           opacity: 1, | ||||||
|  |           width: 2, | ||||||
|  |         }, | ||||||
|  |         data: [{ | ||||||
|  |           yAxis: 1667, | ||||||
|  |           label: { | ||||||
|  |             show: false, | ||||||
|  |             color: '#ffffff', | ||||||
|  |           } | ||||||
|  |         }], | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|     this.mempoolStatsChartOption = { |     this.mempoolStatsChartOption = { | ||||||
|       grid: { |       grid: { | ||||||
|         height: this.height, |         height: this.height, | ||||||
| @ -126,12 +222,16 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges, On | |||||||
|           const colorSpan = (color: string) => `<span class="indicator" style="background-color: ` + color + `"></span>`; |           const colorSpan = (color: string) => `<span class="indicator" style="background-color: ` + color + `"></span>`; | ||||||
|           let itemFormatted = '<div class="title">' + axisValueLabel + '</div>'; |           let itemFormatted = '<div class="title">' + axisValueLabel + '</div>'; | ||||||
|           params.map((item: any, index: number) => { |           params.map((item: any, index: number) => { | ||||||
|             if (index < 26) { | 
 | ||||||
|               itemFormatted += `<div class="item">
 |             //Do no include MA in tooltip legend!
 | ||||||
|                 <div class="indicator-container">${colorSpan(item.color)}</div> |             if (item.seriesName !== 'MA') { | ||||||
|                 <div class="grow"></div> |               if (index < 26) { | ||||||
|                 <div class="value">${formatNumber(this.weightMode ? item.value[1] * 4 : item.value[1], this.locale, '1.0-0')} <span class="symbol">${this.weightMode ? 'WU' : 'vB'}/s</span></div> |                 itemFormatted += `<div class="item">
 | ||||||
|               </div>`;
 |                   <div class="indicator-container">${colorSpan(item.color)}</div> | ||||||
|  |                   <div class="grow"></div> | ||||||
|  |                   <div class="value">${formatNumber(item.value[1], this.locale, '1.0-0')}<span class="symbol">vB/s</span></div> | ||||||
|  |                 </div>`;
 | ||||||
|  |               } | ||||||
|             } |             } | ||||||
|           }); |           }); | ||||||
|           return `<div class="tx-wrapper-tooltip-chart ${(this.template === 'advanced') ? 'tx-wrapper-tooltip-chart-advanced' : ''}">${itemFormatted}</div>`; |           return `<div class="tx-wrapper-tooltip-chart ${(this.template === 'advanced') ? 'tx-wrapper-tooltip-chart-advanced' : ''}">${itemFormatted}</div>`; | ||||||
| @ -171,35 +271,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges, On | |||||||
|           } |           } | ||||||
|         } |         } | ||||||
|       }, |       }, | ||||||
|       series: [ |       series: seriesGraph, | ||||||
|         { |  | ||||||
|           zlevel: 0, |  | ||||||
|           data: this.data.series[0], |  | ||||||
|           type: 'line', |  | ||||||
|           smooth: false, |  | ||||||
|           showSymbol: false, |  | ||||||
|           symbol: 'none', |  | ||||||
|           lineStyle: { |  | ||||||
|             width: 3, |  | ||||||
|           }, |  | ||||||
|           markLine: { |  | ||||||
|             silent: true, |  | ||||||
|             symbol: 'none', |  | ||||||
|             lineStyle: { |  | ||||||
|               color: '#fff', |  | ||||||
|               opacity: 1, |  | ||||||
|               width: 2, |  | ||||||
|             }, |  | ||||||
|             data: [{ |  | ||||||
|               yAxis: 1667, |  | ||||||
|               label: { |  | ||||||
|                 show: false, |  | ||||||
|                 color: '#ffffff', |  | ||||||
|               } |  | ||||||
|             }], |  | ||||||
|           } |  | ||||||
|         }, |  | ||||||
|       ], |  | ||||||
|       visualMap: { |       visualMap: { | ||||||
|         show: false, |         show: false, | ||||||
|         top: 50, |         top: 50, | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user