From 3ceab1493ece2b57d51923ec2339fe57c75f21dc Mon Sep 17 00:00:00 2001 From: Antoni Spaanderman <56turtle56@gmail.com> Date: Sun, 23 Jan 2022 12:20:32 +0100 Subject: [PATCH 01/41] add log priority option for stdout log --- backend/mempool-config.sample.json | 3 ++- backend/src/config.ts | 4 +++- backend/src/logger.ts | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index ea656c1de..d93a326f4 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -14,7 +14,8 @@ "MEMPOOL_BLOCKS_AMOUNT": 8, "PRICE_FEED_UPDATE_INTERVAL": 3600, "USE_SECOND_NODE_FOR_MINFEE": false, - "EXTERNAL_ASSETS": [] + "EXTERNAL_ASSETS": [], + "STDOUT_LOG_MIN_PRIORITY": "debug" }, "CORE_RPC": { "HOST": "127.0.0.1", diff --git a/backend/src/config.ts b/backend/src/config.ts index 4c2888834..617965d5a 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -17,6 +17,7 @@ interface IConfig { PRICE_FEED_UPDATE_INTERVAL: number; USE_SECOND_NODE_FOR_MINFEE: boolean; EXTERNAL_ASSETS: string[]; + STDOUT_LOG_MIN_PRIORITY: 'emerg' | 'alert' | 'crit' | 'err' | 'warn' | 'notice' | 'info' | 'debug'; }; ESPLORA: { REST_API_URL: string; @@ -50,7 +51,7 @@ interface IConfig { ENABLED: boolean; HOST: string; PORT: number; - MIN_PRIORITY: 'emerg' | 'alert' | 'crit' | 'err' |'warn' | 'notice' | 'info' | 'debug'; + MIN_PRIORITY: 'emerg' | 'alert' | 'crit' | 'err' | 'warn' | 'notice' | 'info' | 'debug'; FACILITY: string; }; STATISTICS: { @@ -80,6 +81,7 @@ const defaults: IConfig = { 'PRICE_FEED_UPDATE_INTERVAL': 3600, 'USE_SECOND_NODE_FOR_MINFEE': false, 'EXTERNAL_ASSETS': [], + 'STDOUT_LOG_MIN_PRIORITY': 'debug', }, 'ESPLORA': { 'REST_API_URL': 'http://127.0.0.1:3000', diff --git a/backend/src/logger.ts b/backend/src/logger.ts index 4e8c5ea11..43373e043 100644 --- a/backend/src/logger.ts +++ b/backend/src/logger.ts @@ -97,6 +97,9 @@ class Logger { syslogmsg = `<${(Logger.facilities[config.SYSLOG.FACILITY] * 8 + prionum)}> ${this.name}[${process.pid}]: ${priority.toUpperCase()}${network} ${msg}`; this.syslog(syslogmsg); } + if (Logger.priorities[priority] > Logger.priorities[config.MEMPOOL.STDOUT_LOG_MIN_PRIORITY]) { + return; + } if (priority === 'warning') { priority = 'warn'; } From 9f0b09295df10b91b1545514c94261f67ccdc025 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Fri, 4 Feb 2022 12:51:45 +0900 Subject: [PATCH 02/41] Move our custom fields to a BlockExtension sub object of the IEsploraApi.Block interface --- backend/src/api/blocks.ts | 30 +++++++++++++++---- backend/src/api/websocket-handler.ts | 4 ++- backend/src/mempool.interfaces.ts | 7 ++++- backend/src/repositories/BlocksRepository.ts | 15 ++++++++-- .../app/components/block/block.component.html | 4 +-- .../app/components/block/block.component.ts | 25 ++++++++-------- .../blockchain-blocks.component.html | 4 +-- .../blockchain-blocks.component.ts | 24 +++++++-------- .../mempool-blocks.component.ts | 2 +- .../transaction/transaction.component.ts | 6 ++-- .../transactions-list.component.ts | 5 ++-- .../tx-fee-rating/tx-fee-rating.component.ts | 13 ++++---- .../src/app/dashboard/dashboard.component.ts | 7 ++--- .../src/app/interfaces/electrs.interface.ts | 8 ----- .../src/app/interfaces/node-api.interface.ts | 16 ++++++++++ .../src/app/interfaces/websocket.interface.ts | 7 +++-- .../src/app/services/electrs-api.service.ts | 11 +++---- frontend/src/app/services/state.service.ts | 8 ++--- .../src/app/services/websocket.service.ts | 5 ++-- 19 files changed, 124 insertions(+), 77 deletions(-) diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index 22bea2480..081442567 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -96,14 +96,20 @@ class Blocks { */ private getBlockExtended(block: IEsploraApi.Block, transactions: TransactionExtended[]): BlockExtended { const blockExtended: BlockExtended = Object.assign({}, block); - blockExtended.reward = transactions[0].vout.reduce((acc, curr) => acc + curr.value, 0); - blockExtended.coinbaseTx = transactionUtils.stripCoinbaseTransaction(transactions[0]); + + blockExtended.extra = { + reward: transactions[0].vout.reduce((acc, curr) => acc + curr.value, 0), + coinbaseTx: transactionUtils.stripCoinbaseTransaction(transactions[0]), + }; const transactionsTmp = [...transactions]; transactionsTmp.shift(); transactionsTmp.sort((a, b) => b.effectiveFeePerVsize - a.effectiveFeePerVsize); - blockExtended.medianFee = transactionsTmp.length > 0 ? Common.median(transactionsTmp.map((tx) => tx.effectiveFeePerVsize)) : 0; - blockExtended.feeRange = transactionsTmp.length > 0 ? Common.getFeesInRange(transactionsTmp, 8) : [0, 0]; + + blockExtended.extra.medianFee = transactionsTmp.length > 0 ? + Common.median(transactionsTmp.map((tx) => tx.effectiveFeePerVsize)) : 0; + blockExtended.extra.feeRange = transactionsTmp.length > 0 ? + Common.getFeesInRange(transactionsTmp, 8) : [0, 0]; return blockExtended; } @@ -197,7 +203,14 @@ class Blocks { const block = await bitcoinApi.$getBlock(blockHash); const transactions = await this.$getTransactionsExtended(blockHash, block.height, true); const blockExtended = this.getBlockExtended(block, transactions); - const miner = await this.$findBlockMiner(blockExtended.coinbaseTx); + + let miner: PoolTag; + if (blockExtended?.extra?.coinbaseTx) { + miner = await this.$findBlockMiner(blockExtended.extra.coinbaseTx); + } else { + miner = await poolsRepository.$getUnknownPool(); + } + const coinbase: IEsploraApi.Transaction = await bitcoinApi.$getRawTransaction(transactions[0].txid, true); await blocksRepository.$saveBlockInDatabase(blockExtended, blockHash, coinbase.hex, miner); } catch (e) { @@ -262,7 +275,12 @@ class Blocks { const coinbase: IEsploraApi.Transaction = await bitcoinApi.$getRawTransaction(transactions[0].txid, true); if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK) === true) { - const miner = await this.$findBlockMiner(blockExtended.coinbaseTx); + let miner: PoolTag; + if (blockExtended?.extra?.coinbaseTx) { + miner = await this.$findBlockMiner(blockExtended.extra.coinbaseTx); + } else { + miner = await poolsRepository.$getUnknownPool(); + } await blocksRepository.$saveBlockInDatabase(blockExtended, blockHash, coinbase.hex, miner); } diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index 7891a606a..5478445df 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -380,7 +380,9 @@ class WebsocketHandler { mBlocks = mempoolBlocks.getMempoolBlocks(); } - block.matchRate = matchRate; + if (block.extra) { + block.extra.matchRate = matchRate; + } this.wss.clients.forEach((client) => { if (client.readyState !== WebSocket.OPEN) { diff --git a/backend/src/mempool.interfaces.ts b/backend/src/mempool.interfaces.ts index 5fb83d792..17509b814 100644 --- a/backend/src/mempool.interfaces.ts +++ b/backend/src/mempool.interfaces.ts @@ -76,7 +76,8 @@ export interface TransactionStripped { vsize: number; value: number; } -export interface BlockExtended extends IEsploraApi.Block { + +export interface BlockExtension { medianFee?: number; feeRange?: number[]; reward?: number; @@ -84,6 +85,10 @@ export interface BlockExtended extends IEsploraApi.Block { matchRate?: number; } +export interface BlockExtended extends IEsploraApi.Block { + extra?: BlockExtension; +} + export interface TransactionMinerInfo { vin: VinStrippedToScriptsig[]; vout: VoutStrippedToScriptPubkey[]; diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index 947403e88..2d55fc1cb 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -31,9 +31,18 @@ class BlocksRepository { )`; const params: any[] = [ - block.height, blockHash, block.timestamp, block.size, - block.weight, block.tx_count, coinbaseHex ? coinbaseHex : '', block.difficulty, - poolTag.id, 0, '[]', block.medianFee, + block.height, + blockHash, + block.timestamp, + block.size, + block.weight, + block.tx_count, + coinbaseHex ? coinbaseHex : '', + block.difficulty, + poolTag.id, + 0, + '[]', + block.extra ? block.extra.medianFee : 0, ]; await connection.query(query, params); diff --git a/frontend/src/app/components/block/block.component.html b/frontend/src/app/components/block/block.component.html index 7995d9d1e..4f6e1cc03 100644 --- a/frontend/src/app/components/block/block.component.html +++ b/frontend/src/app/components/block/block.component.html @@ -74,9 +74,9 @@
- + - + diff --git a/frontend/src/app/components/block/block.component.ts b/frontend/src/app/components/block/block.component.ts index a3841a3a6..c079b5efd 100644 --- a/frontend/src/app/components/block/block.component.ts +++ b/frontend/src/app/components/block/block.component.ts @@ -3,12 +3,13 @@ import { Location } from '@angular/common'; import { ActivatedRoute, ParamMap, Router } from '@angular/router'; import { ElectrsApiService } from '../../services/electrs-api.service'; import { switchMap, tap, debounceTime, catchError, map } from 'rxjs/operators'; -import { Block, Transaction, Vout } from '../../interfaces/electrs.interface'; +import { Transaction, Vout } from '../../interfaces/electrs.interface'; import { Observable, of, Subscription } from 'rxjs'; import { StateService } from '../../services/state.service'; import { SeoService } from 'src/app/services/seo.service'; import { WebsocketService } from 'src/app/services/websocket.service'; import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url.pipe'; +import { BlockExtended } from 'src/app/interfaces/node-api.interface'; @Component({ selector: 'app-block', @@ -17,13 +18,13 @@ import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url. }) export class BlockComponent implements OnInit, OnDestroy { network = ''; - block: Block; + block: BlockExtended; blockHeight: number; nextBlockHeight: number; blockHash: string; isLoadingBlock = true; - latestBlock: Block; - latestBlocks: Block[] = []; + latestBlock: BlockExtended; + latestBlocks: BlockExtended[] = []; transactions: Transaction[]; isLoadingTransactions = true; error: any; @@ -76,7 +77,9 @@ export class BlockComponent implements OnInit, OnDestroy { if (block.id === this.blockHash) { this.block = block; - this.fees = block.reward / 100000000 - this.blockSubsidy; + if (block?.extra?.reward != undefined) { + this.fees = block.extra.reward / 100000000 - this.blockSubsidy; + } } }); @@ -108,7 +111,7 @@ export class BlockComponent implements OnInit, OnDestroy { } else { this.isLoadingBlock = true; - let blockInCache: Block; + let blockInCache: BlockExtended; if (isBlockHeight) { blockInCache = this.latestBlocks.find((block) => block.height === parseInt(blockHash, 10)); if (blockInCache) { @@ -134,7 +137,7 @@ export class BlockComponent implements OnInit, OnDestroy { return this.electrsApiService.getBlock$(blockHash); } }), - tap((block: Block) => { + tap((block: BlockExtended) => { this.block = block; this.blockHeight = block.height; this.nextBlockHeight = block.height + 1; @@ -142,12 +145,10 @@ export class BlockComponent implements OnInit, OnDestroy { this.seoService.setTitle($localize`:@@block.component.browser-title:Block ${block.height}:BLOCK_HEIGHT:: ${block.id}:BLOCK_ID:`); this.isLoadingBlock = false; - if (block.coinbaseTx) { - this.coinbaseTx = block.coinbaseTx; - } + this.coinbaseTx = block?.extra?.coinbaseTx; this.setBlockSubsidy(); - if (block.reward !== undefined) { - this.fees = block.reward / 100000000 - this.blockSubsidy; + if (block?.extra?.reward !== undefined) { + this.fees = block.extra.reward / 100000000 - this.blockSubsidy; } this.stateService.markBlock$.next({ blockHeight: this.blockHeight }); this.isLoadingTransactions = true; diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html index 1a3942df1..4a74dab3c 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html @@ -8,10 +8,10 @@
- ~{{ block.medianFee | number:feeRounding }} sat/vB + ~{{ block?.extra?.medianFee | number:feeRounding }} sat/vB
- {{ block.feeRange[1] | number:feeRounding }} - {{ block.feeRange[block.feeRange.length - 1] | number:feeRounding }} sat/vB + {{ block?.extra?.feeRange[1] | number:feeRounding }} - {{ block?.extra?.feeRange[block?.extra?.feeRange.length - 1] | number:feeRounding }} sat/vB
diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts index 665822bd5..7dcec9cc3 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; import { Observable, Subscription } from 'rxjs'; -import { Block } from 'src/app/interfaces/electrs.interface'; import { StateService } from 'src/app/services/state.service'; import { Router } from '@angular/router'; import { specialBlocks } from 'src/app/app.constants'; +import { BlockExtended } from 'src/app/interfaces/node-api.interface'; @Component({ selector: 'app-blockchain-blocks', @@ -14,8 +14,8 @@ import { specialBlocks } from 'src/app/app.constants'; export class BlockchainBlocksComponent implements OnInit, OnDestroy { specialBlocks = specialBlocks; network = ''; - blocks: Block[] = []; - emptyBlocks: Block[] = this.mountEmptyBlocks(); + blocks: BlockExtended[] = []; + emptyBlocks: BlockExtended[] = this.mountEmptyBlocks(); markHeight: number; blocksSubscription: Subscription; networkSubscription: Subscription; @@ -69,8 +69,8 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy { this.blocks.unshift(block); this.blocks = this.blocks.slice(0, this.stateService.env.KEEP_BLOCKS_AMOUNT); - if (this.blocksFilled && !this.tabHidden) { - block.stage = block.matchRate >= 66 ? 1 : 2; + if (this.blocksFilled && !this.tabHidden && block.extra) { + block.extra.stage = block.extra.matchRate >= 66 ? 1 : 2; } if (txConfirmed) { @@ -143,16 +143,16 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy { } } - trackByBlocksFn(index: number, item: Block) { + trackByBlocksFn(index: number, item: BlockExtended) { return item.height; } - getStyleForBlock(block: Block) { + getStyleForBlock(block: BlockExtended) { const greenBackgroundHeight = 100 - (block.weight / this.stateService.env.BLOCK_WEIGHT_UNITS) * 100; let addLeft = 0; - if (block.stage === 1) { - block.stage = 2; + if (block?.extra?.stage === 1) { + block.extra.stage = 2; addLeft = -205; } @@ -167,11 +167,11 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy { }; } - getStyleForEmptyBlock(block: Block) { + getStyleForEmptyBlock(block: BlockExtended) { let addLeft = 0; - if (block.stage === 1) { - block.stage = 2; + if (block?.extra?.stage === 1) { + block.extra.stage = 2; addLeft = -205; } diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts index 5257d6a9e..1bfb665b6 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts @@ -153,7 +153,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { this.blockSubscription = this.stateService.blocks$ .subscribe(([block]) => { - if (block.matchRate >= 66 && !this.tabHidden) { + if (block?.extra?.matchRate >= 66 && !this.tabHidden) { this.blockIndex++; } }); diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts index 2478958f6..bd77c564f 100644 --- a/frontend/src/app/components/transaction/transaction.component.ts +++ b/frontend/src/app/components/transaction/transaction.component.ts @@ -9,14 +9,14 @@ import { delay, map } from 'rxjs/operators'; -import { Transaction, Block } from '../../interfaces/electrs.interface'; +import { Transaction } from '../../interfaces/electrs.interface'; import { of, merge, Subscription, Observable, Subject, timer, combineLatest, from } from 'rxjs'; import { StateService } from '../../services/state.service'; import { WebsocketService } from '../../services/websocket.service'; import { AudioService } from 'src/app/services/audio.service'; import { ApiService } from 'src/app/services/api.service'; import { SeoService } from 'src/app/services/seo.service'; -import { CpfpInfo } from 'src/app/interfaces/node-api.interface'; +import { BlockExtended, CpfpInfo } from 'src/app/interfaces/node-api.interface'; import { LiquidUnblinding } from './liquid-ublinding'; @Component({ @@ -33,7 +33,7 @@ export class TransactionComponent implements OnInit, OnDestroy { error: any = undefined; errorUnblinded: any = undefined; waitingForTransaction = false; - latestBlock: Block; + latestBlock: BlockExtended; transactionTime = -1; subscription: Subscription; fetchCpfpSubscription: Subscription; diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.ts b/frontend/src/app/components/transactions-list/transactions-list.component.ts index e1fb7d2e6..dac0e8857 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.ts +++ b/frontend/src/app/components/transactions-list/transactions-list.component.ts @@ -1,11 +1,12 @@ import { Component, OnInit, Input, ChangeDetectionStrategy, OnChanges, ChangeDetectorRef, Output, EventEmitter } from '@angular/core'; import { StateService } from '../../services/state.service'; import { Observable, forkJoin } from 'rxjs'; -import { Block, Outspend, Transaction } from '../../interfaces/electrs.interface'; +import { Outspend, Transaction } from '../../interfaces/electrs.interface'; import { ElectrsApiService } from '../../services/electrs-api.service'; import { environment } from 'src/environments/environment'; import { AssetsService } from 'src/app/services/assets.service'; import { map } from 'rxjs/operators'; +import { BlockExtended } from 'src/app/interfaces/node-api.interface'; @Component({ selector: 'app-transactions-list', @@ -26,7 +27,7 @@ export class TransactionsListComponent implements OnInit, OnChanges { @Output() loadMore = new EventEmitter(); - latestBlock$: Observable; + latestBlock$: Observable; outspends: Outspend[] = []; assetsMinimal: any; diff --git a/frontend/src/app/components/tx-fee-rating/tx-fee-rating.component.ts b/frontend/src/app/components/tx-fee-rating/tx-fee-rating.component.ts index d5637421b..0a2100831 100644 --- a/frontend/src/app/components/tx-fee-rating/tx-fee-rating.component.ts +++ b/frontend/src/app/components/tx-fee-rating/tx-fee-rating.component.ts @@ -1,7 +1,8 @@ import { Component, ChangeDetectionStrategy, OnChanges, Input, OnInit, ChangeDetectorRef, OnDestroy } from '@angular/core'; -import { Transaction, Block } from 'src/app/interfaces/electrs.interface'; +import { Transaction } from 'src/app/interfaces/electrs.interface'; import { StateService } from 'src/app/services/state.service'; import { Subscription } from 'rxjs'; +import { BlockExtended } from 'src/app/interfaces/node-api.interface'; @Component({ selector: 'app-tx-fee-rating', @@ -18,7 +19,7 @@ export class TxFeeRatingComponent implements OnInit, OnChanges, OnDestroy { overpaidTimes: number; feeRating: number; - blocks: Block[] = []; + blocks: BlockExtended[] = []; constructor( private stateService: StateService, @@ -28,7 +29,7 @@ export class TxFeeRatingComponent implements OnInit, OnChanges, OnDestroy { ngOnInit() { this.blocksSubscription = this.stateService.blocks$.subscribe(([block]) => { this.blocks.push(block); - if (this.tx.status.confirmed && this.tx.status.block_height === block.height && block.medianFee > 0) { + if (this.tx.status.confirmed && this.tx.status.block_height === block.height && block?.extra?.medianFee > 0) { this.calculateRatings(block); this.cd.markForCheck(); } @@ -42,7 +43,7 @@ export class TxFeeRatingComponent implements OnInit, OnChanges, OnDestroy { } const foundBlock = this.blocks.find((b) => b.height === this.tx.status.block_height); - if (foundBlock && foundBlock.medianFee > 0) { + if (foundBlock && foundBlock?.extra?.medianFee > 0) { this.calculateRatings(foundBlock); } } @@ -51,9 +52,9 @@ export class TxFeeRatingComponent implements OnInit, OnChanges, OnDestroy { this.blocksSubscription.unsubscribe(); } - calculateRatings(block: Block) { + calculateRatings(block: BlockExtended) { const feePervByte = this.tx.effectiveFeePerVsize || this.tx.fee / (this.tx.weight / 4); - this.medianFeeNeeded = block.medianFee; + this.medianFeeNeeded = block?.extra?.medianFee; // Block not filled if (block.weight < this.stateService.env.BLOCK_WEIGHT_UNITS * 0.95) { diff --git a/frontend/src/app/dashboard/dashboard.component.ts b/frontend/src/app/dashboard/dashboard.component.ts index a582baba3..7a7e1fbf2 100644 --- a/frontend/src/app/dashboard/dashboard.component.ts +++ b/frontend/src/app/dashboard/dashboard.component.ts @@ -1,8 +1,7 @@ import { ChangeDetectionStrategy, Component, Inject, LOCALE_ID, OnInit } from '@angular/core'; import { combineLatest, merge, Observable, of, timer } from 'rxjs'; import { filter, map, scan, share, switchMap, tap } from 'rxjs/operators'; -import { Block } from '../interfaces/electrs.interface'; -import { OptimizedMempoolStats } from '../interfaces/node-api.interface'; +import { BlockExtended, OptimizedMempoolStats } from '../interfaces/node-api.interface'; import { MempoolInfo, TransactionStripped } from '../interfaces/websocket.interface'; import { ApiService } from '../services/api.service'; import { StateService } from '../services/state.service'; @@ -40,7 +39,7 @@ export class DashboardComponent implements OnInit { mempoolInfoData$: Observable; mempoolLoadingStatus$: Observable; vBytesPerSecondLimit = 1667; - blocks$: Observable; + blocks$: Observable; transactions$: Observable; latestBlockHeight: number; mempoolTransactionsWeightPerSecondData: any; @@ -199,7 +198,7 @@ export class DashboardComponent implements OnInit { }; } - trackByBlock(index: number, block: Block) { + trackByBlock(index: number, block: BlockExtended) { return block.height; } diff --git a/frontend/src/app/interfaces/electrs.interface.ts b/frontend/src/app/interfaces/electrs.interface.ts index ff948551f..803a7227e 100644 --- a/frontend/src/app/interfaces/electrs.interface.ts +++ b/frontend/src/app/interfaces/electrs.interface.ts @@ -107,14 +107,6 @@ export interface Block { size: number; weight: number; previousblockhash: string; - - // Custom properties - medianFee?: number; - feeRange?: number[]; - reward?: number; - coinbaseTx?: Transaction; - matchRate: number; - stage: number; } export interface Address { diff --git a/frontend/src/app/interfaces/node-api.interface.ts b/frontend/src/app/interfaces/node-api.interface.ts index 6d87f648d..c48b3e000 100644 --- a/frontend/src/app/interfaces/node-api.interface.ts +++ b/frontend/src/app/interfaces/node-api.interface.ts @@ -1,3 +1,5 @@ +import { Block, Transaction } from "./electrs.interface"; + export interface OptimizedMempoolStats { added: number; vbytes_per_second: number; @@ -80,3 +82,17 @@ export interface MiningStats { pools: SinglePoolStats[], } +export interface BlockExtension { + medianFee?: number; + feeRange?: number[]; + reward?: number; + coinbaseTx?: Transaction; + matchRate?: number; + + stage?: number; // Frontend only +} + +export interface BlockExtended extends Block { + extra?: BlockExtension; +} + diff --git a/frontend/src/app/interfaces/websocket.interface.ts b/frontend/src/app/interfaces/websocket.interface.ts index 989c4176b..1dbaa90af 100644 --- a/frontend/src/app/interfaces/websocket.interface.ts +++ b/frontend/src/app/interfaces/websocket.interface.ts @@ -1,9 +1,10 @@ import { ILoadingIndicators } from '../services/state.service'; -import { Block, Transaction } from './electrs.interface'; +import { Transaction } from './electrs.interface'; +import { BlockExtended } from './node-api.interface'; export interface WebsocketResponse { - block?: Block; - blocks?: Block[]; + block?: BlockExtended; + blocks?: BlockExtended[]; conversions?: any; txConfirmed?: boolean; historicalDate?: string; diff --git a/frontend/src/app/services/electrs-api.service.ts b/frontend/src/app/services/electrs-api.service.ts index 63018ec63..5756f7fb2 100644 --- a/frontend/src/app/services/electrs-api.service.ts +++ b/frontend/src/app/services/electrs-api.service.ts @@ -1,8 +1,9 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; -import { Block, Transaction, Address, Outspend, Recent, Asset } from '../interfaces/electrs.interface'; +import { Transaction, Address, Outspend, Recent, Asset } from '../interfaces/electrs.interface'; import { StateService } from './state.service'; +import { BlockExtended } from '../interfaces/node-api.interface'; @Injectable({ providedIn: 'root' @@ -28,12 +29,12 @@ export class ElectrsApiService { }); } - getBlock$(hash: string): Observable { - return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/block/' + hash); + getBlock$(hash: string): Observable { + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/block/' + hash); } - listBlocks$(height?: number): Observable { - return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/blocks/' + (height || '')); + listBlocks$(height?: number): Observable { + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/blocks/' + (height || '')); } getTransaction$(txId: string): Observable { diff --git a/frontend/src/app/services/state.service.ts b/frontend/src/app/services/state.service.ts index 8050e4286..230c9b150 100644 --- a/frontend/src/app/services/state.service.ts +++ b/frontend/src/app/services/state.service.ts @@ -1,8 +1,8 @@ import { Inject, Injectable, PLATFORM_ID } from '@angular/core'; import { ReplaySubject, BehaviorSubject, Subject, fromEvent, Observable } from 'rxjs'; -import { Block, Transaction } from '../interfaces/electrs.interface'; +import { Transaction } from '../interfaces/electrs.interface'; import { IBackendInfo, MempoolBlock, MempoolInfo, TransactionStripped } from '../interfaces/websocket.interface'; -import { OptimizedMempoolStats } from '../interfaces/node-api.interface'; +import { BlockExtended, OptimizedMempoolStats } from '../interfaces/node-api.interface'; import { Router, NavigationStart } from '@angular/router'; import { isPlatformBrowser } from '@angular/common'; import { map, shareReplay } from 'rxjs/operators'; @@ -72,7 +72,7 @@ export class StateService { latestBlockHeight = 0; networkChanged$ = new ReplaySubject(1); - blocks$: ReplaySubject<[Block, boolean]>; + blocks$: ReplaySubject<[BlockExtended, boolean]>; transactions$ = new ReplaySubject(6); conversions$ = new ReplaySubject(1); bsqPrice$ = new ReplaySubject(1); @@ -122,7 +122,7 @@ export class StateService { } }); - this.blocks$ = new ReplaySubject<[Block, boolean]>(this.env.KEEP_BLOCKS_AMOUNT); + this.blocks$ = new ReplaySubject<[BlockExtended, boolean]>(this.env.KEEP_BLOCKS_AMOUNT); if (this.env.BASE_MODULE === 'bisq') { this.network = this.env.BASE_MODULE; diff --git a/frontend/src/app/services/websocket.service.ts b/frontend/src/app/services/websocket.service.ts index dc65cf8f7..b50cbc494 100644 --- a/frontend/src/app/services/websocket.service.ts +++ b/frontend/src/app/services/websocket.service.ts @@ -2,11 +2,12 @@ import { Injectable } from '@angular/core'; import { webSocket, WebSocketSubject } from 'rxjs/webSocket'; import { WebsocketResponse, IBackendInfo } from '../interfaces/websocket.interface'; import { StateService } from './state.service'; -import { Block, Transaction } from '../interfaces/electrs.interface'; +import { Transaction } from '../interfaces/electrs.interface'; import { Subscription } from 'rxjs'; import { ApiService } from './api.service'; import { take } from 'rxjs/operators'; import { TransferState, makeStateKey } from '@angular/platform-browser'; +import { BlockExtended } from '../interfaces/node-api.interface'; const OFFLINE_RETRY_AFTER_MS = 10000; const OFFLINE_PING_CHECK_AFTER_MS = 30000; @@ -207,7 +208,7 @@ export class WebsocketService { handleResponse(response: WebsocketResponse) { if (response.blocks && response.blocks.length) { const blocks = response.blocks; - blocks.forEach((block: Block) => { + blocks.forEach((block: BlockExtended) => { if (block.height > this.stateService.latestBlockHeight) { this.stateService.latestBlockHeight = block.height; this.stateService.blocks$.next([block, false]); From 0400deacf29e2141f856cd5806955010025195e1 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Thu, 3 Feb 2022 23:14:56 -0800 Subject: [PATCH 03/41] Add socks-proxy-agent dependency --- backend/package-lock.json | 161 ++++++++++++++++++++++++++++++++++++++ backend/package.json | 1 + 2 files changed, 162 insertions(+) diff --git a/backend/package-lock.json b/backend/package-lock.json index a93e977a3..f2ef1abb3 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -19,6 +19,7 @@ "locutus": "^2.0.12", "mysql2": "2.3.3", "node-worker-threads-pool": "^1.4.3", + "socks-proxy-agent": "^6.1.1", "typescript": "4.4.4", "ws": "8.3.0" }, @@ -181,6 +182,38 @@ "node": ">= 0.6" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -731,6 +764,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -1189,6 +1227,62 @@ "sha.js": "bin.js" } }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.1.tgz", + "integrity": "sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA==", + "dependencies": { + "ip": "^1.1.5", + "smart-buffer": "^4.1.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz", + "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.1", + "socks": "^2.6.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/socks-proxy-agent/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socks-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -1538,6 +1632,29 @@ "negotiator": "0.6.2" } }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -1992,6 +2109,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -2352,6 +2474,45 @@ "safe-buffer": "^5.0.1" } }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + }, + "socks": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.1.tgz", + "integrity": "sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA==", + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.1.0" + } + }, + "socks-proxy-agent": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz", + "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.1", + "socks": "^2.6.1" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", diff --git a/backend/package.json b/backend/package.json index a5c9a32ff..e72d163b2 100644 --- a/backend/package.json +++ b/backend/package.json @@ -38,6 +38,7 @@ "locutus": "^2.0.12", "mysql2": "2.3.3", "node-worker-threads-pool": "^1.4.3", + "socks-proxy-agent": "^6.1.1", "typescript": "4.4.4", "ws": "8.3.0" }, From 0a954e8bcf90f91e17766241160af5094d491431 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Thu, 3 Feb 2022 23:16:30 -0800 Subject: [PATCH 04/41] Allow synthetic default imports due to the socks library --- backend/tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 85a3cb358..8b4cbea2e 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -10,7 +10,8 @@ "moduleResolution": "node", "typeRoots": [ "node_modules/@types" - ] + ], + "allowSyntheticDefaultImports": true }, "include": [ "src/**/*.ts" From 8a996cedb4e2df50bdc6fe63d98c975a5f5fc678 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Thu, 3 Feb 2022 23:21:19 -0800 Subject: [PATCH 05/41] Update README, reference config files and Docker with the new SOCKS config --- README.md | 19 +++++++++++++++++++ backend/mempool-config.sample.json | 7 +++++++ docker/backend/mempool-config.json | 7 +++++++ docker/backend/start.sh | 13 +++++++++++++ 4 files changed, 46 insertions(+) diff --git a/README.md b/README.md index 34dca4862..151edfab7 100644 --- a/README.md +++ b/README.md @@ -245,6 +245,25 @@ docker-compose overrides: BISQ_DATA_PATH: "" ``` +JSON: +``` + "SOCKS5PROXY": { + "ENABLED": false, + "HOST": "127.0.0.1", + "PORT": "9050", + "USERNAME": "", + "PASSWORD": "" + } +``` + +docker-compose overrides: +``` + SOCKS5PROXY_ENABLED: "" + SOCKS5PROXY_HOST: "" + SOCKS5PROXY_PORT: "" + SOCKS5PROXY_USERNAME: "" + SOCKS5PROXY_PASSWORD: "" +``` # Manual Installation diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index 8a9295b3a..e977d8046 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -61,5 +61,12 @@ "BISQ": { "ENABLED": false, "DATA_PATH": "/bisq/statsnode-data/btc_mainnet/db" + }, + "SOCKS5PROXY": { + "ENABLED": false, + "HOST": "127.0.0.1", + "PORT": 9050, + "USERNAME": "", + "PASSWORD": "" } } diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json index 00dc31aad..788ab6505 100644 --- a/docker/backend/mempool-config.json +++ b/docker/backend/mempool-config.json @@ -58,5 +58,12 @@ "BISQ": { "ENABLED": __BISQ_ENABLED__, "DATA_PATH": "__BISQ_DATA_PATH__" + }, + "SOCKS5PROXY": { + "ENABLED": __SOCKS5PROXY_ENABLED__, + "HOST": "__SOCKS5PROXY_HOST__", + "PORT": "__SOCKS5PROXY_PORT__", + "USERNAME": "__SOCKS5PROXY_USERNAME__", + "PASSWORD": "__SOCKS5PROXY_PASSWORD__" } } diff --git a/docker/backend/start.sh b/docker/backend/start.sh index 372be346e..1d1155a66 100644 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -61,6 +61,13 @@ __STATISTICS_TX_PER_SECOND_SAMPLE_PERIOD__=${STATISTICS_TX_PER_SECOND_SAMPLE_PER __BISQ_ENABLED__=${BISQ_ENABLED:=false} __BISQ_DATA_PATH__=${BISQ_DATA_PATH:=/bisq/statsnode-data/btc_mainnet/db} +# SOCKS5PROXY +__SOCKS5PROXY_ENABLED__=${SOCKS5PROXY_ENABLED:=false} +__SOCKS5PROXY_HOST__=${SOCKS5PROXY_HOST:=localhost} +__SOCKS5PROXY_PORT__=${SOCKS5PROXY_PORT:=9050} +__SOCKS5PROXY_USERNAME__=${SOCKS5PROXY_USERNAME:=""} +__SOCKS5PROXY_PASSWORD__=${SOCKS5PROXY_PASSWORD:=""} + mkdir -p "${__MEMPOOL_CACHE_DIR__}" sed -i "s/__MEMPOOL_NETWORK__/${__MEMPOOL_NETWORK__}/g" mempool-config.json @@ -115,4 +122,10 @@ sed -i "s/__STATISTICS_TX_PER_SECOND_SAMPLE_PERIOD__/${__STATISTICS_TX_PER_SECON sed -i "s/__BISQ_ENABLED__/${__BISQ_ENABLED__}/g" mempool-config.json sed -i "s!__BISQ_DATA_PATH__!${__BISQ_DATA_PATH__}!g" mempool-config.json +sed -i "s/__SOCKS5PROXY_ENABLED__/${__SOCKS5PROXY_ENABLED__}/g" mempool-config.json +sed -i "s/__SOCKS5PROXY_HOST__/${__SOCKS5PROXY_HOST__}/g" mempool-config.json +sed -i "s/__SOCKS5PROXY_PORT__/${__SOCKS5PROXY_PORT__}/g" mempool-config.json +sed -i "s/__SOCKS5PROXY_USERNAME__/${__SOCKS5PROXY_USERNAME__}/g" mempool-config.json +sed -i "s/__SOCKS5PROXY_PASSWORD__/${__SOCKS5PROXY_PASSWORD__}/g" mempool-config.json + node /backend/dist/index.js From b1dde4d8b1c5382c43349a12dc840885f24fbd2f Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Thu, 3 Feb 2022 23:23:57 -0800 Subject: [PATCH 06/41] Query conversion rates service over clearnet or Tor with mempool User-Agent --- backend/src/api/fiat-conversion.ts | 27 ++++++++++++++++++++++++++- backend/src/config.ts | 18 +++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/backend/src/api/fiat-conversion.ts b/backend/src/api/fiat-conversion.ts index d779e31fd..e6b44300a 100644 --- a/backend/src/api/fiat-conversion.ts +++ b/backend/src/api/fiat-conversion.ts @@ -2,6 +2,8 @@ import logger from '../logger'; import axios from 'axios'; import { IConversionRates } from '../mempool.interfaces'; import config from '../config'; +import backendInfo from './backend-info'; +import { SocksProxyAgent } from 'socks-proxy-agent'; class FiatConversion { private conversionRates: IConversionRates = { @@ -17,6 +19,9 @@ class FiatConversion { public startService() { logger.info('Starting currency rates service'); + if (config.SOCKS5PROXY.ENABLED) { + logger.info('Currency rates service will be queried over the Tor network'); + } setInterval(this.updateCurrency.bind(this), 1000 * config.MEMPOOL.PRICE_FEED_UPDATE_INTERVAL); this.updateCurrency(); } @@ -26,8 +31,28 @@ class FiatConversion { } private async updateCurrency(): Promise { + const headers = { 'User-Agent': `mempool/v${backendInfo.getBackendInfo().version}` }; + let response; try { - const response = await axios.get('https://price.bisq.wiz.biz/getAllMarketPrices', { timeout: 10000 }); + let fiatConversionUrl = 'https://price.bisq.wiz.biz/getAllMarketPrices'; + if (config.SOCKS5PROXY.ENABLED) { + let socksOptions: any = { + agentOptions: { + keepAlive: true, + }, + host: config.SOCKS5PROXY.HOST, + port: config.SOCKS5PROXY.PORT + }; + if (config.SOCKS5PROXY.USERNAME && config.SOCKS5PROXY.PASSWORD) { + socksOptions.username = config.SOCKS5PROXY.USERNAME; + socksOptions.password = config.SOCKS5PROXY.PASSWORD; + } + const agent = new SocksProxyAgent(socksOptions); + fiatConversionUrl = 'http://wizpriceje6q5tdrxkyiazsgu7irquiqjy2dptezqhrtu7l2qelqktid.onion/getAllMarketPrices'; + response = await axios.get(fiatConversionUrl, { httpAgent: agent, headers: headers, timeout: 30000 }); + } else { + response = await axios.get(fiatConversionUrl, { headers: headers, timeout: 10000 }); + } const usd = response.data.data.find((item: any) => item.currencyCode === 'USD'); this.conversionRates = { 'USD': usd.price, diff --git a/backend/src/config.ts b/backend/src/config.ts index 085d538c4..e610e9f47 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -51,7 +51,7 @@ interface IConfig { ENABLED: boolean; HOST: string; PORT: number; - MIN_PRIORITY: 'emerg' | 'alert' | 'crit' | 'err' |'warn' | 'notice' | 'info' | 'debug'; + MIN_PRIORITY: 'emerg' | 'alert' | 'crit' | 'err' | 'warn' | 'notice' | 'info' | 'debug'; FACILITY: string; }; STATISTICS: { @@ -62,6 +62,13 @@ interface IConfig { ENABLED: boolean; DATA_PATH: string; }; + SOCKS5PROXY: { + ENABLED: boolean; + HOST: string; + PORT: number; + USERNAME: string; + PASSWORD: string; + }; } const defaults: IConfig = { @@ -128,6 +135,13 @@ const defaults: IConfig = { 'ENABLED': false, 'DATA_PATH': '/bisq/statsnode-data/btc_mainnet/db' }, + 'SOCKS5PROXY': { + 'ENABLED': false, + 'HOST': '127.0.0.1', + 'PORT': 9050, + 'USERNAME': '', + 'PASSWORD': '' + } }; class Config implements IConfig { @@ -140,6 +154,7 @@ class Config implements IConfig { SYSLOG: IConfig['SYSLOG']; STATISTICS: IConfig['STATISTICS']; BISQ: IConfig['BISQ']; + SOCKS5PROXY: IConfig['SOCKS5PROXY']; constructor() { const configs = this.merge(configFile, defaults); @@ -152,6 +167,7 @@ class Config implements IConfig { this.SYSLOG = configs.SYSLOG; this.STATISTICS = configs.STATISTICS; this.BISQ = configs.BISQ; + this.SOCKS5PROXY = configs.SOCKS5PROXY; } merge = (...objects: object[]): IConfig => { From 02e15cbea457672dc58b46ee8776d2adccb2c4c1 Mon Sep 17 00:00:00 2001 From: softsimon Date: Fri, 4 Feb 2022 13:47:34 +0400 Subject: [PATCH 07/41] Proxy all /api and /api/v1 requests to local nodejs server --- frontend/proxy.conf.local.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/frontend/proxy.conf.local.js b/frontend/proxy.conf.local.js index ba2248e5a..51365fc68 100644 --- a/frontend/proxy.conf.local.js +++ b/frontend/proxy.conf.local.js @@ -49,7 +49,14 @@ PROXY_CONFIG.map(conf => conf.target = "http://localhost:8999"); // Add rules for local backend if (backendConfigContent) { PROXY_CONFIG.push({ - context: ['/api/address/**', '/api/tx/**', '/api/block/**', '/api/blocks/**'], + context: ['/api/v1/**'], + target: `http://localhost:8999`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000 + }); + PROXY_CONFIG.push({ + context: ['/api/**'], target: `http://localhost:8999`, secure: false, changeOrigin: true, @@ -57,15 +64,7 @@ if (backendConfigContent) { pathRewrite: { "^/api/": "/api/v1/" }, - }); - PROXY_CONFIG.push({ - context: ['/api/v1/**'], - target: `http://localhost:8999`, - secure: false, - changeOrigin: true, - proxyTimeout: 30000 }); - } console.log(PROXY_CONFIG); From 456bd5a18e688e3773b806522779c2d414793a15 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Fri, 4 Feb 2022 19:28:00 +0900 Subject: [PATCH 08/41] Renamed `extra` to `extras` --- backend/src/api/blocks.ts | 14 +++++++------- backend/src/api/websocket-handler.ts | 4 ++-- backend/src/mempool.interfaces.ts | 2 +- backend/src/repositories/BlocksRepository.ts | 2 +- .../src/app/components/block/block.component.html | 4 ++-- .../src/app/components/block/block.component.ts | 10 +++++----- .../blockchain-blocks.component.html | 4 ++-- .../blockchain-blocks.component.ts | 12 ++++++------ .../mempool-blocks/mempool-blocks.component.ts | 2 +- .../tx-fee-rating/tx-fee-rating.component.ts | 6 +++--- frontend/src/app/interfaces/node-api.interface.ts | 2 +- 11 files changed, 31 insertions(+), 31 deletions(-) diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index 081442567..cd72d91e0 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -97,7 +97,7 @@ class Blocks { private getBlockExtended(block: IEsploraApi.Block, transactions: TransactionExtended[]): BlockExtended { const blockExtended: BlockExtended = Object.assign({}, block); - blockExtended.extra = { + blockExtended.extras = { reward: transactions[0].vout.reduce((acc, curr) => acc + curr.value, 0), coinbaseTx: transactionUtils.stripCoinbaseTransaction(transactions[0]), }; @@ -106,9 +106,9 @@ class Blocks { transactionsTmp.shift(); transactionsTmp.sort((a, b) => b.effectiveFeePerVsize - a.effectiveFeePerVsize); - blockExtended.extra.medianFee = transactionsTmp.length > 0 ? + blockExtended.extras.medianFee = transactionsTmp.length > 0 ? Common.median(transactionsTmp.map((tx) => tx.effectiveFeePerVsize)) : 0; - blockExtended.extra.feeRange = transactionsTmp.length > 0 ? + blockExtended.extras.feeRange = transactionsTmp.length > 0 ? Common.getFeesInRange(transactionsTmp, 8) : [0, 0]; return blockExtended; @@ -205,8 +205,8 @@ class Blocks { const blockExtended = this.getBlockExtended(block, transactions); let miner: PoolTag; - if (blockExtended?.extra?.coinbaseTx) { - miner = await this.$findBlockMiner(blockExtended.extra.coinbaseTx); + if (blockExtended?.extras?.coinbaseTx) { + miner = await this.$findBlockMiner(blockExtended.extras.coinbaseTx); } else { miner = await poolsRepository.$getUnknownPool(); } @@ -276,8 +276,8 @@ class Blocks { if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK) === true) { let miner: PoolTag; - if (blockExtended?.extra?.coinbaseTx) { - miner = await this.$findBlockMiner(blockExtended.extra.coinbaseTx); + if (blockExtended?.extras?.coinbaseTx) { + miner = await this.$findBlockMiner(blockExtended.extras.coinbaseTx); } else { miner = await poolsRepository.$getUnknownPool(); } diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index 5478445df..53d74925d 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -380,8 +380,8 @@ class WebsocketHandler { mBlocks = mempoolBlocks.getMempoolBlocks(); } - if (block.extra) { - block.extra.matchRate = matchRate; + if (block.extras) { + block.extras.matchRate = matchRate; } this.wss.clients.forEach((client) => { diff --git a/backend/src/mempool.interfaces.ts b/backend/src/mempool.interfaces.ts index 17509b814..7dfcd3956 100644 --- a/backend/src/mempool.interfaces.ts +++ b/backend/src/mempool.interfaces.ts @@ -86,7 +86,7 @@ export interface BlockExtension { } export interface BlockExtended extends IEsploraApi.Block { - extra?: BlockExtension; + extras?: BlockExtension; } export interface TransactionMinerInfo { diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index 2d55fc1cb..fd9549845 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -42,7 +42,7 @@ class BlocksRepository { poolTag.id, 0, '[]', - block.extra ? block.extra.medianFee : 0, + block.extras ? block.extras.medianFee : 0, ]; await connection.query(query, params); diff --git a/frontend/src/app/components/block/block.component.html b/frontend/src/app/components/block/block.component.html index 4f6e1cc03..8970bd372 100644 --- a/frontend/src/app/components/block/block.component.html +++ b/frontend/src/app/components/block/block.component.html @@ -74,9 +74,9 @@
Median fee~{{ block.medianFee | number:'1.0-0' }} sat/vB ~{{ block?.extra?.medianFee | number:'1.0-0' }} sat/vB
- + - + diff --git a/frontend/src/app/components/block/block.component.ts b/frontend/src/app/components/block/block.component.ts index c079b5efd..4e7b08373 100644 --- a/frontend/src/app/components/block/block.component.ts +++ b/frontend/src/app/components/block/block.component.ts @@ -77,8 +77,8 @@ export class BlockComponent implements OnInit, OnDestroy { if (block.id === this.blockHash) { this.block = block; - if (block?.extra?.reward != undefined) { - this.fees = block.extra.reward / 100000000 - this.blockSubsidy; + if (block?.extras?.reward != undefined) { + this.fees = block.extras.reward / 100000000 - this.blockSubsidy; } } }); @@ -145,10 +145,10 @@ export class BlockComponent implements OnInit, OnDestroy { this.seoService.setTitle($localize`:@@block.component.browser-title:Block ${block.height}:BLOCK_HEIGHT:: ${block.id}:BLOCK_ID:`); this.isLoadingBlock = false; - this.coinbaseTx = block?.extra?.coinbaseTx; + this.coinbaseTx = block?.extras?.coinbaseTx; this.setBlockSubsidy(); - if (block?.extra?.reward !== undefined) { - this.fees = block.extra.reward / 100000000 - this.blockSubsidy; + if (block?.extras?.reward !== undefined) { + this.fees = block.extras.reward / 100000000 - this.blockSubsidy; } this.stateService.markBlock$.next({ blockHeight: this.blockHeight }); this.isLoadingTransactions = true; diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html index 4a74dab3c..50fd82b09 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html @@ -8,10 +8,10 @@
- ~{{ block?.extra?.medianFee | number:feeRounding }} sat/vB + ~{{ block?.extras?.medianFee | number:feeRounding }} sat/vB
- {{ block?.extra?.feeRange[1] | number:feeRounding }} - {{ block?.extra?.feeRange[block?.extra?.feeRange.length - 1] | number:feeRounding }} sat/vB + {{ block?.extras?.feeRange[1] | number:feeRounding }} - {{ block?.extras?.feeRange[block?.extras?.feeRange.length - 1] | number:feeRounding }} sat/vB
diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts index 7dcec9cc3..ef076e74b 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts @@ -69,8 +69,8 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy { this.blocks.unshift(block); this.blocks = this.blocks.slice(0, this.stateService.env.KEEP_BLOCKS_AMOUNT); - if (this.blocksFilled && !this.tabHidden && block.extra) { - block.extra.stage = block.extra.matchRate >= 66 ? 1 : 2; + if (this.blocksFilled && !this.tabHidden && block.extras) { + block.extras.stage = block.extras.matchRate >= 66 ? 1 : 2; } if (txConfirmed) { @@ -151,8 +151,8 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy { const greenBackgroundHeight = 100 - (block.weight / this.stateService.env.BLOCK_WEIGHT_UNITS) * 100; let addLeft = 0; - if (block?.extra?.stage === 1) { - block.extra.stage = 2; + if (block?.extras?.stage === 1) { + block.extras.stage = 2; addLeft = -205; } @@ -170,8 +170,8 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy { getStyleForEmptyBlock(block: BlockExtended) { let addLeft = 0; - if (block?.extra?.stage === 1) { - block.extra.stage = 2; + if (block?.extras?.stage === 1) { + block.extras.stage = 2; addLeft = -205; } diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts index 1bfb665b6..de345a7d8 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts @@ -153,7 +153,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { this.blockSubscription = this.stateService.blocks$ .subscribe(([block]) => { - if (block?.extra?.matchRate >= 66 && !this.tabHidden) { + if (block?.extras?.matchRate >= 66 && !this.tabHidden) { this.blockIndex++; } }); diff --git a/frontend/src/app/components/tx-fee-rating/tx-fee-rating.component.ts b/frontend/src/app/components/tx-fee-rating/tx-fee-rating.component.ts index 0a2100831..3879ca835 100644 --- a/frontend/src/app/components/tx-fee-rating/tx-fee-rating.component.ts +++ b/frontend/src/app/components/tx-fee-rating/tx-fee-rating.component.ts @@ -29,7 +29,7 @@ export class TxFeeRatingComponent implements OnInit, OnChanges, OnDestroy { ngOnInit() { this.blocksSubscription = this.stateService.blocks$.subscribe(([block]) => { this.blocks.push(block); - if (this.tx.status.confirmed && this.tx.status.block_height === block.height && block?.extra?.medianFee > 0) { + if (this.tx.status.confirmed && this.tx.status.block_height === block.height && block?.extras?.medianFee > 0) { this.calculateRatings(block); this.cd.markForCheck(); } @@ -43,7 +43,7 @@ export class TxFeeRatingComponent implements OnInit, OnChanges, OnDestroy { } const foundBlock = this.blocks.find((b) => b.height === this.tx.status.block_height); - if (foundBlock && foundBlock?.extra?.medianFee > 0) { + if (foundBlock && foundBlock?.extras?.medianFee > 0) { this.calculateRatings(foundBlock); } } @@ -54,7 +54,7 @@ export class TxFeeRatingComponent implements OnInit, OnChanges, OnDestroy { calculateRatings(block: BlockExtended) { const feePervByte = this.tx.effectiveFeePerVsize || this.tx.fee / (this.tx.weight / 4); - this.medianFeeNeeded = block?.extra?.medianFee; + this.medianFeeNeeded = block?.extras?.medianFee; // Block not filled if (block.weight < this.stateService.env.BLOCK_WEIGHT_UNITS * 0.95) { diff --git a/frontend/src/app/interfaces/node-api.interface.ts b/frontend/src/app/interfaces/node-api.interface.ts index c48b3e000..373385422 100644 --- a/frontend/src/app/interfaces/node-api.interface.ts +++ b/frontend/src/app/interfaces/node-api.interface.ts @@ -93,6 +93,6 @@ export interface BlockExtension { } export interface BlockExtended extends Block { - extra?: BlockExtension; + extras?: BlockExtension; } From 174907cf6a840657141ce43fd08f97b767509c50 Mon Sep 17 00:00:00 2001 From: Antoni Spaanderman <56turtle56@gmail.com> Date: Fri, 4 Feb 2022 19:19:32 +0100 Subject: [PATCH 09/41] add STDOUT_LOG_MIN_PRIORITY to README and docker config --- README.md | 4 +++- docker/backend/mempool-config.json | 3 ++- docker/backend/start.sh | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 34dca4862..3b4cfafcc 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,8 @@ JSON: "MEMPOOL_BLOCKS_AMOUNT": 8, "PRICE_FEED_UPDATE_INTERVAL": 3600, "USE_SECOND_NODE_FOR_MINFEE": false, - "EXTERNAL_ASSETS": [] + "EXTERNAL_ASSETS": [], + "STDOUT_LOG_MIN_PRIORITY": "debug" }, ``` @@ -111,6 +112,7 @@ docker-compose overrides:: MEMPOOL_PRICE_FEED_UPDATE_INTERVAL: "" MEMPOOL_USE_SECOND_NODE_FOR_MINFEE: "" MEMPOOL_EXTERNAL_ASSETS: "" + MEMPOOL_STDOUT_LOG_MIN_PRIORITY: "" ``` JSON: diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json index 00dc31aad..f0579e75f 100644 --- a/docker/backend/mempool-config.json +++ b/docker/backend/mempool-config.json @@ -14,7 +14,8 @@ "MEMPOOL_BLOCKS_AMOUNT": __MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__, "PRICE_FEED_UPDATE_INTERVAL": __MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__, "USE_SECOND_NODE_FOR_MINFEE": __MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__, - "EXTERNAL_ASSETS": __MEMPOOL_EXTERNAL_ASSETS__ + "EXTERNAL_ASSETS": __MEMPOOL_EXTERNAL_ASSETS__, + "STDOUT_LOG_MIN_PRIORITY": __MEMPOOL_STDOUT_LOG_MIN_PRIORITY__ }, "CORE_RPC": { "HOST": "__CORE_RPC_HOST__", diff --git a/docker/backend/start.sh b/docker/backend/start.sh index 372be346e..2190b55c5 100644 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -17,6 +17,7 @@ __MEMPOOL_INDEXING_BLOCKS_AMOUNT__=${MEMPOOL_INDEXING_BLOCKS_AMOUNT:=1100} __MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__=${MEMPOOL_PRICE_FEED_UPDATE_INTERVAL:=3600} __MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__=${MEMPOOL_USE_SECOND_NODE_FOR_MINFEE:=false} __MEMPOOL_EXTERNAL_ASSETS__=${MEMPOOL_EXTERNAL_ASSETS:=[]} +__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__=${MEMPOOL_STDOUT_LOG_MIN_PRIORITY:=[]} # CORE_RPC __CORE_RPC_HOST__=${CORE_RPC_HOST:=127.0.0.1} @@ -79,6 +80,7 @@ sed -i "s/__MEMPOOL_INDEXING_BLOCKS_AMOUNT__/${__MEMPOOL_INDEXING_BLOCKS_AMOUNT_ sed -i "s/__MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__/${__MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__}/g" mempool-config.json sed -i "s/__MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__/${__MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__}/g" mempool-config.json sed -i "s/__MEMPOOL_EXTERNAL_ASSETS__/${__MEMPOOL_EXTERNAL_ASSETS__}/g" mempool-config.json +sed -i "s/__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__/${__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__}/g" mempool-config.json sed -i "s/__CORE_RPC_HOST__/${__CORE_RPC_HOST__}/g" mempool-config.json sed -i "s/__CORE_RPC_PORT__/${__CORE_RPC_PORT__}/g" mempool-config.json From 30c79a20259a8422dc117f3a2a1a07199ec150fa Mon Sep 17 00:00:00 2001 From: Antoni Spaanderman <49868160+antonilol@users.noreply.github.com> Date: Fri, 4 Feb 2022 20:03:25 +0100 Subject: [PATCH 10/41] Update docker/backend/start.sh oops i just copied the line above and forgot that one Co-authored-by: Felipe Knorr Kuhn <100320+knorrium@users.noreply.github.com> --- docker/backend/start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/backend/start.sh b/docker/backend/start.sh index 2190b55c5..2d502d397 100644 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -17,7 +17,7 @@ __MEMPOOL_INDEXING_BLOCKS_AMOUNT__=${MEMPOOL_INDEXING_BLOCKS_AMOUNT:=1100} __MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__=${MEMPOOL_PRICE_FEED_UPDATE_INTERVAL:=3600} __MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__=${MEMPOOL_USE_SECOND_NODE_FOR_MINFEE:=false} __MEMPOOL_EXTERNAL_ASSETS__=${MEMPOOL_EXTERNAL_ASSETS:=[]} -__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__=${MEMPOOL_STDOUT_LOG_MIN_PRIORITY:=[]} +__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__=${MEMPOOL_STDOUT_LOG_MIN_PRIORITY:=debug} # CORE_RPC __CORE_RPC_HOST__=${CORE_RPC_HOST:=127.0.0.1} From 20996cfb49c0312bb06659fe46eb92e8ac82e5e9 Mon Sep 17 00:00:00 2001 From: Antoni Spaanderman <49868160+antonilol@users.noreply.github.com> Date: Fri, 4 Feb 2022 20:03:36 +0100 Subject: [PATCH 11/41] Update docker/backend/mempool-config.json oops (2) Co-authored-by: Felipe Knorr Kuhn <100320+knorrium@users.noreply.github.com> --- docker/backend/mempool-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json index f0579e75f..c26b76f0a 100644 --- a/docker/backend/mempool-config.json +++ b/docker/backend/mempool-config.json @@ -15,7 +15,7 @@ "PRICE_FEED_UPDATE_INTERVAL": __MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__, "USE_SECOND_NODE_FOR_MINFEE": __MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__, "EXTERNAL_ASSETS": __MEMPOOL_EXTERNAL_ASSETS__, - "STDOUT_LOG_MIN_PRIORITY": __MEMPOOL_STDOUT_LOG_MIN_PRIORITY__ + "STDOUT_LOG_MIN_PRIORITY": "__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__" }, "CORE_RPC": { "HOST": "__CORE_RPC_HOST__", From 452375aaf7aadd3fc0f6350d4a306fa6d4c62adb Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Fri, 4 Feb 2022 22:48:16 -0800 Subject: [PATCH 12/41] Make the Currency Conversion Service URLs configurable and log when queried --- README.md | 14 ++++++++++++++ backend/mempool-config.sample.json | 4 ++++ backend/src/api/fiat-conversion.ts | 23 ++++++++++++++++++----- backend/src/config.ts | 10 ++++++++++ docker/backend/mempool-config.json | 4 ++++ docker/backend/start.sh | 7 +++++++ 6 files changed, 57 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 151edfab7..c50282311 100644 --- a/README.md +++ b/README.md @@ -265,6 +265,20 @@ docker-compose overrides: SOCKS5PROXY_PASSWORD: "" ``` +JSON: +``` + "PRICENODE": { + "TOR_URL": "http://wizpriceje6q5tdrxkyiazsgu7irquiqjy2dptezqhrtu7l2qelqktid.onion/getAllMarketPrices", + "CLEARNET_URL": "https://price.bisq.wiz.biz/getAllMarketPrices" + } +``` + +docker-compose overrides: +``` + PRICENODE_TOR_URL: "" + PRICENODE_CLEARNET_URL: "" +``` + # Manual Installation The following instructions are for a manual installation on Linux or FreeBSD. The file and directory paths may need to be changed to match your OS. diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index e977d8046..1b874c665 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -68,5 +68,9 @@ "PORT": 9050, "USERNAME": "", "PASSWORD": "" + }, + "PRICENODE": { + "TOR_URL": "http://wizpriceje6q5tdrxkyiazsgu7irquiqjy2dptezqhrtu7l2qelqktid.onion/getAllMarketPrices", + "CLEARNET_URL": "https://price.bisq.wiz.biz/getAllMarketPrices" } } diff --git a/backend/src/api/fiat-conversion.ts b/backend/src/api/fiat-conversion.ts index e6b44300a..df10d7698 100644 --- a/backend/src/api/fiat-conversion.ts +++ b/backend/src/api/fiat-conversion.ts @@ -1,5 +1,5 @@ import logger from '../logger'; -import axios from 'axios'; +import axios, { AxiosResponse } from 'axios'; import { IConversionRates } from '../mempool.interfaces'; import config from '../config'; import backendInfo from './backend-info'; @@ -20,7 +20,9 @@ class FiatConversion { public startService() { logger.info('Starting currency rates service'); if (config.SOCKS5PROXY.ENABLED) { - logger.info('Currency rates service will be queried over the Tor network'); + logger.info(`Currency rates service will be queried over the Tor network using ${config.PRICENODE.TOR_URL}`); + } else { + logger.info(`Currency rates service will be queried over clearnet using ${config.PRICENODE.CLEARNET_URL}`); } setInterval(this.updateCurrency.bind(this), 1000 * config.MEMPOOL.PRICE_FEED_UPDATE_INTERVAL); this.updateCurrency(); @@ -32,9 +34,10 @@ class FiatConversion { private async updateCurrency(): Promise { const headers = { 'User-Agent': `mempool/v${backendInfo.getBackendInfo().version}` }; - let response; + let fiatConversionUrl: string; + let response: AxiosResponse; + try { - let fiatConversionUrl = 'https://price.bisq.wiz.biz/getAllMarketPrices'; if (config.SOCKS5PROXY.ENABLED) { let socksOptions: any = { agentOptions: { @@ -43,20 +46,30 @@ class FiatConversion { host: config.SOCKS5PROXY.HOST, port: config.SOCKS5PROXY.PORT }; + if (config.SOCKS5PROXY.USERNAME && config.SOCKS5PROXY.PASSWORD) { socksOptions.username = config.SOCKS5PROXY.USERNAME; socksOptions.password = config.SOCKS5PROXY.PASSWORD; } + const agent = new SocksProxyAgent(socksOptions); - fiatConversionUrl = 'http://wizpriceje6q5tdrxkyiazsgu7irquiqjy2dptezqhrtu7l2qelqktid.onion/getAllMarketPrices'; + fiatConversionUrl = config.PRICENODE.TOR_URL; + logger.info('Querying currency rates service...'); response = await axios.get(fiatConversionUrl, { httpAgent: agent, headers: headers, timeout: 30000 }); } else { + fiatConversionUrl = config.PRICENODE.CLEARNET_URL; + logger.info('Querying currency rates service...'); response = await axios.get(fiatConversionUrl, { headers: headers, timeout: 10000 }); } + const usd = response.data.data.find((item: any) => item.currencyCode === 'USD'); + this.conversionRates = { 'USD': usd.price, }; + + logger.info(`USD Conversion Rate: ${usd.price}`); + if (this.ratesChangedCallback) { this.ratesChangedCallback(this.conversionRates); } diff --git a/backend/src/config.ts b/backend/src/config.ts index e610e9f47..058895efb 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -69,6 +69,10 @@ interface IConfig { USERNAME: string; PASSWORD: string; }; + PRICENODE: { + TOR_URL: string; + CLEARNET_URL: string; + }; } const defaults: IConfig = { @@ -141,6 +145,10 @@ const defaults: IConfig = { 'PORT': 9050, 'USERNAME': '', 'PASSWORD': '' + }, + "PRICENODE": { + 'TOR_URL': 'http://wizpriceje6q5tdrxkyiazsgu7irquiqjy2dptezqhrtu7l2qelqktid.onion/getAllMarketPrices', + 'CLEARNET_URL': 'https://price.bisq.wiz.biz/getAllMarketPrices' } }; @@ -155,6 +163,7 @@ class Config implements IConfig { STATISTICS: IConfig['STATISTICS']; BISQ: IConfig['BISQ']; SOCKS5PROXY: IConfig['SOCKS5PROXY']; + PRICENODE: IConfig['PRICENODE']; constructor() { const configs = this.merge(configFile, defaults); @@ -168,6 +177,7 @@ class Config implements IConfig { this.STATISTICS = configs.STATISTICS; this.BISQ = configs.BISQ; this.SOCKS5PROXY = configs.SOCKS5PROXY; + this.PRICENODE = configs.PRICENODE; } merge = (...objects: object[]): IConfig => { diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json index 788ab6505..5a069455d 100644 --- a/docker/backend/mempool-config.json +++ b/docker/backend/mempool-config.json @@ -65,5 +65,9 @@ "PORT": "__SOCKS5PROXY_PORT__", "USERNAME": "__SOCKS5PROXY_USERNAME__", "PASSWORD": "__SOCKS5PROXY_PASSWORD__" + }, + "PRICENODE": { + "TOR_URL": "__PRICENODE_TOR_URL__", + "CLEARNET_URL": "__PRICENODE_CLEARNET_URL__" } } diff --git a/docker/backend/start.sh b/docker/backend/start.sh index 1d1155a66..0ae1e32a2 100644 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -68,6 +68,10 @@ __SOCKS5PROXY_PORT__=${SOCKS5PROXY_PORT:=9050} __SOCKS5PROXY_USERNAME__=${SOCKS5PROXY_USERNAME:=""} __SOCKS5PROXY_PASSWORD__=${SOCKS5PROXY_PASSWORD:=""} +# PRICENODE +__PRICENODE_TOR_URL__=${PRICENODE_TOR_URL:=http://wizpriceje6q5tdrxkyiazsgu7irquiqjy2dptezqhrtu7l2qelqktid.onion/getAllMarketPrices} +__PRICENODE_CLEARNET_URL__=${PRICENODE_CLEARNET_URL:=https://price.bisq.wiz.biz/getAllMarketPrices} + mkdir -p "${__MEMPOOL_CACHE_DIR__}" sed -i "s/__MEMPOOL_NETWORK__/${__MEMPOOL_NETWORK__}/g" mempool-config.json @@ -128,4 +132,7 @@ sed -i "s/__SOCKS5PROXY_PORT__/${__SOCKS5PROXY_PORT__}/g" mempool-config.json sed -i "s/__SOCKS5PROXY_USERNAME__/${__SOCKS5PROXY_USERNAME__}/g" mempool-config.json sed -i "s/__SOCKS5PROXY_PASSWORD__/${__SOCKS5PROXY_PASSWORD__}/g" mempool-config.json +sed -i "s!__PRICENODE_TOR_URL__!${__PRICENODE_TOR_URL__}!g" mempool-config.json +sed -i "s!__PRICENODE_CLEARNET_URL__!${__PRICENODE_CLEARNET_URL__}!g" mempool-config.json + node /backend/dist/index.js From ee7f8d8d1845239aa691710aff1c65f21e0fb5f1 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Sat, 5 Feb 2022 00:33:16 -0800 Subject: [PATCH 13/41] Reduce currency rates polling interval from 1 hour to 10 minutes --- README.md | 2 +- backend/mempool-config.sample.json | 2 +- backend/src/config.ts | 2 +- docker/backend/start.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c50282311..3dc04b81b 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ JSON: "BLOCK_WEIGHT_UNITS": 4000000, "INITIAL_BLOCKS_AMOUNT": 8, "MEMPOOL_BLOCKS_AMOUNT": 8, - "PRICE_FEED_UPDATE_INTERVAL": 3600, + "PRICE_FEED_UPDATE_INTERVAL": 600, "USE_SECOND_NODE_FOR_MINFEE": false, "EXTERNAL_ASSETS": [] }, diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index 1b874c665..b9d7fb982 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -13,7 +13,7 @@ "INITIAL_BLOCKS_AMOUNT": 8, "MEMPOOL_BLOCKS_AMOUNT": 8, "INDEXING_BLOCKS_AMOUNT": 1100, - "PRICE_FEED_UPDATE_INTERVAL": 3600, + "PRICE_FEED_UPDATE_INTERVAL": 600, "USE_SECOND_NODE_FOR_MINFEE": false, "EXTERNAL_ASSETS": [ "https://mempool.space/resources/pools.json" diff --git a/backend/src/config.ts b/backend/src/config.ts index 058895efb..f2787977b 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -90,7 +90,7 @@ const defaults: IConfig = { 'INITIAL_BLOCKS_AMOUNT': 8, 'MEMPOOL_BLOCKS_AMOUNT': 8, 'INDEXING_BLOCKS_AMOUNT': 1100, // 0 = disable indexing, -1 = index all blocks - 'PRICE_FEED_UPDATE_INTERVAL': 3600, + 'PRICE_FEED_UPDATE_INTERVAL': 600, 'USE_SECOND_NODE_FOR_MINFEE': false, 'EXTERNAL_ASSETS': [ 'https://mempool.space/resources/pools.json' diff --git a/docker/backend/start.sh b/docker/backend/start.sh index 0ae1e32a2..d1422bf45 100644 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -14,7 +14,7 @@ __MEMPOOL_BLOCK_WEIGHT_UNITS__=${MEMPOOL_BLOCK_WEIGHT_UNITS:=4000000} __MEMPOOL_INITIAL_BLOCKS_AMOUNT__=${MEMPOOL_INITIAL_BLOCKS_AMOUNT:=8} __MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__=${MEMPOOL_MEMPOOL_BLOCKS_AMOUNT:=8} __MEMPOOL_INDEXING_BLOCKS_AMOUNT__=${MEMPOOL_INDEXING_BLOCKS_AMOUNT:=1100} -__MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__=${MEMPOOL_PRICE_FEED_UPDATE_INTERVAL:=3600} +__MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__=${MEMPOOL_PRICE_FEED_UPDATE_INTERVAL:=600} __MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__=${MEMPOOL_USE_SECOND_NODE_FOR_MINFEE:=false} __MEMPOOL_EXTERNAL_ASSETS__=${MEMPOOL_EXTERNAL_ASSETS:=[]} From 006ed39bf203323e11e0b1a8c07b38b213802b52 Mon Sep 17 00:00:00 2001 From: softsimon Date: Sat, 5 Feb 2022 01:41:17 +0400 Subject: [PATCH 14/41] Local dev proxy working with all base modules --- frontend/proxy.conf.local.js | 132 ++++++++++++++++++++++------------- 1 file changed, 83 insertions(+), 49 deletions(-) diff --git a/frontend/proxy.conf.local.js b/frontend/proxy.conf.local.js index 51365fc68..5a6d1454e 100644 --- a/frontend/proxy.conf.local.js +++ b/frontend/proxy.conf.local.js @@ -1,17 +1,13 @@ - const fs = require('fs'); -let PROXY_CONFIG = require('./proxy.conf.js'); -const BACKEND_CONFIG_FILE_NAME = '../backend/mempool-config.json'; const FRONTEND_CONFIG_FILE_NAME = 'mempool-frontend-config.json'; -let backendConfigContent; -let frontendConfigContent; +let configContent; // Read frontend config try { const rawConfig = fs.readFileSync(FRONTEND_CONFIG_FILE_NAME); - frontendConfigContent = JSON.parse(rawConfig); + configContent = JSON.parse(rawConfig); console.log(`${FRONTEND_CONFIG_FILE_NAME} file found, using provided config`); } catch (e) { console.log(e); @@ -22,50 +18,88 @@ try { } } -// Read backend config -try { - const rawConfig = fs.readFileSync(BACKEND_CONFIG_FILE_NAME); - backendConfigContent = JSON.parse(rawConfig); - console.log(`${BACKEND_CONFIG_FILE_NAME} file found, using provided config`); -} catch (e) { - console.log(e); - if (e.code !== 'ENOENT') { - throw new Error(e); - } else { - console.log(`${BACKEND_CONFIG_FILE_NAME} file not found, using default config`); +let PROXY_CONFIG = []; + +if (configContent && configContent.BASE_MODULE === 'liquid') { + PROXY_CONFIG.push(...[ + { + context: ['/liquid/api/v1/**'], + target: `http://localhost:8999`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/liquid": "" + }, + }, + { + context: ['/liquid/api/**'], + target: `http://localhost:8999`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/liquid/api/": "/api/v1/" + }, + } + ]); +} + + +if (configContent && configContent.BASE_MODULE === 'bisq') { + PROXY_CONFIG.push(...[ + { + context: ['/bisq/api/v1/ws'], + target: `http://localhost:8999`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/bisq": "" + }, + }, + { + context: ['/bisq/api/v1/**'], + target: `http://localhost:8999`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + }, + { + context: ['/bisq/api/**'], + target: `http://localhost:8999`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/bisq/api/": "/api/v1/bisq/" + }, + } + ]); +} + +PROXY_CONFIG.push(...[ + { + context: ['/api/v1/**'], + target: `http://localhost:8999`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + }, + { + context: ['/api/**'], + target: `http://localhost:8999`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/api/": "/api/v1/" + }, } -} - -// Remove the "/api/**" entry from the default proxy config -let localDevContext = PROXY_CONFIG[0].context - -localDevContext.splice(PROXY_CONFIG[0].context.indexOf('/api/**'), 1); - -PROXY_CONFIG[0].context = localDevContext; - -// Change all targets to localhost -PROXY_CONFIG.map(conf => conf.target = "http://localhost:8999"); - -// Add rules for local backend -if (backendConfigContent) { - PROXY_CONFIG.push({ - context: ['/api/v1/**'], - target: `http://localhost:8999`, - secure: false, - changeOrigin: true, - proxyTimeout: 30000 - }); - PROXY_CONFIG.push({ - context: ['/api/**'], - target: `http://localhost:8999`, - secure: false, - changeOrigin: true, - proxyTimeout: 30000, - pathRewrite: { - "^/api/": "/api/v1/" - }, - }); -} +]); console.log(PROXY_CONFIG); From a45c371e278080617b5e425dfa079b37017ec2d8 Mon Sep 17 00:00:00 2001 From: softsimon Date: Sat, 5 Feb 2022 02:15:28 +0400 Subject: [PATCH 15/41] Adding a "mixed" dev proxy --- frontend/angular.json | 4 ++ frontend/package.json | 1 + frontend/proxy.conf.mixed.js | 99 ++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 frontend/proxy.conf.mixed.js diff --git a/frontend/angular.json b/frontend/angular.json index 054f72318..c2ecbea23 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -218,6 +218,10 @@ "proxyConfig": "proxy.conf.local.js", "verbose": true }, + "mixed": { + "proxyConfig": "proxy.conf.mixed.js", + "verbose": true + }, "staging": { "proxyConfig": "proxy.conf.js", "disableHostCheck": true, diff --git a/frontend/package.json b/frontend/package.json index f00594803..4ef9fb48b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -30,6 +30,7 @@ "start": "npm run generate-config && npm run sync-assets-dev && ng serve -c local", "start:stg": "npm run generate-config && npm run sync-assets-dev && ng serve -c staging", "start:local-prod": "npm run generate-config && npm run sync-assets-dev && ng serve -c local-prod", + "start:mixed": "npm run generate-config && npm run sync-assets-dev && ng serve -c mixed", "build": "npm run generate-config && ng build --configuration production --localize && npm run sync-assets && npm run build-mempool.js", "sync-assets": "node sync-assets.js && rsync -av ./dist/mempool/browser/en-US/resources ./dist/mempool/browser/resources", "sync-assets-dev": "node sync-assets.js dev", diff --git a/frontend/proxy.conf.mixed.js b/frontend/proxy.conf.mixed.js new file mode 100644 index 000000000..6ee44a16f --- /dev/null +++ b/frontend/proxy.conf.mixed.js @@ -0,0 +1,99 @@ +const fs = require('fs'); + +const FRONTEND_CONFIG_FILE_NAME = 'mempool-frontend-config.json'; + +let configContent; + +// Read frontend config +try { + const rawConfig = fs.readFileSync(FRONTEND_CONFIG_FILE_NAME); + configContent = JSON.parse(rawConfig); + console.log(`${FRONTEND_CONFIG_FILE_NAME} file found, using provided config`); +} catch (e) { + console.log(e); + if (e.code !== 'ENOENT') { + throw new Error(e); + } else { + console.log(`${FRONTEND_CONFIG_FILE_NAME} file not found, using default config`); + } +} + +let PROXY_CONFIG = []; + +if (configContent && configContent.BASE_MODULE === 'liquid') { + PROXY_CONFIG.push(...[ + { + context: ['/liquid/api/v1/**'], + target: `http://localhost:8999`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/liquid": "" + }, + }, + { + context: ['/liquid/api/**'], + target: `https://liquid.network`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + }, + ]); +} + +if (configContent && configContent.BASE_MODULE === 'bisq') { + PROXY_CONFIG.push(...[ + { + context: ['/bisq/api/v1/ws'], + target: `http://localhost:8999`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/bisq": "" + }, + }, + { + context: ['/bisq/api/v1/**'], + target: `http://localhost:8999`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + }, + { + context: ['/bisq/api/**'], + target: `http://localhost:8999`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/bisq/api/": "/api/v1/bisq/" + }, + }, + ]); +} + +PROXY_CONFIG.push(...[ + { + context: ['/api/v1/**'], + target: `http://localhost:8999`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + }, + { + context: ['/api/**'], + target: `https://mempool.space`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + } +]); + +console.log(PROXY_CONFIG); + +module.exports = PROXY_CONFIG; \ No newline at end of file From 6b2900345a55ed6676bed9e6a3087a4257539915 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn <100320+knorrium@users.noreply.github.com> Date: Sat, 5 Feb 2022 07:58:35 -0800 Subject: [PATCH 16/41] Rename PRICENODE to PRICE_DATA_SERVER --- README.md | 6 +++--- backend/mempool-config.sample.json | 2 +- backend/src/api/fiat-conversion.ts | 8 ++++---- backend/src/config.ts | 8 ++++---- docker/backend/mempool-config.json | 6 +++--- docker/backend/start.sh | 10 +++++----- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 3dc04b81b..75146d4b1 100644 --- a/README.md +++ b/README.md @@ -267,7 +267,7 @@ docker-compose overrides: JSON: ``` - "PRICENODE": { + "PRICE_DATA_SERVER": { "TOR_URL": "http://wizpriceje6q5tdrxkyiazsgu7irquiqjy2dptezqhrtu7l2qelqktid.onion/getAllMarketPrices", "CLEARNET_URL": "https://price.bisq.wiz.biz/getAllMarketPrices" } @@ -275,8 +275,8 @@ JSON: docker-compose overrides: ``` - PRICENODE_TOR_URL: "" - PRICENODE_CLEARNET_URL: "" + PRICE_DATA_SERVER_TOR_URL: "" + PRICE_DATA_SERVER_CLEARNET_URL: "" ``` # Manual Installation diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index b9d7fb982..dc0f1a69e 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -69,7 +69,7 @@ "USERNAME": "", "PASSWORD": "" }, - "PRICENODE": { + "PRICE_DATA_SERVER": { "TOR_URL": "http://wizpriceje6q5tdrxkyiazsgu7irquiqjy2dptezqhrtu7l2qelqktid.onion/getAllMarketPrices", "CLEARNET_URL": "https://price.bisq.wiz.biz/getAllMarketPrices" } diff --git a/backend/src/api/fiat-conversion.ts b/backend/src/api/fiat-conversion.ts index df10d7698..be5331d7a 100644 --- a/backend/src/api/fiat-conversion.ts +++ b/backend/src/api/fiat-conversion.ts @@ -20,9 +20,9 @@ class FiatConversion { public startService() { logger.info('Starting currency rates service'); if (config.SOCKS5PROXY.ENABLED) { - logger.info(`Currency rates service will be queried over the Tor network using ${config.PRICENODE.TOR_URL}`); + logger.info(`Currency rates service will be queried over the Tor network using ${config.PRICE_DATA_SERVER.TOR_URL}`); } else { - logger.info(`Currency rates service will be queried over clearnet using ${config.PRICENODE.CLEARNET_URL}`); + logger.info(`Currency rates service will be queried over clearnet using ${config.PRICE_DATA_SERVER.CLEARNET_URL}`); } setInterval(this.updateCurrency.bind(this), 1000 * config.MEMPOOL.PRICE_FEED_UPDATE_INTERVAL); this.updateCurrency(); @@ -53,11 +53,11 @@ class FiatConversion { } const agent = new SocksProxyAgent(socksOptions); - fiatConversionUrl = config.PRICENODE.TOR_URL; + fiatConversionUrl = config.PRICE_DATA_SERVER.TOR_URL; logger.info('Querying currency rates service...'); response = await axios.get(fiatConversionUrl, { httpAgent: agent, headers: headers, timeout: 30000 }); } else { - fiatConversionUrl = config.PRICENODE.CLEARNET_URL; + fiatConversionUrl = config.PRICE_DATA_SERVER.CLEARNET_URL; logger.info('Querying currency rates service...'); response = await axios.get(fiatConversionUrl, { headers: headers, timeout: 10000 }); } diff --git a/backend/src/config.ts b/backend/src/config.ts index f2787977b..040d94bf1 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -69,7 +69,7 @@ interface IConfig { USERNAME: string; PASSWORD: string; }; - PRICENODE: { + PRICE_DATA_SERVER: { TOR_URL: string; CLEARNET_URL: string; }; @@ -146,7 +146,7 @@ const defaults: IConfig = { 'USERNAME': '', 'PASSWORD': '' }, - "PRICENODE": { + "PRICE_DATA_SERVER": { 'TOR_URL': 'http://wizpriceje6q5tdrxkyiazsgu7irquiqjy2dptezqhrtu7l2qelqktid.onion/getAllMarketPrices', 'CLEARNET_URL': 'https://price.bisq.wiz.biz/getAllMarketPrices' } @@ -163,7 +163,7 @@ class Config implements IConfig { STATISTICS: IConfig['STATISTICS']; BISQ: IConfig['BISQ']; SOCKS5PROXY: IConfig['SOCKS5PROXY']; - PRICENODE: IConfig['PRICENODE']; + PRICE_DATA_SERVER: IConfig['PRICE_DATA_SERVER']; constructor() { const configs = this.merge(configFile, defaults); @@ -177,7 +177,7 @@ class Config implements IConfig { this.STATISTICS = configs.STATISTICS; this.BISQ = configs.BISQ; this.SOCKS5PROXY = configs.SOCKS5PROXY; - this.PRICENODE = configs.PRICENODE; + this.PRICE_DATA_SERVER = configs.PRICE_DATA_SERVER; } merge = (...objects: object[]): IConfig => { diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json index 5a069455d..b97c9e571 100644 --- a/docker/backend/mempool-config.json +++ b/docker/backend/mempool-config.json @@ -66,8 +66,8 @@ "USERNAME": "__SOCKS5PROXY_USERNAME__", "PASSWORD": "__SOCKS5PROXY_PASSWORD__" }, - "PRICENODE": { - "TOR_URL": "__PRICENODE_TOR_URL__", - "CLEARNET_URL": "__PRICENODE_CLEARNET_URL__" + "PRICE_DATA_SERVER": { + "TOR_URL": "__PRICE_DATA_SERVER_TOR_URL__", + "CLEARNET_URL": "__PRICE_DATA_SERVER_CLEARNET_URL__" } } diff --git a/docker/backend/start.sh b/docker/backend/start.sh index d1422bf45..d12978970 100644 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -68,9 +68,9 @@ __SOCKS5PROXY_PORT__=${SOCKS5PROXY_PORT:=9050} __SOCKS5PROXY_USERNAME__=${SOCKS5PROXY_USERNAME:=""} __SOCKS5PROXY_PASSWORD__=${SOCKS5PROXY_PASSWORD:=""} -# PRICENODE -__PRICENODE_TOR_URL__=${PRICENODE_TOR_URL:=http://wizpriceje6q5tdrxkyiazsgu7irquiqjy2dptezqhrtu7l2qelqktid.onion/getAllMarketPrices} -__PRICENODE_CLEARNET_URL__=${PRICENODE_CLEARNET_URL:=https://price.bisq.wiz.biz/getAllMarketPrices} +# PRICE_DATA_SERVER +__PRICE_DATA_SERVER_TOR_URL__=${PRICE_DATA_SERVER_TOR_URL:=http://wizpriceje6q5tdrxkyiazsgu7irquiqjy2dptezqhrtu7l2qelqktid.onion/getAllMarketPrices} +__PRICE_DATA_SERVER_CLEARNET_URL__=${PRICE_DATA_SERVER_CLEARNET_URL:=https://price.bisq.wiz.biz/getAllMarketPrices} mkdir -p "${__MEMPOOL_CACHE_DIR__}" @@ -132,7 +132,7 @@ sed -i "s/__SOCKS5PROXY_PORT__/${__SOCKS5PROXY_PORT__}/g" mempool-config.json sed -i "s/__SOCKS5PROXY_USERNAME__/${__SOCKS5PROXY_USERNAME__}/g" mempool-config.json sed -i "s/__SOCKS5PROXY_PASSWORD__/${__SOCKS5PROXY_PASSWORD__}/g" mempool-config.json -sed -i "s!__PRICENODE_TOR_URL__!${__PRICENODE_TOR_URL__}!g" mempool-config.json -sed -i "s!__PRICENODE_CLEARNET_URL__!${__PRICENODE_CLEARNET_URL__}!g" mempool-config.json +sed -i "s!__PRICE_DATA_SERVER_TOR_URL__!${__PRICE_DATA_SERVER_TOR_URL__}!g" mempool-config.json +sed -i "s!__PRICE_DATA_SERVER_CLEARNET_URL__!${__PRICE_DATA_SERVER_CLEARNET_URL__}!g" mempool-config.json node /backend/dist/index.js From 4afeb3998a247dbd49bdfdbbd1631268ca5eb8d9 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn <100320+knorrium@users.noreply.github.com> Date: Sat, 5 Feb 2022 15:38:03 -0800 Subject: [PATCH 17/41] Change fiat conversion logs to DEBUG --- backend/src/api/fiat-conversion.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/api/fiat-conversion.ts b/backend/src/api/fiat-conversion.ts index be5331d7a..f28f34a0b 100644 --- a/backend/src/api/fiat-conversion.ts +++ b/backend/src/api/fiat-conversion.ts @@ -54,11 +54,11 @@ class FiatConversion { const agent = new SocksProxyAgent(socksOptions); fiatConversionUrl = config.PRICE_DATA_SERVER.TOR_URL; - logger.info('Querying currency rates service...'); + logger.debug('Querying currency rates service...'); response = await axios.get(fiatConversionUrl, { httpAgent: agent, headers: headers, timeout: 30000 }); } else { fiatConversionUrl = config.PRICE_DATA_SERVER.CLEARNET_URL; - logger.info('Querying currency rates service...'); + logger.debug('Querying currency rates service...'); response = await axios.get(fiatConversionUrl, { headers: headers, timeout: 10000 }); } @@ -68,7 +68,7 @@ class FiatConversion { 'USD': usd.price, }; - logger.info(`USD Conversion Rate: ${usd.price}`); + logger.debug(`USD Conversion Rate: ${usd.price}`); if (this.ratesChangedCallback) { this.ratesChangedCallback(this.conversionRates); From 81ee0e39bc9cc0733b9dbd75f9a0a0e76fee266e Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn <100320+knorrium@users.noreply.github.com> Date: Sat, 5 Feb 2022 21:24:24 -0800 Subject: [PATCH 18/41] Add EXTERNAL_ASSETS defaults to the Docker start script and the README --- README.md | 2 +- docker/backend/start.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 34dca4862..2a7f3d4ea 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ JSON: "MEMPOOL_BLOCKS_AMOUNT": 8, "PRICE_FEED_UPDATE_INTERVAL": 3600, "USE_SECOND_NODE_FOR_MINFEE": false, - "EXTERNAL_ASSETS": [] + "EXTERNAL_ASSETS": ["https://mempool.space/resources/pools.json"] }, ``` diff --git a/docker/backend/start.sh b/docker/backend/start.sh index 372be346e..c72b7f421 100644 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -16,7 +16,7 @@ __MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__=${MEMPOOL_MEMPOOL_BLOCKS_AMOUNT:=8} __MEMPOOL_INDEXING_BLOCKS_AMOUNT__=${MEMPOOL_INDEXING_BLOCKS_AMOUNT:=1100} __MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__=${MEMPOOL_PRICE_FEED_UPDATE_INTERVAL:=3600} __MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__=${MEMPOOL_USE_SECOND_NODE_FOR_MINFEE:=false} -__MEMPOOL_EXTERNAL_ASSETS__=${MEMPOOL_EXTERNAL_ASSETS:=[]} +__MEMPOOL_EXTERNAL_ASSETS__=${MEMPOOL_EXTERNAL_ASSETS:=[\"https://mempool.space/resources/pools.json\"]} # CORE_RPC __CORE_RPC_HOST__=${CORE_RPC_HOST:=127.0.0.1} @@ -78,7 +78,7 @@ sed -i "s/__MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__/${__MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__} sed -i "s/__MEMPOOL_INDEXING_BLOCKS_AMOUNT__/${__MEMPOOL_INDEXING_BLOCKS_AMOUNT__}/g" mempool-config.json sed -i "s/__MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__/${__MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__}/g" mempool-config.json sed -i "s/__MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__/${__MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__}/g" mempool-config.json -sed -i "s/__MEMPOOL_EXTERNAL_ASSETS__/${__MEMPOOL_EXTERNAL_ASSETS__}/g" mempool-config.json +sed -i "s!__MEMPOOL_EXTERNAL_ASSETS__!${__MEMPOOL_EXTERNAL_ASSETS__}!g" mempool-config.json sed -i "s/__CORE_RPC_HOST__/${__CORE_RPC_HOST__}/g" mempool-config.json sed -i "s/__CORE_RPC_PORT__/${__CORE_RPC_PORT__}/g" mempool-config.json From ad38e5fa2dcc12c2dff5707501622e0d48d9d7d7 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn <100320+knorrium@users.noreply.github.com> Date: Sun, 6 Feb 2022 15:10:35 -0800 Subject: [PATCH 19/41] Add mining pools resources route --- frontend/proxy.conf.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/frontend/proxy.conf.js b/frontend/proxy.conf.js index 4a0489c77..77a77bb5a 100644 --- a/frontend/proxy.conf.js +++ b/frontend/proxy.conf.js @@ -20,8 +20,8 @@ try { PROXY_CONFIG = [ { - context: ['*', - '/api/**', '!/api/v1/ws', + context: ['*', + '/api/**', '!/api/v1/ws', '!/bisq', '!/bisq/**', '!/bisq/', '!/liquid', '!/liquid/**', '!/liquid/', '!/liquidtestnet', '!/liquidtestnet/**', '!/liquidtestnet/', @@ -65,7 +65,13 @@ PROXY_CONFIG = [ ws: true, secure: false, changeOrigin: true - } + }, + { + context: ['/resources/mining-pools/**'], + target: "https://mempool.space", + secure: false, + changeOrigin: true + } ]; if (configContent && configContent.BASE_MODULE == "liquid") { From 4af0a75aad1494828bdd55e1e443410d80f38b94 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn <100320+knorrium@users.noreply.github.com> Date: Sun, 6 Feb 2022 15:11:13 -0800 Subject: [PATCH 20/41] Add new proxy config for staging --- frontend/proxy.conf.staging.js | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 frontend/proxy.conf.staging.js diff --git a/frontend/proxy.conf.staging.js b/frontend/proxy.conf.staging.js new file mode 100644 index 000000000..098edb619 --- /dev/null +++ b/frontend/proxy.conf.staging.js @@ -0,0 +1,11 @@ +const fs = require('fs'); + +let PROXY_CONFIG = require('./proxy.conf'); + +PROXY_CONFIG.forEach(entry => { + entry.target = entry.target.replace("mempool.space", "mempool.ninja"); + entry.target = entry.target.replace("liquid.network", "liquid.place"); + entry.target = entry.target.replace("bisq.markets", "bisq.ninja"); +}); + +module.exports = PROXY_CONFIG; From 18a7b13077d551b1ef95c44674dd7a7faf18df37 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn <100320+knorrium@users.noreply.github.com> Date: Sun, 6 Feb 2022 15:12:03 -0800 Subject: [PATCH 21/41] Add new targets to run locally hitting the staging backends --- frontend/angular.json | 6 ++++++ frontend/package.json | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/frontend/angular.json b/frontend/angular.json index c2ecbea23..1d2fe3e6b 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -233,6 +233,12 @@ "disableHostCheck": true, "host": "0.0.0.0", "verbose": false + }, + "local-staging": { + "proxyConfig": "proxy.conf.staging.js", + "disableHostCheck": true, + "host": "0.0.0.0", + "verbose": false } } }, diff --git a/frontend/package.json b/frontend/package.json index 4ef9fb48b..b1723da19 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -27,9 +27,11 @@ "serve": "npm run generate-config && ng serve -c local", "serve:stg": "npm run generate-config && ng serve -c staging", "serve:local-prod": "npm run generate-config && ng serve -c local-prod", + "serve:local-staging": "npm run generate-config && ng serve -c local-staging", "start": "npm run generate-config && npm run sync-assets-dev && ng serve -c local", "start:stg": "npm run generate-config && npm run sync-assets-dev && ng serve -c staging", "start:local-prod": "npm run generate-config && npm run sync-assets-dev && ng serve -c local-prod", + "start:local-staging": "npm run generate-config && npm run sync-assets-dev && ng serve -c local-staging", "start:mixed": "npm run generate-config && npm run sync-assets-dev && ng serve -c mixed", "build": "npm run generate-config && ng build --configuration production --localize && npm run sync-assets && npm run build-mempool.js", "sync-assets": "node sync-assets.js && rsync -av ./dist/mempool/browser/en-US/resources ./dist/mempool/browser/resources", @@ -54,7 +56,10 @@ "cypress:run": "cypress run", "cypress:run:record": "cypress run --record", "cypress:open:ci": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 && npm run generate-config && start-server-and-test serve:local-prod 4200 cypress:open", - "cypress:run:ci": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 && npm run generate-config && start-server-and-test serve:local-prod 4200 cypress:run:record" + "cypress:run:ci": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 && npm run generate-config && start-server-and-test serve:local-prod 4200 cypress:run:record", + "cypress:open:ci:staging": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 && npm run generate-config && start-server-and-test serve:local-staging 4200 cypress:open", + "cypress:run:ci:staging": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 && npm run generate-config && start-server-and-test serve:local-staging 4200 cypress:run:record" + }, "dependencies": { "@angular-devkit/build-angular": "^13.1.2", From 90784ea1eee8b472f25967e45445aa6081130d55 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn <100320+knorrium@users.noreply.github.com> Date: Sun, 6 Feb 2022 15:13:31 -0800 Subject: [PATCH 22/41] Update CI Cypress config to hit staging --- .github/workflows/cypress.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml index 832efcbbf..9173f8827 100644 --- a/.github/workflows/cypress.yml +++ b/.github/workflows/cypress.yml @@ -26,7 +26,7 @@ jobs: with: working-directory: frontend build: npm run config:defaults:mempool - start: npm run start:local-prod + start: npm run start:local-staging wait-on: 'http://localhost:4200' wait-on-timeout: 120 record: true @@ -49,7 +49,7 @@ jobs: with: working-directory: frontend build: npm run config:defaults:liquid - start: npm run start:local-prod + start: npm run start:local-staging wait-on: 'http://localhost:4200' wait-on-timeout: 120 record: true @@ -71,7 +71,7 @@ jobs: with: working-directory: frontend build: npm run config:defaults:bisq - start: npm run start:local-prod + start: npm run start:local-staging wait-on: 'http://localhost:4200' wait-on-timeout: 120 record: true From 2e5c8bdfd33baaaaa75810f1054b561e448ae25a Mon Sep 17 00:00:00 2001 From: softsimon Date: Sun, 6 Feb 2022 01:20:26 +0400 Subject: [PATCH 23/41] Featured assets and asset groups --- backend/src/index.ts | 2 + backend/src/routes.ts | 20 ++++++ frontend/src/app/app-routing.module.ts | 35 +++++++-- frontend/src/app/app.module.ts | 8 ++- frontend/src/app/assets/assets.component.html | 71 ------------------- .../src/app/assets/assets.component.spec.ts | 25 ------- .../asset-group/asset-group.component.html | 26 +++++++ .../asset-group/asset-group.component.scss | 57 +++++++++++++++ .../asset-group/asset-group.component.ts | 45 ++++++++++++ .../assets-featured.component.html | 27 +++++++ .../assets-featured.component.scss | 46 ++++++++++++ .../assets-featured.component.ts | 34 +++++++++ .../assets-nav/assets-nav.component.html | 31 ++++++++ .../assets-nav/assets-nav.component.scss | 9 +++ .../assets/assets-nav/assets-nav.component.ts | 23 ++++++ .../components/assets/assets.component.html | 52 ++++++++++++++ .../assets/assets.component.scss | 0 .../assets/assets.component.ts | 12 ++-- frontend/src/app/services/api.service.ts | 8 +++ 19 files changed, 421 insertions(+), 110 deletions(-) delete mode 100644 frontend/src/app/assets/assets.component.html delete mode 100644 frontend/src/app/assets/assets.component.spec.ts create mode 100644 frontend/src/app/components/assets/asset-group/asset-group.component.html create mode 100644 frontend/src/app/components/assets/asset-group/asset-group.component.scss create mode 100644 frontend/src/app/components/assets/asset-group/asset-group.component.ts create mode 100644 frontend/src/app/components/assets/assets-featured/assets-featured.component.html create mode 100644 frontend/src/app/components/assets/assets-featured/assets-featured.component.scss create mode 100644 frontend/src/app/components/assets/assets-featured/assets-featured.component.ts create mode 100644 frontend/src/app/components/assets/assets-nav/assets-nav.component.html create mode 100644 frontend/src/app/components/assets/assets-nav/assets-nav.component.scss create mode 100644 frontend/src/app/components/assets/assets-nav/assets-nav.component.ts create mode 100644 frontend/src/app/components/assets/assets.component.html rename frontend/src/app/{ => components}/assets/assets.component.scss (100%) rename frontend/src/app/{ => components}/assets/assets.component.ts (94%) diff --git a/backend/src/index.ts b/backend/src/index.ts index f78c5922b..5dea199fc 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -319,7 +319,9 @@ class Server { if (Common.isLiquid()) { this.app .get(config.MEMPOOL.API_URL_PREFIX + 'assets/icons', routes.getAllLiquidIcon) + .get(config.MEMPOOL.API_URL_PREFIX + 'assets/featured', routes.$getAllFeaturedLiquidAssets) .get(config.MEMPOOL.API_URL_PREFIX + 'asset/:assetId/icon', routes.getLiquidIcon) + .get(config.MEMPOOL.API_URL_PREFIX + 'asset-group/:id', routes.$getAssetGroup) ; } diff --git a/backend/src/routes.ts b/backend/src/routes.ts index 044f9a3ac..e937678cc 100644 --- a/backend/src/routes.ts +++ b/backend/src/routes.ts @@ -21,6 +21,7 @@ import bitcoinClient from './api/bitcoin/bitcoin-client'; import elementsParser from './api/liquid/elements-parser'; import icons from './api/liquid/icons'; import miningStats from './api/mining'; +import axios from 'axios'; class Routes { constructor() {} @@ -855,6 +856,25 @@ class Routes { res.status(404).send('Asset icons not found'); } } + + public async $getAllFeaturedLiquidAssets(req: Request, res: Response) { + try { + const response = await axios.get('https://mempool.space/api/v1/assets/featured', { responseType: 'stream', timeout: 10000 }); + response.data.pipe(res); + } catch (e) { + res.status(500).end(); + } + } + + public async $getAssetGroup(req: Request, res: Response) { + try { + const response = await axios.get('https://mempool.space/api/v1/asset-group/' + parseInt(req.params.id, 10), + { responseType: 'stream', timeout: 10000 }); + response.data.pipe(res); + } catch (e) { + res.status(500).end(); + } + } } export default new Routes(); diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 36a53781f..243691661 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -10,7 +10,7 @@ import { TelevisionComponent } from './components/television/television.componen import { StatisticsComponent } from './components/statistics/statistics.component'; import { MempoolBlockComponent } from './components/mempool-block/mempool-block.component'; import { AssetComponent } from './components/asset/asset.component'; -import { AssetsComponent } from './assets/assets.component'; +import { AssetsNavComponent } from './components/assets/assets-nav/assets-nav.component'; import { StatusViewComponent } from './components/status-view/status-view.component'; import { DashboardComponent } from './dashboard/dashboard.component'; import { LatestBlocksComponent } from './components/latest-blocks/latest-blocks.component'; @@ -23,6 +23,9 @@ import { SponsorComponent } from './components/sponsor/sponsor.component'; import { LiquidMasterPageComponent } from './components/liquid-master-page/liquid-master-page.component'; import { PushTransactionComponent } from './components/push-transaction/push-transaction.component'; import { PoolRankingComponent } from './components/pool-ranking/pool-ranking.component'; +import { AssetGroupComponent } from './components/assets/asset-group/asset-group.component'; +import { AssetsFeaturedComponent } from './components/assets/assets-featured/assets-featured.component'; +import { AssetsComponent } from './components/assets/assets.component'; let routes: Routes = [ { @@ -343,13 +346,31 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') { path: 'address/:id', component: AddressComponent }, - { - path: 'asset/:id', - component: AssetComponent - }, { path: 'assets', - component: AssetsComponent, + component: AssetsNavComponent, + children: [ + { + path: 'featured', + component: AssetsFeaturedComponent, + }, + { + path: 'all', + component: AssetsComponent, + }, + { + path: 'asset/:id', + component: AssetComponent + }, + { + path: 'asset-group/:id', + component: AssetGroupComponent + }, + { + path: '**', + redirectTo: 'featured' + } + ] }, { path: 'docs/api/:type', @@ -440,7 +461,7 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') { }, { path: 'assets', - component: AssetsComponent, + component: AssetsNavComponent, }, { path: 'docs/api/:type', diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index f9eae0666..97fc16204 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -40,7 +40,8 @@ import { MempoolGraphComponent } from './components/mempool-graph/mempool-graph. import { PoolRankingComponent } from './components/pool-ranking/pool-ranking.component'; import { LbtcPegsGraphComponent } from './components/lbtc-pegs-graph/lbtc-pegs-graph.component'; import { AssetComponent } from './components/asset/asset.component'; -import { AssetsComponent } from './assets/assets.component'; +import { AssetsComponent } from './components/assets/assets.component'; +import { AssetsNavComponent } from './components/assets/assets-nav/assets-nav.component'; import { StatusViewComponent } from './components/status-view/status-view.component'; import { MinerComponent } from './components/miner/miner.component'; import { SharedModule } from './shared/shared.module'; @@ -64,6 +65,8 @@ import { LanguageService } from './services/language.service'; import { SponsorComponent } from './components/sponsor/sponsor.component'; import { PushTransactionComponent } from './components/push-transaction/push-transaction.component'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { AssetsFeaturedComponent } from './components/assets/assets-featured/assets-featured.component'; +import { AssetGroupComponent } from './components/assets/asset-group/asset-group.component'; @NgModule({ declarations: [ @@ -110,6 +113,9 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; PushTransactionComponent, DocsComponent, ApiDocsNavComponent, + AssetsNavComponent, + AssetsFeaturedComponent, + AssetGroupComponent, ], imports: [ BrowserModule.withServerTransition({ appId: 'serverApp' }), diff --git a/frontend/src/app/assets/assets.component.html b/frontend/src/app/assets/assets.component.html deleted file mode 100644 index c8962cd15..000000000 --- a/frontend/src/app/assets/assets.component.html +++ /dev/null @@ -1,71 +0,0 @@ -
-
-

Registered assets

-
-
- -
-
- -
- -
-
- - - -
Median fee~{{ block?.extra?.medianFee | number:'1.0-0' }} sat/vB ~{{ block?.extras?.medianFee | number:'1.0-0' }} sat/vB
- - - - - - - - - - - - - - -
NameTickerIssuer domainAsset ID
{{ asset.name }}{{ asset.ticker }}{{ asset.entity && asset.entity.domain }}{{ asset.asset_id | shortenString : 13 }}
- -
- - - - - - - - - - - - - - - - - - - - - - -
NameTickerIssuer domainAsset ID
- -
- - -
- Error loading assets data. -
- {{ error.error }} -
-
- -
- -
diff --git a/frontend/src/app/assets/assets.component.spec.ts b/frontend/src/app/assets/assets.component.spec.ts deleted file mode 100644 index ed39b7122..000000000 --- a/frontend/src/app/assets/assets.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { AssetsComponent } from './assets.component'; - -describe('AssetsComponent', () => { - let component: AssetsComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ AssetsComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(AssetsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/components/assets/asset-group/asset-group.component.html b/frontend/src/app/components/assets/asset-group/asset-group.component.html new file mode 100644 index 000000000..a6858b76f --- /dev/null +++ b/frontend/src/app/components/assets/asset-group/asset-group.component.html @@ -0,0 +1,26 @@ +
+ +
+

{{ group.group.name }}

+ +
Group of {{ group.group.assets.length | number }} assets
+
+ + +
+ +
+ +
+
+
+ + +
{{ asset.ticker }}
+
+
+
+ +
diff --git a/frontend/src/app/components/assets/asset-group/asset-group.component.scss b/frontend/src/app/components/assets/asset-group/asset-group.component.scss new file mode 100644 index 000000000..7a0735a24 --- /dev/null +++ b/frontend/src/app/components/assets/asset-group/asset-group.component.scss @@ -0,0 +1,57 @@ +.image { + width: 150px; + float: left; +} + +.main-title { + float: left +} + +.sub-title { + color: grey; +} + +.featuredBox { + display: flex; + flex-flow: row wrap; + justify-content: center; + gap: 27px; +} + +.card { + background-color: #1d1f31; + width: 200px; + height: 200px; + align-items: center; + justify-content: center; + flex-wrap: wrap; +} + +.title { + font-size: 14px; + font-weight: bold; + margin-top: 10px; +} + +.sub-title { + color: grey; +} + +.assetIcon { + width: 100px; + height: 100px; +} + +.image { + width: 100px; + height: 100px; + align-self: center; +} + +.view-link { + margin-top: 30px; +} + +.ticker { + color: grey; +} diff --git a/frontend/src/app/components/assets/asset-group/asset-group.component.ts b/frontend/src/app/components/assets/asset-group/asset-group.component.ts new file mode 100644 index 000000000..0143121b5 --- /dev/null +++ b/frontend/src/app/components/assets/asset-group/asset-group.component.ts @@ -0,0 +1,45 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, ParamMap } from '@angular/router'; +import { combineLatest, Observable } from 'rxjs'; +import { map, switchMap } from 'rxjs/operators'; +import { ApiService } from 'src/app/services/api.service'; +import { AssetsService } from 'src/app/services/assets.service'; + +@Component({ + selector: 'app-asset-group', + templateUrl: './asset-group.component.html', + styleUrls: ['./asset-group.component.scss'] +}) +export class AssetGroupComponent implements OnInit { + group$: Observable; + + constructor( + private route: ActivatedRoute, + private apiService: ApiService, + private assetsService: AssetsService, + ) { } + + ngOnInit(): void { + this.group$ = this.route.paramMap + .pipe( + switchMap((params: ParamMap) => { + return combineLatest([ + this.assetsService.getAssetsJson$, + this.apiService.getAssetGroup$(params.get('id')), + ]); + }), + map(([assets, group]) => { + const items = []; + // @ts-ignore + for (const item of group.assets) { + items.push(assets[item]); + } + console.log(group); + return { + group: group, + assets: items + }; + }) + ); + } +} diff --git a/frontend/src/app/components/assets/assets-featured/assets-featured.component.html b/frontend/src/app/components/assets/assets-featured/assets-featured.component.html new file mode 100644 index 000000000..bb5ab7f3c --- /dev/null +++ b/frontend/src/app/components/assets/assets-featured/assets-featured.component.html @@ -0,0 +1,27 @@ +
+ +
+
+ + + +
Group of {{ group.assets.length | number }} assets
+
+ + + +
{{ group.ticker }}
+
+
+
+ +
+ + +
+
+
+
+
\ No newline at end of file diff --git a/frontend/src/app/components/assets/assets-featured/assets-featured.component.scss b/frontend/src/app/components/assets/assets-featured/assets-featured.component.scss new file mode 100644 index 000000000..41be2b748 --- /dev/null +++ b/frontend/src/app/components/assets/assets-featured/assets-featured.component.scss @@ -0,0 +1,46 @@ + +.featuredBox { + display: flex; + flex-flow: row wrap; + justify-content: center; + gap: 27px; +} + +.card { + background-color: #1d1f31; + width: 200px; + height: 200px; + align-items: center; + justify-content: center; + flex-wrap: wrap; +} + +.title { + font-size: 14px; + font-weight: bold; + margin-top: 10px; +} + +.sub-title { + color: grey; + font-size: 12px; +} + +.assetIcon { + width: 100px; + height: 100px; +} + +.image { + width: 100px; + height: 100px; + align-self: center; +} + +.view-link { + margin-top: 30px; +} + +.ticker { + color: grey; +} diff --git a/frontend/src/app/components/assets/assets-featured/assets-featured.component.ts b/frontend/src/app/components/assets/assets-featured/assets-featured.component.ts new file mode 100644 index 000000000..23c84679b --- /dev/null +++ b/frontend/src/app/components/assets/assets-featured/assets-featured.component.ts @@ -0,0 +1,34 @@ +import { Component, OnInit } from '@angular/core'; +import { combineLatest, Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { ApiService } from 'src/app/services/api.service'; +import { AssetsService } from 'src/app/services/assets.service'; + +@Component({ + selector: 'app-assets-featured', + templateUrl: './assets-featured.component.html', + styleUrls: ['./assets-featured.component.scss'] +}) +export class AssetsFeaturedComponent implements OnInit { + featuredAssets$: Observable; + + constructor( + private apiService: ApiService, + private assetsService: AssetsService, + ) { } + + ngOnInit(): void { + this.featuredAssets$ = combineLatest([ + this.assetsService.getAssetsJson$, + this.apiService.listFeaturedAssets$(), + ]).pipe( + map(([assetsJson, featured]) => { + return { + assetsJson: assetsJson, + featured: featured, + }; + }) + ); + } + +} diff --git a/frontend/src/app/components/assets/assets-nav/assets-nav.component.html b/frontend/src/app/components/assets/assets-nav/assets-nav.component.html new file mode 100644 index 000000000..9ee7ac72a --- /dev/null +++ b/frontend/src/app/components/assets/assets-nav/assets-nav.component.html @@ -0,0 +1,31 @@ +
+
+

Assets

+
+ + + +
+
+ +
+ +
+
+
+ +
+ + + +
+ +
diff --git a/frontend/src/app/components/assets/assets-nav/assets-nav.component.scss b/frontend/src/app/components/assets/assets-nav/assets-nav.component.scss new file mode 100644 index 000000000..530ed7bdf --- /dev/null +++ b/frontend/src/app/components/assets/assets-nav/assets-nav.component.scss @@ -0,0 +1,9 @@ +ul { + margin-bottom: 20px; + float: left; + +} + +form { + float: right; +} diff --git a/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts b/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts new file mode 100644 index 000000000..e1b31372b --- /dev/null +++ b/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts @@ -0,0 +1,23 @@ +import { Component, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; + +@Component({ + selector: 'app-assets-nav', + templateUrl: './assets-nav.component.html', + styleUrls: ['./assets-nav.component.scss'] +}) +export class AssetsNavComponent implements OnInit { + activeTab = 0; + searchForm: FormGroup; + + constructor( + private formBuilder: FormBuilder, + ) { } + + ngOnInit(): void { + this.searchForm = this.formBuilder.group({ + searchText: [{ value: '', disabled: true }, Validators.required] + }); + } + +} diff --git a/frontend/src/app/components/assets/assets.component.html b/frontend/src/app/components/assets/assets.component.html new file mode 100644 index 000000000..ec9ac079f --- /dev/null +++ b/frontend/src/app/components/assets/assets.component.html @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + +
NameTickerIssuer domainAsset ID
{{ asset.name }}{{ asset.ticker }}{{ asset.entity && asset.entity.domain }}{{ asset.asset_id | shortenString : 13 }}
+ +
+ + + +
+ + + + + + + + + + + + + + + + + + +
NameTickerIssuer domainAsset ID
+ +
+ + +
+ Error loading assets data. +
+ {{ error.error }} +
+
diff --git a/frontend/src/app/assets/assets.component.scss b/frontend/src/app/components/assets/assets.component.scss similarity index 100% rename from frontend/src/app/assets/assets.component.scss rename to frontend/src/app/components/assets/assets.component.scss diff --git a/frontend/src/app/assets/assets.component.ts b/frontend/src/app/components/assets/assets.component.ts similarity index 94% rename from frontend/src/app/assets/assets.component.ts rename to frontend/src/app/components/assets/assets.component.ts index 49c42d76e..d5cbd10ab 100644 --- a/frontend/src/app/assets/assets.component.ts +++ b/frontend/src/app/components/assets/assets.component.ts @@ -1,13 +1,13 @@ import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; -import { AssetsService } from '../services/assets.service'; +import { AssetsService } from 'src/app/services/assets.service'; import { environment } from 'src/environments/environment'; import { FormGroup, FormBuilder, Validators } from '@angular/forms'; import { distinctUntilChanged, map, filter, mergeMap, tap, take } from 'rxjs/operators'; import { ActivatedRoute, Router } from '@angular/router'; import { merge, combineLatest, Observable } from 'rxjs'; -import { AssetExtended } from '../interfaces/electrs.interface'; -import { SeoService } from '../services/seo.service'; -import { StateService } from '../services/state.service'; +import { AssetExtended } from 'src/app/interfaces/electrs.interface'; +import { SeoService } from 'src/app/services/seo.service'; +import { StateService } from 'src/app/services/state.service'; @Component({ selector: 'app-assets', @@ -23,9 +23,9 @@ export class AssetsComponent implements OnInit { searchForm: FormGroup; assets$: Observable; + page = 1; error: any; - page = 1; itemsPerPage: number; contentSpace = window.innerHeight - (250 + 200); fiveItemsPxSize = 250; @@ -49,7 +49,7 @@ export class AssetsComponent implements OnInit { this.assets$ = combineLatest([ this.assetsService.getAssetsJson$, - this.route.queryParams + this.route.queryParams, ]) .pipe( take(1), diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts index 03200c64c..3d9125c25 100644 --- a/frontend/src/app/services/api.service.ts +++ b/frontend/src/app/services/api.service.ts @@ -117,6 +117,14 @@ export class ApiService { return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/pegs/month'); } + listFeaturedAssets$(): Observable { + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/assets/featured'); + } + + getAssetGroup$(id: string): Observable { + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/asset-group/' + id); + } + postTransaction$(hexPayload: string): Observable { return this.httpClient.post(this.apiBaseUrl + this.apiBasePath + '/api/tx', hexPayload, { responseType: 'text' as 'json'}); } From d33c12cdee3bd2ae0708a1dde3c7e3767360063c Mon Sep 17 00:00:00 2001 From: softsimon Date: Sun, 6 Feb 2022 03:31:50 +0400 Subject: [PATCH 24/41] Asset search --- .../assets-nav/assets-nav.component.html | 2 +- .../assets/assets-nav/assets-nav.component.ts | 78 ++++++++++++- .../app/components/assets/assets.component.ts | 103 +++--------------- frontend/src/app/services/assets.service.ts | 27 ++++- 4 files changed, 118 insertions(+), 92 deletions(-) diff --git a/frontend/src/app/components/assets/assets-nav/assets-nav.component.html b/frontend/src/app/components/assets/assets-nav/assets-nav.component.html index 9ee7ac72a..73d391254 100644 --- a/frontend/src/app/components/assets/assets-nav/assets-nav.component.html +++ b/frontend/src/app/components/assets/assets-nav/assets-nav.component.html @@ -15,7 +15,7 @@
- +
diff --git a/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts b/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts index e1b31372b..d7280d50b 100644 --- a/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts +++ b/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts @@ -1,5 +1,15 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Router } from '@angular/router'; +import { NgbTypeahead } from '@ng-bootstrap/ng-bootstrap'; +import { merge, Observable, of, Subject } from 'rxjs'; +import { distinctUntilChanged, filter, map, switchMap } from 'rxjs/operators'; +import { AssetExtended } from 'src/app/interfaces/electrs.interface'; +import { AssetsService } from 'src/app/services/assets.service'; +import { SeoService } from 'src/app/services/seo.service'; +import { StateService } from 'src/app/services/state.service'; +import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url.pipe'; +import { environment } from 'src/environments/environment'; @Component({ selector: 'app-assets-nav', @@ -7,16 +17,78 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms'; styleUrls: ['./assets-nav.component.scss'] }) export class AssetsNavComponent implements OnInit { - activeTab = 0; + @ViewChild('instance', {static: true}) instance: NgbTypeahead; + nativeAssetId = this.stateService.network === 'liquidtestnet' ? environment.nativeTestAssetId : environment.nativeAssetId; searchForm: FormGroup; + assetsCache: AssetExtended[]; + + typeaheadSearchFn: ((text: Observable) => Observable); + formatterFn = (asset: AssetExtended) => asset.name + ' (' + asset.ticker + ')'; + focus$ = new Subject(); + click$ = new Subject(); + + itemsPerPage = 15; constructor( private formBuilder: FormBuilder, + private seoService: SeoService, + private router: Router, + private assetsService: AssetsService, + private stateService: StateService, + private relativeUrlPipe: RelativeUrlPipe, ) { } ngOnInit(): void { + this.typeaheadSearchFn = this.typeaheadSearch; + this.searchForm = this.formBuilder.group({ - searchText: [{ value: '', disabled: true }, Validators.required] + searchText: [{ value: '', disabled: false }, Validators.required] + }); + } + + typeaheadSearch = (text$: Observable) => { + const debouncedText$ = text$.pipe( + distinctUntilChanged() + ); + const clicksWithClosedPopup$ = this.click$.pipe(filter(() => !this.instance.isPopupOpen())); + const inputFocus$ = this.focus$; + + return merge(debouncedText$, inputFocus$, clicksWithClosedPopup$) + .pipe( + switchMap((searchText) => { + if (!searchText.length) { + return of([]); + } + return this.assetsService.getAssetsJson$.pipe( + map((assets) => { + if (searchText.length ) { + const filteredAssets = assets.filter((asset) => asset.name.toLowerCase().indexOf(searchText.toLowerCase()) > -1 + || (asset.ticker || '').toLowerCase().indexOf(searchText.toLowerCase()) > -1 + || (asset.entity && asset.entity.domain || '').toLowerCase().indexOf(searchText.toLowerCase()) > -1); + assets = filteredAssets; + return filteredAssets.slice(0, this.itemsPerPage); + } else { + return assets.slice(0, this.itemsPerPage); + } + }) + ) + }), + ); + } + + itemSelected() { + setTimeout(() => this.search()); + } + + search() { + const searchText = this.searchForm.value.searchText; + this.navigate('/assets/asset/', searchText.asset_id); + } + + navigate(url: string, searchText: string, extras?: any) { + this.router.navigate([this.relativeUrlPipe.transform(url), searchText], extras); + this.searchForm.setValue({ + searchText: '', }); } diff --git a/frontend/src/app/components/assets/assets.component.ts b/frontend/src/app/components/assets/assets.component.ts index d5cbd10ab..542765033 100644 --- a/frontend/src/app/components/assets/assets.component.ts +++ b/frontend/src/app/components/assets/assets.component.ts @@ -1,10 +1,10 @@ import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; import { AssetsService } from 'src/app/services/assets.service'; import { environment } from 'src/environments/environment'; -import { FormGroup, FormBuilder, Validators } from '@angular/forms'; -import { distinctUntilChanged, map, filter, mergeMap, tap, take } from 'rxjs/operators'; +import { FormGroup } from '@angular/forms'; +import { filter, map, switchMap, take } from 'rxjs/operators'; import { ActivatedRoute, Router } from '@angular/router'; -import { merge, combineLatest, Observable } from 'rxjs'; +import { combineLatest, Observable } from 'rxjs'; import { AssetExtended } from 'src/app/interfaces/electrs.interface'; import { SeoService } from 'src/app/services/seo.service'; import { StateService } from 'src/app/services/state.service'; @@ -32,7 +32,6 @@ export class AssetsComponent implements OnInit { constructor( private assetsService: AssetsService, - private formBuilder: FormBuilder, private route: ActivatedRoute, private router: Router, private seoService: SeoService, @@ -43,56 +42,20 @@ export class AssetsComponent implements OnInit { this.seoService.setTitle($localize`:@@ee8f8008bae6ce3a49840c4e1d39b4af23d4c263:Assets`); this.itemsPerPage = Math.max(Math.round(this.contentSpace / this.fiveItemsPxSize) * 5, 10); - this.searchForm = this.formBuilder.group({ - searchText: [{ value: '', disabled: true }, Validators.required] - }); - this.assets$ = combineLatest([ this.assetsService.getAssetsJson$, this.route.queryParams, ]) - .pipe( - take(1), - mergeMap(([assets, qp]) => { - this.assets = Object.values(assets); - if (this.stateService.network === 'liquid') { - // @ts-ignore - this.assets.push({ - name: 'Liquid Bitcoin', - ticker: 'L-BTC', - asset_id: this.nativeAssetId, - }); - } else if (this.stateService.network === 'liquidtestnet') { - // @ts-ignore - this.assets.push({ - name: 'Test Liquid Bitcoin', - ticker: 'tL-BTC', - asset_id: this.nativeAssetId, - }); - } + .pipe( + take(1), + switchMap(([assets, qp]) => { + this.assets = assets; - this.assets = this.assets.sort((a: any, b: any) => a.name.localeCompare(b.name)); - this.assetsCache = this.assets; - this.searchForm.get('searchText').enable(); - - if (qp.search) { - this.searchForm.get('searchText').setValue(qp.search, { emitEvent: false }); - } - - return merge( - this.searchForm.get('searchText').valueChanges - .pipe( - distinctUntilChanged(), - tap((text) => { - this.page = 1; - this.searchTextChanged(text); - }) - ), - this.route.queryParams + return this.route.queryParams .pipe( filter((queryParams) => { const newPage = parseInt(queryParams.page, 10); - if (newPage !== this.page || queryParams.search !== this.searchForm.get('searchText').value) { + if (newPage !== this.page) { return true; } return false; @@ -104,38 +67,19 @@ export class AssetsComponent implements OnInit { } else { this.page = 1; } - if (this.searchForm.get('searchText').value !== (queryParams.search || '')) { - this.searchTextChanged(queryParams.search); - } - if (queryParams.search) { - this.searchForm.get('searchText').setValue(queryParams.search, { emitEvent: false }); - return queryParams.search; - } return ''; }) - ), - ); - }), - map((searchText) => { - const start = (this.page - 1) * this.itemsPerPage; - if (searchText.length ) { - const filteredAssets = this.assetsCache.filter((asset) => asset.name.toLowerCase().indexOf(searchText.toLowerCase()) > -1 - || (asset.ticker || '').toLowerCase().indexOf(searchText.toLowerCase()) > -1); - this.assets = filteredAssets; - return filteredAssets.slice(start, this.itemsPerPage + start); - } else { - this.assets = this.assetsCache; + ); + }), + map(() => { + const start = (this.page - 1) * this.itemsPerPage; return this.assets.slice(start, this.itemsPerPage + start); - } - }) - ); + }) + ); } pageChange(page: number) { - const queryParams = { page: page, search: this.searchForm.get('searchText').value }; - if (queryParams.search === '') { - queryParams.search = null; - } + const queryParams = { page: page }; if (queryParams.page === 1) { queryParams.page = null; } @@ -147,21 +91,6 @@ export class AssetsComponent implements OnInit { }); } - searchTextChanged(text: string) { - const queryParams = { search: text, page: 1 }; - if (queryParams.search === '') { - queryParams.search = null; - } - if (queryParams.page === 1) { - queryParams.page = null; - } - this.router.navigate([], { - relativeTo: this.route, - queryParams: queryParams, - queryParamsHandling: 'merge', - }); - } - trackByAsset(index: number, asset: any) { return asset.asset_id; } diff --git a/frontend/src/app/services/assets.service.ts b/frontend/src/app/services/assets.service.ts index 260a48b7b..d5693abf8 100644 --- a/frontend/src/app/services/assets.service.ts +++ b/frontend/src/app/services/assets.service.ts @@ -3,12 +3,16 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { map, shareReplay, switchMap } from 'rxjs/operators'; import { StateService } from './state.service'; +import { environment } from 'src/environments/environment'; +import { AssetExtended } from '../interfaces/electrs.interface'; @Injectable({ providedIn: 'root' }) export class AssetsService { - getAssetsJson$: Observable; + nativeAssetId = this.stateService.network === 'liquidtestnet' ? environment.nativeTestAssetId : environment.nativeAssetId; + + getAssetsJson$: Observable; getAssetsMinimalJson$: Observable; getMiningPools$: Observable; @@ -24,6 +28,27 @@ export class AssetsService { this.getAssetsJson$ = this.stateService.networkChanged$ .pipe( switchMap(() => this.httpClient.get(`${apiBaseUrl}/resources/assets${this.stateService.network === 'liquidtestnet' ? '-testnet' : ''}.json`)), + map((rawAssets) => { + const assets: AssetExtended[] = Object.values(rawAssets); + + if (this.stateService.network === 'liquid') { + // @ts-ignore + assets.push({ + name: 'Liquid Bitcoin', + ticker: 'L-BTC', + asset_id: this.nativeAssetId, + }); + } else if (this.stateService.network === 'liquidtestnet') { + // @ts-ignore + assets.push({ + name: 'Test Liquid Bitcoin', + ticker: 'tL-BTC', + asset_id: this.nativeAssetId, + }); + } + + return assets.sort((a: any, b: any) => a.name.localeCompare(b.name)); + }), shareReplay(1), ); this.getAssetsMinimalJson$ = this.stateService.networkChanged$ From 91082f27e7186d37afc945350e9fe5ab52157c56 Mon Sep 17 00:00:00 2001 From: softsimon Date: Sun, 6 Feb 2022 04:18:56 +0400 Subject: [PATCH 25/41] SEO and various render fixes. --- .../src/app/components/asset/asset.component.ts | 1 + .../assets/asset-group/asset-group.component.ts | 3 +-- .../assets-featured.component.html | 2 +- .../assets-featured.component.ts | 17 ++--------------- .../assets/assets-nav/assets-nav.component.ts | 6 +++--- .../app/components/assets/assets.component.ts | 2 +- frontend/src/app/services/assets.service.ts | 7 +++++-- 7 files changed, 14 insertions(+), 24 deletions(-) diff --git a/frontend/src/app/components/asset/asset.component.ts b/frontend/src/app/components/asset/asset.component.ts index ecb216052..e57bbee7a 100644 --- a/frontend/src/app/components/asset/asset.component.ts +++ b/frontend/src/app/components/asset/asset.component.ts @@ -63,6 +63,7 @@ export class AssetComponent implements OnInit, OnDestroy { .pipe( switchMap((params: ParamMap) => { this.error = undefined; + this.imageError = false; this.isLoadingAsset = true; this.loadedConfirmedTxCount = 0; this.asset = null; diff --git a/frontend/src/app/components/assets/asset-group/asset-group.component.ts b/frontend/src/app/components/assets/asset-group/asset-group.component.ts index 0143121b5..29cb10dc7 100644 --- a/frontend/src/app/components/assets/asset-group/asset-group.component.ts +++ b/frontend/src/app/components/assets/asset-group/asset-group.component.ts @@ -32,9 +32,8 @@ export class AssetGroupComponent implements OnInit { const items = []; // @ts-ignore for (const item of group.assets) { - items.push(assets[item]); + items.push(assets.objects[item]); } - console.log(group); return { group: group, assets: items diff --git a/frontend/src/app/components/assets/assets-featured/assets-featured.component.html b/frontend/src/app/components/assets/assets-featured/assets-featured.component.html index bb5ab7f3c..937ca8113 100644 --- a/frontend/src/app/components/assets/assets-featured/assets-featured.component.html +++ b/frontend/src/app/components/assets/assets-featured/assets-featured.component.html @@ -1,6 +1,6 @@
-
+
diff --git a/frontend/src/app/components/assets/assets-featured/assets-featured.component.ts b/frontend/src/app/components/assets/assets-featured/assets-featured.component.ts index 23c84679b..db16a8f2b 100644 --- a/frontend/src/app/components/assets/assets-featured/assets-featured.component.ts +++ b/frontend/src/app/components/assets/assets-featured/assets-featured.component.ts @@ -1,8 +1,6 @@ import { Component, OnInit } from '@angular/core'; -import { combineLatest, Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; +import { Observable } from 'rxjs'; import { ApiService } from 'src/app/services/api.service'; -import { AssetsService } from 'src/app/services/assets.service'; @Component({ selector: 'app-assets-featured', @@ -14,21 +12,10 @@ export class AssetsFeaturedComponent implements OnInit { constructor( private apiService: ApiService, - private assetsService: AssetsService, ) { } ngOnInit(): void { - this.featuredAssets$ = combineLatest([ - this.assetsService.getAssetsJson$, - this.apiService.listFeaturedAssets$(), - ]).pipe( - map(([assetsJson, featured]) => { - return { - assetsJson: assetsJson, - featured: featured, - }; - }) - ); + this.featuredAssets$ = this.apiService.listFeaturedAssets$(); } } diff --git a/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts b/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts index d7280d50b..ac8dded67 100644 --- a/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts +++ b/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts @@ -39,6 +39,7 @@ export class AssetsNavComponent implements OnInit { ) { } ngOnInit(): void { + this.seoService.setTitle($localize`:@@ee8f8008bae6ce3a49840c4e1d39b4af23d4c263:Assets`); this.typeaheadSearchFn = this.typeaheadSearch; this.searchForm = this.formBuilder.group({ @@ -62,13 +63,12 @@ export class AssetsNavComponent implements OnInit { return this.assetsService.getAssetsJson$.pipe( map((assets) => { if (searchText.length ) { - const filteredAssets = assets.filter((asset) => asset.name.toLowerCase().indexOf(searchText.toLowerCase()) > -1 + const filteredAssets = assets.array.filter((asset) => asset.name.toLowerCase().indexOf(searchText.toLowerCase()) > -1 || (asset.ticker || '').toLowerCase().indexOf(searchText.toLowerCase()) > -1 || (asset.entity && asset.entity.domain || '').toLowerCase().indexOf(searchText.toLowerCase()) > -1); - assets = filteredAssets; return filteredAssets.slice(0, this.itemsPerPage); } else { - return assets.slice(0, this.itemsPerPage); + return assets.array.slice(0, this.itemsPerPage); } }) ) diff --git a/frontend/src/app/components/assets/assets.component.ts b/frontend/src/app/components/assets/assets.component.ts index 542765033..b6a8a8f1b 100644 --- a/frontend/src/app/components/assets/assets.component.ts +++ b/frontend/src/app/components/assets/assets.component.ts @@ -49,7 +49,7 @@ export class AssetsComponent implements OnInit { .pipe( take(1), switchMap(([assets, qp]) => { - this.assets = assets; + this.assets = assets.array; return this.route.queryParams .pipe( diff --git a/frontend/src/app/services/assets.service.ts b/frontend/src/app/services/assets.service.ts index d5693abf8..9454ef7e2 100644 --- a/frontend/src/app/services/assets.service.ts +++ b/frontend/src/app/services/assets.service.ts @@ -12,7 +12,7 @@ import { AssetExtended } from '../interfaces/electrs.interface'; export class AssetsService { nativeAssetId = this.stateService.network === 'liquidtestnet' ? environment.nativeTestAssetId : environment.nativeAssetId; - getAssetsJson$: Observable; + getAssetsJson$: Observable<{ array: AssetExtended[]; objects: any}>; getAssetsMinimalJson$: Observable; getMiningPools$: Observable; @@ -47,7 +47,10 @@ export class AssetsService { }); } - return assets.sort((a: any, b: any) => a.name.localeCompare(b.name)); + return { + objects: rawAssets, + array: assets.sort((a: any, b: any) => a.name.localeCompare(b.name)), + }; }), shareReplay(1), ); From ff4c097c4812f5afeda5c5faef35303a6ddf75ec Mon Sep 17 00:00:00 2001 From: softsimon Date: Sun, 6 Feb 2022 04:44:40 +0400 Subject: [PATCH 26/41] Mobile layout fixes. --- .../asset-group/asset-group.component.html | 2 +- .../assets-featured.component.html | 8 +++-- .../assets-nav/assets-nav.component.html | 34 ++++++++++--------- .../assets-nav/assets-nav.component.scss | 15 ++++++++ .../components/assets/assets.component.html | 2 +- .../app/components/assets/assets.component.ts | 2 ++ 6 files changed, 43 insertions(+), 20 deletions(-) diff --git a/frontend/src/app/components/assets/asset-group/asset-group.component.html b/frontend/src/app/components/assets/asset-group/asset-group.component.html index a6858b76f..64fe182e9 100644 --- a/frontend/src/app/components/assets/asset-group/asset-group.component.html +++ b/frontend/src/app/components/assets/asset-group/asset-group.component.html @@ -16,7 +16,7 @@
{{ asset.ticker }}
diff --git a/frontend/src/app/components/assets/assets-featured/assets-featured.component.html b/frontend/src/app/components/assets/assets-featured/assets-featured.component.html index 937ca8113..f94157766 100644 --- a/frontend/src/app/components/assets/assets-featured/assets-featured.component.html +++ b/frontend/src/app/components/assets/assets-featured/assets-featured.component.html @@ -3,12 +3,16 @@
- + + +
Group of {{ group.assets.length | number }} assets
- + + + diff --git a/frontend/src/app/components/assets/assets-nav/assets-nav.component.html b/frontend/src/app/components/assets/assets-nav/assets-nav.component.html index 73d391254..c543e1893 100644 --- a/frontend/src/app/components/assets/assets-nav/assets-nav.component.html +++ b/frontend/src/app/components/assets/assets-nav/assets-nav.component.html @@ -3,24 +3,26 @@

Assets

- +