From 9c09c00fab0a1d3f2f409dc8d54975ec82753d96 Mon Sep 17 00:00:00 2001 From: softsimon Date: Fri, 19 Aug 2022 17:54:52 +0400 Subject: [PATCH 01/10] Updated mempool debug log --- backend/src/api/mempool.ts | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/backend/src/api/mempool.ts b/backend/src/api/mempool.ts index 43aea6059..76c8b169f 100644 --- a/backend/src/api/mempool.ts +++ b/backend/src/api/mempool.ts @@ -103,12 +103,11 @@ class Mempool { return txTimes; } - public async $updateMempool() { - logger.debug('Updating mempool'); + public async $updateMempool(): Promise { + logger.debug(`Updating mempool...`); const start = new Date().getTime(); let hasChange: boolean = false; const currentMempoolSize = Object.keys(this.mempoolCache).length; - let txCount = 0; const transactions = await bitcoinApi.$getRawMempool(); const diff = transactions.length - currentMempoolSize; const newTransactions: TransactionExtended[] = []; @@ -124,7 +123,6 @@ class Mempool { try { const transaction = await transactionUtils.$getTransactionExtended(txid); this.mempoolCache[txid] = transaction; - txCount++; if (this.inSync) { this.txPerSecondArray.push(new Date().getTime()); this.vBytesPerSecondArray.push({ @@ -133,14 +131,9 @@ class Mempool { }); } hasChange = true; - if (diff > 0) { - logger.debug('Fetched transaction ' + txCount + ' / ' + diff); - } else { - logger.debug('Fetched transaction ' + txCount); - } newTransactions.push(transaction); } catch (e) { - logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e)); + logger.debug(`Error finding transaction '${txid}' in the mempool: ` + (e instanceof Error ? e.message : e)); } } @@ -197,8 +190,7 @@ class Mempool { const end = new Date().getTime(); const time = end - start; - logger.debug(`New mempool size: ${Object.keys(this.mempoolCache).length} Change: ${diff}`); - logger.debug('Mempool updated in ' + time / 1000 + ' seconds'); + logger.debug(`Mempool updated in ${time / 1000} seconds. New size: ${Object.keys(this.mempoolCache).length} (${diff > 0 ? '+' + diff : diff})`); } public handleRbfTransactions(rbfTransactions: { [txid: string]: TransactionExtended; }) { From 19467de809301ddecbc414676e9c5bbfe29b2977 Mon Sep 17 00:00:00 2001 From: junderw Date: Sun, 18 Sep 2022 22:30:09 +0900 Subject: [PATCH 02/10] Backend: Add block height from timestamp endpoint --- backend/src/api/mining/mining-routes.ts | 20 +++++++++++++ backend/src/repositories/BlocksRepository.ts | 30 ++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/backend/src/api/mining/mining-routes.ts b/backend/src/api/mining/mining-routes.ts index f52d42d1f..c9ace12e5 100644 --- a/backend/src/api/mining/mining-routes.ts +++ b/backend/src/api/mining/mining-routes.ts @@ -27,6 +27,7 @@ class MiningRoutes { .get(config.MEMPOOL.API_URL_PREFIX + 'mining/difficulty-adjustments/:interval', this.$getDifficultyAdjustments) .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/predictions/:interval', this.$getHistoricalBlockPrediction) .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/audit/:hash', this.$getBlockAudit) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/timestamp/:timestamp', this.$getHeightFromTimestamp) ; } @@ -246,6 +247,25 @@ class MiningRoutes { res.status(500).send(e instanceof Error ? e.message : e); } } + + private async $getHeightFromTimestamp(req: Request, res: Response) { + try { + const timestamp = parseInt(req.params.timestamp, 10); + // Prevent non-integers that are not seconds + if (!/^[1-9][0-9]*$/.test(req.params.timestamp) || timestamp >= 2 ** 32) { + throw new Error(`Invalid timestamp, value must be Unix seconds`); + } + const result = await BlocksRepository.$getBlockHeightFromTimestamp( + timestamp, + ); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString()); + res.json(result); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } } export default new MiningRoutes(); diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index 40f670833..c5a1a2ae4 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -392,6 +392,36 @@ class BlocksRepository { } } + /** + * Get the first block at or directly after a given timestamp + * @param timestamp number unix time in seconds + * @returns The height and timestamp of a block (timestamp might vary from given timestamp) + */ + public async $getBlockHeightFromTimestamp( + timestamp: number, + ): Promise<{ height: number; timestamp: number }> { + try { + // Get first block at or after the given timestamp + const query = `SELECT height, blockTimestamp as timestamp FROM blocks + WHERE blockTimestamp >= FROM_UNIXTIME(?) + ORDER BY blockTimestamp ASC + LIMIT 1`; + const params = [timestamp]; + const [rows]: any[][] = await DB.query(query, params); + if (rows.length === 0) { + throw new Error(`No block was found after timestamp ${timestamp}`); + } + + return rows[0]; + } catch (e) { + logger.err( + 'Cannot get block height from timestamp from the db. Reason: ' + + (e instanceof Error ? e.message : e), + ); + throw e; + } + } + /** * Return blocks height */ From 5d1c5b51dd23c7ef6d4445d4f71aee74f2858370 Mon Sep 17 00:00:00 2001 From: junderw Date: Mon, 19 Sep 2022 16:44:53 +0900 Subject: [PATCH 03/10] Fix: Add hash and reverse search order --- backend/src/api/mining/mining-routes.ts | 6 +++++- backend/src/repositories/BlocksRepository.ts | 10 +++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/backend/src/api/mining/mining-routes.ts b/backend/src/api/mining/mining-routes.ts index c9ace12e5..ac4b82363 100644 --- a/backend/src/api/mining/mining-routes.ts +++ b/backend/src/api/mining/mining-routes.ts @@ -251,8 +251,12 @@ class MiningRoutes { private async $getHeightFromTimestamp(req: Request, res: Response) { try { const timestamp = parseInt(req.params.timestamp, 10); + // This will prevent people from entering milliseconds etc. + // Block timestamps are allowed to be up to 2 hours off, so 24 hours + // will never put the maximum value before the most recent block + const nowPlus1day = Math.floor(Date.now() / 1000) + 60 * 60 * 24; // Prevent non-integers that are not seconds - if (!/^[1-9][0-9]*$/.test(req.params.timestamp) || timestamp >= 2 ** 32) { + if (!/^[1-9][0-9]*$/.test(req.params.timestamp) || timestamp > nowPlus1day) { throw new Error(`Invalid timestamp, value must be Unix seconds`); } const result = await BlocksRepository.$getBlockHeightFromTimestamp( diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index c5a1a2ae4..590e9de37 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -399,17 +399,17 @@ class BlocksRepository { */ public async $getBlockHeightFromTimestamp( timestamp: number, - ): Promise<{ height: number; timestamp: number }> { + ): Promise<{ height: number; hash: string; timestamp: number }> { try { // Get first block at or after the given timestamp - const query = `SELECT height, blockTimestamp as timestamp FROM blocks - WHERE blockTimestamp >= FROM_UNIXTIME(?) - ORDER BY blockTimestamp ASC + const query = `SELECT height, hash, blockTimestamp as timestamp FROM blocks + WHERE blockTimestamp <= FROM_UNIXTIME(?) + ORDER BY blockTimestamp DESC LIMIT 1`; const params = [timestamp]; const [rows]: any[][] = await DB.query(query, params); if (rows.length === 0) { - throw new Error(`No block was found after timestamp ${timestamp}`); + throw new Error(`No block was found before timestamp ${timestamp}`); } return rows[0]; From 82a4212b729d0affe0824a0bfe8b67a146459df8 Mon Sep 17 00:00:00 2001 From: softsimon Date: Mon, 12 Sep 2022 17:31:36 +0200 Subject: [PATCH 04/10] Click to close search dropdown --- .../search-form/search-form.component.html | 4 +--- .../components/search-form/search-form.component.ts | 13 ++++++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/components/search-form/search-form.component.html b/frontend/src/app/components/search-form/search-form.component.html index 1303f4a62..4e38ea6e0 100644 --- a/frontend/src/app/components/search-form/search-form.component.html +++ b/frontend/src/app/components/search-form/search-form.component.html @@ -2,9 +2,7 @@
- - - +