From 3db1486bfb1ac7a684c6d48691591e4adbe7591e Mon Sep 17 00:00:00 2001
From: nymkappa <1612910616@pm.me>
Date: Sun, 26 Mar 2023 14:35:10 +0900
Subject: [PATCH 01/79] Fix transaction amount overflow
---
.../transactions-list.component.html | 4 ++--
.../transactions-list.component.scss | 11 ++++++++++-
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.html b/frontend/src/app/components/transactions-list/transactions-list.component.html
index cb54e1870..1549f7871 100644
--- a/frontend/src/app/components/transactions-list/transactions-list.component.html
+++ b/frontend/src/app/components/transactions-list/transactions-list.component.html
@@ -77,7 +77,7 @@
-
+ 1000000}">
@@ -206,7 +206,7 @@
-
+ 1000000}">
diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.scss b/frontend/src/app/components/transactions-list/transactions-list.component.scss
index 08d7d7486..5d6dd7d61 100644
--- a/frontend/src/app/components/transactions-list/transactions-list.component.scss
+++ b/frontend/src/app/components/transactions-list/transactions-list.component.scss
@@ -46,7 +46,16 @@
}
td.amount {
- width: 32.5%;
+ width: 36%;
+ @media (max-width: 576px) {
+ width: 50%;
+ }
+}
+td.amount.large {
+ width: 45%;
+ @media (max-width: 576px) {
+ width: 60%;
+ }
}
.extra-info {
From e9386ec003682ff921737709d234f4832822b0c8 Mon Sep 17 00:00:00 2001
From: Antoni Spaanderman <56turtle56@gmail.com>
Date: Sun, 26 Mar 2023 16:39:45 +0200
Subject: [PATCH 02/79] Add Bitcoin Core RPC cookie authentication option
---
backend/mempool-config.sample.json | 8 +++++--
.../__fixtures__/mempool-config.template.json | 10 ++++++---
backend/src/__tests__/config.test.ts | 8 +++++--
.../bitcoin/bitcoin-api-abstract-factory.ts | 1 +
backend/src/api/bitcoin/bitcoin-client.ts | 3 +++
.../src/api/bitcoin/bitcoin-second-client.ts | 3 +++
backend/src/config.ts | 8 +++++++
backend/src/rpc-api/jsonrpc.ts | 21 ++++++++++++++++---
docker/README.md | 16 ++++++++++----
docker/backend/mempool-config.json | 8 +++++--
docker/backend/start.sh | 8 +++++++
11 files changed, 78 insertions(+), 16 deletions(-)
diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json
index 32becd00d..68b5c3801 100644
--- a/backend/mempool-config.sample.json
+++ b/backend/mempool-config.sample.json
@@ -35,7 +35,9 @@
"PORT": 8332,
"USERNAME": "mempool",
"PASSWORD": "mempool",
- "TIMEOUT": 60000
+ "TIMEOUT": 60000,
+ "COOKIE": false,
+ "COOKIE_PATH": "/path/to/bitcoin/.cookie"
},
"ELECTRUM": {
"HOST": "127.0.0.1",
@@ -52,7 +54,9 @@
"PORT": 8332,
"USERNAME": "mempool",
"PASSWORD": "mempool",
- "TIMEOUT": 60000
+ "TIMEOUT": 60000,
+ "COOKIE": false,
+ "COOKIE_PATH": "/path/to/bitcoin/.cookie"
},
"DATABASE": {
"ENABLED": true,
diff --git a/backend/src/__fixtures__/mempool-config.template.json b/backend/src/__fixtures__/mempool-config.template.json
index 919784464..1d5c7135a 100644
--- a/backend/src/__fixtures__/mempool-config.template.json
+++ b/backend/src/__fixtures__/mempool-config.template.json
@@ -36,7 +36,9 @@
"PORT": 15,
"USERNAME": "__CORE_RPC_USERNAME__",
"PASSWORD": "__CORE_RPC_PASSWORD__",
- "TIMEOUT": 1000
+ "TIMEOUT": 1000,
+ "COOKIE": "__CORE_RPC_COOKIE__",
+ "COOKIE_PATH": "__CORE_RPC_COOKIE_PATH__"
},
"ELECTRUM": {
"HOST": "__ELECTRUM_HOST__",
@@ -53,7 +55,9 @@
"PORT": 17,
"USERNAME": "__SECOND_CORE_RPC_USERNAME__",
"PASSWORD": "__SECOND_CORE_RPC_PASSWORD__",
- "TIMEOUT": 2000
+ "TIMEOUT": 2000,
+ "COOKIE": "__SECOND_CORE_RPC_COOKIE__",
+ "COOKIE_PATH": "__SECOND_CORE_RPC_COOKIE_PATH__"
},
"DATABASE": {
"ENABLED": false,
@@ -119,4 +123,4 @@
"CLIGHTNING": {
"SOCKET": "__CLIGHTNING_SOCKET__"
}
-}
\ No newline at end of file
+}
diff --git a/backend/src/__tests__/config.test.ts b/backend/src/__tests__/config.test.ts
index 278d83f50..f4cf719c6 100644
--- a/backend/src/__tests__/config.test.ts
+++ b/backend/src/__tests__/config.test.ts
@@ -54,7 +54,9 @@ describe('Mempool Backend Config', () => {
PORT: 8332,
USERNAME: 'mempool',
PASSWORD: 'mempool',
- TIMEOUT: 60000
+ TIMEOUT: 60000,
+ COOKIE: false,
+ COOKIE_PATH: ''
});
expect(config.SECOND_CORE_RPC).toStrictEqual({
@@ -62,7 +64,9 @@ describe('Mempool Backend Config', () => {
PORT: 8332,
USERNAME: 'mempool',
PASSWORD: 'mempool',
- TIMEOUT: 60000
+ TIMEOUT: 60000,
+ COOKIE: false,
+ COOKIE_PATH: ''
});
expect(config.DATABASE).toStrictEqual({
diff --git a/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts b/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts
index 7b2802d1b..f8dfe8c26 100644
--- a/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts
+++ b/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts
@@ -25,4 +25,5 @@ export interface BitcoinRpcCredentials {
user: string;
pass: string;
timeout: number;
+ cookie?: string;
}
diff --git a/backend/src/api/bitcoin/bitcoin-client.ts b/backend/src/api/bitcoin/bitcoin-client.ts
index 429638984..f0dab4441 100644
--- a/backend/src/api/bitcoin/bitcoin-client.ts
+++ b/backend/src/api/bitcoin/bitcoin-client.ts
@@ -2,12 +2,15 @@ import config from '../../config';
const bitcoin = require('../../rpc-api/index');
import { BitcoinRpcCredentials } from './bitcoin-api-abstract-factory';
+export const defaultCookiePath = `${process.env.HOME}/.bitcoin/${{mainnet:'',testnet:'testnet3/',signet:'signet/'}[config.MEMPOOL.NETWORK]}.cookie`;
+
const nodeRpcCredentials: BitcoinRpcCredentials = {
host: config.CORE_RPC.HOST,
port: config.CORE_RPC.PORT,
user: config.CORE_RPC.USERNAME,
pass: config.CORE_RPC.PASSWORD,
timeout: config.CORE_RPC.TIMEOUT,
+ cookie: config.CORE_RPC.COOKIE ? config.CORE_RPC.COOKIE_PATH || defaultCookiePath : undefined,
};
export default new bitcoin.Client(nodeRpcCredentials);
diff --git a/backend/src/api/bitcoin/bitcoin-second-client.ts b/backend/src/api/bitcoin/bitcoin-second-client.ts
index 7f81a96a0..85d05556e 100644
--- a/backend/src/api/bitcoin/bitcoin-second-client.ts
+++ b/backend/src/api/bitcoin/bitcoin-second-client.ts
@@ -2,12 +2,15 @@ import config from '../../config';
const bitcoin = require('../../rpc-api/index');
import { BitcoinRpcCredentials } from './bitcoin-api-abstract-factory';
+import { defaultCookiePath } from './bitcoin-client';
+
const nodeRpcCredentials: BitcoinRpcCredentials = {
host: config.SECOND_CORE_RPC.HOST,
port: config.SECOND_CORE_RPC.PORT,
user: config.SECOND_CORE_RPC.USERNAME,
pass: config.SECOND_CORE_RPC.PASSWORD,
timeout: config.SECOND_CORE_RPC.TIMEOUT,
+ cookie: config.SECOND_CORE_RPC.COOKIE ? config.SECOND_CORE_RPC.COOKIE_PATH || defaultCookiePath : undefined,
};
export default new bitcoin.Client(nodeRpcCredentials);
diff --git a/backend/src/config.ts b/backend/src/config.ts
index ff5ea4f9f..b9a3f366a 100644
--- a/backend/src/config.ts
+++ b/backend/src/config.ts
@@ -70,6 +70,8 @@ interface IConfig {
USERNAME: string;
PASSWORD: string;
TIMEOUT: number;
+ COOKIE: boolean;
+ COOKIE_PATH: string;
};
SECOND_CORE_RPC: {
HOST: string;
@@ -77,6 +79,8 @@ interface IConfig {
USERNAME: string;
PASSWORD: string;
TIMEOUT: number;
+ COOKIE: boolean;
+ COOKIE_PATH: string;
};
DATABASE: {
ENABLED: boolean;
@@ -180,6 +184,8 @@ const defaults: IConfig = {
'USERNAME': 'mempool',
'PASSWORD': 'mempool',
'TIMEOUT': 60000,
+ 'COOKIE': false,
+ 'COOKIE_PATH': '' // default value depends on network, see src/api/bitcoin/bitcoin-client
},
'SECOND_CORE_RPC': {
'HOST': '127.0.0.1',
@@ -187,6 +193,8 @@ const defaults: IConfig = {
'USERNAME': 'mempool',
'PASSWORD': 'mempool',
'TIMEOUT': 60000,
+ 'COOKIE': false,
+ 'COOKIE_PATH': ''
},
'DATABASE': {
'ENABLED': true,
diff --git a/backend/src/rpc-api/jsonrpc.ts b/backend/src/rpc-api/jsonrpc.ts
index 4f7a38baa..0bcbdc16c 100644
--- a/backend/src/rpc-api/jsonrpc.ts
+++ b/backend/src/rpc-api/jsonrpc.ts
@@ -1,5 +1,6 @@
var http = require('http')
var https = require('https')
+import { readFileSync } from 'fs';
var JsonRPC = function (opts) {
// @ts-ignore
@@ -55,7 +56,13 @@ JsonRPC.prototype.call = function (method, params) {
}
// use HTTP auth if user and password set
- if (this.opts.user && this.opts.pass) {
+ if (this.opts.cookie) {
+ if (!this.cachedCookie) {
+ this.cachedCookie = readFileSync(this.opts.cookie).toString();
+ }
+ // @ts-ignore
+ requestOptions.auth = this.cachedCookie;
+ } else if (this.opts.user && this.opts.pass) {
// @ts-ignore
requestOptions.auth = this.opts.user + ':' + this.opts.pass
}
@@ -93,7 +100,7 @@ JsonRPC.prototype.call = function (method, params) {
reject(err)
})
- request.on('response', function (response) {
+ request.on('response', (response) => {
clearTimeout(reqTimeout)
// We need to buffer the response chunks in a nonblocking way.
@@ -104,7 +111,7 @@ JsonRPC.prototype.call = function (method, params) {
// When all the responses are finished, we decode the JSON and
// depending on whether it's got a result or an error, we call
// emitSuccess or emitError on the promise.
- response.on('end', function () {
+ response.on('end', () => {
var err
if (cbCalled) return
@@ -113,6 +120,14 @@ JsonRPC.prototype.call = function (method, params) {
try {
var decoded = JSON.parse(buffer)
} catch (e) {
+ // if we authenticated using a cookie and it failed, read the cookie file again
+ if (
+ response.statusCode === 401 /* Unauthorized */ &&
+ this.opts.cookie
+ ) {
+ this.cachedCookie = undefined;
+ }
+
if (response.statusCode !== 200) {
err = new Error('Invalid params, response status code: ' + response.statusCode)
err.code = -32602
diff --git a/docker/README.md b/docker/README.md
index b669b37c8..74b9be0d9 100644
--- a/docker/README.md
+++ b/docker/README.md
@@ -162,7 +162,9 @@ Corresponding `docker-compose.yml` overrides:
"PORT": 8332,
"USERNAME": "mempool",
"PASSWORD": "mempool",
- "TIMEOUT": 60000
+ "TIMEOUT": 60000,
+ "COOKIE": "false",
+ "COOKIE_PATH": ""
},
```
@@ -174,7 +176,9 @@ Corresponding `docker-compose.yml` overrides:
CORE_RPC_PORT: ""
CORE_RPC_USERNAME: ""
CORE_RPC_PASSWORD: ""
- CORE_RPC_TIMEOUT: 60000
+ CORE_RPC_TIMEOUT: 60000,
+ CORE_RPC_COOKIE: ""
+ CORE_RPC_COOKIE_PATH: ""
...
```
@@ -229,7 +233,9 @@ Corresponding `docker-compose.yml` overrides:
"PORT": 8332,
"USERNAME": "mempool",
"PASSWORD": "mempool",
- "TIMEOUT": 60000
+ "TIMEOUT": 60000,
+ "COOKIE": "false",
+ "COOKIE_PATH": ""
},
```
@@ -241,7 +247,9 @@ Corresponding `docker-compose.yml` overrides:
SECOND_CORE_RPC_PORT: ""
SECOND_CORE_RPC_USERNAME: ""
SECOND_CORE_RPC_PASSWORD: ""
- SECOND_CORE_RPC_TIMEOUT: ""
+ SECOND_CORE_RPC_TIMEOUT: "",
+ SECOND_CORE_RPC_COOKIE: ""
+ SECOND_CORE_RPC_COOKIE_PATH: ""
...
```
diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json
index 06ed51f41..7a1db21b4 100644
--- a/docker/backend/mempool-config.json
+++ b/docker/backend/mempool-config.json
@@ -36,7 +36,9 @@
"PORT": __CORE_RPC_PORT__,
"USERNAME": "__CORE_RPC_USERNAME__",
"PASSWORD": "__CORE_RPC_PASSWORD__",
- "TIMEOUT": __CORE_RPC_TIMEOUT__
+ "TIMEOUT": __CORE_RPC_TIMEOUT__,
+ "COOKIE": __CORE_RPC_COOKIE__,
+ "COOKIE_PATH": "__CORE_RPC_COOKIE_PATH__"
},
"ELECTRUM": {
"HOST": "__ELECTRUM_HOST__",
@@ -53,7 +55,9 @@
"PORT": __SECOND_CORE_RPC_PORT__,
"USERNAME": "__SECOND_CORE_RPC_USERNAME__",
"PASSWORD": "__SECOND_CORE_RPC_PASSWORD__",
- "TIMEOUT": __SECOND_CORE_RPC_TIMEOUT__
+ "TIMEOUT": __SECOND_CORE_RPC_TIMEOUT__,
+ "COOKIE": __SECOND_CORE_RPC_COOKIE__,
+ "COOKIE_PATH": "__SECOND_CORE_RPC_COOKIE_PATH__"
},
"DATABASE": {
"ENABLED": __DATABASE_ENABLED__,
diff --git a/docker/backend/start.sh b/docker/backend/start.sh
index cb1108a05..0aa8fde5c 100755
--- a/docker/backend/start.sh
+++ b/docker/backend/start.sh
@@ -38,6 +38,8 @@ __CORE_RPC_PORT__=${CORE_RPC_PORT:=8332}
__CORE_RPC_USERNAME__=${CORE_RPC_USERNAME:=mempool}
__CORE_RPC_PASSWORD__=${CORE_RPC_PASSWORD:=mempool}
__CORE_RPC_TIMEOUT__=${CORE_RPC_TIMEOUT:=60000}
+__CORE_RPC_COOKIE__=${CORE_RPC_COOKIE:=false}
+__CORE_RPC_COOKIE_PATH__=${CORE_RPC_COOKIE:=""}
# ELECTRUM
__ELECTRUM_HOST__=${ELECTRUM_HOST:=127.0.0.1}
@@ -55,6 +57,8 @@ __SECOND_CORE_RPC_PORT__=${SECOND_CORE_RPC_PORT:=8332}
__SECOND_CORE_RPC_USERNAME__=${SECOND_CORE_RPC_USERNAME:=mempool}
__SECOND_CORE_RPC_PASSWORD__=${SECOND_CORE_RPC_PASSWORD:=mempool}
__SECOND_CORE_RPC_TIMEOUT__=${SECOND_CORE_RPC_TIMEOUT:=60000}
+__SECOND_CORE_RPC_COOKIE__=${SECOND_CORE_RPC_COOKIE:=false}
+__SECOND_CORE_RPC_COOKIE_PATH__=${SECOND_CORE_RPC_COOKIE:=""}
# DATABASE
__DATABASE_ENABLED__=${DATABASE_ENABLED:=true}
@@ -165,6 +169,8 @@ sed -i "s!__CORE_RPC_PORT__!${__CORE_RPC_PORT__}!g" mempool-config.json
sed -i "s!__CORE_RPC_USERNAME__!${__CORE_RPC_USERNAME__}!g" mempool-config.json
sed -i "s!__CORE_RPC_PASSWORD__!${__CORE_RPC_PASSWORD__}!g" mempool-config.json
sed -i "s!__CORE_RPC_TIMEOUT__!${__CORE_RPC_TIMEOUT__}!g" mempool-config.json
+sed -i "s!__CORE_RPC_COOKIE__!${__CORE_RPC_COOKIE__}!g" mempool-config.json
+sed -i "s!__CORE_RPC_COOKIE_PATH__!${__CORE_RPC_COOKIE_PATH__}!g" mempool-config.json
sed -i "s!__ELECTRUM_HOST__!${__ELECTRUM_HOST__}!g" mempool-config.json
sed -i "s!__ELECTRUM_PORT__!${__ELECTRUM_PORT__}!g" mempool-config.json
@@ -179,6 +185,8 @@ sed -i "s!__SECOND_CORE_RPC_PORT__!${__SECOND_CORE_RPC_PORT__}!g" mempool-config
sed -i "s!__SECOND_CORE_RPC_USERNAME__!${__SECOND_CORE_RPC_USERNAME__}!g" mempool-config.json
sed -i "s!__SECOND_CORE_RPC_PASSWORD__!${__SECOND_CORE_RPC_PASSWORD__}!g" mempool-config.json
sed -i "s!__SECOND_CORE_RPC_TIMEOUT__!${__SECOND_CORE_RPC_TIMEOUT__}!g" mempool-config.json
+sed -i "s!__SECOND_CORE_RPC_COOKIE__!${__SECOND_CORE_RPC_COOKIE__}!g" mempool-config.json
+sed -i "s!__SECOND_CORE_RPC_COOKIE_PATH__!${__SECOND_CORE_RPC_COOKIE_PATH__}!g" mempool-config.json
sed -i "s!__DATABASE_ENABLED__!${__DATABASE_ENABLED__}!g" mempool-config.json
sed -i "s!__DATABASE_HOST__!${__DATABASE_HOST__}!g" mempool-config.json
From dc491a598405cfaa641dfbed011e5a5cd3812654 Mon Sep 17 00:00:00 2001
From: Antoni Spaanderman <56turtle56@gmail.com>
Date: Mon, 27 Mar 2023 21:28:45 +0200
Subject: [PATCH 03/79] change default cookie path to /bitcoin/.cookie
---
backend/src/__tests__/config.test.ts | 4 ++--
backend/src/api/bitcoin/bitcoin-client.ts | 4 +---
backend/src/api/bitcoin/bitcoin-second-client.ts | 4 +---
backend/src/config.ts | 4 ++--
4 files changed, 6 insertions(+), 10 deletions(-)
diff --git a/backend/src/__tests__/config.test.ts b/backend/src/__tests__/config.test.ts
index f4cf719c6..d1d8222bd 100644
--- a/backend/src/__tests__/config.test.ts
+++ b/backend/src/__tests__/config.test.ts
@@ -56,7 +56,7 @@ describe('Mempool Backend Config', () => {
PASSWORD: 'mempool',
TIMEOUT: 60000,
COOKIE: false,
- COOKIE_PATH: ''
+ COOKIE_PATH: '/bitcoin/.cookie'
});
expect(config.SECOND_CORE_RPC).toStrictEqual({
@@ -66,7 +66,7 @@ describe('Mempool Backend Config', () => {
PASSWORD: 'mempool',
TIMEOUT: 60000,
COOKIE: false,
- COOKIE_PATH: ''
+ COOKIE_PATH: '/bitcoin/.cookie'
});
expect(config.DATABASE).toStrictEqual({
diff --git a/backend/src/api/bitcoin/bitcoin-client.ts b/backend/src/api/bitcoin/bitcoin-client.ts
index f0dab4441..e8b30a888 100644
--- a/backend/src/api/bitcoin/bitcoin-client.ts
+++ b/backend/src/api/bitcoin/bitcoin-client.ts
@@ -2,15 +2,13 @@ import config from '../../config';
const bitcoin = require('../../rpc-api/index');
import { BitcoinRpcCredentials } from './bitcoin-api-abstract-factory';
-export const defaultCookiePath = `${process.env.HOME}/.bitcoin/${{mainnet:'',testnet:'testnet3/',signet:'signet/'}[config.MEMPOOL.NETWORK]}.cookie`;
-
const nodeRpcCredentials: BitcoinRpcCredentials = {
host: config.CORE_RPC.HOST,
port: config.CORE_RPC.PORT,
user: config.CORE_RPC.USERNAME,
pass: config.CORE_RPC.PASSWORD,
timeout: config.CORE_RPC.TIMEOUT,
- cookie: config.CORE_RPC.COOKIE ? config.CORE_RPC.COOKIE_PATH || defaultCookiePath : undefined,
+ cookie: config.CORE_RPC.COOKIE ? config.CORE_RPC.COOKIE_PATH : undefined,
};
export default new bitcoin.Client(nodeRpcCredentials);
diff --git a/backend/src/api/bitcoin/bitcoin-second-client.ts b/backend/src/api/bitcoin/bitcoin-second-client.ts
index 85d05556e..6ae9cefb0 100644
--- a/backend/src/api/bitcoin/bitcoin-second-client.ts
+++ b/backend/src/api/bitcoin/bitcoin-second-client.ts
@@ -2,15 +2,13 @@ import config from '../../config';
const bitcoin = require('../../rpc-api/index');
import { BitcoinRpcCredentials } from './bitcoin-api-abstract-factory';
-import { defaultCookiePath } from './bitcoin-client';
-
const nodeRpcCredentials: BitcoinRpcCredentials = {
host: config.SECOND_CORE_RPC.HOST,
port: config.SECOND_CORE_RPC.PORT,
user: config.SECOND_CORE_RPC.USERNAME,
pass: config.SECOND_CORE_RPC.PASSWORD,
timeout: config.SECOND_CORE_RPC.TIMEOUT,
- cookie: config.SECOND_CORE_RPC.COOKIE ? config.SECOND_CORE_RPC.COOKIE_PATH || defaultCookiePath : undefined,
+ cookie: config.SECOND_CORE_RPC.COOKIE ? config.SECOND_CORE_RPC.COOKIE_PATH : undefined,
};
export default new bitcoin.Client(nodeRpcCredentials);
diff --git a/backend/src/config.ts b/backend/src/config.ts
index b9a3f366a..eb1b0af21 100644
--- a/backend/src/config.ts
+++ b/backend/src/config.ts
@@ -185,7 +185,7 @@ const defaults: IConfig = {
'PASSWORD': 'mempool',
'TIMEOUT': 60000,
'COOKIE': false,
- 'COOKIE_PATH': '' // default value depends on network, see src/api/bitcoin/bitcoin-client
+ 'COOKIE_PATH': '/bitcoin/.cookie'
},
'SECOND_CORE_RPC': {
'HOST': '127.0.0.1',
@@ -194,7 +194,7 @@ const defaults: IConfig = {
'PASSWORD': 'mempool',
'TIMEOUT': 60000,
'COOKIE': false,
- 'COOKIE_PATH': ''
+ 'COOKIE_PATH': '/bitcoin/.cookie'
},
'DATABASE': {
'ENABLED': true,
From 0d69ad43ab26c7d2150e4b8460e762b7e06241e0 Mon Sep 17 00:00:00 2001
From: Antoni Spaanderman <56turtle56@gmail.com>
Date: Sun, 18 Jun 2023 20:34:56 +0200
Subject: [PATCH 04/79] fix config issues
---
.../src/__fixtures__/mempool-config.template.json | 4 ++--
docker/README.md | 12 ++++++------
docker/backend/mempool-config.json | 2 +-
docker/backend/start.sh | 4 ++--
4 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/backend/src/__fixtures__/mempool-config.template.json b/backend/src/__fixtures__/mempool-config.template.json
index 1d5c7135a..cdf188b88 100644
--- a/backend/src/__fixtures__/mempool-config.template.json
+++ b/backend/src/__fixtures__/mempool-config.template.json
@@ -37,7 +37,7 @@
"USERNAME": "__CORE_RPC_USERNAME__",
"PASSWORD": "__CORE_RPC_PASSWORD__",
"TIMEOUT": 1000,
- "COOKIE": "__CORE_RPC_COOKIE__",
+ "COOKIE": false,
"COOKIE_PATH": "__CORE_RPC_COOKIE_PATH__"
},
"ELECTRUM": {
@@ -56,7 +56,7 @@
"USERNAME": "__SECOND_CORE_RPC_USERNAME__",
"PASSWORD": "__SECOND_CORE_RPC_PASSWORD__",
"TIMEOUT": 2000,
- "COOKIE": "__SECOND_CORE_RPC_COOKIE__",
+ "COOKIE": false,
"COOKIE_PATH": "__SECOND_CORE_RPC_COOKIE_PATH__"
},
"DATABASE": {
diff --git a/docker/README.md b/docker/README.md
index 74b9be0d9..997a330b4 100644
--- a/docker/README.md
+++ b/docker/README.md
@@ -163,7 +163,7 @@ Corresponding `docker-compose.yml` overrides:
"USERNAME": "mempool",
"PASSWORD": "mempool",
"TIMEOUT": 60000,
- "COOKIE": "false",
+ "COOKIE": false,
"COOKIE_PATH": ""
},
```
@@ -176,8 +176,8 @@ Corresponding `docker-compose.yml` overrides:
CORE_RPC_PORT: ""
CORE_RPC_USERNAME: ""
CORE_RPC_PASSWORD: ""
- CORE_RPC_TIMEOUT: 60000,
- CORE_RPC_COOKIE: ""
+ CORE_RPC_TIMEOUT: 60000
+ CORE_RPC_COOKIE: false
CORE_RPC_COOKIE_PATH: ""
...
```
@@ -234,7 +234,7 @@ Corresponding `docker-compose.yml` overrides:
"USERNAME": "mempool",
"PASSWORD": "mempool",
"TIMEOUT": 60000,
- "COOKIE": "false",
+ "COOKIE": false,
"COOKIE_PATH": ""
},
```
@@ -247,8 +247,8 @@ Corresponding `docker-compose.yml` overrides:
SECOND_CORE_RPC_PORT: ""
SECOND_CORE_RPC_USERNAME: ""
SECOND_CORE_RPC_PASSWORD: ""
- SECOND_CORE_RPC_TIMEOUT: "",
- SECOND_CORE_RPC_COOKIE: ""
+ SECOND_CORE_RPC_TIMEOUT: ""
+ SECOND_CORE_RPC_COOKIE: false
SECOND_CORE_RPC_COOKIE_PATH: ""
...
```
diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json
index 7a1db21b4..a91a52d6b 100644
--- a/docker/backend/mempool-config.json
+++ b/docker/backend/mempool-config.json
@@ -129,4 +129,4 @@
"GEOLITE2_ASN": "__MAXMIND_GEOLITE2_ASN__",
"GEOIP2_ISP": "__MAXMIND_GEOIP2_ISP__"
}
-}
\ No newline at end of file
+}
diff --git a/docker/backend/start.sh b/docker/backend/start.sh
index 0aa8fde5c..1dce5e811 100755
--- a/docker/backend/start.sh
+++ b/docker/backend/start.sh
@@ -39,7 +39,7 @@ __CORE_RPC_USERNAME__=${CORE_RPC_USERNAME:=mempool}
__CORE_RPC_PASSWORD__=${CORE_RPC_PASSWORD:=mempool}
__CORE_RPC_TIMEOUT__=${CORE_RPC_TIMEOUT:=60000}
__CORE_RPC_COOKIE__=${CORE_RPC_COOKIE:=false}
-__CORE_RPC_COOKIE_PATH__=${CORE_RPC_COOKIE:=""}
+__CORE_RPC_COOKIE_PATH__=${CORE_RPC_COOKIE_PATH:=""}
# ELECTRUM
__ELECTRUM_HOST__=${ELECTRUM_HOST:=127.0.0.1}
@@ -58,7 +58,7 @@ __SECOND_CORE_RPC_USERNAME__=${SECOND_CORE_RPC_USERNAME:=mempool}
__SECOND_CORE_RPC_PASSWORD__=${SECOND_CORE_RPC_PASSWORD:=mempool}
__SECOND_CORE_RPC_TIMEOUT__=${SECOND_CORE_RPC_TIMEOUT:=60000}
__SECOND_CORE_RPC_COOKIE__=${SECOND_CORE_RPC_COOKIE:=false}
-__SECOND_CORE_RPC_COOKIE_PATH__=${SECOND_CORE_RPC_COOKIE:=""}
+__SECOND_CORE_RPC_COOKIE_PATH__=${SECOND_CORE_RPC_COOKIE_PATH:=""}
# DATABASE
__DATABASE_ENABLED__=${DATABASE_ENABLED:=true}
From 223f6df3713729eb02dbedd4eefdf16a43c53dc9 Mon Sep 17 00:00:00 2001
From: nymkappa <1612910616@pm.me>
Date: Sat, 5 Aug 2023 10:52:11 +0900
Subject: [PATCH 05/79] fix 'large' class trigger
---
.../transactions-list/transactions-list.component.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.html b/frontend/src/app/components/transactions-list/transactions-list.component.html
index ef34bf822..24d34d6ec 100644
--- a/frontend/src/app/components/transactions-list/transactions-list.component.html
+++ b/frontend/src/app/components/transactions-list/transactions-list.component.html
@@ -81,7 +81,7 @@
- 1000000}">
+ 1000000000}">
@@ -222,7 +222,7 @@
- 1000000}">
+ 1000000000}">
From c1f0eac8f8d3aa7db9a8cc93ed7ee4ee24ff5603 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Thu, 14 Sep 2023 22:57:37 +0000
Subject: [PATCH 06/79] Add REQUEST_TIMEOUT and FALLBACK_TIMEOUT esplora config
options
---
backend/mempool-config.sample.json | 2 ++
backend/src/__fixtures__/mempool-config.template.json | 2 ++
backend/src/__tests__/config.test.ts | 2 ++
backend/src/api/bitcoin/esplora-api.ts | 8 ++++----
backend/src/config.ts | 4 ++++
docker/backend/mempool-config.json | 2 ++
docker/backend/start.sh | 4 ++++
7 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json
index 00fe95cc5..32ff8330f 100644
--- a/backend/mempool-config.sample.json
+++ b/backend/mempool-config.sample.json
@@ -51,6 +51,8 @@
"REST_API_URL": "http://127.0.0.1:3000",
"UNIX_SOCKET_PATH": "/tmp/esplora-bitcoin-mainnet",
"RETRY_UNIX_SOCKET_AFTER": 30000,
+ "REQUEST_TIMEOUT": 10000,
+ "FALLBACK_TIMEOUT": 5000,
"FALLBACK": []
},
"SECOND_CORE_RPC": {
diff --git a/backend/src/__fixtures__/mempool-config.template.json b/backend/src/__fixtures__/mempool-config.template.json
index 1b6c8d411..060bcad4f 100644
--- a/backend/src/__fixtures__/mempool-config.template.json
+++ b/backend/src/__fixtures__/mempool-config.template.json
@@ -52,6 +52,8 @@
"REST_API_URL": "__ESPLORA_REST_API_URL__",
"UNIX_SOCKET_PATH": "__ESPLORA_UNIX_SOCKET_PATH__",
"RETRY_UNIX_SOCKET_AFTER": 888,
+ "REQUEST_TIMEOUT": 10000,
+ "FALLBACK_TIMEOUT": 5000,
"FALLBACK": []
},
"SECOND_CORE_RPC": {
diff --git a/backend/src/__tests__/config.test.ts b/backend/src/__tests__/config.test.ts
index 8097a2465..0ca6fa98a 100644
--- a/backend/src/__tests__/config.test.ts
+++ b/backend/src/__tests__/config.test.ts
@@ -56,6 +56,8 @@ describe('Mempool Backend Config', () => {
REST_API_URL: 'http://127.0.0.1:3000',
UNIX_SOCKET_PATH: null,
RETRY_UNIX_SOCKET_AFTER: 30000,
+ REQUEST_TIMEOUT: 10000,
+ FALLBACK_TIMEOUT: 5000,
FALLBACK: [],
});
diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts
index d6d4327cb..0f3c6290d 100644
--- a/backend/src/api/bitcoin/esplora-api.ts
+++ b/backend/src/api/bitcoin/esplora-api.ts
@@ -75,9 +75,9 @@ class FailoverRouter {
const results = await Promise.allSettled(this.hosts.map(async (host) => {
if (host.socket) {
- return this.pollConnection.get('/blocks/tip/height', { socketPath: host.host, timeout: 5000 });
+ return this.pollConnection.get('/blocks/tip/height', { socketPath: host.host, timeout: config.ESPLORA.FALLBACK_TIMEOUT });
} else {
- return this.pollConnection.get(host.host + '/blocks/tip/height', { timeout: 5000 });
+ return this.pollConnection.get(host.host + '/blocks/tip/height', { timeout: config.ESPLORA.FALLBACK_TIMEOUT });
}
}));
const maxHeight = results.reduce((max, result) => Math.max(max, result.status === 'fulfilled' ? result.value?.data || 0 : 0), 0);
@@ -168,10 +168,10 @@ class FailoverRouter {
let axiosConfig;
let url;
if (host.socket) {
- axiosConfig = { socketPath: host.host, timeout: 10000, responseType };
+ axiosConfig = { socketPath: host.host, timeout: config.ESPLORA.REQUEST_TIMEOUT, responseType };
url = path;
} else {
- axiosConfig = { timeout: 10000, responseType };
+ axiosConfig = { timeout: config.ESPLORA.REQUEST_TIMEOUT, responseType };
url = host.host + path;
}
return (method === 'post'
diff --git a/backend/src/config.ts b/backend/src/config.ts
index ed320d957..275d3314e 100644
--- a/backend/src/config.ts
+++ b/backend/src/config.ts
@@ -44,6 +44,8 @@ interface IConfig {
REST_API_URL: string;
UNIX_SOCKET_PATH: string | void | null;
RETRY_UNIX_SOCKET_AFTER: number;
+ REQUEST_TIMEOUT: number;
+ FALLBACK_TIMEOUT: number;
FALLBACK: string[];
};
LIGHTNING: {
@@ -189,6 +191,8 @@ const defaults: IConfig = {
'REST_API_URL': 'http://127.0.0.1:3000',
'UNIX_SOCKET_PATH': null,
'RETRY_UNIX_SOCKET_AFTER': 30000,
+ 'REQUEST_TIMEOUT': 10000,
+ 'FALLBACK_TIMEOUT': 5000,
'FALLBACK': [],
},
'ELECTRUM': {
diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json
index aa084133f..caa7b045f 100644
--- a/docker/backend/mempool-config.json
+++ b/docker/backend/mempool-config.json
@@ -52,6 +52,8 @@
"REST_API_URL": "__ESPLORA_REST_API_URL__",
"UNIX_SOCKET_PATH": "__ESPLORA_UNIX_SOCKET_PATH__",
"RETRY_UNIX_SOCKET_AFTER": __ESPLORA_RETRY_UNIX_SOCKET_AFTER__,
+ "REQUEST_TIMEOUT": __ESPLORA_REQUEST_TIMEOUT__,
+ "FALLBACK_TIMEOUT": __ESPLORA_FALLBACK_TIMEOUT__,
"FALLBACK": __ESPLORA_FALLBACK__
},
"SECOND_CORE_RPC": {
diff --git a/docker/backend/start.sh b/docker/backend/start.sh
index 2e293ce34..5b8ae1464 100755
--- a/docker/backend/start.sh
+++ b/docker/backend/start.sh
@@ -53,6 +53,8 @@ __ELECTRUM_TLS_ENABLED__=${ELECTRUM_TLS_ENABLED:=false}
__ESPLORA_REST_API_URL__=${ESPLORA_REST_API_URL:=http://127.0.0.1:3000}
__ESPLORA_UNIX_SOCKET_PATH__=${ESPLORA_UNIX_SOCKET_PATH:="null"}
__ESPLORA_RETRY_UNIX_SOCKET_AFTER__=${ESPLORA_RETRY_UNIX_SOCKET_AFTER:=30000}
+__ESPLORA_REQUEST_TIMEOUT__=${ESPLORA_REQUEST_TIMEOUT:=5000}
+__ESPLORA_FALLBACK_TIMEOUT__=${ESPLORA_FALLBACK_TIMEOUT:=5000}
__ESPLORA_FALLBACK__=${ESPLORA_FALLBACK:=[]}
# SECOND_CORE_RPC
@@ -193,6 +195,8 @@ sed -i "s!__ELECTRUM_TLS_ENABLED__!${__ELECTRUM_TLS_ENABLED__}!g" mempool-config
sed -i "s!__ESPLORA_REST_API_URL__!${__ESPLORA_REST_API_URL__}!g" mempool-config.json
sed -i "s!__ESPLORA_UNIX_SOCKET_PATH__!${__ESPLORA_UNIX_SOCKET_PATH__}!g" mempool-config.json
sed -i "s!__ESPLORA_RETRY_UNIX_SOCKET_AFTER__!${__ESPLORA_RETRY_UNIX_SOCKET_AFTER__}!g" mempool-config.json
+sed -i "s!__ESPLORA_REQUEST_TIMEOUT__!${__ESPLORA_REQUEST_TIMEOUT__}!g" mempool-config.json
+sed -i "s!__ESPLORA_FALLBACK_TIMEOUT__!${__ESPLORA_FALLBACK_TIMEOUT__}!g" mempool-config.json
sed -i "s!__ESPLORA_FALLBACK__!${__ESPLORA_FALLBACK__}!g" mempool-config.json
sed -i "s!__SECOND_CORE_RPC_HOST__!${__SECOND_CORE_RPC_HOST__}!g" mempool-config.json
From 441b505aa3666b6298b8f6792f4ca5a1a4e0cf53 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Mon, 11 Sep 2023 11:04:01 +0900
Subject: [PATCH 07/79] Send correct tx conf status in websocket msgs
---
backend/src/api/blocks.ts | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts
index 73b010b91..64dc1d5ba 100644
--- a/backend/src/api/blocks.ts
+++ b/backend/src/api/blocks.ts
@@ -81,6 +81,7 @@ class Blocks {
private async $getTransactionsExtended(
blockHash: string,
blockHeight: number,
+ blockTime: number,
onlyCoinbase: boolean,
txIds: string[] | null = null,
quiet: boolean = false,
@@ -101,6 +102,12 @@ class Blocks {
if (!onlyCoinbase) {
for (const txid of txIds) {
if (mempool[txid]) {
+ mempool[txid].status = {
+ confirmed: true,
+ block_height: blockHeight,
+ block_hash: blockHash,
+ block_time: blockTime,
+ };
transactionMap[txid] = mempool[txid];
foundInMempool++;
totalFound++;
@@ -608,7 +615,7 @@ class Blocks {
}
const blockHash = await bitcoinApi.$getBlockHash(blockHeight);
const block: IEsploraApi.Block = await bitcoinApi.$getBlock(blockHash);
- const transactions = await this.$getTransactionsExtended(blockHash, block.height, true, null, true);
+ const transactions = await this.$getTransactionsExtended(blockHash, block.height, block.timestamp, true, null, true);
const blockExtended = await this.$getBlockExtended(block, transactions);
newlyIndexed++;
@@ -701,7 +708,7 @@ class Blocks {
const verboseBlock = await bitcoinClient.getBlock(blockHash, 2);
const block = BitcoinApi.convertBlock(verboseBlock);
const txIds: string[] = verboseBlock.tx.map(tx => tx.txid);
- const transactions = await this.$getTransactionsExtended(blockHash, block.height, false, txIds, false, true) as MempoolTransactionExtended[];
+ const transactions = await this.$getTransactionsExtended(blockHash, block.height, block.timestamp, false, txIds, false, true) as MempoolTransactionExtended[];
// fill in missing transaction fee data from verboseBlock
for (let i = 0; i < transactions.length; i++) {
@@ -890,7 +897,7 @@ class Blocks {
const blockHash = await bitcoinApi.$getBlockHash(height);
const block: IEsploraApi.Block = await bitcoinApi.$getBlock(blockHash);
- const transactions = await this.$getTransactionsExtended(blockHash, block.height, true);
+ const transactions = await this.$getTransactionsExtended(blockHash, block.height, block.timestamp, true);
const blockExtended = await this.$getBlockExtended(block, transactions);
if (Common.indexingEnabled()) {
@@ -902,7 +909,7 @@ class Blocks {
public async $indexStaleBlock(hash: string): Promise {
const block: IEsploraApi.Block = await bitcoinApi.$getBlock(hash);
- const transactions = await this.$getTransactionsExtended(hash, block.height, true);
+ const transactions = await this.$getTransactionsExtended(hash, block.height, block.timestamp, true);
const blockExtended = await this.$getBlockExtended(block, transactions);
blockExtended.canonical = await bitcoinApi.$getBlockHash(block.height);
From f3fc774c2d3f5de657e00414ab37a654b20e7605 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Thu, 21 Sep 2023 21:57:54 +0100
Subject: [PATCH 08/79] Add standalone block visualization page
---
frontend/src/app/app-routing.module.ts | 5 +
.../block-view/block-view.component.html | 13 ++
.../block-view/block-view.component.scss | 22 +++
.../block-view/block-view.component.ts | 176 ++++++++++++++++++
frontend/src/app/shared/shared.module.ts | 3 +
5 files changed, 219 insertions(+)
create mode 100644 frontend/src/app/components/block-view/block-view.component.html
create mode 100644 frontend/src/app/components/block-view/block-view.component.scss
create mode 100644 frontend/src/app/components/block-view/block-view.component.ts
diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts
index 79a8e1c02..7ca9e107b 100644
--- a/frontend/src/app/app-routing.module.ts
+++ b/frontend/src/app/app-routing.module.ts
@@ -4,6 +4,7 @@ import { AppPreloadingStrategy } from './app.preloading-strategy'
import { StartComponent } from './components/start/start.component';
import { TransactionComponent } from './components/transaction/transaction.component';
import { BlockComponent } from './components/block/block.component';
+import { BlockViewComponent } from './components/block-view/block-view.component';
import { ClockComponent } from './components/clock/clock.component';
import { AddressComponent } from './components/address/address.component';
import { MasterPageComponent } from './components/master-page/master-page.component';
@@ -373,6 +374,10 @@ let routes: Routes = [
path: 'clock/:mode/:index',
component: ClockComponent,
},
+ {
+ path: 'view/block/:id',
+ component: BlockViewComponent,
+ },
{
path: 'status',
data: { networks: ['bitcoin', 'liquid'] },
diff --git a/frontend/src/app/components/block-view/block-view.component.html b/frontend/src/app/components/block-view/block-view.component.html
new file mode 100644
index 000000000..905c69198
--- /dev/null
+++ b/frontend/src/app/components/block-view/block-view.component.html
@@ -0,0 +1,13 @@
+
diff --git a/frontend/src/app/components/block-view/block-view.component.scss b/frontend/src/app/components/block-view/block-view.component.scss
new file mode 100644
index 000000000..782d416d8
--- /dev/null
+++ b/frontend/src/app/components/block-view/block-view.component.scss
@@ -0,0 +1,22 @@
+.block-wrapper {
+ width: 100vw;
+ height: 100vh;
+ background: #181b2d;
+}
+
+.block-container {
+ flex-grow: 0;
+ flex-shrink: 0;
+ width: 100vw;
+ max-width: 100vh;
+ height: 100vh;
+ padding: 0;
+ margin: auto;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ * {
+ flex-grow: 1;
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/app/components/block-view/block-view.component.ts b/frontend/src/app/components/block-view/block-view.component.ts
new file mode 100644
index 000000000..ef1a7247b
--- /dev/null
+++ b/frontend/src/app/components/block-view/block-view.component.ts
@@ -0,0 +1,176 @@
+import { Component, OnInit, OnDestroy, ViewChild, HostListener } from '@angular/core';
+import { ActivatedRoute, ParamMap } from '@angular/router';
+import { ElectrsApiService } from '../../services/electrs-api.service';
+import { switchMap, tap, throttleTime, catchError, shareReplay, startWith, pairwise, filter } from 'rxjs/operators';
+import { of, Subscription, asyncScheduler } from 'rxjs';
+import { StateService } from '../../services/state.service';
+import { SeoService } from '../../services/seo.service';
+import { OpenGraphService } from '../../services/opengraph.service';
+import { BlockExtended, TransactionStripped } from '../../interfaces/node-api.interface';
+import { ApiService } from '../../services/api.service';
+import { seoDescriptionNetwork } from '../../shared/common.utils';
+import { BlockOverviewGraphComponent } from '../block-overview-graph/block-overview-graph.component';
+
+function bestFitResolution(min, max, n) {
+ const target = (min + max) / 2;
+ let bestScore = Infinity;
+ let best = null;
+ for (let i = min; i <= max; i++) {
+ const remainder = (n % i);
+ if (remainder < bestScore || (remainder === bestScore && (Math.abs(i - target) < Math.abs(best - target)))) {
+ bestScore = remainder;
+ best = i;
+ }
+ }
+ return best;
+}
+
+@Component({
+ selector: 'app-block-view',
+ templateUrl: './block-view.component.html',
+ styleUrls: ['./block-view.component.scss']
+})
+export class BlockViewComponent implements OnInit, OnDestroy {
+ network = '';
+ block: BlockExtended;
+ blockHeight: number;
+ blockHash: string;
+ rawId: string;
+ isLoadingBlock = true;
+ strippedTransactions: TransactionStripped[];
+ isLoadingOverview = true;
+ autofit: boolean = false;
+ resolution: number = 80;
+
+ overviewSubscription: Subscription;
+ networkChangedSubscription: Subscription;
+ queryParamsSubscription: Subscription;
+
+ @ViewChild('blockGraph') blockGraph: BlockOverviewGraphComponent;
+
+ constructor(
+ private route: ActivatedRoute,
+ private electrsApiService: ElectrsApiService,
+ public stateService: StateService,
+ private seoService: SeoService,
+ private openGraphService: OpenGraphService,
+ private apiService: ApiService
+ ) { }
+
+ ngOnInit() {
+ this.network = this.stateService.network;
+
+ this.queryParamsSubscription = this.route.queryParams.subscribe((params) => {
+ this.autofit = params.autofit === 'true';
+ if (this.autofit) {
+ this.onResize();
+ }
+ });
+
+ const block$ = this.route.paramMap.pipe(
+ switchMap((params: ParamMap) => {
+ this.rawId = params.get('id') || '';
+
+ const blockHash: string = params.get('id') || '';
+ this.block = undefined;
+
+ let isBlockHeight = false;
+ if (/^[0-9]+$/.test(blockHash)) {
+ isBlockHeight = true;
+ } else {
+ this.blockHash = blockHash;
+ }
+
+ this.isLoadingBlock = true;
+ this.isLoadingOverview = true;
+
+ if (isBlockHeight) {
+ return this.electrsApiService.getBlockHashFromHeight$(parseInt(blockHash, 10))
+ .pipe(
+ switchMap((hash) => {
+ if (hash) {
+ this.blockHash = hash;
+ return this.apiService.getBlock$(hash);
+ } else {
+ return null;
+ }
+ }),
+ catchError(() => {
+ return of(null);
+ }),
+ );
+ }
+ return this.apiService.getBlock$(blockHash);
+ }),
+ filter((block: BlockExtended | void) => block != null),
+ tap((block: BlockExtended) => {
+ this.block = block;
+ this.blockHeight = block.height;
+
+ this.seoService.setTitle($localize`:@@block.component.browser-title:Block ${block.height}:BLOCK_HEIGHT:: ${block.id}:BLOCK_ID:`);
+ if( this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet' ) {
+ this.seoService.setDescription($localize`:@@meta.description.liquid.block:See size, weight, fee range, included transactions, and more for Liquid${seoDescriptionNetwork(this.stateService.network)} block ${block.height}:BLOCK_HEIGHT: (${block.id}:BLOCK_ID:).`);
+ } else {
+ this.seoService.setDescription($localize`:@@meta.description.bitcoin.block:See size, weight, fee range, included transactions, audit (expected v actual), and more for Bitcoin${seoDescriptionNetwork(this.stateService.network)} block ${block.height}:BLOCK_HEIGHT: (${block.id}:BLOCK_ID:).`);
+ }
+ this.isLoadingBlock = false;
+ this.isLoadingOverview = true;
+ }),
+ shareReplay(1)
+ );
+
+ this.overviewSubscription = block$.pipe(
+ switchMap((block) => this.apiService.getStrippedBlockTransactions$(block.id)
+ .pipe(
+ catchError(() => {
+ return of([]);
+ }),
+ switchMap((transactions) => {
+ return of(transactions);
+ })
+ )
+ ),
+ )
+ .subscribe((transactions: TransactionStripped[]) => {
+ this.strippedTransactions = transactions;
+ this.isLoadingOverview = false;
+ if (this.blockGraph) {
+ this.blockGraph.destroy();
+ this.blockGraph.setup(this.strippedTransactions);
+ }
+ },
+ () => {
+ this.isLoadingOverview = false;
+ if (this.blockGraph) {
+ this.blockGraph.destroy();
+ }
+ });
+
+ this.networkChangedSubscription = this.stateService.networkChanged$
+ .subscribe((network) => this.network = network);
+ }
+
+ @HostListener('window:resize', ['$event'])
+ onResize(): void {
+ if (this.autofit) {
+ this.resolution = bestFitResolution(64, 96, Math.min(window.innerWidth, window.innerHeight));
+ console.log('resized, new resolution ', this.resolution, window.innerWidth, window.innerHeight);
+ // if (this.blockGraph && this.strippedTransactions) {
+ // this.blockGraph.destroy();
+ // this.blockGraph.setup(this.strippedTransactions);
+ // }
+ }
+ }
+
+ ngOnDestroy() {
+ if (this.overviewSubscription) {
+ this.overviewSubscription.unsubscribe();
+ }
+ if (this.networkChangedSubscription) {
+ this.networkChangedSubscription.unsubscribe();
+ }
+ if (this.queryParamsSubscription) {
+ this.queryParamsSubscription.unsubscribe();
+ }
+ }
+}
diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts
index f7c253a96..bba70a2ce 100644
--- a/frontend/src/app/shared/shared.module.ts
+++ b/frontend/src/app/shared/shared.module.ts
@@ -97,6 +97,7 @@ import { AcceleratePreviewComponent } from '../components/accelerate-preview/acc
import { AccelerateFeeGraphComponent } from '../components/accelerate-preview/accelerate-fee-graph.component';
import { MempoolErrorComponent } from './components/mempool-error/mempool-error.component';
+import { BlockViewComponent } from '../components/block-view/block-view.component';
import { MempoolBlockOverviewComponent } from '../components/mempool-block-overview/mempool-block-overview.component';
import { ClockchainComponent } from '../components/clockchain/clockchain.component';
import { ClockFaceComponent } from '../components/clock-face/clock-face.component';
@@ -134,6 +135,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
FiatCurrencyPipe,
ColoredPriceDirective,
BlockchainComponent,
+ BlockViewComponent,
MempoolBlocksComponent,
BlockchainBlocksComponent,
AmountComponent,
@@ -196,6 +198,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
AccelerateFeeGraphComponent,
CalculatorComponent,
BitcoinsatoshisPipe,
+ BlockViewComponent,
MempoolBlockOverviewComponent,
ClockchainComponent,
ClockComponent,
From 80afcae645a282235a08428c3e2e3b7179539443 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sat, 23 Sep 2023 00:40:47 +0100
Subject: [PATCH 09/79] Fix faq blockchain positioning
---
.../app/docs/api-docs/api-docs.component.html | 12 +++++-
.../app/docs/api-docs/api-docs.component.scss | 43 ++++++++++++++++---
.../app/docs/api-docs/api-docs.component.ts | 9 +++-
3 files changed, 56 insertions(+), 8 deletions(-)
diff --git a/frontend/src/app/docs/api-docs/api-docs.component.html b/frontend/src/app/docs/api-docs/api-docs.component.html
index 40a7ae486..48a8bf418 100644
--- a/frontend/src/app/docs/api-docs/api-docs.component.html
+++ b/frontend/src/app/docs/api-docs/api-docs.component.html
@@ -137,8 +137,16 @@
A mempool explorer is a tool that enables you to view real-time and historical information about a node's mempool, visualize its transactions, and search and view those transactions.
The mempool.space website invented the concept of visualizing a Bitcoin node's mempool as projected blocks . These blocks are the inspiration for our half-filled block logo.
Projected blocks are on the left of the dotted white line, and confirmed blocks are on the right.
-
-
+
diff --git a/frontend/src/app/docs/api-docs/api-docs.component.scss b/frontend/src/app/docs/api-docs/api-docs.component.scss
index b90b843d9..f90274046 100644
--- a/frontend/src/app/docs/api-docs/api-docs.component.scss
+++ b/frontend/src/app/docs/api-docs/api-docs.component.scss
@@ -259,13 +259,46 @@ h3 {
}
.blockchain-wrapper {
- position: relative;
+ display: block;
+ height: 100%;
width: 100%;
- overflow: auto;
- scrollbar-width: none;
+ min-height: 220px;
+ position: relative;
+ overflow: hidden;
+
+ .position-container {
+ position: absolute;
+ left: 50%;
+ bottom: 150px;
+ }
+
+ #divider {
+ width: 2px;
+ height: 175px;
+ left: 0;
+ top: -40px;
+ position: absolute;
+ }
+
+ &.time-ltr {
+ .blocks-wrapper {
+ transform: scaleX(-1);
+ }
+ }
}
-.blockchain-wrapper::-webkit-scrollbar {
- display: none;
+
+:host-context(.ltr-layout) {
+ .blockchain-wrapper.time-ltr .blocks-wrapper,
+ .blockchain-wrapper .blocks-wrapper {
+ direction: ltr;
+ }
+}
+
+:host-context(.rtl-layout) {
+ .blockchain-wrapper.time-ltr .blocks-wrapper,
+ .blockchain-wrapper .blocks-wrapper {
+ direction: rtl;
+ }
}
#disclaimer {
diff --git a/frontend/src/app/docs/api-docs/api-docs.component.ts b/frontend/src/app/docs/api-docs/api-docs.component.ts
index b0ae5967d..333bb01ad 100644
--- a/frontend/src/app/docs/api-docs/api-docs.component.ts
+++ b/frontend/src/app/docs/api-docs/api-docs.component.ts
@@ -1,6 +1,6 @@
import { Component, OnInit, Input, QueryList, AfterViewInit, ViewChildren } from '@angular/core';
import { Env, StateService } from '../../services/state.service';
-import { Observable, merge, of, Subject } from 'rxjs';
+import { Observable, merge, of, Subject, Subscription } from 'rxjs';
import { tap, takeUntil } from 'rxjs/operators';
import { ActivatedRoute } from "@angular/router";
import { faqData, restApiDocsData, wsApiDocsData } from './api-docs-data';
@@ -30,6 +30,8 @@ export class ApiDocsComponent implements OnInit, AfterViewInit {
officialMempoolInstance: boolean;
auditEnabled: boolean;
mobileViewport: boolean = false;
+ timeLtrSubscription: Subscription;
+ timeLtr: boolean = this.stateService.timeLtr.value;
@ViewChildren(FaqTemplateDirective) faqTemplates: QueryList
;
dict = {};
@@ -104,12 +106,17 @@ export class ApiDocsComponent implements OnInit, AfterViewInit {
this.electrsPort = 51302; break;
}
});
+
+ this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => {
+ this.timeLtr = !!ltr;
+ });
}
ngOnDestroy(): void {
this.destroy$.next(true);
this.destroy$.complete();
window.removeEventListener('scroll', this.onDocScroll);
+ this.timeLtrSubscription.unsubscribe();
}
onDocScroll() {
From 72750267d01922f0e189e8105c12e5f48c2e6001 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sat, 23 Sep 2023 22:25:22 +0100
Subject: [PATCH 10/79] Enable navigation from standalone block page
---
.../block-view/block-view.component.html | 1 +
.../block-view/block-view.component.ts | 30 +++++++++++--------
2 files changed, 18 insertions(+), 13 deletions(-)
diff --git a/frontend/src/app/components/block-view/block-view.component.html b/frontend/src/app/components/block-view/block-view.component.html
index 905c69198..9a2ddf373 100644
--- a/frontend/src/app/components/block-view/block-view.component.html
+++ b/frontend/src/app/components/block-view/block-view.component.html
@@ -8,6 +8,7 @@
[orientation]="'top'"
[flip]="false"
[disableSpinner]="true"
+ (txClickEvent)="onTxClick($event)"
>
diff --git a/frontend/src/app/components/block-view/block-view.component.ts b/frontend/src/app/components/block-view/block-view.component.ts
index ef1a7247b..5c3b7719c 100644
--- a/frontend/src/app/components/block-view/block-view.component.ts
+++ b/frontend/src/app/components/block-view/block-view.component.ts
@@ -1,17 +1,17 @@
import { Component, OnInit, OnDestroy, ViewChild, HostListener } from '@angular/core';
-import { ActivatedRoute, ParamMap } from '@angular/router';
+import { ActivatedRoute, ParamMap, Router } from '@angular/router';
import { ElectrsApiService } from '../../services/electrs-api.service';
-import { switchMap, tap, throttleTime, catchError, shareReplay, startWith, pairwise, filter } from 'rxjs/operators';
-import { of, Subscription, asyncScheduler } from 'rxjs';
+import { switchMap, tap, catchError, shareReplay, filter } from 'rxjs/operators';
+import { of, Subscription } from 'rxjs';
import { StateService } from '../../services/state.service';
import { SeoService } from '../../services/seo.service';
-import { OpenGraphService } from '../../services/opengraph.service';
import { BlockExtended, TransactionStripped } from '../../interfaces/node-api.interface';
import { ApiService } from '../../services/api.service';
import { seoDescriptionNetwork } from '../../shared/common.utils';
import { BlockOverviewGraphComponent } from '../block-overview-graph/block-overview-graph.component';
+import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
-function bestFitResolution(min, max, n) {
+function bestFitResolution(min, max, n): number {
const target = (min + max) / 2;
let bestScore = Infinity;
let best = null;
@@ -50,14 +50,14 @@ export class BlockViewComponent implements OnInit, OnDestroy {
constructor(
private route: ActivatedRoute,
+ private router: Router,
private electrsApiService: ElectrsApiService,
public stateService: StateService,
private seoService: SeoService,
- private openGraphService: OpenGraphService,
private apiService: ApiService
) { }
- ngOnInit() {
+ ngOnInit(): void {
this.network = this.stateService.network;
this.queryParamsSubscription = this.route.queryParams.subscribe((params) => {
@@ -150,19 +150,23 @@ export class BlockViewComponent implements OnInit, OnDestroy {
.subscribe((network) => this.network = network);
}
+ onTxClick(event: { tx: TransactionStripped, keyModifier: boolean }): void {
+ const url = new RelativeUrlPipe(this.stateService).transform(`/tx/${event.tx.txid}`);
+ if (!event.keyModifier) {
+ this.router.navigate([url]);
+ } else {
+ window.open(url, '_blank');
+ }
+ }
+
@HostListener('window:resize', ['$event'])
onResize(): void {
if (this.autofit) {
this.resolution = bestFitResolution(64, 96, Math.min(window.innerWidth, window.innerHeight));
- console.log('resized, new resolution ', this.resolution, window.innerWidth, window.innerHeight);
- // if (this.blockGraph && this.strippedTransactions) {
- // this.blockGraph.destroy();
- // this.blockGraph.setup(this.strippedTransactions);
- // }
}
}
- ngOnDestroy() {
+ ngOnDestroy(): void {
if (this.overviewSubscription) {
this.overviewSubscription.unsubscribe();
}
From 6773af92edce65739570682dc55ffca369b6ed74 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sat, 23 Sep 2023 23:09:11 +0100
Subject: [PATCH 11/79] Add standalone mempool block visualization page
---
frontend/src/app/app-routing.module.ts | 5 ++
.../mempool-block-view.component.html | 5 ++
.../mempool-block-view.component.scss | 22 +++++
.../mempool-block-view.component.ts | 85 +++++++++++++++++++
frontend/src/app/shared/shared.module.ts | 3 +
5 files changed, 120 insertions(+)
create mode 100644 frontend/src/app/components/mempool-block-view/mempool-block-view.component.html
create mode 100644 frontend/src/app/components/mempool-block-view/mempool-block-view.component.scss
create mode 100644 frontend/src/app/components/mempool-block-view/mempool-block-view.component.ts
diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts
index 7ca9e107b..7c2ac1274 100644
--- a/frontend/src/app/app-routing.module.ts
+++ b/frontend/src/app/app-routing.module.ts
@@ -5,6 +5,7 @@ import { StartComponent } from './components/start/start.component';
import { TransactionComponent } from './components/transaction/transaction.component';
import { BlockComponent } from './components/block/block.component';
import { BlockViewComponent } from './components/block-view/block-view.component';
+import { MempoolBlockViewComponent } from './components/mempool-block-view/mempool-block-view.component';
import { ClockComponent } from './components/clock/clock.component';
import { AddressComponent } from './components/address/address.component';
import { MasterPageComponent } from './components/master-page/master-page.component';
@@ -378,6 +379,10 @@ let routes: Routes = [
path: 'view/block/:id',
component: BlockViewComponent,
},
+ {
+ path: 'view/mempool-block/:index',
+ component: MempoolBlockViewComponent,
+ },
{
path: 'status',
data: { networks: ['bitcoin', 'liquid'] },
diff --git a/frontend/src/app/components/mempool-block-view/mempool-block-view.component.html b/frontend/src/app/components/mempool-block-view/mempool-block-view.component.html
new file mode 100644
index 000000000..9d51ff4e9
--- /dev/null
+++ b/frontend/src/app/components/mempool-block-view/mempool-block-view.component.html
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/frontend/src/app/components/mempool-block-view/mempool-block-view.component.scss b/frontend/src/app/components/mempool-block-view/mempool-block-view.component.scss
new file mode 100644
index 000000000..782d416d8
--- /dev/null
+++ b/frontend/src/app/components/mempool-block-view/mempool-block-view.component.scss
@@ -0,0 +1,22 @@
+.block-wrapper {
+ width: 100vw;
+ height: 100vh;
+ background: #181b2d;
+}
+
+.block-container {
+ flex-grow: 0;
+ flex-shrink: 0;
+ width: 100vw;
+ max-width: 100vh;
+ height: 100vh;
+ padding: 0;
+ margin: auto;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ * {
+ flex-grow: 1;
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/app/components/mempool-block-view/mempool-block-view.component.ts b/frontend/src/app/components/mempool-block-view/mempool-block-view.component.ts
new file mode 100644
index 000000000..ebeb0801c
--- /dev/null
+++ b/frontend/src/app/components/mempool-block-view/mempool-block-view.component.ts
@@ -0,0 +1,85 @@
+import { Component, OnInit, OnDestroy, HostListener } from '@angular/core';
+import { ActivatedRoute, ParamMap } from '@angular/router';
+import { Subscription, filter, map, switchMap, tap } from 'rxjs';
+import { StateService } from '../../services/state.service';
+import { WebsocketService } from '../../services/websocket.service';
+
+function bestFitResolution(min, max, n): number {
+ const target = (min + max) / 2;
+ let bestScore = Infinity;
+ let best = null;
+ for (let i = min; i <= max; i++) {
+ const remainder = (n % i);
+ if (remainder < bestScore || (remainder === bestScore && (Math.abs(i - target) < Math.abs(best - target)))) {
+ bestScore = remainder;
+ best = i;
+ }
+ }
+ return best;
+}
+
+@Component({
+ selector: 'app-mempool-block-view',
+ templateUrl: './mempool-block-view.component.html',
+ styleUrls: ['./mempool-block-view.component.scss']
+})
+export class MempoolBlockViewComponent implements OnInit, OnDestroy {
+ autofit: boolean = false;
+ resolution: number = 80;
+ index: number = 0;
+
+ routeParamsSubscription: Subscription;
+ queryParamsSubscription: Subscription;
+
+ constructor(
+ private route: ActivatedRoute,
+ private websocketService: WebsocketService,
+ public stateService: StateService,
+ ) { }
+
+ ngOnInit(): void {
+ this.websocketService.want(['blocks', 'mempool-blocks']);
+
+ this.routeParamsSubscription = this.route.paramMap
+ .pipe(
+ switchMap((params: ParamMap) => {
+ this.index = parseInt(params.get('index'), 10) || 0;
+ return this.stateService.mempoolBlocks$
+ .pipe(
+ map((blocks) => {
+ if (!blocks.length) {
+ return [{ index: 0, blockSize: 0, blockVSize: 0, feeRange: [0, 0], medianFee: 0, nTx: 0, totalFees: 0 }];
+ }
+ return blocks;
+ }),
+ filter((mempoolBlocks) => mempoolBlocks.length > 0),
+ tap((mempoolBlocks) => {
+ while (!mempoolBlocks[this.index]) {
+ this.index--;
+ }
+ })
+ );
+ })
+ ).subscribe();
+
+ this.queryParamsSubscription = this.route.queryParams.subscribe((params) => {
+ this.autofit = params.autofit === 'true';
+ if (this.autofit) {
+ this.onResize();
+ }
+ });
+ }
+
+
+ @HostListener('window:resize', ['$event'])
+ onResize(): void {
+ if (this.autofit) {
+ this.resolution = bestFitResolution(64, 96, Math.min(window.innerWidth, window.innerHeight));
+ }
+ }
+
+ ngOnDestroy(): void {
+ this.routeParamsSubscription.unsubscribe();
+ this.queryParamsSubscription.unsubscribe();
+ }
+}
diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts
index bba70a2ce..dce65bfae 100644
--- a/frontend/src/app/shared/shared.module.ts
+++ b/frontend/src/app/shared/shared.module.ts
@@ -98,6 +98,7 @@ import { AccelerateFeeGraphComponent } from '../components/accelerate-preview/ac
import { MempoolErrorComponent } from './components/mempool-error/mempool-error.component';
import { BlockViewComponent } from '../components/block-view/block-view.component';
+import { MempoolBlockViewComponent } from '../components/mempool-block-view/mempool-block-view.component';
import { MempoolBlockOverviewComponent } from '../components/mempool-block-overview/mempool-block-overview.component';
import { ClockchainComponent } from '../components/clockchain/clockchain.component';
import { ClockFaceComponent } from '../components/clock-face/clock-face.component';
@@ -136,6 +137,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
ColoredPriceDirective,
BlockchainComponent,
BlockViewComponent,
+ MempoolBlockViewComponent,
MempoolBlocksComponent,
BlockchainBlocksComponent,
AmountComponent,
@@ -199,6 +201,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
CalculatorComponent,
BitcoinsatoshisPipe,
BlockViewComponent,
+ MempoolBlockViewComponent,
MempoolBlockOverviewComponent,
ClockchainComponent,
ClockComponent,
From 6de8cbe9b904e20b8a266b4f19f8e0b6ea23e688 Mon Sep 17 00:00:00 2001
From: orangesurf
Date: Mon, 25 Sep 2023 19:57:52 +0100
Subject: [PATCH 12/79] Add primal.net logo to footer
---
.../shared/components/global-footer/global-footer.component.html | 1 +
1 file changed, 1 insertion(+)
diff --git a/frontend/src/app/shared/components/global-footer/global-footer.component.html b/frontend/src/app/shared/components/global-footer/global-footer.component.html
index 34d47379e..a717bd7ab 100644
--- a/frontend/src/app/shared/components/global-footer/global-footer.component.html
+++ b/frontend/src/app/shared/components/global-footer/global-footer.component.html
@@ -84,6 +84,7 @@
GitHub
Twitter
+
YouTube
Matrix
From 420fbf3d6feec10a3e2ce6b507c2e5ded7717fb1 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Fri, 29 Sep 2023 00:02:01 +0100
Subject: [PATCH 13/79] Hide the blockchain arrow when transaction is replaced
---
backend/src/api/websocket-handler.ts | 2 +-
.../src/app/components/transaction/transaction.component.ts | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts
index c50941f39..3a444701f 100644
--- a/backend/src/api/websocket-handler.ts
+++ b/backend/src/api/websocket-handler.ts
@@ -577,7 +577,7 @@ class WebsocketHandler {
response['utxoSpent'] = JSON.stringify(outspends);
}
- const rbfReplacedBy = rbfCache.getReplacedBy(client['track-tx']);
+ const rbfReplacedBy = rbfChanges.map[client['track-tx']] ? rbfCache.getReplacedBy(client['track-tx']) : false;
if (rbfReplacedBy) {
response['rbfTransaction'] = JSON.stringify({
txid: rbfReplacedBy,
diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts
index 505c4686d..4743e5cd6 100644
--- a/frontend/src/app/components/transaction/transaction.component.ts
+++ b/frontend/src/app/components/transaction/transaction.component.ts
@@ -422,6 +422,8 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
}
this.rbfTransaction = rbfTransaction;
this.replaced = true;
+ this.stateService.markBlock$.next({});
+
if (rbfTransaction && !this.tx) {
this.fetchCachedTx$.next(this.txId);
}
From 10be2c8176813bd82ca6f14effeac78ab0143389 Mon Sep 17 00:00:00 2001
From: softsimon
Date: Wed, 4 Oct 2023 01:41:49 +0400
Subject: [PATCH 14/79] Fix block pagination for liquid
---
backend/src/api/bitcoin/bitcoin.routes.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/src/api/bitcoin/bitcoin.routes.ts b/backend/src/api/bitcoin/bitcoin.routes.ts
index 90a31ecae..240fb07ce 100644
--- a/backend/src/api/bitcoin/bitcoin.routes.ts
+++ b/backend/src/api/bitcoin/bitcoin.routes.ts
@@ -478,7 +478,7 @@ class BitcoinRoutes {
}
let nextHash = startFromHash;
- for (let i = 0; i < 10 && nextHash; i++) {
+ for (let i = 0; i < 15 && nextHash; i++) {
const localBlock = blocks.getBlocks().find((b) => b.id === nextHash);
if (localBlock) {
returnBlocks.push(localBlock);
From a35c8be25c6f1f17a93d25215e08e346c6f6c753 Mon Sep 17 00:00:00 2001
From: Felipe Knorr Kuhn
Date: Sun, 8 Oct 2023 09:03:22 -0700
Subject: [PATCH 15/79] Configurable unfurler config
---
unfurler/src/config.ts | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/unfurler/src/config.ts b/unfurler/src/config.ts
index 76bc2a75f..5d5104478 100644
--- a/unfurler/src/config.ts
+++ b/unfurler/src/config.ts
@@ -1,4 +1,16 @@
-const configFile = require('../config.json');
+const fs = require('fs');
+const path = require('path');
+
+const configPath = process.env.UNFURLER_CONFIG || '../config.json';
+const absolutePath = path.resolve(configPath);
+let config;
+
+try {
+ config = JSON.parse(fs.readFileSync(absolutePath, 'utf8'));
+} catch (e) {
+ console.error(`Could not read config file ${absolutePath}: ${e}`);
+ process.exit(-1);
+}
interface IConfig {
SERVER: {
@@ -57,7 +69,7 @@ class Config implements IConfig {
SYSLOG: IConfig['SYSLOG'];
constructor() {
- const configs = this.merge(configFile, defaults);
+ const configs = this.merge(config, defaults);
this.SERVER = configs.SERVER;
this.MEMPOOL = configs.MEMPOOL;
this.PUPPETEER = configs.PUPPETEER;
From e27cf3398187aa3b26d370caad4990384b99571b Mon Sep 17 00:00:00 2001
From: orangesurf
Date: Sun, 8 Oct 2023 17:52:03 +0100
Subject: [PATCH 16/79] Improve footer formatting for small screens
---
.../global-footer/global-footer.component.html | 2 +-
.../global-footer/global-footer.component.scss | 18 +++++++++---------
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/frontend/src/app/shared/components/global-footer/global-footer.component.html b/frontend/src/app/shared/components/global-footer/global-footer.component.html
index a717bd7ab..b162d9070 100644
--- a/frontend/src/app/shared/components/global-footer/global-footer.component.html
+++ b/frontend/src/app/shared/components/global-footer/global-footer.component.html
@@ -84,7 +84,7 @@
GitHub
Twitter
-
+
YouTube
Matrix
diff --git a/frontend/src/app/shared/components/global-footer/global-footer.component.scss b/frontend/src/app/shared/components/global-footer/global-footer.component.scss
index 3bdc239a9..148383cb4 100644
--- a/frontend/src/app/shared/components/global-footer/global-footer.component.scss
+++ b/frontend/src/app/shared/components/global-footer/global-footer.component.scss
@@ -88,7 +88,14 @@ footer .row.link-tree {
footer .row.social-links {
text-align: center;
- margin: 24px 0;
+ display: flex;
+ flex-wrap: wrap;
+ width: fit-content;
+ margin: 0 auto;
+
+ @media (max-width: 450px){
+ width: 250px;
+ }
}
footer .row.social-links a {
@@ -97,6 +104,7 @@ footer .row.social-links a {
footer .row.social-links svg {
width: 20px;
+ margin: 10px 0 10px 0;
}
footer .row.version {
@@ -189,10 +197,6 @@ footer .sponsor {
margin-top: 15px;
}
- footer .row.social-links {
- margin: 48px 0 24px 0;
- }
-
footer .selector:not(:last-child) {
margin-right: 10px;
}
@@ -236,10 +240,6 @@ footer .sponsor {
margin-top: 15px;
}
- footer .services.row.social-links {
- margin: 48px 0 24px 0;
- }
-
footer .services.selector:not(:last-child) {
margin-right: 10px;
}
From 21ede8671d2d5ac18a05f9f526bb0623e4b5067a Mon Sep 17 00:00:00 2001
From: orangesurf <91332210+orangesurf@users.noreply.github.com>
Date: Mon, 9 Oct 2023 19:01:48 +0000
Subject: [PATCH 17/79] Update global-footer.component.html
---
.../components/global-footer/global-footer.component.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frontend/src/app/shared/components/global-footer/global-footer.component.html b/frontend/src/app/shared/components/global-footer/global-footer.component.html
index b162d9070..a571e33c5 100644
--- a/frontend/src/app/shared/components/global-footer/global-footer.component.html
+++ b/frontend/src/app/shared/components/global-footer/global-footer.component.html
@@ -84,7 +84,7 @@
GitHub
Twitter
-
+
YouTube
Matrix
From af3d6eccfbe056011eb028a97fd1186f3c081794 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Wed, 11 Oct 2023 01:09:10 +0000
Subject: [PATCH 18/79] Fix node group map channel count
---
frontend/src/app/lightning/group/group-preview.component.ts | 2 +-
frontend/src/app/lightning/group/group.component.ts | 2 +-
frontend/src/app/lightning/lightning-api.service.ts | 2 +-
frontend/src/app/lightning/nodes-map/nodes-map.component.ts | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/frontend/src/app/lightning/group/group-preview.component.ts b/frontend/src/app/lightning/group/group-preview.component.ts
index fc81eab38..35bcb6e0f 100644
--- a/frontend/src/app/lightning/group/group-preview.component.ts
+++ b/frontend/src/app/lightning/group/group-preview.component.ts
@@ -57,7 +57,7 @@ export class GroupPreviewComponent implements OnInit {
return of(null);
}
- return this.lightningApiService.getNodGroupNodes$(this.groupId);
+ return this.lightningApiService.getNodeGroup$(this.groupId);
}),
map((nodes) => {
for (const node of nodes) {
diff --git a/frontend/src/app/lightning/group/group.component.ts b/frontend/src/app/lightning/group/group.component.ts
index 0786076ed..4c2cd4dd9 100644
--- a/frontend/src/app/lightning/group/group.component.ts
+++ b/frontend/src/app/lightning/group/group.component.ts
@@ -41,7 +41,7 @@ export class GroupComponent implements OnInit {
this.seoService.setTitle(`Mempool.space Lightning Nodes`);
this.seoService.setDescription(`See all Lightning nodes run by mempool.space -- these are the nodes that provide the data on the mempool.space Lightning dashboard.`);
- this.nodes$ = this.lightningApiService.getNodGroupNodes$('mempool.space')
+ this.nodes$ = this.lightningApiService.getNodeGroup$('mempool.space')
.pipe(
map((nodes) => {
for (const node of nodes) {
diff --git a/frontend/src/app/lightning/lightning-api.service.ts b/frontend/src/app/lightning/lightning-api.service.ts
index bdcc78f3f..fda93d446 100644
--- a/frontend/src/app/lightning/lightning-api.service.ts
+++ b/frontend/src/app/lightning/lightning-api.service.ts
@@ -27,7 +27,7 @@ export class LightningApiService {
return this.httpClient.get(this.apiBasePath + '/api/v1/lightning/nodes/' + publicKey);
}
- getNodGroupNodes$(name: string): Observable {
+ getNodeGroup$(name: string): Observable {
return this.httpClient.get(this.apiBasePath + '/api/v1/lightning/nodes/group/' + name);
}
diff --git a/frontend/src/app/lightning/nodes-map/nodes-map.component.ts b/frontend/src/app/lightning/nodes-map/nodes-map.component.ts
index ea80d8799..fef3fe021 100644
--- a/frontend/src/app/lightning/nodes-map/nodes-map.component.ts
+++ b/frontend/src/app/lightning/nodes-map/nodes-map.component.ts
@@ -88,7 +88,7 @@ export class NodesMap implements OnInit, OnChanges {
node.public_key,
node.alias,
node.capacity,
- node.channels,
+ node.active_channel_count,
node.country,
node.iso_code,
]);
From e9e507af691c04f453f6a569e9433e0a588398d4 Mon Sep 17 00:00:00 2001
From: Felipe Knorr Kuhn
Date: Tue, 10 Oct 2023 19:53:57 -0700
Subject: [PATCH 19/79] Fix default config path
---
unfurler/src/config.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/unfurler/src/config.ts b/unfurler/src/config.ts
index 5d5104478..445ae4514 100644
--- a/unfurler/src/config.ts
+++ b/unfurler/src/config.ts
@@ -1,7 +1,7 @@
const fs = require('fs');
const path = require('path');
-const configPath = process.env.UNFURLER_CONFIG || '../config.json';
+const configPath = process.env.UNFURLER_CONFIG || './config.json';
const absolutePath = path.resolve(configPath);
let config;
From 0783507821480884c74fc27eb8994f5515b2ee33 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 12 Oct 2023 02:38:59 +0000
Subject: [PATCH 20/79] Bump @babel/core from 7.21.4 to 7.23.2 in /backend
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.21.4 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/@babel/core@7.23.2/packages/babel-core)
---
updated-dependencies:
- dependency-name: "@babel/core"
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
---
backend/package-lock.json | 557 ++++++++++++++++++++------------------
backend/package.json | 4 +-
2 files changed, 289 insertions(+), 272 deletions(-)
diff --git a/backend/package-lock.json b/backend/package-lock.json
index c8dea34c0..5b1252599 100644
--- a/backend/package-lock.json
+++ b/backend/package-lock.json
@@ -9,7 +9,6 @@
"version": "3.0.0-dev",
"license": "GNU Affero General Public License v3.0",
"dependencies": {
- "@babel/core": "^7.21.3",
"@mempool/electrum-client": "1.1.9",
"@types/node": "^18.15.3",
"axios": "~1.5.0",
@@ -26,7 +25,7 @@
},
"devDependencies": {
"@babel/code-frame": "^7.18.6",
- "@babel/core": "^7.21.3",
+ "@babel/core": "^7.23.2",
"@types/compression": "^1.7.2",
"@types/crypto-js": "^4.1.1",
"@types/express": "^4.17.17",
@@ -65,47 +64,48 @@
}
},
"node_modules/@babel/code-frame": {
- "version": "7.21.4",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz",
- "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==",
+ "version": "7.22.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
+ "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"dev": true,
"dependencies": {
- "@babel/highlight": "^7.18.6"
+ "@babel/highlight": "^7.22.13",
+ "chalk": "^2.4.2"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/compat-data": {
- "version": "7.21.4",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz",
- "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz",
+ "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/core": {
- "version": "7.21.4",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz",
- "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz",
+ "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==",
"dev": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
- "@babel/code-frame": "^7.21.4",
- "@babel/generator": "^7.21.4",
- "@babel/helper-compilation-targets": "^7.21.4",
- "@babel/helper-module-transforms": "^7.21.2",
- "@babel/helpers": "^7.21.0",
- "@babel/parser": "^7.21.4",
- "@babel/template": "^7.20.7",
- "@babel/traverse": "^7.21.4",
- "@babel/types": "^7.21.4",
- "convert-source-map": "^1.7.0",
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.23.0",
+ "@babel/helper-compilation-targets": "^7.22.15",
+ "@babel/helper-module-transforms": "^7.23.0",
+ "@babel/helpers": "^7.23.2",
+ "@babel/parser": "^7.23.0",
+ "@babel/template": "^7.22.15",
+ "@babel/traverse": "^7.23.2",
+ "@babel/types": "^7.23.0",
+ "convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
- "json5": "^2.2.2",
- "semver": "^6.3.0"
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
},
"engines": {
"node": ">=6.9.0"
@@ -115,13 +115,19 @@
"url": "https://opencollective.com/babel"
}
},
+ "node_modules/@babel/core/node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true
+ },
"node_modules/@babel/generator": {
- "version": "7.21.4",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz",
- "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
+ "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.21.4",
+ "@babel/types": "^7.23.0",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
@@ -145,87 +151,84 @@
}
},
"node_modules/@babel/helper-compilation-targets": {
- "version": "7.21.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz",
- "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz",
+ "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==",
"dev": true,
"dependencies": {
- "@babel/compat-data": "^7.21.4",
- "@babel/helper-validator-option": "^7.21.0",
- "browserslist": "^4.21.3",
+ "@babel/compat-data": "^7.22.9",
+ "@babel/helper-validator-option": "^7.22.15",
+ "browserslist": "^4.21.9",
"lru-cache": "^5.1.1",
- "semver": "^6.3.0"
+ "semver": "^6.3.1"
},
"engines": {
"node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
}
},
"node_modules/@babel/helper-environment-visitor": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
- "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
+ "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-function-name": {
- "version": "7.21.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz",
- "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
+ "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"dev": true,
"dependencies": {
- "@babel/template": "^7.20.7",
- "@babel/types": "^7.21.0"
+ "@babel/template": "^7.22.15",
+ "@babel/types": "^7.23.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-hoist-variables": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
- "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
+ "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.18.6"
+ "@babel/types": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-imports": {
- "version": "7.21.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz",
- "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz",
+ "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.21.4"
+ "@babel/types": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-transforms": {
- "version": "7.21.2",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz",
- "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz",
+ "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==",
"dev": true,
"dependencies": {
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-module-imports": "^7.18.6",
- "@babel/helper-simple-access": "^7.20.2",
- "@babel/helper-split-export-declaration": "^7.18.6",
- "@babel/helper-validator-identifier": "^7.19.1",
- "@babel/template": "^7.20.7",
- "@babel/traverse": "^7.21.2",
- "@babel/types": "^7.21.2"
+ "@babel/helper-environment-visitor": "^7.22.20",
+ "@babel/helper-module-imports": "^7.22.15",
+ "@babel/helper-simple-access": "^7.22.5",
+ "@babel/helper-split-export-declaration": "^7.22.6",
+ "@babel/helper-validator-identifier": "^7.22.20"
},
"engines": {
"node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
}
},
"node_modules/@babel/helper-plugin-utils": {
@@ -238,78 +241,78 @@
}
},
"node_modules/@babel/helper-simple-access": {
- "version": "7.20.2",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
- "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz",
+ "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.20.2"
+ "@babel/types": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-split-export-declaration": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
- "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
+ "version": "7.22.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
+ "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.18.6"
+ "@babel/types": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-string-parser": {
- "version": "7.19.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
- "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
+ "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.19.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
- "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-option": {
- "version": "7.21.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz",
- "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz",
+ "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helpers": {
- "version": "7.21.0",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz",
- "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz",
+ "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==",
"dev": true,
"dependencies": {
- "@babel/template": "^7.20.7",
- "@babel/traverse": "^7.21.0",
- "@babel/types": "^7.21.0"
+ "@babel/template": "^7.22.15",
+ "@babel/traverse": "^7.23.2",
+ "@babel/types": "^7.23.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/highlight": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
- "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
+ "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
"dev": true,
"dependencies": {
- "@babel/helper-validator-identifier": "^7.18.6",
- "chalk": "^2.0.0",
+ "@babel/helper-validator-identifier": "^7.22.20",
+ "chalk": "^2.4.2",
"js-tokens": "^4.0.0"
},
"engines": {
@@ -317,9 +320,9 @@
}
},
"node_modules/@babel/parser": {
- "version": "7.21.4",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz",
- "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
+ "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
@@ -506,33 +509,33 @@
}
},
"node_modules/@babel/template": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
- "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
+ "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
"dev": true,
"dependencies": {
- "@babel/code-frame": "^7.18.6",
- "@babel/parser": "^7.20.7",
- "@babel/types": "^7.20.7"
+ "@babel/code-frame": "^7.22.13",
+ "@babel/parser": "^7.22.15",
+ "@babel/types": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
- "version": "7.21.4",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz",
- "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
+ "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
"dev": true,
"dependencies": {
- "@babel/code-frame": "^7.21.4",
- "@babel/generator": "^7.21.4",
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-function-name": "^7.21.0",
- "@babel/helper-hoist-variables": "^7.18.6",
- "@babel/helper-split-export-declaration": "^7.18.6",
- "@babel/parser": "^7.21.4",
- "@babel/types": "^7.21.4",
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.23.0",
+ "@babel/helper-environment-visitor": "^7.22.20",
+ "@babel/helper-function-name": "^7.23.0",
+ "@babel/helper-hoist-variables": "^7.22.5",
+ "@babel/helper-split-export-declaration": "^7.22.6",
+ "@babel/parser": "^7.23.0",
+ "@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
},
@@ -541,13 +544,13 @@
}
},
"node_modules/@babel/types": {
- "version": "7.21.4",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz",
- "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
+ "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"dev": true,
"dependencies": {
- "@babel/helper-string-parser": "^7.19.4",
- "@babel/helper-validator-identifier": "^7.19.1",
+ "@babel/helper-string-parser": "^7.22.5",
+ "@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
},
"engines": {
@@ -2590,9 +2593,9 @@
}
},
"node_modules/browserslist": {
- "version": "4.21.5",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz",
- "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==",
+ "version": "4.22.1",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz",
+ "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==",
"dev": true,
"funding": [
{
@@ -2602,13 +2605,17 @@
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
- "caniuse-lite": "^1.0.30001449",
- "electron-to-chromium": "^1.4.284",
- "node-releases": "^2.0.8",
- "update-browserslist-db": "^1.0.10"
+ "caniuse-lite": "^1.0.30001541",
+ "electron-to-chromium": "^1.4.535",
+ "node-releases": "^2.0.13",
+ "update-browserslist-db": "^1.0.13"
},
"bin": {
"browserslist": "cli.js"
@@ -2700,9 +2707,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001473",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001473.tgz",
- "integrity": "sha512-ewDad7+D2vlyy+E4UJuVfiBsU69IL+8oVmTuZnH5Q6CIUbxNfI50uVpRHbUPDD6SUaN2o0Lh4DhTrvLG/Tn1yg==",
+ "version": "1.0.30001547",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001547.tgz",
+ "integrity": "sha512-W7CrtIModMAxobGhz8iXmDfuJiiKg1WADMO/9x7/CLNin5cpSbuBjooyoIUVB5eyCc36QuTVlkVa1iB2S5+/eA==",
"dev": true,
"funding": [
{
@@ -3023,9 +3030,9 @@
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
},
"node_modules/electron-to-chromium": {
- "version": "1.4.348",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.348.tgz",
- "integrity": "sha512-gM7TdwuG3amns/1rlgxMbeeyNoBFPa+4Uu0c7FeROWh4qWmvSOnvcslKmWy51ggLKZ2n/F/4i2HJ+PVNxH9uCQ==",
+ "version": "1.4.551",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.551.tgz",
+ "integrity": "sha512-/Ng/W/kFv7wdEHYzxdK7Cv0BHEGSkSB3M0Ssl8Ndr1eMiYeas/+Mv4cNaDqamqWx6nd2uQZfPz6g25z25M/sdw==",
"dev": true
},
"node_modules/emittery": {
@@ -6184,9 +6191,9 @@
"dev": true
},
"node_modules/node-releases": {
- "version": "2.0.10",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
- "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==",
+ "version": "2.0.13",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
+ "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==",
"dev": true
},
"node_modules/normalize-path": {
@@ -7399,9 +7406,9 @@
}
},
"node_modules/update-browserslist-db": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
- "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
+ "version": "1.0.13",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
+ "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==",
"dev": true,
"funding": [
{
@@ -7411,6 +7418,10 @@
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
@@ -7418,7 +7429,7 @@
"picocolors": "^1.0.0"
},
"bin": {
- "browserslist-lint": "cli.js"
+ "update-browserslist-db": "cli.js"
},
"peerDependencies": {
"browserslist": ">= 4.21.0"
@@ -7683,50 +7694,59 @@
}
},
"@babel/code-frame": {
- "version": "7.21.4",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz",
- "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==",
+ "version": "7.22.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
+ "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"dev": true,
"requires": {
- "@babel/highlight": "^7.18.6"
+ "@babel/highlight": "^7.22.13",
+ "chalk": "^2.4.2"
}
},
"@babel/compat-data": {
- "version": "7.21.4",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz",
- "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz",
+ "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==",
"dev": true
},
"@babel/core": {
- "version": "7.21.4",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz",
- "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz",
+ "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==",
"dev": true,
"requires": {
"@ampproject/remapping": "^2.2.0",
- "@babel/code-frame": "^7.21.4",
- "@babel/generator": "^7.21.4",
- "@babel/helper-compilation-targets": "^7.21.4",
- "@babel/helper-module-transforms": "^7.21.2",
- "@babel/helpers": "^7.21.0",
- "@babel/parser": "^7.21.4",
- "@babel/template": "^7.20.7",
- "@babel/traverse": "^7.21.4",
- "@babel/types": "^7.21.4",
- "convert-source-map": "^1.7.0",
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.23.0",
+ "@babel/helper-compilation-targets": "^7.22.15",
+ "@babel/helper-module-transforms": "^7.23.0",
+ "@babel/helpers": "^7.23.2",
+ "@babel/parser": "^7.23.0",
+ "@babel/template": "^7.22.15",
+ "@babel/traverse": "^7.23.2",
+ "@babel/types": "^7.23.0",
+ "convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
- "json5": "^2.2.2",
- "semver": "^6.3.0"
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "dependencies": {
+ "convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true
+ }
}
},
"@babel/generator": {
- "version": "7.21.4",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz",
- "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
+ "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
"dev": true,
"requires": {
- "@babel/types": "^7.21.4",
+ "@babel/types": "^7.23.0",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
@@ -7746,66 +7766,63 @@
}
},
"@babel/helper-compilation-targets": {
- "version": "7.21.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz",
- "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz",
+ "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==",
"dev": true,
"requires": {
- "@babel/compat-data": "^7.21.4",
- "@babel/helper-validator-option": "^7.21.0",
- "browserslist": "^4.21.3",
+ "@babel/compat-data": "^7.22.9",
+ "@babel/helper-validator-option": "^7.22.15",
+ "browserslist": "^4.21.9",
"lru-cache": "^5.1.1",
- "semver": "^6.3.0"
+ "semver": "^6.3.1"
}
},
"@babel/helper-environment-visitor": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
- "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
+ "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"dev": true
},
"@babel/helper-function-name": {
- "version": "7.21.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz",
- "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
+ "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"dev": true,
"requires": {
- "@babel/template": "^7.20.7",
- "@babel/types": "^7.21.0"
+ "@babel/template": "^7.22.15",
+ "@babel/types": "^7.23.0"
}
},
"@babel/helper-hoist-variables": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
- "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
+ "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
"dev": true,
"requires": {
- "@babel/types": "^7.18.6"
+ "@babel/types": "^7.22.5"
}
},
"@babel/helper-module-imports": {
- "version": "7.21.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz",
- "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz",
+ "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==",
"dev": true,
"requires": {
- "@babel/types": "^7.21.4"
+ "@babel/types": "^7.22.15"
}
},
"@babel/helper-module-transforms": {
- "version": "7.21.2",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz",
- "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz",
+ "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==",
"dev": true,
"requires": {
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-module-imports": "^7.18.6",
- "@babel/helper-simple-access": "^7.20.2",
- "@babel/helper-split-export-declaration": "^7.18.6",
- "@babel/helper-validator-identifier": "^7.19.1",
- "@babel/template": "^7.20.7",
- "@babel/traverse": "^7.21.2",
- "@babel/types": "^7.21.2"
+ "@babel/helper-environment-visitor": "^7.22.20",
+ "@babel/helper-module-imports": "^7.22.15",
+ "@babel/helper-simple-access": "^7.22.5",
+ "@babel/helper-split-export-declaration": "^7.22.6",
+ "@babel/helper-validator-identifier": "^7.22.20"
}
},
"@babel/helper-plugin-utils": {
@@ -7815,67 +7832,67 @@
"dev": true
},
"@babel/helper-simple-access": {
- "version": "7.20.2",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
- "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz",
+ "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==",
"dev": true,
"requires": {
- "@babel/types": "^7.20.2"
+ "@babel/types": "^7.22.5"
}
},
"@babel/helper-split-export-declaration": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
- "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
+ "version": "7.22.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
+ "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"dev": true,
"requires": {
- "@babel/types": "^7.18.6"
+ "@babel/types": "^7.22.5"
}
},
"@babel/helper-string-parser": {
- "version": "7.19.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
- "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
+ "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
"dev": true
},
"@babel/helper-validator-identifier": {
- "version": "7.19.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
- "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true
},
"@babel/helper-validator-option": {
- "version": "7.21.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz",
- "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz",
+ "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==",
"dev": true
},
"@babel/helpers": {
- "version": "7.21.0",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz",
- "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz",
+ "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==",
"dev": true,
"requires": {
- "@babel/template": "^7.20.7",
- "@babel/traverse": "^7.21.0",
- "@babel/types": "^7.21.0"
+ "@babel/template": "^7.22.15",
+ "@babel/traverse": "^7.23.2",
+ "@babel/types": "^7.23.0"
}
},
"@babel/highlight": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
- "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
+ "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
"dev": true,
"requires": {
- "@babel/helper-validator-identifier": "^7.18.6",
- "chalk": "^2.0.0",
+ "@babel/helper-validator-identifier": "^7.22.20",
+ "chalk": "^2.4.2",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
- "version": "7.21.4",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz",
- "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
+ "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
"dev": true
},
"@babel/plugin-syntax-async-generators": {
@@ -8005,42 +8022,42 @@
}
},
"@babel/template": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
- "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
+ "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
"dev": true,
"requires": {
- "@babel/code-frame": "^7.18.6",
- "@babel/parser": "^7.20.7",
- "@babel/types": "^7.20.7"
+ "@babel/code-frame": "^7.22.13",
+ "@babel/parser": "^7.22.15",
+ "@babel/types": "^7.22.15"
}
},
"@babel/traverse": {
- "version": "7.21.4",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz",
- "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
+ "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
"dev": true,
"requires": {
- "@babel/code-frame": "^7.21.4",
- "@babel/generator": "^7.21.4",
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-function-name": "^7.21.0",
- "@babel/helper-hoist-variables": "^7.18.6",
- "@babel/helper-split-export-declaration": "^7.18.6",
- "@babel/parser": "^7.21.4",
- "@babel/types": "^7.21.4",
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.23.0",
+ "@babel/helper-environment-visitor": "^7.22.20",
+ "@babel/helper-function-name": "^7.23.0",
+ "@babel/helper-hoist-variables": "^7.22.5",
+ "@babel/helper-split-export-declaration": "^7.22.6",
+ "@babel/parser": "^7.23.0",
+ "@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
}
},
"@babel/types": {
- "version": "7.21.4",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz",
- "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
+ "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"dev": true,
"requires": {
- "@babel/helper-string-parser": "^7.19.4",
- "@babel/helper-validator-identifier": "^7.19.1",
+ "@babel/helper-string-parser": "^7.22.5",
+ "@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
}
},
@@ -9615,15 +9632,15 @@
}
},
"browserslist": {
- "version": "4.21.5",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz",
- "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==",
+ "version": "4.22.1",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz",
+ "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==",
"dev": true,
"requires": {
- "caniuse-lite": "^1.0.30001449",
- "electron-to-chromium": "^1.4.284",
- "node-releases": "^2.0.8",
- "update-browserslist-db": "^1.0.10"
+ "caniuse-lite": "^1.0.30001541",
+ "electron-to-chromium": "^1.4.535",
+ "node-releases": "^2.0.13",
+ "update-browserslist-db": "^1.0.13"
}
},
"bs-logger": {
@@ -9694,9 +9711,9 @@
"dev": true
},
"caniuse-lite": {
- "version": "1.0.30001473",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001473.tgz",
- "integrity": "sha512-ewDad7+D2vlyy+E4UJuVfiBsU69IL+8oVmTuZnH5Q6CIUbxNfI50uVpRHbUPDD6SUaN2o0Lh4DhTrvLG/Tn1yg==",
+ "version": "1.0.30001547",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001547.tgz",
+ "integrity": "sha512-W7CrtIModMAxobGhz8iXmDfuJiiKg1WADMO/9x7/CLNin5cpSbuBjooyoIUVB5eyCc36QuTVlkVa1iB2S5+/eA==",
"dev": true
},
"chalk": {
@@ -9924,9 +9941,9 @@
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
},
"electron-to-chromium": {
- "version": "1.4.348",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.348.tgz",
- "integrity": "sha512-gM7TdwuG3amns/1rlgxMbeeyNoBFPa+4Uu0c7FeROWh4qWmvSOnvcslKmWy51ggLKZ2n/F/4i2HJ+PVNxH9uCQ==",
+ "version": "1.4.551",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.551.tgz",
+ "integrity": "sha512-/Ng/W/kFv7wdEHYzxdK7Cv0BHEGSkSB3M0Ssl8Ndr1eMiYeas/+Mv4cNaDqamqWx6nd2uQZfPz6g25z25M/sdw==",
"dev": true
},
"emittery": {
@@ -12280,9 +12297,9 @@
"dev": true
},
"node-releases": {
- "version": "2.0.10",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
- "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==",
+ "version": "2.0.13",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
+ "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==",
"dev": true
},
"normalize-path": {
@@ -13118,9 +13135,9 @@
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
},
"update-browserslist-db": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
- "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
+ "version": "1.0.13",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
+ "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==",
"dev": true,
"requires": {
"escalade": "^3.1.1",
diff --git a/backend/package.json b/backend/package.json
index 2db8f2046..621ef93bb 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -38,7 +38,7 @@
"rust-build": "cd rust-gbt && npm run build-release"
},
"dependencies": {
- "@babel/core": "^7.21.3",
+ "@babel/core": "^7.23.2",
"@mempool/electrum-client": "1.1.9",
"@types/node": "^18.15.3",
"axios": "~1.5.0",
@@ -55,7 +55,7 @@
},
"devDependencies": {
"@babel/code-frame": "^7.18.6",
- "@babel/core": "^7.21.3",
+ "@babel/core": "^7.23.2",
"@types/compression": "^1.7.2",
"@types/crypto-js": "^4.1.1",
"@types/express": "^4.17.17",
From 1bc02fd2163d809be4e9983ea85cc653c50be6d6 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 19 Oct 2023 11:23:40 +0000
Subject: [PATCH 21/79] Bump @babel/traverse from 7.22.8 to 7.23.2 in /frontend
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.22.8 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)
---
updated-dependencies:
- dependency-name: "@babel/traverse"
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
---
frontend/package-lock.json | 217 ++++++++++++++++++++++++-------------
1 file changed, 144 insertions(+), 73 deletions(-)
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 087c738ac..3001dbf70 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -31,7 +31,6 @@
"bootstrap": "~4.6.2",
"browserify": "^17.0.0",
"clipboard": "^2.0.11",
- "cypress": "^13.3.0",
"domino": "^2.1.6",
"echarts": "~5.4.3",
"echarts-gl": "^2.0.9",
@@ -1251,11 +1250,12 @@
"integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg=="
},
"node_modules/@babel/code-frame": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
- "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
+ "version": "7.22.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
+ "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"dependencies": {
- "@babel/highlight": "^7.22.5"
+ "@babel/highlight": "^7.22.13",
+ "chalk": "^2.4.2"
},
"engines": {
"node": ">=6.9.0"
@@ -1465,20 +1465,33 @@
}
},
"node_modules/@babel/helper-environment-visitor": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz",
- "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
+ "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-function-name": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
- "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
+ "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"dependencies": {
- "@babel/template": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/template": "^7.22.15",
+ "@babel/types": "^7.23.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-function-name/node_modules/@babel/template": {
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
+ "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
+ "dependencies": {
+ "@babel/code-frame": "^7.22.13",
+ "@babel/parser": "^7.22.15",
+ "@babel/types": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
@@ -1628,9 +1641,9 @@
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
- "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"engines": {
"node": ">=6.9.0"
}
@@ -1670,12 +1683,12 @@
}
},
"node_modules/@babel/highlight": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
- "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
+ "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
"dependencies": {
- "@babel/helper-validator-identifier": "^7.22.5",
- "chalk": "^2.0.0",
+ "@babel/helper-validator-identifier": "^7.22.20",
+ "chalk": "^2.4.2",
"js-tokens": "^4.0.0"
},
"engines": {
@@ -1683,9 +1696,9 @@
}
},
"node_modules/@babel/parser": {
- "version": "7.22.7",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz",
- "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
+ "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
"bin": {
"parser": "bin/babel-parser.js"
},
@@ -2880,18 +2893,18 @@
}
},
"node_modules/@babel/traverse": {
- "version": "7.22.8",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz",
- "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
+ "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
"dependencies": {
- "@babel/code-frame": "^7.22.5",
- "@babel/generator": "^7.22.7",
- "@babel/helper-environment-visitor": "^7.22.5",
- "@babel/helper-function-name": "^7.22.5",
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.23.0",
+ "@babel/helper-environment-visitor": "^7.22.20",
+ "@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/parser": "^7.22.7",
- "@babel/types": "^7.22.5",
+ "@babel/parser": "^7.23.0",
+ "@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
},
@@ -2899,13 +2912,36 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/traverse/node_modules/@babel/generator": {
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
+ "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
+ "dependencies": {
+ "@babel/types": "^7.23.0",
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "@jridgewell/trace-mapping": "^0.3.17",
+ "jsesc": "^2.5.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse/node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.20",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz",
+ "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
"node_modules/@babel/types": {
- "version": "7.22.10",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.10.tgz",
- "integrity": "sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
+ "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"dependencies": {
"@babel/helper-string-parser": "^7.22.5",
- "@babel/helper-validator-identifier": "^7.22.5",
+ "@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
},
"engines": {
@@ -17769,11 +17805,12 @@
"integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg=="
},
"@babel/code-frame": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
- "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
+ "version": "7.22.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
+ "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"requires": {
- "@babel/highlight": "^7.22.5"
+ "@babel/highlight": "^7.22.13",
+ "chalk": "^2.4.2"
}
},
"@babel/compat-data": {
@@ -17938,17 +17975,29 @@
}
},
"@babel/helper-environment-visitor": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz",
- "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q=="
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
+ "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA=="
},
"@babel/helper-function-name": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
- "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
+ "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"requires": {
- "@babel/template": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/template": "^7.22.15",
+ "@babel/types": "^7.23.0"
+ },
+ "dependencies": {
+ "@babel/template": {
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
+ "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
+ "requires": {
+ "@babel/code-frame": "^7.22.13",
+ "@babel/parser": "^7.22.15",
+ "@babel/types": "^7.22.15"
+ }
+ }
}
},
"@babel/helper-hoist-variables": {
@@ -18050,9 +18099,9 @@
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw=="
},
"@babel/helper-validator-identifier": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
- "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ=="
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A=="
},
"@babel/helper-validator-option": {
"version": "7.22.5",
@@ -18080,19 +18129,19 @@
}
},
"@babel/highlight": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
- "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
+ "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
"requires": {
- "@babel/helper-validator-identifier": "^7.22.5",
- "chalk": "^2.0.0",
+ "@babel/helper-validator-identifier": "^7.22.20",
+ "chalk": "^2.4.2",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
- "version": "7.22.7",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz",
- "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q=="
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
+ "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw=="
},
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
"version": "7.22.5",
@@ -18869,29 +18918,51 @@
}
},
"@babel/traverse": {
- "version": "7.22.8",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz",
- "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
+ "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
"requires": {
- "@babel/code-frame": "^7.22.5",
- "@babel/generator": "^7.22.7",
- "@babel/helper-environment-visitor": "^7.22.5",
- "@babel/helper-function-name": "^7.22.5",
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.23.0",
+ "@babel/helper-environment-visitor": "^7.22.20",
+ "@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/parser": "^7.22.7",
- "@babel/types": "^7.22.5",
+ "@babel/parser": "^7.23.0",
+ "@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
+ },
+ "dependencies": {
+ "@babel/generator": {
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
+ "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
+ "requires": {
+ "@babel/types": "^7.23.0",
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "@jridgewell/trace-mapping": "^0.3.17",
+ "jsesc": "^2.5.1"
+ }
+ },
+ "@jridgewell/trace-mapping": {
+ "version": "0.3.20",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz",
+ "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==",
+ "requires": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ }
}
},
"@babel/types": {
- "version": "7.22.10",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.10.tgz",
- "integrity": "sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
+ "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"requires": {
"@babel/helper-string-parser": "^7.22.5",
- "@babel/helper-validator-identifier": "^7.22.5",
+ "@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
}
},
From 6efeeb1d64c0eaff9ca2a375e5efba999b4c6ebc Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Fri, 20 Oct 2023 15:10:40 +0000
Subject: [PATCH 22/79] Hide mempool count line by default
---
.../app/components/mempool-graph/mempool-graph.component.ts | 4 ++--
.../src/app/components/statistics/statistics.component.ts | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts
index 935e79b2c..6e1d99f37 100644
--- a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts
+++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts
@@ -27,7 +27,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
@Input() data: any[];
@Input() filterSize = 100000;
@Input() limitFilterFee = 1;
- @Input() hideCount: boolean = false;
+ @Input() hideCount: boolean = true;
@Input() height: number | string = 200;
@Input() top: number | string = 20;
@Input() right: number | string = 10;
@@ -53,7 +53,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
chartInstance: any = undefined;
weightMode: boolean = false;
isWidget: boolean = false;
- showCount: boolean = true;
+ showCount: boolean = false;
constructor(
private vbytesPipe: VbytesPipe,
diff --git a/frontend/src/app/components/statistics/statistics.component.ts b/frontend/src/app/components/statistics/statistics.component.ts
index ba9068975..6bc58b6d7 100644
--- a/frontend/src/app/components/statistics/statistics.component.ts
+++ b/frontend/src/app/components/statistics/statistics.component.ts
@@ -32,7 +32,7 @@ export class StatisticsComponent implements OnInit {
chartColors = chartColors;
filterSize = 100000;
filterFeeIndex = 1;
- showCount = true;
+ showCount = false;
maxFeeIndex: number;
dropDownOpen = false;
From abee175f4f1817ef766c5f8bcf32b00896a2b92d Mon Sep 17 00:00:00 2001
From: fanquake
Date: Mon, 23 Oct 2023 14:43:51 +0100
Subject: [PATCH 23/79] contrib: add fanquake CLA
---
contributors/fanquake.txt | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 contributors/fanquake.txt
diff --git a/contributors/fanquake.txt b/contributors/fanquake.txt
new file mode 100644
index 000000000..3212bdcbf
--- /dev/null
+++ b/contributors/fanquake.txt
@@ -0,0 +1,3 @@
+I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of October 23, 2023.
+
+Signed: fanquake
From 26f5776d6db02889fbfe2baba2d8851cad5ed6a4 Mon Sep 17 00:00:00 2001
From: fanquake
Date: Mon, 23 Oct 2023 14:39:30 +0100
Subject: [PATCH 24/79] Upgrade bitcoin core to v25.1
---
production/install | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/production/install b/production/install
index b4f6d53c5..18ee06233 100755
--- a/production/install
+++ b/production/install
@@ -332,7 +332,7 @@ BITCOIN_REPO_URL=https://github.com/bitcoin/bitcoin
BITCOIN_REPO_NAME=bitcoin
BITCOIN_REPO_BRANCH=master
#BITCOIN_LATEST_RELEASE=$(curl -s https://api.github.com/repos/bitcoin/bitcoin/releases/latest|grep tag_name|head -1|cut -d '"' -f4)
-BITCOIN_LATEST_RELEASE=v25.0
+BITCOIN_LATEST_RELEASE=v25.1
echo -n '.'
BISQ_REPO_URL=https://github.com/bisq-network/bisq
From 59a92d03638ac0bf48e31a4b125b9eb2cc28b20b Mon Sep 17 00:00:00 2001
From: TKone7
Date: Mon, 23 Oct 2023 15:49:34 +0200
Subject: [PATCH 25/79] Fix cleanup logic
Keep only cache entries with an expiry in the future.
---
backend/src/api/memory-cache.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/src/api/memory-cache.ts b/backend/src/api/memory-cache.ts
index fe4162420..e71aaa6a2 100644
--- a/backend/src/api/memory-cache.ts
+++ b/backend/src/api/memory-cache.ts
@@ -31,7 +31,7 @@ class MemoryCache {
}
private cleanup() {
- this.cache = this.cache.filter((cache) => cache.expires < (new Date()));
+ this.cache = this.cache.filter((cache) => cache.expires > (new Date()));
}
}
From 4ca273c8c18c753c97fa54fe4cb0d0c305c6d704 Mon Sep 17 00:00:00 2001
From: TKone7
Date: Mon, 23 Oct 2023 15:56:07 +0200
Subject: [PATCH 26/79] Agree to Contributor License Agreement
---
contributors/TKone7.txt | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 contributors/TKone7.txt
diff --git a/contributors/TKone7.txt b/contributors/TKone7.txt
new file mode 100644
index 000000000..0112e34a3
--- /dev/null
+++ b/contributors/TKone7.txt
@@ -0,0 +1,3 @@
+I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of October 23, 2023.
+
+Signed: TKone7
From 83fde600f12dcfd213a9ddd9a38c03e412ccf5bf Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Wed, 25 Oct 2023 16:53:05 +0000
Subject: [PATCH 27/79] Enforce purging rate minimum on recommended fees
---
backend/src/api/fee-api.ts | 29 +++++++++++++++++++++--------
1 file changed, 21 insertions(+), 8 deletions(-)
diff --git a/backend/src/api/fee-api.ts b/backend/src/api/fee-api.ts
index 82778825e..97dfc29d2 100644
--- a/backend/src/api/fee-api.ts
+++ b/backend/src/api/fee-api.ts
@@ -3,21 +3,30 @@ import { Common } from './common';
import mempool from './mempool';
import projectedBlocks from './mempool-blocks';
+interface RecommendedFees {
+ fastestFee: number,
+ halfHourFee: number,
+ hourFee: number,
+ economyFee: number,
+ minimumFee: number,
+}
+
class FeeApi {
constructor() { }
defaultFee = Common.isLiquid() ? 0.1 : 1;
- public getRecommendedFee() {
+ public getRecommendedFee(): RecommendedFees {
const pBlocks = projectedBlocks.getMempoolBlocks();
const mPool = mempool.getMempoolInfo();
const minimumFee = Math.ceil(mPool.mempoolminfee * 100000);
+ const defaultMinFee = Math.max(minimumFee, this.defaultFee);
if (!pBlocks.length) {
return {
- 'fastestFee': this.defaultFee,
- 'halfHourFee': this.defaultFee,
- 'hourFee': this.defaultFee,
+ 'fastestFee': defaultMinFee,
+ 'halfHourFee': defaultMinFee,
+ 'hourFee': defaultMinFee,
'economyFee': minimumFee,
'minimumFee': minimumFee,
};
@@ -27,11 +36,15 @@ class FeeApi {
const secondMedianFee = pBlocks[1] ? this.optimizeMedianFee(pBlocks[1], pBlocks[2], firstMedianFee) : this.defaultFee;
const thirdMedianFee = pBlocks[2] ? this.optimizeMedianFee(pBlocks[2], pBlocks[3], secondMedianFee) : this.defaultFee;
+ // explicitly enforce a minimum of ceil(mempoolminfee) on all recommendations.
+ // simply rounding up recommended rates is insufficient, as the purging rate
+ // can exceed the median rate of projected blocks in some extreme scenarios
+ // (see https://bitcoin.stackexchange.com/a/120024)
return {
- 'fastestFee': firstMedianFee,
- 'halfHourFee': secondMedianFee,
- 'hourFee': thirdMedianFee,
- 'economyFee': Math.min(2 * minimumFee, thirdMedianFee),
+ 'fastestFee': Math.max(minimumFee, firstMedianFee),
+ 'halfHourFee': Math.max(minimumFee, secondMedianFee),
+ 'hourFee': Math.max(minimumFee, thirdMedianFee),
+ 'economyFee': Math.max(minimumFee, Math.min(2 * minimumFee, thirdMedianFee)),
'minimumFee': minimumFee,
};
}
From 5523c77a043b6d704b24c3ddd3036df5445ee931 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sat, 28 Oct 2023 21:06:33 +0000
Subject: [PATCH 28/79] Fix stray , in docker backend config
---
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 457eccd4a..712b95b3e 100644
--- a/docker/backend/mempool-config.json
+++ b/docker/backend/mempool-config.json
@@ -70,7 +70,7 @@
"USERNAME": "__DATABASE_USERNAME__",
"PASSWORD": "__DATABASE_PASSWORD__",
"TIMEOUT": __DATABASE_TIMEOUT__,
- "PID_DIR": "__DATABASE_PID_DIR__",
+ "PID_DIR": "__DATABASE_PID_DIR__"
},
"SYSLOG": {
"ENABLED": __SYSLOG_ENABLED__,
From 939fe951d47dcd6a9681e50155e491ffd38d3f82 Mon Sep 17 00:00:00 2001
From: Erik Arvstedt
Date: Sun, 5 Nov 2023 13:47:23 +0100
Subject: [PATCH 29/79] README: add `nix-bitcoin` to node distros
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index dd2e62478..9b56dc436 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,7 @@ Mempool can be conveniently installed on the following full-node distros:
- [RoninDojo](https://code.samourai.io/ronindojo/RoninDojo)
- [myNode](https://github.com/mynodebtc/mynode)
- [Start9](https://github.com/Start9Labs/embassy-os)
+- [nix-bitcoin](https://github.com/fort-nix/nix-bitcoin/blob/a1eacce6768ca4894f365af8f79be5bbd594e1c3/examples/configuration.nix#L129)
**We highly recommend you deploy your own Mempool instance this way.** No matter which option you pick, you'll be able to get your own fully-sovereign instance of Mempool up quickly without needing to fiddle with any settings.
From 14c87e2f03f5a5976e8188c9de96c157d391f06a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 7 Nov 2023 01:44:00 +0000
Subject: [PATCH 30/79] Bump crypto-js from 4.1.1 to 4.2.0 in /backend
Bumps [crypto-js](https://github.com/brix/crypto-js) from 4.1.1 to 4.2.0.
- [Commits](https://github.com/brix/crypto-js/compare/4.1.1...4.2.0)
---
updated-dependencies:
- dependency-name: crypto-js
dependency-type: direct:production
...
Signed-off-by: dependabot[bot]
---
backend/package-lock.json | 15 ++++++++-------
backend/package.json | 2 +-
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/backend/package-lock.json b/backend/package-lock.json
index 5b1252599..33f19a26d 100644
--- a/backend/package-lock.json
+++ b/backend/package-lock.json
@@ -9,11 +9,12 @@
"version": "3.0.0-dev",
"license": "GNU Affero General Public License v3.0",
"dependencies": {
+ "@babel/core": "^7.23.2",
"@mempool/electrum-client": "1.1.9",
"@types/node": "^18.15.3",
"axios": "~1.5.0",
"bitcoinjs-lib": "~6.1.3",
- "crypto-js": "~4.1.1",
+ "crypto-js": "~4.2.0",
"express": "~4.18.2",
"maxmind": "~4.3.11",
"mysql2": "~3.6.0",
@@ -2899,9 +2900,9 @@
}
},
"node_modules/crypto-js": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
- "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw=="
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
+ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
},
"node_modules/debug": {
"version": "4.3.4",
@@ -9849,9 +9850,9 @@
}
},
"crypto-js": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
- "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw=="
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
+ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
},
"debug": {
"version": "4.3.4",
diff --git a/backend/package.json b/backend/package.json
index 621ef93bb..bdce50902 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -43,7 +43,7 @@
"@types/node": "^18.15.3",
"axios": "~1.5.0",
"bitcoinjs-lib": "~6.1.3",
- "crypto-js": "~4.1.1",
+ "crypto-js": "~4.2.0",
"express": "~4.18.2",
"maxmind": "~4.3.11",
"mysql2": "~3.6.0",
From 5f034d34b341b8a840dc6093b9a2beb1831f9514 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 7 Nov 2023 01:45:30 +0000
Subject: [PATCH 31/79] Bump browserify-sign from 4.2.1 to 4.2.2 in /frontend
Bumps [browserify-sign](https://github.com/crypto-browserify/browserify-sign) from 4.2.1 to 4.2.2.
- [Changelog](https://github.com/browserify/browserify-sign/blob/main/CHANGELOG.md)
- [Commits](https://github.com/crypto-browserify/browserify-sign/compare/v4.2.1...v4.2.2)
---
updated-dependencies:
- dependency-name: browserify-sign
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
---
frontend/package-lock.json | 63 ++++++++++++++++++++------------------
1 file changed, 33 insertions(+), 30 deletions(-)
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 3001dbf70..49410de87 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -5611,9 +5611,9 @@
"optional": true
},
"node_modules/bn.js": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
- "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw=="
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
+ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ=="
},
"node_modules/body-parser": {
"version": "1.20.1",
@@ -5908,25 +5908,28 @@
}
},
"node_modules/browserify-sign": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
- "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz",
+ "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==",
"dependencies": {
- "bn.js": "^5.1.1",
- "browserify-rsa": "^4.0.1",
+ "bn.js": "^5.2.1",
+ "browserify-rsa": "^4.1.0",
"create-hash": "^1.2.0",
"create-hmac": "^1.1.7",
- "elliptic": "^6.5.3",
+ "elliptic": "^6.5.4",
"inherits": "^2.0.4",
- "parse-asn1": "^5.1.5",
- "readable-stream": "^3.6.0",
- "safe-buffer": "^5.2.0"
+ "parse-asn1": "^5.1.6",
+ "readable-stream": "^3.6.2",
+ "safe-buffer": "^5.2.1"
+ },
+ "engines": {
+ "node": ">= 4"
}
},
"node_modules/browserify-sign/node_modules/readable-stream": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
- "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -20918,9 +20921,9 @@
"optional": true
},
"bn.js": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
- "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw=="
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
+ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ=="
},
"body-parser": {
"version": "1.20.1",
@@ -21264,25 +21267,25 @@
}
},
"browserify-sign": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
- "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz",
+ "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==",
"requires": {
- "bn.js": "^5.1.1",
- "browserify-rsa": "^4.0.1",
+ "bn.js": "^5.2.1",
+ "browserify-rsa": "^4.1.0",
"create-hash": "^1.2.0",
"create-hmac": "^1.1.7",
- "elliptic": "^6.5.3",
+ "elliptic": "^6.5.4",
"inherits": "^2.0.4",
- "parse-asn1": "^5.1.5",
- "readable-stream": "^3.6.0",
- "safe-buffer": "^5.2.0"
+ "parse-asn1": "^5.1.6",
+ "readable-stream": "^3.6.2",
+ "safe-buffer": "^5.2.1"
},
"dependencies": {
"readable-stream": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
- "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
From a33dc74c884359166a2d3dc86712933a327d4029 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Mon, 6 Nov 2023 18:19:54 +0000
Subject: [PATCH 32/79] Shake the echarts tree
---
frontend/package.json | 1 -
.../block-fee-rates-graph.component.ts | 2 +-
.../block-fees-graph.component.ts | 6 +++---
.../block-health-graph.component.ts | 2 +-
.../block-rewards-graph.component.ts | 6 +++---
.../block-sizes-weights-graph.component.ts | 2 +-
.../hashrate-chart/hashrate-chart.component.ts | 12 ++++++------
.../hashrate-chart-pools.component.ts | 2 +-
.../incoming-transactions-graph.component.ts | 2 +-
.../lbtc-pegs-graph.component.ts | 2 +-
.../mempool-graph/mempool-graph.component.ts | 2 +-
.../pool-ranking/pool-ranking.component.ts | 2 +-
.../components/pool/pool-preview.component.ts | 4 ++--
.../src/app/components/pool/pool.component.ts | 4 ++--
frontend/src/app/graphs/echarts.ts | 17 +++++++++++++++++
frontend/src/app/graphs/graphs.module.ts | 2 +-
.../node-fee-chart/node-fee-chart.component.ts | 2 +-
.../node-statistics-chart.component.ts | 2 +-
.../nodes-channels-map.component.ts | 5 ++---
.../nodes-channels/node-channels.component.ts | 6 +++---
.../lightning/nodes-map/nodes-map.component.ts | 4 ++--
.../nodes-networks-chart.component.ts | 10 +++++-----
.../nodes-per-country-chart.component.ts | 2 +-
.../nodes-per-isp-chart.component.ts | 2 +-
.../lightning-statistics-chart.component.ts | 4 ++--
25 files changed, 60 insertions(+), 45 deletions(-)
create mode 100644 frontend/src/app/graphs/echarts.ts
diff --git a/frontend/package.json b/frontend/package.json
index 294ace61d..0c7874c30 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -85,7 +85,6 @@
"clipboard": "^2.0.11",
"domino": "^2.1.6",
"echarts": "~5.4.3",
- "echarts-gl": "^2.0.9",
"lightweight-charts": "~3.8.0",
"ngx-echarts": "~16.0.0",
"ngx-infinite-scroll": "^16.0.0",
diff --git a/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts b/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts
index b4c4e9a3b..c4d061927 100644
--- a/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts
+++ b/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts
@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, NgZone, OnInit } from '@angular/core';
-import { EChartsOption } from 'echarts';
+import { EChartsOption } from '../../graphs/echarts';
import { Observable, Subscription, combineLatest } from 'rxjs';
import { map, share, startWith, switchMap, tap } from 'rxjs/operators';
import { ApiService } from '../../services/api.service';
diff --git a/frontend/src/app/components/block-fees-graph/block-fees-graph.component.ts b/frontend/src/app/components/block-fees-graph/block-fees-graph.component.ts
index 722929f9e..fc71fb575 100644
--- a/frontend/src/app/components/block-fees-graph/block-fees-graph.component.ts
+++ b/frontend/src/app/components/block-fees-graph/block-fees-graph.component.ts
@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core';
-import { EChartsOption, graphic } from 'echarts';
+import { echarts, EChartsOption } from '../../graphs/echarts';
import { Observable } from 'rxjs';
import { map, share, startWith, switchMap, tap } from 'rxjs/operators';
import { ApiService } from '../../services/api.service';
@@ -123,11 +123,11 @@ export class BlockFeesGraphComponent implements OnInit {
this.chartOptions = {
title: title,
color: [
- new graphic.LinearGradient(0, 0, 0, 1, [
+ new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#FDD835' },
{ offset: 1, color: '#FB8C00' },
]),
- new graphic.LinearGradient(0, 0, 0, 1, [
+ new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#C0CA33' },
{ offset: 1, color: '#1B5E20' },
]),
diff --git a/frontend/src/app/components/block-health-graph/block-health-graph.component.ts b/frontend/src/app/components/block-health-graph/block-health-graph.component.ts
index 299044dbb..4fea6f245 100644
--- a/frontend/src/app/components/block-health-graph/block-health-graph.component.ts
+++ b/frontend/src/app/components/block-health-graph/block-health-graph.component.ts
@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, NgZone, OnInit } from '@angular/core';
-import { EChartsOption } from 'echarts';
+import { EChartsOption } from '../../graphs/echarts';
import { Observable } from 'rxjs';
import { map, share, startWith, switchMap, tap } from 'rxjs/operators';
import { ApiService } from '../../services/api.service';
diff --git a/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.ts b/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.ts
index 505da17a5..9c987fb57 100644
--- a/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.ts
+++ b/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.ts
@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core';
-import { EChartsOption, graphic } from 'echarts';
+import { echarts, EChartsOption } from '../../graphs/echarts';
import { Observable } from 'rxjs';
import { map, share, startWith, switchMap, tap } from 'rxjs/operators';
import { ApiService } from '../../services/api.service';
@@ -123,11 +123,11 @@ export class BlockRewardsGraphComponent implements OnInit {
title: title,
animation: false,
color: [
- new graphic.LinearGradient(0, 0, 0, 1, [
+ new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#FDD835' },
{ offset: 1, color: '#FB8C00' },
]),
- new graphic.LinearGradient(0, 0, 0, 1, [
+ new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#C0CA33' },
{ offset: 1, color: '#1B5E20' },
]),
diff --git a/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.ts b/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.ts
index e42c6a8df..5d01e48e9 100644
--- a/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.ts
+++ b/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.ts
@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit, HostBinding } from '@angular/core';
-import { EChartsOption} from 'echarts';
+import { EChartsOption} from '../../graphs/echarts';
import { Observable } from 'rxjs';
import { map, share, startWith, switchMap, tap } from 'rxjs/operators';
import { ApiService } from '../../services/api.service';
diff --git a/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts b/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts
index 592aba60b..5f17938ae 100644
--- a/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts
+++ b/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts
@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit, HostBinding } from '@angular/core';
-import { EChartsOption, graphic } from 'echarts';
+import { echarts, EChartsOption } from '../../graphs/echarts';
import { merge, Observable, of } from 'rxjs';
import { map, mergeMap, share, startWith, switchMap, tap } from 'rxjs/operators';
import { ApiService } from '../../services/api.service';
@@ -204,7 +204,7 @@ export class HashrateChartComponent implements OnInit {
title: title,
animation: false,
color: [
- new graphic.LinearGradient(0, 0, 0, 0.65, [
+ new echarts.graphic.LinearGradient(0, 0, 0, 0.65, [
{ offset: 0, color: '#F4511E99' },
{ offset: 0.25, color: '#FB8C0099' },
{ offset: 0.5, color: '#FFB30099' },
@@ -212,7 +212,7 @@ export class HashrateChartComponent implements OnInit {
{ offset: 1, color: '#7CB34299' }
]),
'#D81B60',
- new graphic.LinearGradient(0, 0, 0, 0.65, [
+ new echarts.graphic.LinearGradient(0, 0, 0, 0.65, [
{ offset: 0, color: '#F4511E' },
{ offset: 0.25, color: '#FB8C00' },
{ offset: 0.5, color: '#FFB300' },
@@ -342,7 +342,7 @@ export class HashrateChartComponent implements OnInit {
type: 'value',
axisLabel: {
color: 'rgb(110, 112, 121)',
- formatter: (val) => {
+ formatter: (val): string => {
const selectedPowerOfTen: any = selectPowerOfTen(val);
const newVal = Math.round(val / selectedPowerOfTen.divider);
return `${newVal} ${selectedPowerOfTen.unit}H/s`;
@@ -364,9 +364,9 @@ export class HashrateChartComponent implements OnInit {
position: 'right',
axisLabel: {
color: 'rgb(110, 112, 121)',
- formatter: (val) => {
+ formatter: (val): string => {
if (this.stateService.network === 'signet') {
- return val;
+ return `${val}`;
}
const selectedPowerOfTen: any = selectPowerOfTen(val);
const newVal = Math.round(val / selectedPowerOfTen.divider);
diff --git a/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.ts b/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.ts
index e7e3685d3..b0557ca7c 100644
--- a/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.ts
+++ b/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.ts
@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, LOCALE_ID, OnInit, HostBinding } from '@angular/core';
-import { EChartsOption } from 'echarts';
+import { EChartsOption } from '../../graphs/echarts';
import { Observable } from 'rxjs';
import { delay, map, retryWhen, share, startWith, switchMap, tap } from 'rxjs/operators';
import { ApiService } from '../../services/api.service';
diff --git a/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts b/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts
index 3b93cb686..1b68a5a99 100644
--- a/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts
+++ b/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts
@@ -1,5 +1,5 @@
import { Component, Input, Inject, LOCALE_ID, ChangeDetectionStrategy, OnInit, OnDestroy } from '@angular/core';
-import { EChartsOption } from 'echarts';
+import { EChartsOption } from '../../graphs/echarts';
import { OnChanges } from '@angular/core';
import { StorageService } from '../../services/storage.service';
import { download, formatterXAxis, formatterXAxisLabel } from '../../shared/graphs.utils';
diff --git a/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.ts b/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.ts
index e4aa95492..c4e8cbf91 100644
--- a/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.ts
+++ b/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.ts
@@ -1,6 +1,6 @@
import { Component, Inject, LOCALE_ID, ChangeDetectionStrategy, Input, OnChanges, OnInit } from '@angular/core';
import { formatDate, formatNumber } from '@angular/common';
-import { EChartsOption } from 'echarts';
+import { EChartsOption } from '../../graphs/echarts';
@Component({
selector: 'app-lbtc-pegs-graph',
diff --git a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts
index 935e79b2c..3ea30810f 100644
--- a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts
+++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts
@@ -6,7 +6,7 @@ import { formatNumber } from '@angular/common';
import { OptimizedMempoolStats } from '../../interfaces/node-api.interface';
import { StateService } from '../../services/state.service';
import { StorageService } from '../../services/storage.service';
-import { EChartsOption } from 'echarts';
+import { EChartsOption } from '../../graphs/echarts';
import { feeLevels, chartColors } from '../../app.constants';
import { download, formatterXAxis, formatterXAxisLabel } from '../../shared/graphs.utils';
diff --git a/frontend/src/app/components/pool-ranking/pool-ranking.component.ts b/frontend/src/app/components/pool-ranking/pool-ranking.component.ts
index 91475040c..392cdf8c5 100644
--- a/frontend/src/app/components/pool-ranking/pool-ranking.component.ts
+++ b/frontend/src/app/components/pool-ranking/pool-ranking.component.ts
@@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, Component, Input, NgZone, OnInit, HostBinding } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
-import { EChartsOption, PieSeriesOption } from 'echarts';
+import { EChartsOption, PieSeriesOption } from '../../graphs/echarts';
import { merge, Observable } from 'rxjs';
import { map, share, startWith, switchMap, tap } from 'rxjs/operators';
import { SeoService } from '../../services/seo.service';
diff --git a/frontend/src/app/components/pool/pool-preview.component.ts b/frontend/src/app/components/pool/pool-preview.component.ts
index b2302b9a7..e0c786082 100644
--- a/frontend/src/app/components/pool/pool-preview.component.ts
+++ b/frontend/src/app/components/pool/pool-preview.component.ts
@@ -1,6 +1,6 @@
import { ChangeDetectionStrategy, Component, Inject, LOCALE_ID, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
-import { EChartsOption, graphic } from 'echarts';
+import { echarts, EChartsOption } from '../../graphs/echarts';
import { Observable, of } from 'rxjs';
import { map, switchMap, catchError } from 'rxjs/operators';
import { PoolStat } from '../../interfaces/node-api.interface';
@@ -127,7 +127,7 @@ export class PoolPreviewComponent implements OnInit {
title: title,
animation: false,
color: [
- new graphic.LinearGradient(0, 0, 0, 0.65, [
+ new echarts.graphic.LinearGradient(0, 0, 0, 0.65, [
{ offset: 0, color: '#F4511E' },
{ offset: 0.25, color: '#FB8C00' },
{ offset: 0.5, color: '#FFB300' },
diff --git a/frontend/src/app/components/pool/pool.component.ts b/frontend/src/app/components/pool/pool.component.ts
index 0d465bc3c..86fdeda18 100644
--- a/frontend/src/app/components/pool/pool.component.ts
+++ b/frontend/src/app/components/pool/pool.component.ts
@@ -1,6 +1,6 @@
import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
-import { EChartsOption, graphic } from 'echarts';
+import { echarts, EChartsOption } from '../../graphs/echarts';
import { BehaviorSubject, Observable, of, timer } from 'rxjs';
import { catchError, distinctUntilChanged, map, share, switchMap, tap } from 'rxjs/operators';
import { BlockExtended, PoolStat } from '../../interfaces/node-api.interface';
@@ -131,7 +131,7 @@ export class PoolComponent implements OnInit {
title: title,
animation: false,
color: [
- new graphic.LinearGradient(0, 0, 0, 0.65, [
+ new echarts.graphic.LinearGradient(0, 0, 0, 0.65, [
{ offset: 0, color: '#F4511E' },
{ offset: 0.25, color: '#FB8C00' },
{ offset: 0.5, color: '#FFB300' },
diff --git a/frontend/src/app/graphs/echarts.ts b/frontend/src/app/graphs/echarts.ts
new file mode 100644
index 000000000..588e5e5f1
--- /dev/null
+++ b/frontend/src/app/graphs/echarts.ts
@@ -0,0 +1,17 @@
+// Import tree-shakeable echarts
+import * as echarts from 'echarts/core';
+import { LineChart, LinesChart, BarChart, TreemapChart, PieChart, ScatterChart } from 'echarts/charts';
+import { TitleComponent, TooltipComponent, GridComponent, LegendComponent, GeoComponent, DataZoomComponent, VisualMapComponent } from 'echarts/components';
+import { SVGRenderer, CanvasRenderer } from 'echarts/renderers';
+// Typescript interfaces
+import { EChartsOption, TreemapSeriesOption, LineSeriesOption, PieSeriesOption } from 'echarts';
+
+
+echarts.use([
+ SVGRenderer, CanvasRenderer,
+ TitleComponent, TooltipComponent, GridComponent,
+ LegendComponent, GeoComponent, DataZoomComponent,
+ VisualMapComponent,
+ LineChart, LinesChart, BarChart, TreemapChart, PieChart, ScatterChart
+]);
+export { echarts, EChartsOption, TreemapSeriesOption, LineSeriesOption, PieSeriesOption };
\ No newline at end of file
diff --git a/frontend/src/app/graphs/graphs.module.ts b/frontend/src/app/graphs/graphs.module.ts
index 87e8a620b..a2160977c 100644
--- a/frontend/src/app/graphs/graphs.module.ts
+++ b/frontend/src/app/graphs/graphs.module.ts
@@ -53,7 +53,7 @@ import { CommonModule } from '@angular/common';
SharedModule,
GraphsRoutingModule,
NgxEchartsModule.forRoot({
- echarts: () => import('echarts')
+ echarts: () => import('./echarts').then(m => m.echarts),
})
],
exports: [
diff --git a/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.ts b/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.ts
index f20142e47..ad667bcf6 100644
--- a/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.ts
+++ b/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.ts
@@ -1,5 +1,5 @@
import { Component, Inject, Input, LOCALE_ID, OnInit, HostBinding } from '@angular/core';
-import { EChartsOption } from 'echarts';
+import { EChartsOption } from '../../graphs/echarts';
import { switchMap } from 'rxjs/operators';
import { download } from '../../shared/graphs.utils';
import { LightningApiService } from '../lightning-api.service';
diff --git a/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.ts b/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.ts
index 9b10152b5..a9308a887 100644
--- a/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.ts
+++ b/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.ts
@@ -1,5 +1,5 @@
import { Component, Inject, Input, LOCALE_ID, OnInit, HostBinding } from '@angular/core';
-import { EChartsOption } from 'echarts';
+import { EChartsOption } from '../../graphs/echarts';
import { Observable } from 'rxjs';
import { switchMap, tap } from 'rxjs/operators';
import { formatNumber } from '@angular/common';
diff --git a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts
index 3090a803c..01978c324 100644
--- a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts
+++ b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts
@@ -6,8 +6,7 @@ import { AssetsService } from '../../services/assets.service';
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
import { StateService } from '../../services/state.service';
-import { EChartsOption, registerMap } from 'echarts';
-import 'echarts-gl';
+import { EChartsOption, echarts } from '../../graphs/echarts';
import { isMobile } from '../../shared/common.utils';
@Component({
@@ -88,7 +87,7 @@ export class NodesChannelsMap implements OnInit {
this.style !== 'channelpage' ? this.apiService.getChannelsGeo$(params.get('public_key') ?? undefined, this.style) : [''],
[params.get('public_key') ?? undefined]
).pipe(tap((data) => {
- registerMap('world', data[0]);
+ echarts.registerMap('world', data[0]);
const channelsLoc = [];
const nodes = [];
diff --git a/frontend/src/app/lightning/nodes-channels/node-channels.component.ts b/frontend/src/app/lightning/nodes-channels/node-channels.component.ts
index 91d43f6ab..be596d8f9 100644
--- a/frontend/src/app/lightning/nodes-channels/node-channels.component.ts
+++ b/frontend/src/app/lightning/nodes-channels/node-channels.component.ts
@@ -1,7 +1,7 @@
import { formatNumber } from '@angular/common';
import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, NgZone, OnChanges } from '@angular/core';
import { Router } from '@angular/router';
-import { ECharts, EChartsOption, TreemapSeriesOption } from 'echarts';
+import { EChartsOption, TreemapSeriesOption } from '../../graphs/echarts';
import { Observable, share, switchMap, tap } from 'rxjs';
import { lerpColor } from '../../shared/graphs.utils';
import { AmountShortenerPipe } from '../../shared/pipes/amount-shortener.pipe';
@@ -18,7 +18,7 @@ import { StateService } from '../../services/state.service';
export class NodeChannels implements OnChanges {
@Input() publicKey: string;
- chartInstance: ECharts;
+ chartInstance: any;
chartOptions: EChartsOption = {};
chartInitOptions = {
renderer: 'svg',
@@ -129,7 +129,7 @@ export class NodeChannels implements OnChanges {
};
}
- onChartInit(ec: ECharts): void {
+ onChartInit(ec: any): void {
this.chartInstance = ec;
this.chartInstance.on('click', (e) => {
diff --git a/frontend/src/app/lightning/nodes-map/nodes-map.component.ts b/frontend/src/app/lightning/nodes-map/nodes-map.component.ts
index ea80d8799..bb9e21c4b 100644
--- a/frontend/src/app/lightning/nodes-map/nodes-map.component.ts
+++ b/frontend/src/app/lightning/nodes-map/nodes-map.component.ts
@@ -3,7 +3,7 @@ import { SeoService } from '../../services/seo.service';
import { ApiService } from '../../services/api.service';
import { Observable, BehaviorSubject, switchMap, tap, combineLatest } from 'rxjs';
import { AssetsService } from '../../services/assets.service';
-import { EChartsOption, registerMap } from 'echarts';
+import { EChartsOption, echarts } from '../../graphs/echarts';
import { lerpColor } from '../../shared/graphs.utils';
import { Router } from '@angular/router';
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
@@ -63,7 +63,7 @@ export class NodesMap implements OnInit, OnChanges {
this.assetsService.getWorldMapJson$,
this.nodes$
).pipe(tap((data) => {
- registerMap('world', data[0]);
+ echarts.registerMap('world', data[0]);
let maxLiquidity = data[1].maxLiquidity;
let inputNodes: any[] = data[1].nodes;
diff --git a/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts b/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts
index f62a6a244..7352d884d 100644
--- a/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts
+++ b/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts
@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit, HostBinding } from '@angular/core';
-import { EChartsOption, graphic, LineSeriesOption} from 'echarts';
+import { echarts, EChartsOption, LineSeriesOption } from '../../graphs/echarts';
import { Observable } from 'rxjs';
import { map, share, startWith, switchMap, tap } from 'rxjs/operators';
import { formatNumber } from '@angular/common';
@@ -152,7 +152,7 @@ export class NodesNetworksChartComponent implements OnInit {
opacity: 0.5,
},
stack: 'Total',
- color: new graphic.LinearGradient(0, 0.75, 0, 1, [
+ color: new echarts.graphic.LinearGradient(0, 0.75, 0, 1, [
{ offset: 0, color: '#D81B60' },
{ offset: 1, color: '#D81B60AA' },
]),
@@ -174,7 +174,7 @@ export class NodesNetworksChartComponent implements OnInit {
opacity: 0.5,
},
stack: 'Total',
- color: new graphic.LinearGradient(0, 0.75, 0, 1, [
+ color: new echarts.graphic.LinearGradient(0, 0.75, 0, 1, [
{ offset: 0, color: '#be7d4c' },
{ offset: 1, color: '#be7d4cAA' },
]),
@@ -195,7 +195,7 @@ export class NodesNetworksChartComponent implements OnInit {
opacity: 0.5,
},
stack: 'Total',
- color: new graphic.LinearGradient(0, 0.75, 0, 1, [
+ color: new echarts.graphic.LinearGradient(0, 0.75, 0, 1, [
{ offset: 0, color: '#FFB300' },
{ offset: 1, color: '#FFB300AA' },
]),
@@ -216,7 +216,7 @@ export class NodesNetworksChartComponent implements OnInit {
opacity: 0.5,
},
stack: 'Total',
- color: new graphic.LinearGradient(0, 0.75, 0, 1, [
+ color: new echarts.graphic.LinearGradient(0, 0.75, 0, 1, [
{ offset: 0, color: '#7D4698' },
{ offset: 1, color: '#7D4698AA' },
]),
diff --git a/frontend/src/app/lightning/nodes-per-country-chart/nodes-per-country-chart.component.ts b/frontend/src/app/lightning/nodes-per-country-chart/nodes-per-country-chart.component.ts
index 5bfa0fc2c..e305d8959 100644
--- a/frontend/src/app/lightning/nodes-per-country-chart/nodes-per-country-chart.component.ts
+++ b/frontend/src/app/lightning/nodes-per-country-chart/nodes-per-country-chart.component.ts
@@ -1,6 +1,6 @@
import { ChangeDetectionStrategy, Component, OnInit, HostBinding, NgZone } from '@angular/core';
import { Router } from '@angular/router';
-import { EChartsOption, PieSeriesOption } from 'echarts';
+import { EChartsOption, PieSeriesOption } from '../../graphs/echarts';
import { map, Observable, share, tap } from 'rxjs';
import { chartColors } from '../../app.constants';
import { ApiService } from '../../services/api.service';
diff --git a/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.ts b/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.ts
index 67f393bc2..5342f616b 100644
--- a/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.ts
+++ b/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.ts
@@ -1,6 +1,6 @@
import { ChangeDetectionStrategy, Component, OnInit, HostBinding, NgZone, Input } from '@angular/core';
import { Router } from '@angular/router';
-import { EChartsOption, PieSeriesOption } from 'echarts';
+import { EChartsOption, PieSeriesOption } from '../../graphs/echarts';
import { combineLatest, map, Observable, share, startWith, Subject, switchMap, tap } from 'rxjs';
import { chartColors } from '../../app.constants';
import { ApiService } from '../../services/api.service';
diff --git a/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.ts b/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.ts
index 41e170de6..7417a35cd 100644
--- a/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.ts
+++ b/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.ts
@@ -1,5 +1,5 @@
import { Component, Inject, Input, LOCALE_ID, OnInit, HostBinding } from '@angular/core';
-import { EChartsOption, graphic } from 'echarts';
+import { echarts, EChartsOption } from '../../graphs/echarts';
import { Observable } from 'rxjs';
import { map, share, startWith, switchMap, tap } from 'rxjs/operators';
import { SeoService } from '../../services/seo.service';
@@ -132,7 +132,7 @@ export class LightningStatisticsChartComponent implements OnInit {
animation: false,
color: [
'#FFB300',
- new graphic.LinearGradient(0, 0.75, 0, 1, [
+ new echarts.graphic.LinearGradient(0, 0.75, 0, 1, [
{ offset: 0, color: '#D81B60' },
{ offset: 1, color: '#D81B60AA' },
]),
From d18b8881d0660774af7d3a5c3ee7411f8baad6fb Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 9 Nov 2023 02:16:55 +0000
Subject: [PATCH 33/79] Bump axios from 1.5.0 to 1.6.1 in /backend
Bumps [axios](https://github.com/axios/axios) from 1.5.0 to 1.6.1.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.5.0...v1.6.1)
---
updated-dependencies:
- dependency-name: axios
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
---
backend/package-lock.json | 14 +++++++-------
backend/package.json | 2 +-
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/backend/package-lock.json b/backend/package-lock.json
index 33f19a26d..3e9e31988 100644
--- a/backend/package-lock.json
+++ b/backend/package-lock.json
@@ -12,7 +12,7 @@
"@babel/core": "^7.23.2",
"@mempool/electrum-client": "1.1.9",
"@types/node": "^18.15.3",
- "axios": "~1.5.0",
+ "axios": "~1.6.1",
"bitcoinjs-lib": "~6.1.3",
"crypto-js": "~4.2.0",
"express": "~4.18.2",
@@ -2325,9 +2325,9 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz",
- "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==",
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz",
+ "integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==",
"dependencies": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
@@ -9415,9 +9415,9 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"axios": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz",
- "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==",
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz",
+ "integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==",
"requires": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
diff --git a/backend/package.json b/backend/package.json
index bdce50902..0c1d3cc4a 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -41,7 +41,7 @@
"@babel/core": "^7.23.2",
"@mempool/electrum-client": "1.1.9",
"@types/node": "^18.15.3",
- "axios": "~1.5.0",
+ "axios": "~1.6.1",
"bitcoinjs-lib": "~6.1.3",
"crypto-js": "~4.2.0",
"express": "~4.18.2",
From b5a8687b6a9fa3273ab1de2e38c0612b67600c51 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Wed, 8 Nov 2023 00:09:23 +0000
Subject: [PATCH 34/79] Split Block component into separate module
---
frontend/src/app/app-routing.module.ts | 61 +++----------------
.../src/app/components/block/block.module.ts | 43 +++++++++++++
frontend/src/app/shared/shared.module.ts | 3 -
3 files changed, 53 insertions(+), 54 deletions(-)
create mode 100644 frontend/src/app/components/block/block.module.ts
diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts
index 7c2ac1274..cbf38c69d 100644
--- a/frontend/src/app/app-routing.module.ts
+++ b/frontend/src/app/app-routing.module.ts
@@ -3,7 +3,6 @@ import { Routes, RouterModule } from '@angular/router';
import { AppPreloadingStrategy } from './app.preloading-strategy'
import { StartComponent } from './components/start/start.component';
import { TransactionComponent } from './components/transaction/transaction.component';
-import { BlockComponent } from './components/block/block.component';
import { BlockViewComponent } from './components/block-view/block-view.component';
import { MempoolBlockViewComponent } from './components/mempool-block-view/mempool-block-view.component';
import { ClockComponent } from './components/clock/clock.component';
@@ -100,16 +99,8 @@ let routes: Routes = [
{
path: 'block',
component: StartComponent,
- data: { networkSpecific: true },
- children: [
- {
- path: ':id',
- component: BlockComponent,
- data: {
- ogImage: true
- }
- },
- ],
+ data: { preload: true, networkSpecific: true },
+ loadChildren: () => import('./components/block/block.module').then(m => m.BlockModule),
},
{
path: 'docs',
@@ -209,17 +200,9 @@ let routes: Routes = [
},
{
path: 'block',
- data: { networkSpecific: true },
component: StartComponent,
- children: [
- {
- path: ':id',
- component: BlockComponent,
- data: {
- ogImage: true
- }
- },
- ],
+ data: { preload: true, networkSpecific: true },
+ loadChildren: () => import('./components/block/block.module').then(m => m.BlockModule),
},
{
path: 'docs',
@@ -319,17 +302,9 @@ let routes: Routes = [
},
{
path: 'block',
- data: { networkSpecific: true },
component: StartComponent,
- children: [
- {
- path: ':id',
- component: BlockComponent,
- data: {
- ogImage: true
- }
- },
- ],
+ data: { preload: true, networkSpecific: true },
+ loadChildren: () => import('./components/block/block.module').then(m => m.BlockModule),
},
{
path: 'docs',
@@ -466,17 +441,9 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
},
{
path: 'block',
- data: { networkSpecific: true },
component: StartComponent,
- children: [
- {
- path: ':id',
- component: BlockComponent,
- data: {
- ogImage: true
- }
- },
- ],
+ data: { preload: true, networkSpecific: true },
+ loadChildren: () => import('./components/block/block.module').then(m => m.BlockModule),
},
{
path: 'assets',
@@ -584,17 +551,9 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
},
{
path: 'block',
- data: { networkSpecific: true },
component: StartComponent,
- children: [
- {
- path: ':id',
- component: BlockComponent,
- data: {
- ogImage: true
- }
- },
- ],
+ data: { preload: true, networkSpecific: true },
+ loadChildren: () => import('./components/block/block.module').then(m => m.BlockModule),
},
{
path: 'assets',
diff --git a/frontend/src/app/components/block/block.module.ts b/frontend/src/app/components/block/block.module.ts
new file mode 100644
index 000000000..d6991c68a
--- /dev/null
+++ b/frontend/src/app/components/block/block.module.ts
@@ -0,0 +1,43 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { Routes, RouterModule } from '@angular/router';
+import { BlockComponent } from './block.component';
+import { SharedModule } from '../../shared/shared.module';
+
+const routes: Routes = [
+ {
+ path: ':id',
+ component: BlockComponent,
+ data: {
+ ogImage: true
+ }
+ }
+];
+
+@NgModule({
+ imports: [
+ RouterModule.forChild(routes)
+ ],
+ exports: [
+ RouterModule
+ ]
+})
+export class BlockRoutingModule { }
+
+@NgModule({
+ imports: [
+ CommonModule,
+ BlockRoutingModule,
+ SharedModule,
+ ],
+ declarations: [
+ BlockComponent,
+ ]
+})
+export class BlockModule { }
+
+
+
+
+
+
diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts
index dce65bfae..fb10a9e19 100644
--- a/frontend/src/app/shared/shared.module.ts
+++ b/frontend/src/app/shared/shared.module.ts
@@ -47,7 +47,6 @@ import { CapAddressPipe } from './pipes/cap-address-pipe/cap-address-pipe';
import { StartComponent } from '../components/start/start.component';
import { TransactionComponent } from '../components/transaction/transaction.component';
import { TransactionsListComponent } from '../components/transactions-list/transactions-list.component';
-import { BlockComponent } from '../components/block/block.component';
import { BlockOverviewGraphComponent } from '../components/block-overview-graph/block-overview-graph.component';
import { BlockOverviewTooltipComponent } from '../components/block-overview-tooltip/block-overview-tooltip.component';
import { AddressComponent } from '../components/address/address.component';
@@ -149,7 +148,6 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
LiquidMasterPageComponent,
StartComponent,
TransactionComponent,
- BlockComponent,
BlockOverviewGraphComponent,
BlockOverviewTooltipComponent,
TransactionsListComponent,
@@ -276,7 +274,6 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
AmountComponent,
StartComponent,
TransactionComponent,
- BlockComponent,
BlockOverviewGraphComponent,
BlockOverviewTooltipComponent,
TransactionsListComponent,
From 0cf898a19ff71771aef35e63f2caf38612bac1e5 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Thu, 9 Nov 2023 07:05:37 +0000
Subject: [PATCH 35/79] Split transaction components into separate module
---
frontend/src/app/app-routing.module.ts | 46 ++++---------------
.../transaction/transaction.module.ts | 45 ++++++++++++++++++
.../tx-bowtie-graph/tx-bowtie.module.ts | 28 +++++++++++
frontend/src/app/previews.module.ts | 2 +
frontend/src/app/shared/shared.module.ts | 9 ----
5 files changed, 85 insertions(+), 45 deletions(-)
create mode 100644 frontend/src/app/components/transaction/transaction.module.ts
create mode 100644 frontend/src/app/components/tx-bowtie-graph/tx-bowtie.module.ts
diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts
index cbf38c69d..479080af5 100644
--- a/frontend/src/app/app-routing.module.ts
+++ b/frontend/src/app/app-routing.module.ts
@@ -2,7 +2,6 @@ import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AppPreloadingStrategy } from './app.preloading-strategy'
import { StartComponent } from './components/start/start.component';
-import { TransactionComponent } from './components/transaction/transaction.component';
import { BlockViewComponent } from './components/block-view/block-view.component';
import { MempoolBlockViewComponent } from './components/mempool-block-view/mempool-block-view.component';
import { ClockComponent } from './components/clock/clock.component';
@@ -88,13 +87,8 @@ let routes: Routes = [
{
path: 'tx',
component: StartComponent,
- data: { networkSpecific: true },
- children: [
- {
- path: ':id',
- component: TransactionComponent
- },
- ],
+ data: { preload: true, networkSpecific: true },
+ loadChildren: () => import('./components/transaction/transaction.module').then(m => m.TransactionModule),
},
{
path: 'block',
@@ -189,14 +183,9 @@ let routes: Routes = [
},
{
path: 'tx',
- data: { networkSpecific: true },
component: StartComponent,
- children: [
- {
- path: ':id',
- component: TransactionComponent
- },
- ],
+ data: { preload: true, networkSpecific: true },
+ loadChildren: () => import('./components/transaction/transaction.module').then(m => m.TransactionModule),
},
{
path: 'block',
@@ -291,14 +280,9 @@ let routes: Routes = [
},
{
path: 'tx',
- data: { networkSpecific: true },
component: StartComponent,
- children: [
- {
- path: ':id',
- component: TransactionComponent
- },
- ],
+ data: { preload: true, networkSpecific: true },
+ loadChildren: () => import('./components/transaction/transaction.module').then(m => m.TransactionModule),
},
{
path: 'block',
@@ -430,14 +414,9 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
},
{
path: 'tx',
- data: { networkSpecific: true },
component: StartComponent,
- children: [
- {
- path: ':id',
- component: TransactionComponent
- },
- ],
+ data: { preload: true, networkSpecific: true },
+ loadChildren: () => import('./components/transaction/transaction.module').then(m => m.TransactionModule),
},
{
path: 'block',
@@ -540,14 +519,9 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
},
{
path: 'tx',
- data: { networkSpecific: true },
component: StartComponent,
- children: [
- {
- path: ':id',
- component: TransactionComponent
- },
- ],
+ data: { preload: true, networkSpecific: true },
+ loadChildren: () => import('./components/transaction/transaction.module').then(m => m.TransactionModule),
},
{
path: 'block',
diff --git a/frontend/src/app/components/transaction/transaction.module.ts b/frontend/src/app/components/transaction/transaction.module.ts
new file mode 100644
index 000000000..d933cc350
--- /dev/null
+++ b/frontend/src/app/components/transaction/transaction.module.ts
@@ -0,0 +1,45 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { Routes, RouterModule } from '@angular/router';
+import { TransactionComponent } from './transaction.component';
+import { SharedModule } from '../../shared/shared.module';
+import { TxBowtieModule } from '../tx-bowtie-graph/tx-bowtie.module';
+
+const routes: Routes = [
+ {
+ path: ':id',
+ component: TransactionComponent,
+ data: {
+ ogImage: true
+ }
+ }
+];
+
+@NgModule({
+ imports: [
+ RouterModule.forChild(routes)
+ ],
+ exports: [
+ RouterModule
+ ]
+})
+export class TransactionRoutingModule { }
+
+@NgModule({
+ imports: [
+ CommonModule,
+ TransactionRoutingModule,
+ SharedModule,
+ TxBowtieModule,
+ ],
+ declarations: [
+ TransactionComponent,
+ ]
+})
+export class TransactionModule { }
+
+
+
+
+
+
diff --git a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie.module.ts b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie.module.ts
new file mode 100644
index 000000000..617425e7a
--- /dev/null
+++ b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie.module.ts
@@ -0,0 +1,28 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { SharedModule } from '../../shared/shared.module';
+import { TxBowtieGraphComponent } from '../tx-bowtie-graph/tx-bowtie-graph.component';
+import { TxBowtieGraphTooltipComponent } from '../tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component';
+
+
+@NgModule({
+ imports: [
+ CommonModule,
+ SharedModule,
+ ],
+ declarations: [
+ TxBowtieGraphComponent,
+ TxBowtieGraphTooltipComponent,
+ ],
+ exports: [
+ TxBowtieGraphComponent,
+ TxBowtieGraphTooltipComponent,
+ ]
+})
+export class TxBowtieModule { }
+
+
+
+
+
+
diff --git a/frontend/src/app/previews.module.ts b/frontend/src/app/previews.module.ts
index 2e8dbdc75..95124f232 100644
--- a/frontend/src/app/previews.module.ts
+++ b/frontend/src/app/previews.module.ts
@@ -9,6 +9,7 @@ import { BlockPreviewComponent } from './components/block/block-preview.componen
import { AddressPreviewComponent } from './components/address/address-preview.component';
import { PoolPreviewComponent } from './components/pool/pool-preview.component';
import { MasterPagePreviewComponent } from './components/master-page-preview/master-page-preview.component';
+import { TxBowtieModule } from './components/tx-bowtie-graph/tx-bowtie.module';
@NgModule({
declarations: [
TransactionPreviewComponent,
@@ -23,6 +24,7 @@ import { MasterPagePreviewComponent } from './components/master-page-preview/mas
RouterModule,
PreviewsRoutingModule,
GraphsModule,
+ TxBowtieModule,
],
})
export class PreviewsModule { }
diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts
index fb10a9e19..76ed41477 100644
--- a/frontend/src/app/shared/shared.module.ts
+++ b/frontend/src/app/shared/shared.module.ts
@@ -45,7 +45,6 @@ import { AmountComponent } from '../components/amount/amount.component';
import { RouterModule } from '@angular/router';
import { CapAddressPipe } from './pipes/cap-address-pipe/cap-address-pipe';
import { StartComponent } from '../components/start/start.component';
-import { TransactionComponent } from '../components/transaction/transaction.component';
import { TransactionsListComponent } from '../components/transactions-list/transactions-list.component';
import { BlockOverviewGraphComponent } from '../components/block-overview-graph/block-overview-graph.component';
import { BlockOverviewTooltipComponent } from '../components/block-overview-tooltip/block-overview-tooltip.component';
@@ -64,8 +63,6 @@ import { DifficultyMiningComponent } from '../components/difficulty-mining/diffi
import { TermsOfServiceComponent } from '../components/terms-of-service/terms-of-service.component';
import { RbfTimelineComponent } from '../components/rbf-timeline/rbf-timeline.component';
import { RbfTimelineTooltipComponent } from '../components/rbf-timeline/rbf-timeline-tooltip.component';
-import { TxBowtieGraphComponent } from '../components/tx-bowtie-graph/tx-bowtie-graph.component';
-import { TxBowtieGraphTooltipComponent } from '../components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component';
import { PrivacyPolicyComponent } from '../components/privacy-policy/privacy-policy.component';
import { TrademarkPolicyComponent } from '../components/trademark-policy/trademark-policy.component';
import { PushTransactionComponent } from '../components/push-transaction/push-transaction.component';
@@ -147,7 +144,6 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
BisqMasterPageComponent,
LiquidMasterPageComponent,
StartComponent,
- TransactionComponent,
BlockOverviewGraphComponent,
BlockOverviewTooltipComponent,
TransactionsListComponent,
@@ -164,8 +160,6 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
DifficultyTooltipComponent,
RbfTimelineComponent,
RbfTimelineTooltipComponent,
- TxBowtieGraphComponent,
- TxBowtieGraphTooltipComponent,
TermsOfServiceComponent,
PrivacyPolicyComponent,
TrademarkPolicyComponent,
@@ -273,7 +267,6 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
BlockchainBlocksComponent,
AmountComponent,
StartComponent,
- TransactionComponent,
BlockOverviewGraphComponent,
BlockOverviewTooltipComponent,
TransactionsListComponent,
@@ -290,8 +283,6 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
DifficultyTooltipComponent,
RbfTimelineComponent,
RbfTimelineTooltipComponent,
- TxBowtieGraphComponent,
- TxBowtieGraphTooltipComponent,
TermsOfServiceComponent,
PrivacyPolicyComponent,
TrademarkPolicyComponent,
From ae02ff5b0dbdf88e7288b02fb41eea482a836c3c Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Thu, 9 Nov 2023 07:06:09 +0000
Subject: [PATCH 36/79] Split About component into separate module
---
frontend/src/app/app-routing.module.ts | 11 +++--
frontend/src/app/bisq/bisq.routing.module.ts | 3 +-
.../src/app/components/about/about.module.ts | 40 +++++++++++++++++++
frontend/src/app/shared/shared.module.ts | 2 -
4 files changed, 46 insertions(+), 10 deletions(-)
create mode 100644 frontend/src/app/components/about/about.module.ts
diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts
index 479080af5..8faa16add 100644
--- a/frontend/src/app/app-routing.module.ts
+++ b/frontend/src/app/app-routing.module.ts
@@ -7,7 +7,6 @@ import { MempoolBlockViewComponent } from './components/mempool-block-view/mempo
import { ClockComponent } from './components/clock/clock.component';
import { AddressComponent } from './components/address/address.component';
import { MasterPageComponent } from './components/master-page/master-page.component';
-import { AboutComponent } from './components/about/about.component';
import { StatusViewComponent } from './components/status-view/status-view.component';
import { TermsOfServiceComponent } from './components/terms-of-service/terms-of-service.component';
import { PrivacyPolicyComponent } from './components/privacy-policy/privacy-policy.component';
@@ -53,7 +52,7 @@ let routes: Routes = [
},
{
path: 'about',
- component: AboutComponent,
+ loadChildren: () => import('./components/about/about.module').then(m => m.AboutModule),
},
{
path: 'blocks',
@@ -150,7 +149,7 @@ let routes: Routes = [
},
{
path: 'about',
- component: AboutComponent,
+ loadChildren: () => import('./components/about/about.module').then(m => m.AboutModule),
},
{
path: 'blocks',
@@ -243,7 +242,7 @@ let routes: Routes = [
},
{
path: 'about',
- component: AboutComponent,
+ loadChildren: () => import('./components/about/about.module').then(m => m.AboutModule),
},
{
path: 'blocks',
@@ -385,7 +384,7 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
},
{
path: 'about',
- component: AboutComponent,
+ loadChildren: () => import('./components/about/about.module').then(m => m.AboutModule),
},
{
path: 'blocks',
@@ -490,7 +489,7 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
},
{
path: 'about',
- component: AboutComponent,
+ loadChildren: () => import('./components/about/about.module').then(m => m.AboutModule),
},
{
path: 'blocks',
diff --git a/frontend/src/app/bisq/bisq.routing.module.ts b/frontend/src/app/bisq/bisq.routing.module.ts
index 11acdca2a..b211afeaf 100644
--- a/frontend/src/app/bisq/bisq.routing.module.ts
+++ b/frontend/src/app/bisq/bisq.routing.module.ts
@@ -1,6 +1,5 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
-import { AboutComponent } from '../components/about/about.component';
import { BisqTransactionsComponent } from './bisq-transactions/bisq-transactions.component';
import { BisqTransactionComponent } from './bisq-transaction/bisq-transaction.component';
import { BisqBlockComponent } from './bisq-block/bisq-block.component';
@@ -64,7 +63,7 @@ const routes: Routes = [
},
{
path: 'about',
- component: AboutComponent,
+ loadChildren: () => import('../components/about/about.module').then(m => m.AboutModule),
},
{
path: 'docs',
diff --git a/frontend/src/app/components/about/about.module.ts b/frontend/src/app/components/about/about.module.ts
new file mode 100644
index 000000000..1eb471f14
--- /dev/null
+++ b/frontend/src/app/components/about/about.module.ts
@@ -0,0 +1,40 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { Routes, RouterModule } from '@angular/router';
+import { AboutComponent } from './about.component';
+import { SharedModule } from '../../shared/shared.module';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: AboutComponent,
+ }
+];
+
+@NgModule({
+ imports: [
+ RouterModule.forChild(routes)
+ ],
+ exports: [
+ RouterModule
+ ]
+})
+export class AboutRoutingModule { }
+
+@NgModule({
+ imports: [
+ CommonModule,
+ AboutRoutingModule,
+ SharedModule,
+ ],
+ declarations: [
+ AboutComponent,
+ ]
+})
+export class AboutModule { }
+
+
+
+
+
+
diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts
index 76ed41477..1e1fe42b3 100644
--- a/frontend/src/app/shared/shared.module.ts
+++ b/frontend/src/app/shared/shared.module.ts
@@ -11,7 +11,6 @@ import { MenuComponent } from '../components/menu/menu.component';
import { PreviewTitleComponent } from '../components/master-page-preview/preview-title.component';
import { BisqMasterPageComponent } from '../components/bisq-master-page/bisq-master-page.component';
import { LiquidMasterPageComponent } from '../components/liquid-master-page/liquid-master-page.component';
-import { AboutComponent } from '../components/about/about.component';
import { VbytesPipe } from './pipes/bytes-pipe/vbytes.pipe';
import { ShortenStringPipe } from './pipes/shorten-string-pipe/shorten-string.pipe';
import { CeilPipe } from './pipes/math-ceil/math-ceil.pipe';
@@ -137,7 +136,6 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
MempoolBlocksComponent,
BlockchainBlocksComponent,
AmountComponent,
- AboutComponent,
MasterPageComponent,
MenuComponent,
PreviewTitleComponent,
From 854a9dd05718833e240127935a2759558a2b36b1 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Thu, 9 Nov 2023 07:53:46 +0000
Subject: [PATCH 37/79] Split legal page components into separate modules
---
frontend/src/app/app-routing.module.ts | 33 +++++++--------
frontend/src/app/bisq/bisq.routing.module.ts | 3 +-
.../privacy-policy/privacy-policy.module.ts | 40 +++++++++++++++++++
.../terms-of-service.module.ts | 40 +++++++++++++++++++
.../trademark-policy.module.ts | 40 +++++++++++++++++++
frontend/src/app/shared/shared.module.ts | 9 -----
6 files changed, 136 insertions(+), 29 deletions(-)
create mode 100644 frontend/src/app/components/privacy-policy/privacy-policy.module.ts
create mode 100644 frontend/src/app/components/terms-of-service/terms-of-service.module.ts
create mode 100644 frontend/src/app/components/trademark-policy/trademark-policy.module.ts
diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts
index 8faa16add..2ebb1c74b 100644
--- a/frontend/src/app/app-routing.module.ts
+++ b/frontend/src/app/app-routing.module.ts
@@ -8,9 +8,6 @@ import { ClockComponent } from './components/clock/clock.component';
import { AddressComponent } from './components/address/address.component';
import { MasterPageComponent } from './components/master-page/master-page.component';
import { StatusViewComponent } from './components/status-view/status-view.component';
-import { TermsOfServiceComponent } from './components/terms-of-service/terms-of-service.component';
-import { PrivacyPolicyComponent } from './components/privacy-policy/privacy-policy.component';
-import { TrademarkPolicyComponent } from './components/trademark-policy/trademark-policy.component';
import { BisqMasterPageComponent } from './components/bisq-master-page/bisq-master-page.component';
import { PushTransactionComponent } from './components/push-transaction/push-transaction.component';
import { BlocksList } from './components/blocks-list/blocks-list.component';
@@ -64,15 +61,15 @@ let routes: Routes = [
},
{
path: 'terms-of-service',
- component: TermsOfServiceComponent
+ loadChildren: () => import('./components/terms-of-service/terms-of-service.module').then(m => m.TermsOfServiceModule),
},
{
path: 'privacy-policy',
- component: PrivacyPolicyComponent
+ loadChildren: () => import('./components/privacy-policy/privacy-policy.module').then(m => m.PrivacyPolicyModule),
},
{
path: 'trademark-policy',
- component: TrademarkPolicyComponent
+ loadChildren: () => import('./components/trademark-policy/trademark-policy.module').then(m => m.TrademarkModule),
},
{
path: 'address/:id',
@@ -161,15 +158,15 @@ let routes: Routes = [
},
{
path: 'terms-of-service',
- component: TermsOfServiceComponent
+ loadChildren: () => import('./components/terms-of-service/terms-of-service.module').then(m => m.TermsOfServiceModule),
},
{
path: 'privacy-policy',
- component: PrivacyPolicyComponent
+ loadChildren: () => import('./components/privacy-policy/privacy-policy.module').then(m => m.PrivacyPolicyModule),
},
{
path: 'trademark-policy',
- component: TrademarkPolicyComponent
+ loadChildren: () => import('./components/trademark-policy/trademark-policy.module').then(m => m.TrademarkModule),
},
{
path: 'address/:id',
@@ -258,15 +255,15 @@ let routes: Routes = [
},
{
path: 'terms-of-service',
- component: TermsOfServiceComponent
+ loadChildren: () => import('./components/terms-of-service/terms-of-service.module').then(m => m.TermsOfServiceModule),
},
{
path: 'privacy-policy',
- component: PrivacyPolicyComponent
+ loadChildren: () => import('./components/privacy-policy/privacy-policy.module').then(m => m.PrivacyPolicyModule),
},
{
path: 'trademark-policy',
- component: TrademarkPolicyComponent
+ loadChildren: () => import('./components/trademark-policy/trademark-policy.module').then(m => m.TrademarkModule),
},
{
path: 'address/:id',
@@ -392,15 +389,15 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
},
{
path: 'terms-of-service',
- component: TermsOfServiceComponent
+ loadChildren: () => import('./components/terms-of-service/terms-of-service.module').then(m => m.TermsOfServiceModule),
},
{
path: 'privacy-policy',
- component: PrivacyPolicyComponent
+ loadChildren: () => import('./components/privacy-policy/privacy-policy.module').then(m => m.PrivacyPolicyModule),
},
{
path: 'trademark-policy',
- component: TrademarkPolicyComponent
+ loadChildren: () => import('./components/trademark-policy/trademark-policy.module').then(m => m.TrademarkModule),
},
{
path: 'address/:id',
@@ -497,15 +494,15 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
},
{
path: 'terms-of-service',
- component: TermsOfServiceComponent
+ loadChildren: () => import('./components/terms-of-service/terms-of-service.module').then(m => m.TermsOfServiceModule),
},
{
path: 'privacy-policy',
- component: PrivacyPolicyComponent
+ loadChildren: () => import('./components/privacy-policy/privacy-policy.module').then(m => m.PrivacyPolicyModule),
},
{
path: 'trademark-policy',
- component: TrademarkPolicyComponent
+ loadChildren: () => import('./components/trademark-policy/trademark-policy.module').then(m => m.TrademarkModule),
},
{
path: 'address/:id',
diff --git a/frontend/src/app/bisq/bisq.routing.module.ts b/frontend/src/app/bisq/bisq.routing.module.ts
index b211afeaf..beea6b018 100644
--- a/frontend/src/app/bisq/bisq.routing.module.ts
+++ b/frontend/src/app/bisq/bisq.routing.module.ts
@@ -9,7 +9,6 @@ import { BisqStatsComponent } from './bisq-stats/bisq-stats.component';
import { BisqDashboardComponent } from './bisq-dashboard/bisq-dashboard.component';
import { BisqMarketComponent } from './bisq-market/bisq-market.component';
import { BisqMainDashboardComponent } from './bisq-main-dashboard/bisq-main-dashboard.component';
-import { TermsOfServiceComponent } from '../components/terms-of-service/terms-of-service.component';
import { PushTransactionComponent } from '../components/push-transaction/push-transaction.component';
const routes: Routes = [
@@ -75,7 +74,7 @@ const routes: Routes = [
},
{
path: 'terms-of-service',
- component: TermsOfServiceComponent
+ loadChildren: () => import('../components/terms-of-service/terms-of-service.module').then(m => m.TermsOfServiceModule),
},
{
path: '**',
diff --git a/frontend/src/app/components/privacy-policy/privacy-policy.module.ts b/frontend/src/app/components/privacy-policy/privacy-policy.module.ts
new file mode 100644
index 000000000..6d279d80a
--- /dev/null
+++ b/frontend/src/app/components/privacy-policy/privacy-policy.module.ts
@@ -0,0 +1,40 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { Routes, RouterModule } from '@angular/router';
+import { PrivacyPolicyComponent } from './privacy-policy.component';
+import { SharedModule } from '../../shared/shared.module';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: PrivacyPolicyComponent,
+ }
+];
+
+@NgModule({
+ imports: [
+ RouterModule.forChild(routes)
+ ],
+ exports: [
+ RouterModule
+ ]
+})
+export class PrivacyPolicyRoutingModule { }
+
+@NgModule({
+ imports: [
+ CommonModule,
+ PrivacyPolicyRoutingModule,
+ SharedModule,
+ ],
+ declarations: [
+ PrivacyPolicyComponent,
+ ]
+})
+export class PrivacyPolicyModule { }
+
+
+
+
+
+
diff --git a/frontend/src/app/components/terms-of-service/terms-of-service.module.ts b/frontend/src/app/components/terms-of-service/terms-of-service.module.ts
new file mode 100644
index 000000000..2ab139d8b
--- /dev/null
+++ b/frontend/src/app/components/terms-of-service/terms-of-service.module.ts
@@ -0,0 +1,40 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { Routes, RouterModule } from '@angular/router';
+import { TermsOfServiceComponent } from './terms-of-service.component';
+import { SharedModule } from '../../shared/shared.module';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: TermsOfServiceComponent,
+ }
+];
+
+@NgModule({
+ imports: [
+ RouterModule.forChild(routes)
+ ],
+ exports: [
+ RouterModule
+ ]
+})
+export class TermsModule { }
+
+@NgModule({
+ imports: [
+ CommonModule,
+ TermsModule,
+ SharedModule,
+ ],
+ declarations: [
+ TermsOfServiceComponent,
+ ]
+})
+export class TermsOfServiceModule { }
+
+
+
+
+
+
diff --git a/frontend/src/app/components/trademark-policy/trademark-policy.module.ts b/frontend/src/app/components/trademark-policy/trademark-policy.module.ts
new file mode 100644
index 000000000..24f70be52
--- /dev/null
+++ b/frontend/src/app/components/trademark-policy/trademark-policy.module.ts
@@ -0,0 +1,40 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { Routes, RouterModule } from '@angular/router';
+import { TrademarkPolicyComponent } from './trademark-policy.component';
+import { SharedModule } from '../../shared/shared.module';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: TrademarkPolicyComponent,
+ }
+];
+
+@NgModule({
+ imports: [
+ RouterModule.forChild(routes)
+ ],
+ exports: [
+ RouterModule
+ ]
+})
+export class TrademarkRoutingModule { }
+
+@NgModule({
+ imports: [
+ CommonModule,
+ TrademarkRoutingModule,
+ SharedModule,
+ ],
+ declarations: [
+ TrademarkPolicyComponent,
+ ]
+})
+export class TrademarkModule { }
+
+
+
+
+
+
diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts
index 1e1fe42b3..82f9b5d00 100644
--- a/frontend/src/app/shared/shared.module.ts
+++ b/frontend/src/app/shared/shared.module.ts
@@ -59,11 +59,8 @@ import { FeesBoxComponent } from '../components/fees-box/fees-box.component';
import { DifficultyComponent } from '../components/difficulty/difficulty.component';
import { DifficultyTooltipComponent } from '../components/difficulty/difficulty-tooltip.component';
import { DifficultyMiningComponent } from '../components/difficulty-mining/difficulty-mining.component';
-import { TermsOfServiceComponent } from '../components/terms-of-service/terms-of-service.component';
import { RbfTimelineComponent } from '../components/rbf-timeline/rbf-timeline.component';
import { RbfTimelineTooltipComponent } from '../components/rbf-timeline/rbf-timeline-tooltip.component';
-import { PrivacyPolicyComponent } from '../components/privacy-policy/privacy-policy.component';
-import { TrademarkPolicyComponent } from '../components/trademark-policy/trademark-policy.component';
import { PushTransactionComponent } from '../components/push-transaction/push-transaction.component';
import { AssetsFeaturedComponent } from '../components/assets/assets-featured/assets-featured.component';
import { AssetGroupComponent } from '../components/assets/asset-group/asset-group.component';
@@ -158,9 +155,6 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
DifficultyTooltipComponent,
RbfTimelineComponent,
RbfTimelineTooltipComponent,
- TermsOfServiceComponent,
- PrivacyPolicyComponent,
- TrademarkPolicyComponent,
PushTransactionComponent,
AssetsNavComponent,
AssetsFeaturedComponent,
@@ -281,9 +275,6 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
DifficultyTooltipComponent,
RbfTimelineComponent,
RbfTimelineTooltipComponent,
- TermsOfServiceComponent,
- PrivacyPolicyComponent,
- TrademarkPolicyComponent,
PushTransactionComponent,
AssetsNavComponent,
AssetsFeaturedComponent,
From 80bf2f9ebd3daeae019bab74438d140cfe9082ef Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Thu, 9 Nov 2023 08:22:53 +0000
Subject: [PATCH 38/79] Split master page components & deduplicate main routes
---
frontend/src/app/app-routing.module.ts | 393 +-----------------
frontend/src/app/bisq/bisq.module.ts | 2 +
frontend/src/app/bisq/bisq.routing.module.ts | 143 ++++---
.../app/liquid/liquid-master-page.module.ts | 124 ++++++
frontend/src/app/master-page.module.ts | 119 ++++++
frontend/src/app/shared/shared.module.ts | 8 +-
6 files changed, 329 insertions(+), 460 deletions(-)
create mode 100644 frontend/src/app/liquid/liquid-master-page.module.ts
create mode 100644 frontend/src/app/master-page.module.ts
diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts
index 2ebb1c74b..4159f4184 100644
--- a/frontend/src/app/app-routing.module.ts
+++ b/frontend/src/app/app-routing.module.ts
@@ -6,19 +6,14 @@ import { BlockViewComponent } from './components/block-view/block-view.component
import { MempoolBlockViewComponent } from './components/mempool-block-view/mempool-block-view.component';
import { ClockComponent } from './components/clock/clock.component';
import { AddressComponent } from './components/address/address.component';
-import { MasterPageComponent } from './components/master-page/master-page.component';
import { StatusViewComponent } from './components/status-view/status-view.component';
-import { BisqMasterPageComponent } from './components/bisq-master-page/bisq-master-page.component';
import { PushTransactionComponent } from './components/push-transaction/push-transaction.component';
import { BlocksList } from './components/blocks-list/blocks-list.component';
-import { RbfList } from './components/rbf-list/rbf-list.component';
-import { LiquidMasterPageComponent } from './components/liquid-master-page/liquid-master-page.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';
import { AssetComponent } from './components/asset/asset.component';
import { AssetsNavComponent } from './components/assets/assets-nav/assets-nav.component';
-import { CalculatorComponent } from './components/calculator/calculator.component';
const browserWindow = window || {};
// @ts-ignore
@@ -36,77 +31,8 @@ let routes: Routes = [
},
{
path: '',
- component: MasterPageComponent,
- children: [
- {
- path: 'mining/blocks',
- redirectTo: 'blocks',
- pathMatch: 'full'
- },
- {
- path: 'tx/push',
- component: PushTransactionComponent,
- },
- {
- path: 'about',
- loadChildren: () => import('./components/about/about.module').then(m => m.AboutModule),
- },
- {
- path: 'blocks',
- component: BlocksList,
- },
- {
- path: 'rbf',
- component: RbfList,
- },
- {
- path: 'terms-of-service',
- loadChildren: () => import('./components/terms-of-service/terms-of-service.module').then(m => m.TermsOfServiceModule),
- },
- {
- path: 'privacy-policy',
- loadChildren: () => import('./components/privacy-policy/privacy-policy.module').then(m => m.PrivacyPolicyModule),
- },
- {
- path: 'trademark-policy',
- loadChildren: () => import('./components/trademark-policy/trademark-policy.module').then(m => m.TrademarkModule),
- },
- {
- path: 'address/:id',
- children: [],
- component: AddressComponent,
- data: {
- ogImage: true,
- networkSpecific: true,
- }
- },
- {
- path: 'tx',
- component: StartComponent,
- data: { preload: true, networkSpecific: true },
- loadChildren: () => import('./components/transaction/transaction.module').then(m => m.TransactionModule),
- },
- {
- path: 'block',
- component: StartComponent,
- data: { preload: true, networkSpecific: true },
- loadChildren: () => import('./components/block/block.module').then(m => m.BlockModule),
- },
- {
- path: 'docs',
- loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule),
- data: { preload: true },
- },
- {
- path: 'api',
- loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
- },
- {
- path: 'lightning',
- loadChildren: () => import('./lightning/lightning.module').then(m => m.LightningModule),
- data: { preload: browserWindowEnv && browserWindowEnv.LIGHTNING === true, networks: ['bitcoin'] },
- },
- ],
+ loadChildren: () => import('./master-page.module').then(m => m.MasterPageModule),
+ data: { preload: true },
},
{
path: 'status',
@@ -138,71 +64,8 @@ let routes: Routes = [
},
{
path: '',
- component: MasterPageComponent,
- children: [
- {
- path: 'tx/push',
- component: PushTransactionComponent,
- },
- {
- path: 'about',
- loadChildren: () => import('./components/about/about.module').then(m => m.AboutModule),
- },
- {
- path: 'blocks',
- component: BlocksList,
- },
- {
- path: 'rbf',
- component: RbfList,
- },
- {
- path: 'terms-of-service',
- loadChildren: () => import('./components/terms-of-service/terms-of-service.module').then(m => m.TermsOfServiceModule),
- },
- {
- path: 'privacy-policy',
- loadChildren: () => import('./components/privacy-policy/privacy-policy.module').then(m => m.PrivacyPolicyModule),
- },
- {
- path: 'trademark-policy',
- loadChildren: () => import('./components/trademark-policy/trademark-policy.module').then(m => m.TrademarkModule),
- },
- {
- path: 'address/:id',
- children: [],
- component: AddressComponent,
- data: {
- ogImage: true,
- networkSpecific: true,
- }
- },
- {
- path: 'tx',
- component: StartComponent,
- data: { preload: true, networkSpecific: true },
- loadChildren: () => import('./components/transaction/transaction.module').then(m => m.TransactionModule),
- },
- {
- path: 'block',
- component: StartComponent,
- data: { preload: true, networkSpecific: true },
- loadChildren: () => import('./components/block/block.module').then(m => m.BlockModule),
- },
- {
- path: 'docs',
- loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
- },
- {
- path: 'api',
- loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
- },
- {
- path: 'lightning',
- data: { networks: ['bitcoin'] },
- loadChildren: () => import('./lightning/lightning.module').then(m => m.LightningModule)
- },
- ],
+ loadChildren: () => import('./master-page.module').then(m => m.MasterPageModule),
+ data: { preload: true },
},
{
path: 'status',
@@ -226,80 +89,8 @@ let routes: Routes = [
},
{
path: '',
- component: MasterPageComponent,
- children: [
- {
- path: 'mining/blocks',
- redirectTo: 'blocks',
- pathMatch: 'full'
- },
- {
- path: 'tx/push',
- component: PushTransactionComponent,
- },
- {
- path: 'about',
- loadChildren: () => import('./components/about/about.module').then(m => m.AboutModule),
- },
- {
- path: 'blocks',
- component: BlocksList,
- },
- {
- path: 'rbf',
- component: RbfList,
- },
- {
- path: 'tools/calculator',
- component: CalculatorComponent
- },
- {
- path: 'terms-of-service',
- loadChildren: () => import('./components/terms-of-service/terms-of-service.module').then(m => m.TermsOfServiceModule),
- },
- {
- path: 'privacy-policy',
- loadChildren: () => import('./components/privacy-policy/privacy-policy.module').then(m => m.PrivacyPolicyModule),
- },
- {
- path: 'trademark-policy',
- loadChildren: () => import('./components/trademark-policy/trademark-policy.module').then(m => m.TrademarkModule),
- },
- {
- path: 'address/:id',
- children: [],
- component: AddressComponent,
- data: {
- ogImage: true,
- networkSpecific: true,
- }
- },
- {
- path: 'tx',
- component: StartComponent,
- data: { preload: true, networkSpecific: true },
- loadChildren: () => import('./components/transaction/transaction.module').then(m => m.TransactionModule),
- },
- {
- path: 'block',
- component: StartComponent,
- data: { preload: true, networkSpecific: true },
- loadChildren: () => import('./components/block/block.module').then(m => m.BlockModule),
- },
- {
- path: 'docs',
- loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
- },
- {
- path: 'api',
- loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
- },
- {
- path: 'lightning',
- data: { networks: ['bitcoin'] },
- loadChildren: () => import('./lightning/lightning.module').then(m => m.LightningModule)
- },
- ],
+ loadChildren: () => import('./master-page.module').then(m => m.MasterPageModule),
+ data: { preload: true },
},
{
path: 'preview',
@@ -356,7 +147,6 @@ let routes: Routes = [
if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'bisq') {
routes = [{
path: '',
- component: BisqMasterPageComponent,
loadChildren: () => import('./bisq/bisq.module').then(m => m.BisqModule)
}];
}
@@ -373,88 +163,7 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
},
{
path: '',
- component: LiquidMasterPageComponent,
- children: [
- {
- path: 'tx/push',
- component: PushTransactionComponent,
- },
- {
- path: 'about',
- loadChildren: () => import('./components/about/about.module').then(m => m.AboutModule),
- },
- {
- path: 'blocks',
- component: BlocksList,
- },
- {
- path: 'terms-of-service',
- loadChildren: () => import('./components/terms-of-service/terms-of-service.module').then(m => m.TermsOfServiceModule),
- },
- {
- path: 'privacy-policy',
- loadChildren: () => import('./components/privacy-policy/privacy-policy.module').then(m => m.PrivacyPolicyModule),
- },
- {
- path: 'trademark-policy',
- loadChildren: () => import('./components/trademark-policy/trademark-policy.module').then(m => m.TrademarkModule),
- },
- {
- path: 'address/:id',
- children: [],
- component: AddressComponent,
- data: {
- ogImage: true,
- networkSpecific: true,
- }
- },
- {
- path: 'tx',
- component: StartComponent,
- data: { preload: true, networkSpecific: true },
- loadChildren: () => import('./components/transaction/transaction.module').then(m => m.TransactionModule),
- },
- {
- path: 'block',
- component: StartComponent,
- data: { preload: true, networkSpecific: true },
- loadChildren: () => import('./components/block/block.module').then(m => m.BlockModule),
- },
- {
- path: 'assets',
- data: { networks: ['liquid'] },
- component: AssetsNavComponent,
- children: [
- {
- path: 'all',
- data: { networks: ['liquid'] },
- component: AssetsComponent,
- },
- {
- path: 'asset/:id',
- data: { networkSpecific: true },
- component: AssetComponent
- },
- {
- path: 'group/:id',
- data: { networkSpecific: true },
- component: AssetGroupComponent
- },
- {
- path: '**',
- redirectTo: 'all'
- }
- ]
- },
- {
- path: 'docs',
- loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
- },
- {
- path: 'api',
- loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
- },
- ],
+ loadChildren: () => import ('./liquid/liquid-master-page.module').then(m => m.LiquidMasterPageModule)
},
{
path: 'status',
@@ -478,93 +187,7 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
},
{
path: '',
- component: LiquidMasterPageComponent,
- children: [
- {
- path: 'tx/push',
- component: PushTransactionComponent,
- },
- {
- path: 'about',
- loadChildren: () => import('./components/about/about.module').then(m => m.AboutModule),
- },
- {
- path: 'blocks',
- component: BlocksList,
- },
- {
- path: 'terms-of-service',
- loadChildren: () => import('./components/terms-of-service/terms-of-service.module').then(m => m.TermsOfServiceModule),
- },
- {
- path: 'privacy-policy',
- loadChildren: () => import('./components/privacy-policy/privacy-policy.module').then(m => m.PrivacyPolicyModule),
- },
- {
- path: 'trademark-policy',
- loadChildren: () => import('./components/trademark-policy/trademark-policy.module').then(m => m.TrademarkModule),
- },
- {
- path: 'address/:id',
- children: [],
- component: AddressComponent,
- data: {
- ogImage: true,
- networkSpecific: true,
- }
- },
- {
- path: 'tx',
- component: StartComponent,
- data: { preload: true, networkSpecific: true },
- loadChildren: () => import('./components/transaction/transaction.module').then(m => m.TransactionModule),
- },
- {
- path: 'block',
- component: StartComponent,
- data: { preload: true, networkSpecific: true },
- loadChildren: () => import('./components/block/block.module').then(m => m.BlockModule),
- },
- {
- path: 'assets',
- data: { networks: ['liquid'] },
- component: AssetsNavComponent,
- children: [
- {
- path: 'featured',
- data: { networkSpecific: true },
- component: AssetsFeaturedComponent,
- },
- {
- path: 'all',
- data: { networks: ['liquid'] },
- component: AssetsComponent,
- },
- {
- path: 'asset/:id',
- data: { networkSpecific: true },
- component: AssetComponent
- },
- {
- path: 'group/:id',
- data: { networkSpecific: true },
- component: AssetGroupComponent
- },
- {
- path: '**',
- redirectTo: 'featured'
- }
- ]
- },
- {
- path: 'docs',
- loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
- },
- {
- path: 'api',
- loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
- },
- ],
+ loadChildren: () => import ('./liquid/liquid-master-page.module').then(m => m.LiquidMasterPageModule)
},
{
path: 'preview',
diff --git a/frontend/src/app/bisq/bisq.module.ts b/frontend/src/app/bisq/bisq.module.ts
index 93658d95a..f7f71156b 100644
--- a/frontend/src/app/bisq/bisq.module.ts
+++ b/frontend/src/app/bisq/bisq.module.ts
@@ -27,9 +27,11 @@ import { AutofocusDirective } from '../components/ngx-bootstrap-multiselect/auto
import { MultiSelectSearchFilter } from '../components/ngx-bootstrap-multiselect/search-filter.pipe';
import { OffClickDirective } from '../components/ngx-bootstrap-multiselect/off-click.directive';
import { NgxDropdownMultiselectComponent } from '../components/ngx-bootstrap-multiselect/ngx-bootstrap-multiselect.component';
+import { BisqMasterPageComponent } from '../components/bisq-master-page/bisq-master-page.component';
@NgModule({
declarations: [
+ BisqMasterPageComponent,
BisqTransactionsComponent,
BisqTransactionComponent,
BisqBlockComponent,
diff --git a/frontend/src/app/bisq/bisq.routing.module.ts b/frontend/src/app/bisq/bisq.routing.module.ts
index beea6b018..7c6d2ee1b 100644
--- a/frontend/src/app/bisq/bisq.routing.module.ts
+++ b/frontend/src/app/bisq/bisq.routing.module.ts
@@ -1,5 +1,6 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
+import { BisqMasterPageComponent } from '../components/bisq-master-page/bisq-master-page.component';
import { BisqTransactionsComponent } from './bisq-transactions/bisq-transactions.component';
import { BisqTransactionComponent } from './bisq-transaction/bisq-transaction.component';
import { BisqBlockComponent } from './bisq-block/bisq-block.component';
@@ -12,74 +13,80 @@ import { BisqMainDashboardComponent } from './bisq-main-dashboard/bisq-main-dash
import { PushTransactionComponent } from '../components/push-transaction/push-transaction.component';
const routes: Routes = [
- {
- path: '',
- component: BisqMainDashboardComponent,
- },
- {
- path: 'markets',
- data: { networks: ['bisq'] },
- component: BisqDashboardComponent,
- },
- {
- path: 'transactions',
- data: { networks: ['bisq'] },
- component: BisqTransactionsComponent
- },
- {
- path: 'market/:pair',
- data: { networkSpecific: true },
- component: BisqMarketComponent,
- },
- {
- path: 'tx/push',
- component: PushTransactionComponent,
- },
- {
- path: 'tx/:id',
- data: { networkSpecific: true },
- component: BisqTransactionComponent
- },
- {
- path: 'blocks',
- children: [],
- component: BisqBlocksComponent
- },
- {
- path: 'block/:id',
- data: { networkSpecific: true },
- component: BisqBlockComponent,
- },
- {
- path: 'address/:id',
- data: { networkSpecific: true },
- component: BisqAddressComponent,
- },
- {
- path: 'stats',
- data: { networks: ['bisq'] },
- component: BisqStatsComponent,
- },
- {
- path: 'about',
- loadChildren: () => import('../components/about/about.module').then(m => m.AboutModule),
- },
- {
- path: 'docs',
- loadChildren: () => import('../docs/docs.module').then(m => m.DocsModule)
- },
- {
- path: 'api',
- loadChildren: () => import('../docs/docs.module').then(m => m.DocsModule)
- },
- {
- path: 'terms-of-service',
- loadChildren: () => import('../components/terms-of-service/terms-of-service.module').then(m => m.TermsOfServiceModule),
- },
- {
- path: '**',
- redirectTo: ''
- }
+ {
+ path: '',
+ component: BisqMasterPageComponent,
+ children: [
+ {
+ path: '',
+ component: BisqMainDashboardComponent,
+ },
+ {
+ path: 'markets',
+ data: { networks: ['bisq'] },
+ component: BisqDashboardComponent,
+ },
+ {
+ path: 'transactions',
+ data: { networks: ['bisq'] },
+ component: BisqTransactionsComponent
+ },
+ {
+ path: 'market/:pair',
+ data: { networkSpecific: true },
+ component: BisqMarketComponent,
+ },
+ {
+ path: 'tx/push',
+ component: PushTransactionComponent,
+ },
+ {
+ path: 'tx/:id',
+ data: { networkSpecific: true },
+ component: BisqTransactionComponent
+ },
+ {
+ path: 'blocks',
+ children: [],
+ component: BisqBlocksComponent
+ },
+ {
+ path: 'block/:id',
+ data: { networkSpecific: true },
+ component: BisqBlockComponent,
+ },
+ {
+ path: 'address/:id',
+ data: { networkSpecific: true },
+ component: BisqAddressComponent,
+ },
+ {
+ path: 'stats',
+ data: { networks: ['bisq'] },
+ component: BisqStatsComponent,
+ },
+ {
+ path: 'about',
+ loadChildren: () => import('../components/about/about.module').then(m => m.AboutModule),
+ },
+ {
+ path: 'docs',
+ loadChildren: () => import('../docs/docs.module').then(m => m.DocsModule)
+ },
+ {
+ path: 'api',
+ loadChildren: () => import('../docs/docs.module').then(m => m.DocsModule)
+ },
+ {
+ path: 'terms-of-service',
+ loadChildren: () => import('../components/terms-of-service/terms-of-service.module').then(m => m.TermsOfServiceModule),
+ },
+ {
+ path: '**',
+ redirectTo: ''
+ }
+ ]
+ }
];
@NgModule({
diff --git a/frontend/src/app/liquid/liquid-master-page.module.ts b/frontend/src/app/liquid/liquid-master-page.module.ts
new file mode 100644
index 000000000..37c6e0708
--- /dev/null
+++ b/frontend/src/app/liquid/liquid-master-page.module.ts
@@ -0,0 +1,124 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { Routes, RouterModule } from '@angular/router';
+import { SharedModule } from '../shared/shared.module';
+import { LiquidMasterPageComponent } from '../components/liquid-master-page/liquid-master-page.component';
+
+import { StartComponent } from '../components/start/start.component';
+import { AddressComponent } from '../components/address/address.component';
+import { PushTransactionComponent } from '../components/push-transaction/push-transaction.component';
+import { BlocksList } from '../components/blocks-list/blocks-list.component';
+import { AssetGroupComponent } from '../components/assets/asset-group/asset-group.component';
+import { AssetsComponent } from '../components/assets/assets.component';
+import { AssetComponent } from '../components/asset/asset.component';
+import { AssetsNavComponent } from '../components/assets/assets-nav/assets-nav.component';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: LiquidMasterPageComponent,
+ children: [
+ {
+ path: 'tx/push',
+ component: PushTransactionComponent,
+ },
+ {
+ path: 'about',
+ loadChildren: () => import('../components/about/about.module').then(m => m.AboutModule),
+ },
+ {
+ path: 'blocks',
+ component: BlocksList,
+ },
+ {
+ path: 'terms-of-service',
+ loadChildren: () => import('../components/terms-of-service/terms-of-service.module').then(m => m.TermsOfServiceModule),
+ },
+ {
+ path: 'privacy-policy',
+ loadChildren: () => import('../components/privacy-policy/privacy-policy.module').then(m => m.PrivacyPolicyModule),
+ },
+ {
+ path: 'trademark-policy',
+ loadChildren: () => import('../components/trademark-policy/trademark-policy.module').then(m => m.TrademarkModule),
+ },
+ {
+ path: 'address/:id',
+ children: [],
+ component: AddressComponent,
+ data: {
+ ogImage: true,
+ networkSpecific: true,
+ }
+ },
+ {
+ path: 'tx',
+ component: StartComponent,
+ data: { preload: true, networkSpecific: true },
+ loadChildren: () => import('../components/transaction/transaction.module').then(m => m.TransactionModule),
+ },
+ {
+ path: 'block',
+ component: StartComponent,
+ data: { preload: true, networkSpecific: true },
+ loadChildren: () => import('../components/block/block.module').then(m => m.BlockModule),
+ },
+ {
+ path: 'assets',
+ data: { networks: ['liquid'] },
+ component: AssetsNavComponent,
+ children: [
+ {
+ path: 'all',
+ data: { networks: ['liquid'] },
+ component: AssetsComponent,
+ },
+ {
+ path: 'asset/:id',
+ data: { networkSpecific: true },
+ component: AssetComponent
+ },
+ {
+ path: 'group/:id',
+ data: { networkSpecific: true },
+ component: AssetGroupComponent
+ },
+ {
+ path: '**',
+ redirectTo: 'all'
+ }
+ ]
+ },
+ {
+ path: 'docs',
+ loadChildren: () => import('../docs/docs.module').then(m => m.DocsModule)
+ },
+ {
+ path: 'api',
+ loadChildren: () => import('../docs/docs.module').then(m => m.DocsModule)
+ },
+ ],
+ },
+];
+
+@NgModule({
+ imports: [
+ RouterModule.forChild(routes)
+ ],
+ exports: [
+ RouterModule
+ ]
+})
+export class LiquidRoutingModule { }
+
+@NgModule({
+ imports: [
+ CommonModule,
+ LiquidRoutingModule,
+ SharedModule,
+ ],
+ declarations: [
+ LiquidMasterPageComponent,
+ ]
+})
+export class LiquidMasterPageModule { }
\ No newline at end of file
diff --git a/frontend/src/app/master-page.module.ts b/frontend/src/app/master-page.module.ts
new file mode 100644
index 000000000..5bd808b94
--- /dev/null
+++ b/frontend/src/app/master-page.module.ts
@@ -0,0 +1,119 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { Routes, RouterModule } from '@angular/router';
+import { MasterPageComponent } from './components/master-page/master-page.component';
+import { SharedModule } from './shared/shared.module';
+
+import { StartComponent } from './components/start/start.component';
+import { AddressComponent } from './components/address/address.component';
+import { PushTransactionComponent } from './components/push-transaction/push-transaction.component';
+import { BlocksList } from './components/blocks-list/blocks-list.component';
+import { RbfList } from './components/rbf-list/rbf-list.component';
+
+const browserWindow = window || {};
+// @ts-ignore
+const browserWindowEnv = browserWindow.__env || {};
+
+const routes: Routes = [
+ {
+ component: MasterPageComponent,
+ children: [
+ {
+ path: 'mining/blocks',
+ redirectTo: 'blocks',
+ pathMatch: 'full'
+ },
+ {
+ path: 'tx/push',
+ component: PushTransactionComponent,
+ },
+ {
+ path: 'about',
+ loadChildren: () => import('./components/about/about.module').then(m => m.AboutModule),
+ },
+ {
+ path: 'blocks',
+ component: BlocksList,
+ },
+ {
+ path: 'rbf',
+ component: RbfList,
+ },
+ {
+ path: 'terms-of-service',
+ loadChildren: () => import('./components/terms-of-service/terms-of-service.module').then(m => m.TermsOfServiceModule),
+ },
+ {
+ path: 'privacy-policy',
+ loadChildren: () => import('./components/privacy-policy/privacy-policy.module').then(m => m.PrivacyPolicyModule),
+ },
+ {
+ path: 'trademark-policy',
+ loadChildren: () => import('./components/trademark-policy/trademark-policy.module').then(m => m.TrademarkModule),
+ },
+ {
+ path: 'address/:id',
+ children: [],
+ component: AddressComponent,
+ data: {
+ ogImage: true,
+ networkSpecific: true,
+ }
+ },
+ {
+ path: 'tx',
+ component: StartComponent,
+ data: { preload: true, networkSpecific: true },
+ loadChildren: () => import('./components/transaction/transaction.module').then(m => m.TransactionModule),
+ },
+ {
+ path: 'block',
+ component: StartComponent,
+ data: { preload: true, networkSpecific: true },
+ loadChildren: () => import('./components/block/block.module').then(m => m.BlockModule),
+ },
+ {
+ path: 'docs',
+ loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule),
+ data: { preload: true },
+ },
+ {
+ path: 'api',
+ loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
+ },
+ {
+ path: 'lightning',
+ loadChildren: () => import('./lightning/lightning.module').then(m => m.LightningModule),
+ data: { preload: browserWindowEnv && browserWindowEnv.LIGHTNING === true, networks: ['bitcoin'] },
+ },
+ ],
+ }
+];
+
+@NgModule({
+ imports: [
+ RouterModule.forChild(routes)
+ ],
+ exports: [
+ RouterModule
+ ]
+})
+export class MasterPageRoutingModule { }
+
+@NgModule({
+ imports: [
+ CommonModule,
+ MasterPageRoutingModule,
+ SharedModule,
+ ],
+ declarations: [
+ MasterPageComponent,
+ ]
+})
+export class MasterPageModule { }
+
+
+
+
+
+
diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts
index 82f9b5d00..76dbc65f1 100644
--- a/frontend/src/app/shared/shared.module.ts
+++ b/frontend/src/app/shared/shared.module.ts
@@ -6,11 +6,8 @@ import { faFilter, faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, fa
faLink, faList, faSearch, faCaretUp, faCaretDown, faTachometerAlt, faThList, faTint, faTv, faClock, faAngleDoubleDown, faSortUp, faAngleDoubleUp, faChevronDown,
faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft, faArrowsRotate, faCircleLeft, faFastForward, faWallet, faUserClock, faWrench, faUserFriends, faQuestionCircle, faHistory, faSignOutAlt, faKey, faSuitcase, faIdCardAlt, faNetworkWired, faUserCheck, faCircleCheck, faUserCircle } from '@fortawesome/free-solid-svg-icons';
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
-import { MasterPageComponent } from '../components/master-page/master-page.component';
import { MenuComponent } from '../components/menu/menu.component';
import { PreviewTitleComponent } from '../components/master-page-preview/preview-title.component';
-import { BisqMasterPageComponent } from '../components/bisq-master-page/bisq-master-page.component';
-import { LiquidMasterPageComponent } from '../components/liquid-master-page/liquid-master-page.component';
import { VbytesPipe } from './pipes/bytes-pipe/vbytes.pipe';
import { ShortenStringPipe } from './pipes/shorten-string-pipe/shorten-string.pipe';
import { CeilPipe } from './pipes/math-ceil/math-ceil.pipe';
@@ -133,11 +130,8 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
MempoolBlocksComponent,
BlockchainBlocksComponent,
AmountComponent,
- MasterPageComponent,
MenuComponent,
PreviewTitleComponent,
- BisqMasterPageComponent,
- LiquidMasterPageComponent,
StartComponent,
BlockOverviewGraphComponent,
BlockOverviewTooltipComponent,
@@ -217,7 +211,6 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
AmountShortenerPipe,
],
exports: [
- MasterPageComponent,
MenuComponent,
RouterModule,
ReactiveFormsModule,
@@ -297,6 +290,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
ConfirmationsComponent,
ToggleComponent,
GeolocationComponent,
+ TestnetAlertComponent,
PreviewTitleComponent,
GlobalFooterComponent,
AcceleratePreviewComponent,
From db8ed5b70521a843934c4c1b7baccde2a07c6335 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Fri, 10 Nov 2023 03:03:16 +0000
Subject: [PATCH 39/79] Split liquid, lightning & mainnet graphs
---
frontend/src/app/app-routing.module.ts | 29 ++++------
frontend/src/app/bitcoin-graphs.module.ts | 36 ++++++++++++
.../src/app/graphs/graphs.routing.module.ts | 43 +-------------
.../src/app/graphs/lightning-graphs.module.ts | 58 +++++++++++++++++++
.../src/app/liquid/liquid-graphs.module.ts | 36 ++++++++++++
frontend/src/app/master-page.module.ts | 1 +
6 files changed, 143 insertions(+), 60 deletions(-)
create mode 100644 frontend/src/app/bitcoin-graphs.module.ts
create mode 100644 frontend/src/app/graphs/lightning-graphs.module.ts
create mode 100644 frontend/src/app/liquid/liquid-graphs.module.ts
diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts
index 4159f4184..4ee5b81a2 100644
--- a/frontend/src/app/app-routing.module.ts
+++ b/frontend/src/app/app-routing.module.ts
@@ -1,19 +1,10 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AppPreloadingStrategy } from './app.preloading-strategy'
-import { StartComponent } from './components/start/start.component';
import { BlockViewComponent } from './components/block-view/block-view.component';
import { MempoolBlockViewComponent } from './components/mempool-block-view/mempool-block-view.component';
import { ClockComponent } from './components/clock/clock.component';
-import { AddressComponent } from './components/address/address.component';
import { StatusViewComponent } from './components/status-view/status-view.component';
-import { PushTransactionComponent } from './components/push-transaction/push-transaction.component';
-import { BlocksList } from './components/blocks-list/blocks-list.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';
-import { AssetComponent } from './components/asset/asset.component';
-import { AssetsNavComponent } from './components/assets/assets-nav/assets-nav.component';
const browserWindow = window || {};
// @ts-ignore
@@ -26,7 +17,7 @@ let routes: Routes = [
{
path: '',
pathMatch: 'full',
- loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule),
+ loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule),
data: { preload: true },
},
{
@@ -41,7 +32,7 @@ let routes: Routes = [
},
{
path: '',
- loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
+ loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule),
},
{
path: '**',
@@ -60,7 +51,7 @@ let routes: Routes = [
{
path: '',
pathMatch: 'full',
- loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
+ loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule),
},
{
path: '',
@@ -74,7 +65,7 @@ let routes: Routes = [
},
{
path: '',
- loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
+ loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule),
},
{
path: '**',
@@ -85,7 +76,7 @@ let routes: Routes = [
{
path: '',
pathMatch: 'full',
- loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
+ loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule),
},
{
path: '',
@@ -136,7 +127,7 @@ let routes: Routes = [
},
{
path: '',
- loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
+ loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule),
},
{
path: '**',
@@ -159,7 +150,7 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
{
path: '',
pathMatch: 'full',
- loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
+ loadChildren: () => import('./liquid/liquid-graphs.module').then(m => m.LiquidGraphsModule),
},
{
path: '',
@@ -172,7 +163,7 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
},
{
path: '',
- loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
+ loadChildren: () => import('./liquid/liquid-graphs.module').then(m => m.LiquidGraphsModule),
},
{
path: '**',
@@ -183,7 +174,7 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
{
path: '',
pathMatch: 'full',
- loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
+ loadChildren: () => import('./liquid/liquid-graphs.module').then(m => m.LiquidGraphsModule),
},
{
path: '',
@@ -209,7 +200,7 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
},
{
path: '',
- loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
+ loadChildren: () => import('./liquid/liquid-graphs.module').then(m => m.LiquidGraphsModule),
},
{
path: '**',
diff --git a/frontend/src/app/bitcoin-graphs.module.ts b/frontend/src/app/bitcoin-graphs.module.ts
new file mode 100644
index 000000000..bff9bd632
--- /dev/null
+++ b/frontend/src/app/bitcoin-graphs.module.ts
@@ -0,0 +1,36 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { Routes, RouterModule } from '@angular/router';
+import { MasterPageComponent } from './components/master-page/master-page.component';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: MasterPageComponent,
+ loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
+ }
+];
+
+@NgModule({
+ imports: [
+ RouterModule.forChild(routes)
+ ],
+ exports: [
+ RouterModule
+ ]
+})
+export class BitcoinGraphsRoutingModule { }
+
+@NgModule({
+ imports: [
+ CommonModule,
+ BitcoinGraphsRoutingModule,
+ ],
+})
+export class BitcoinGraphsModule { }
+
+
+
+
+
+
diff --git a/frontend/src/app/graphs/graphs.routing.module.ts b/frontend/src/app/graphs/graphs.routing.module.ts
index 03800dcfc..28a2ed260 100644
--- a/frontend/src/app/graphs/graphs.routing.module.ts
+++ b/frontend/src/app/graphs/graphs.routing.module.ts
@@ -8,8 +8,6 @@ import { BlockSizesWeightsGraphComponent } from '../components/block-sizes-weigh
import { GraphsComponent } from '../components/graphs/graphs.component';
import { HashrateChartComponent } from '../components/hashrate-chart/hashrate-chart.component';
import { HashrateChartPoolsComponent } from '../components/hashrates-chart-pools/hashrate-chart-pools.component';
-import { LiquidMasterPageComponent } from '../components/liquid-master-page/liquid-master-page.component';
-import { MasterPageComponent } from '../components/master-page/master-page.component';
import { MempoolBlockComponent } from '../components/mempool-block/mempool-block.component';
import { MiningDashboardComponent } from '../components/mining-dashboard/mining-dashboard.component';
import { PoolRankingComponent } from '../components/pool-ranking/pool-ranking.component';
@@ -18,22 +16,10 @@ import { StartComponent } from '../components/start/start.component';
import { StatisticsComponent } from '../components/statistics/statistics.component';
import { TelevisionComponent } from '../components/television/television.component';
import { DashboardComponent } from '../dashboard/dashboard.component';
-import { NodesNetworksChartComponent } from '../lightning/nodes-networks-chart/nodes-networks-chart.component';
-import { LightningStatisticsChartComponent } from '../lightning/statistics-chart/lightning-statistics-chart.component';
-import { NodesPerISPChartComponent } from '../lightning/nodes-per-isp-chart/nodes-per-isp-chart.component';
-import { NodesPerCountryChartComponent } from '../lightning/nodes-per-country-chart/nodes-per-country-chart.component';
-import { NodesMap } from '../lightning/nodes-map/nodes-map.component';
-import { NodesChannelsMap } from '../lightning/nodes-channels-map/nodes-channels-map.component';
-
-const browserWindow = window || {};
-// @ts-ignore
-const browserWindowEnv = browserWindow.__env || {};
-const isLiquid = browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid';
const routes: Routes = [
{
path: '',
- component: isLiquid ? LiquidMasterPageComponent : MasterPageComponent,
children: [
{
path: 'mining/pool/:slug',
@@ -108,34 +94,9 @@ const routes: Routes = [
component: BlockSizesWeightsGraphComponent,
},
{
- path: 'lightning/nodes-networks',
+ path: 'lightning',
data: { networks: ['bitcoin'] },
- component: NodesNetworksChartComponent,
- },
- {
- path: 'lightning/capacity',
- data: { networks: ['bitcoin'] },
- component: LightningStatisticsChartComponent,
- },
- {
- path: 'lightning/nodes-per-isp',
- data: { networks: ['bitcoin'] },
- component: NodesPerISPChartComponent,
- },
- {
- path: 'lightning/nodes-per-country',
- data: { networks: ['bitcoin'] },
- component: NodesPerCountryChartComponent,
- },
- {
- path: 'lightning/nodes-map',
- data: { networks: ['bitcoin'] },
- component: NodesMap,
- },
- {
- path: 'lightning/nodes-channels-map',
- data: { networks: ['bitcoin'] },
- component: NodesChannelsMap,
+ loadChildren: () => import ('./lightning-graphs.module').then(m => m.LightningGraphsModule)
},
{
path: '',
diff --git a/frontend/src/app/graphs/lightning-graphs.module.ts b/frontend/src/app/graphs/lightning-graphs.module.ts
new file mode 100644
index 000000000..ac123be33
--- /dev/null
+++ b/frontend/src/app/graphs/lightning-graphs.module.ts
@@ -0,0 +1,58 @@
+import { NgModule } from '@angular/core';
+import { SharedModule } from '../shared/shared.module';
+import { CommonModule } from '@angular/common';
+import { RouterModule, Routes } from '@angular/router';
+import { NodesNetworksChartComponent } from '../lightning/nodes-networks-chart/nodes-networks-chart.component';
+import { LightningStatisticsChartComponent } from '../lightning/statistics-chart/lightning-statistics-chart.component';
+import { NodesPerISPChartComponent } from '../lightning/nodes-per-isp-chart/nodes-per-isp-chart.component';
+import { NodesPerCountryChartComponent } from '../lightning/nodes-per-country-chart/nodes-per-country-chart.component';
+import { NodesMap } from '../lightning/nodes-map/nodes-map.component';
+import { NodesChannelsMap } from '../lightning/nodes-channels-map/nodes-channels-map.component';
+
+const routes: Routes = [
+ {
+ path: 'nodes-networks',
+ data: { networks: ['bitcoin'] },
+ component: NodesNetworksChartComponent,
+ },
+ {
+ path: 'capacity',
+ data: { networks: ['bitcoin'] },
+ component: LightningStatisticsChartComponent,
+ },
+ {
+ path: 'nodes-per-isp',
+ data: { networks: ['bitcoin'] },
+ component: NodesPerISPChartComponent,
+ },
+ {
+ path: 'nodes-per-country',
+ data: { networks: ['bitcoin'] },
+ component: NodesPerCountryChartComponent,
+ },
+ {
+ path: 'nodes-map',
+ data: { networks: ['bitcoin'] },
+ component: NodesMap,
+ },
+ {
+ path: 'nodes-channels-map',
+ data: { networks: ['bitcoin'] },
+ component: NodesChannelsMap,
+ },
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule],
+})
+export class LightningGraphsRoutingModule { }
+
+@NgModule({
+ imports: [
+ CommonModule,
+ SharedModule,
+ LightningGraphsRoutingModule,
+ ],
+})
+export class LightningGraphsModule { }
diff --git a/frontend/src/app/liquid/liquid-graphs.module.ts b/frontend/src/app/liquid/liquid-graphs.module.ts
new file mode 100644
index 000000000..0878bb773
--- /dev/null
+++ b/frontend/src/app/liquid/liquid-graphs.module.ts
@@ -0,0 +1,36 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { Routes, RouterModule } from '@angular/router';
+import { LiquidMasterPageComponent } from '../components/liquid-master-page/liquid-master-page.component';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: LiquidMasterPageComponent,
+ loadChildren: () => import('../graphs/graphs.module').then(m => m.GraphsModule)
+ }
+];
+
+@NgModule({
+ imports: [
+ RouterModule.forChild(routes)
+ ],
+ exports: [
+ RouterModule
+ ]
+})
+export class LiquidGraphsRoutingModule { }
+
+@NgModule({
+ imports: [
+ CommonModule,
+ LiquidGraphsRoutingModule,
+ ],
+})
+export class LiquidGraphsModule { }
+
+
+
+
+
+
diff --git a/frontend/src/app/master-page.module.ts b/frontend/src/app/master-page.module.ts
index 5bd808b94..bfc1aed53 100644
--- a/frontend/src/app/master-page.module.ts
+++ b/frontend/src/app/master-page.module.ts
@@ -16,6 +16,7 @@ const browserWindowEnv = browserWindow.__env || {};
const routes: Routes = [
{
+ path: '',
component: MasterPageComponent,
children: [
{
From af7b9c0dc8915d05d2c099589f477308573b3f45 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Fri, 10 Nov 2023 04:58:07 +0000
Subject: [PATCH 40/79] Adjust webpack chunk preloading strategy
---
frontend/src/app/app-routing.module.ts | 15 +++++++++++++--
frontend/src/app/bitcoin-graphs.module.ts | 3 ++-
frontend/src/app/graphs/graphs.routing.module.ts | 4 ++--
frontend/src/app/liquid/liquid-graphs.module.ts | 3 ++-
.../src/app/liquid/liquid-master-page.module.ts | 3 ++-
frontend/src/app/previews.routing.module.ts | 3 ++-
6 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts
index 4ee5b81a2..ce91019ff 100644
--- a/frontend/src/app/app-routing.module.ts
+++ b/frontend/src/app/app-routing.module.ts
@@ -33,6 +33,7 @@ let routes: Routes = [
{
path: '',
loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule),
+ data: { preload: true },
},
{
path: '**',
@@ -52,6 +53,7 @@ let routes: Routes = [
path: '',
pathMatch: 'full',
loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule),
+ data: { preload: true },
},
{
path: '',
@@ -66,6 +68,7 @@ let routes: Routes = [
{
path: '',
loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule),
+ data: { preload: true },
},
{
path: '**',
@@ -77,6 +80,7 @@ let routes: Routes = [
path: '',
pathMatch: 'full',
loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule),
+ data: { preload: true },
},
{
path: '',
@@ -128,6 +132,7 @@ let routes: Routes = [
{
path: '',
loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule),
+ data: { preload: true },
},
{
path: '**',
@@ -151,10 +156,12 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
path: '',
pathMatch: 'full',
loadChildren: () => import('./liquid/liquid-graphs.module').then(m => m.LiquidGraphsModule),
+ data: { preload: true },
},
{
path: '',
- loadChildren: () => import ('./liquid/liquid-master-page.module').then(m => m.LiquidMasterPageModule)
+ loadChildren: () => import ('./liquid/liquid-master-page.module').then(m => m.LiquidMasterPageModule),
+ data: { preload: true },
},
{
path: 'status',
@@ -164,6 +171,7 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
{
path: '',
loadChildren: () => import('./liquid/liquid-graphs.module').then(m => m.LiquidGraphsModule),
+ data: { preload: true },
},
{
path: '**',
@@ -175,10 +183,12 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
path: '',
pathMatch: 'full',
loadChildren: () => import('./liquid/liquid-graphs.module').then(m => m.LiquidGraphsModule),
+ data: { preload: true },
},
{
path: '',
- loadChildren: () => import ('./liquid/liquid-master-page.module').then(m => m.LiquidMasterPageModule)
+ loadChildren: () => import ('./liquid/liquid-master-page.module').then(m => m.LiquidMasterPageModule),
+ data: { preload: true },
},
{
path: 'preview',
@@ -201,6 +211,7 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
{
path: '',
loadChildren: () => import('./liquid/liquid-graphs.module').then(m => m.LiquidGraphsModule),
+ data: { preload: true },
},
{
path: '**',
diff --git a/frontend/src/app/bitcoin-graphs.module.ts b/frontend/src/app/bitcoin-graphs.module.ts
index bff9bd632..710743245 100644
--- a/frontend/src/app/bitcoin-graphs.module.ts
+++ b/frontend/src/app/bitcoin-graphs.module.ts
@@ -7,7 +7,8 @@ const routes: Routes = [
{
path: '',
component: MasterPageComponent,
- loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
+ loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule),
+ data: { preload: true },
}
];
diff --git a/frontend/src/app/graphs/graphs.routing.module.ts b/frontend/src/app/graphs/graphs.routing.module.ts
index 28a2ed260..346bcf7f1 100644
--- a/frontend/src/app/graphs/graphs.routing.module.ts
+++ b/frontend/src/app/graphs/graphs.routing.module.ts
@@ -95,8 +95,8 @@ const routes: Routes = [
},
{
path: 'lightning',
- data: { networks: ['bitcoin'] },
- loadChildren: () => import ('./lightning-graphs.module').then(m => m.LightningGraphsModule)
+ data: { preload: true, networks: ['bitcoin'] },
+ loadChildren: () => import ('./lightning-graphs.module').then(m => m.LightningGraphsModule),
},
{
path: '',
diff --git a/frontend/src/app/liquid/liquid-graphs.module.ts b/frontend/src/app/liquid/liquid-graphs.module.ts
index 0878bb773..3da93fc9d 100644
--- a/frontend/src/app/liquid/liquid-graphs.module.ts
+++ b/frontend/src/app/liquid/liquid-graphs.module.ts
@@ -7,7 +7,8 @@ const routes: Routes = [
{
path: '',
component: LiquidMasterPageComponent,
- loadChildren: () => import('../graphs/graphs.module').then(m => m.GraphsModule)
+ loadChildren: () => import('../graphs/graphs.module').then(m => m.GraphsModule),
+ data: { preload: true },
}
];
diff --git a/frontend/src/app/liquid/liquid-master-page.module.ts b/frontend/src/app/liquid/liquid-master-page.module.ts
index 37c6e0708..10d87bc4b 100644
--- a/frontend/src/app/liquid/liquid-master-page.module.ts
+++ b/frontend/src/app/liquid/liquid-master-page.module.ts
@@ -91,7 +91,8 @@ const routes: Routes = [
},
{
path: 'docs',
- loadChildren: () => import('../docs/docs.module').then(m => m.DocsModule)
+ loadChildren: () => import('../docs/docs.module').then(m => m.DocsModule),
+ data: { preload: true },
},
{
path: 'api',
diff --git a/frontend/src/app/previews.routing.module.ts b/frontend/src/app/previews.routing.module.ts
index c2ad8db5f..6ac44a370 100644
--- a/frontend/src/app/previews.routing.module.ts
+++ b/frontend/src/app/previews.routing.module.ts
@@ -31,7 +31,8 @@ const routes: Routes = [
},
{
path: 'lightning',
- loadChildren: () => import('./lightning/lightning-previews.module').then(m => m.LightningPreviewsModule)
+ loadChildren: () => import('./lightning/lightning-previews.module').then(m => m.LightningPreviewsModule),
+ data: { preload: true },
},
],
}
From e08665dee5cc92ca7ed68a31bd16ac35a8f5bc17 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 11 Nov 2023 02:47:53 +0000
Subject: [PATCH 41/79] Bump cypress from 13.3.0 to 13.5.0 in /frontend
Bumps [cypress](https://github.com/cypress-io/cypress) from 13.3.0 to 13.5.0.
- [Release notes](https://github.com/cypress-io/cypress/releases)
- [Changelog](https://github.com/cypress-io/cypress/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/cypress-io/cypress/compare/v13.3.0...v13.5.0)
---
updated-dependencies:
- dependency-name: cypress
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
---
frontend/package-lock.json | 47 +++++++-------------------------------
frontend/package.json | 2 +-
2 files changed, 9 insertions(+), 40 deletions(-)
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 49410de87..c29a0f316 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -31,9 +31,9 @@
"bootstrap": "~4.6.2",
"browserify": "^17.0.0",
"clipboard": "^2.0.11",
+ "cypress": "^13.5.0",
"domino": "^2.1.6",
"echarts": "~5.4.3",
- "echarts-gl": "^2.0.9",
"lightweight-charts": "~3.8.0",
"ngx-echarts": "~16.0.0",
"ngx-infinite-scroll": "^16.0.0",
@@ -59,7 +59,7 @@
"optionalDependencies": {
"@cypress/schematic": "^2.5.0",
"@types/cypress": "^1.1.3",
- "cypress": "^13.3.0",
+ "cypress": "^13.5.0",
"cypress-fail-on-console-error": "~5.0.0",
"cypress-wait-until": "^2.0.1",
"mock-socket": "~9.2.1",
@@ -6429,11 +6429,6 @@
"safe-buffer": "^5.0.1"
}
},
- "node_modules/claygl": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/claygl/-/claygl-1.3.0.tgz",
- "integrity": "sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ=="
- },
"node_modules/clean-stack": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
@@ -7153,9 +7148,9 @@
"peer": true
},
"node_modules/cypress": {
- "version": "13.3.0",
- "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.3.0.tgz",
- "integrity": "sha512-mpI8qcTwLGiA4zEQvTC/U1xGUezVV4V8HQCOYjlEOrVmU1etVvxOjkCXHGwrlYdZU/EPmUiWfsO3yt1o+Q2bgw==",
+ "version": "13.5.0",
+ "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.5.0.tgz",
+ "integrity": "sha512-oh6U7h9w8wwHfzNDJQ6wVcAeXu31DlIYlNOBvfd6U4CcB8oe4akawQmH+QJVOMZlM42eBoCne015+svVqdwdRQ==",
"hasInstallScript": true,
"optional": true,
"dependencies": {
@@ -7825,18 +7820,6 @@
"zrender": "5.4.4"
}
},
- "node_modules/echarts-gl": {
- "version": "2.0.9",
- "resolved": "https://registry.npmjs.org/echarts-gl/-/echarts-gl-2.0.9.tgz",
- "integrity": "sha512-oKeMdkkkpJGWOzjgZUsF41DOh6cMsyrGGXimbjK2l6Xeq/dBQu4ShG2w2Dzrs/1bD27b2pLTGSaUzouY191gzA==",
- "dependencies": {
- "claygl": "^1.2.1",
- "zrender": "^5.1.1"
- },
- "peerDependencies": {
- "echarts": "^5.1.2"
- }
- },
"node_modules/echarts/node_modules/tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
@@ -21550,11 +21533,6 @@
"safe-buffer": "^5.0.1"
}
},
- "claygl": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/claygl/-/claygl-1.3.0.tgz",
- "integrity": "sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ=="
- },
"clean-stack": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
@@ -22118,9 +22096,9 @@
"peer": true
},
"cypress": {
- "version": "13.3.0",
- "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.3.0.tgz",
- "integrity": "sha512-mpI8qcTwLGiA4zEQvTC/U1xGUezVV4V8HQCOYjlEOrVmU1etVvxOjkCXHGwrlYdZU/EPmUiWfsO3yt1o+Q2bgw==",
+ "version": "13.5.0",
+ "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.5.0.tgz",
+ "integrity": "sha512-oh6U7h9w8wwHfzNDJQ6wVcAeXu31DlIYlNOBvfd6U4CcB8oe4akawQmH+QJVOMZlM42eBoCne015+svVqdwdRQ==",
"optional": true,
"requires": {
"@cypress/request": "^3.0.0",
@@ -22659,15 +22637,6 @@
}
}
},
- "echarts-gl": {
- "version": "2.0.9",
- "resolved": "https://registry.npmjs.org/echarts-gl/-/echarts-gl-2.0.9.tgz",
- "integrity": "sha512-oKeMdkkkpJGWOzjgZUsF41DOh6cMsyrGGXimbjK2l6Xeq/dBQu4ShG2w2Dzrs/1bD27b2pLTGSaUzouY191gzA==",
- "requires": {
- "claygl": "^1.2.1",
- "zrender": "^5.1.1"
- }
- },
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 0c7874c30..984cba3de 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -110,7 +110,7 @@
"optionalDependencies": {
"@cypress/schematic": "^2.5.0",
"@types/cypress": "^1.1.3",
- "cypress": "^13.3.0",
+ "cypress": "^13.5.0",
"cypress-fail-on-console-error": "~5.0.0",
"cypress-wait-until": "^2.0.1",
"mock-socket": "~9.2.1",
From 0e420d819673e0816ea93d9e5975e7e804433b62 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Mon, 16 Oct 2023 01:00:18 +0000
Subject: [PATCH 42/79] Fix rbf tree leak, clean up stale trees in Redis
---
backend/src/api/rbf-cache.ts | 25 ++++++++++++++++++++++---
backend/src/api/redis-cache.ts | 2 +-
2 files changed, 23 insertions(+), 4 deletions(-)
diff --git a/backend/src/api/rbf-cache.ts b/backend/src/api/rbf-cache.ts
index b5592252c..6ca38eb15 100644
--- a/backend/src/api/rbf-cache.ts
+++ b/backend/src/api/rbf-cache.ts
@@ -53,6 +53,9 @@ class RbfCache {
private expiring: Map = new Map();
private cacheQueue: CacheEvent[] = [];
+ private evictionCount = 0;
+ private staleCount = 0;
+
constructor() {
setInterval(this.cleanup.bind(this), 1000 * 60 * 10);
}
@@ -245,6 +248,7 @@ class RbfCache {
// flag a transaction as removed from the mempool
public evict(txid: string, fast: boolean = false): void {
+ this.evictionCount++;
if (this.txs.has(txid) && (fast || !this.expiring.has(txid))) {
const expiryTime = fast ? Date.now() + (1000 * 60 * 10) : Date.now() + (1000 * 86400); // 24 hours
this.addExpiration(txid, expiryTime);
@@ -272,18 +276,23 @@ class RbfCache {
this.remove(txid);
}
}
- logger.debug(`rbf cache contains ${this.txs.size} txs, ${this.rbfTrees.size} trees, ${this.expiring.size} due to expire`);
+ logger.debug(`rbf cache contains ${this.txs.size} txs, ${this.rbfTrees.size} trees, ${this.expiring.size} due to expire (${this.evictionCount} newly expired)`);
+ this.evictionCount = 0;
}
// remove a transaction & all previous versions from the cache
private remove(txid): void {
// don't remove a transaction if a newer version remains in the mempool
if (!this.replacedBy.has(txid)) {
+ const root = this.treeMap.get(txid);
const replaces = this.replaces.get(txid);
this.replaces.delete(txid);
this.treeMap.delete(txid);
this.removeTx(txid);
this.removeExpiration(txid);
+ if (root === txid) {
+ this.removeTree(txid);
+ }
for (const tx of (replaces || [])) {
// recursively remove prior versions from the cache
this.replacedBy.delete(tx);
@@ -360,8 +369,9 @@ class RbfCache {
public async load({ txs, trees, expiring }): Promise {
txs.forEach(txEntry => {
- this.txs.set(txEntry.key, txEntry.value);
+ this.txs.set(txEntry.value.txid, txEntry.value);
});
+ this.staleCount = 0;
for (const deflatedTree of trees) {
await this.importTree(deflatedTree.root, deflatedTree.root, deflatedTree, this.txs);
}
@@ -370,6 +380,8 @@ class RbfCache {
this.expiring.set(expiringEntry.key, new Date(expiringEntry.value).getTime());
}
});
+ logger.debug(`loaded ${txs.length} txs, ${trees.length} trees into rbf cache, ${expiring.length} due to expire, ${this.staleCount} were stale`);
+ this.staleCount = 0;
this.cleanup();
}
@@ -398,6 +410,13 @@ class RbfCache {
const treeInfo = deflated[txid];
const replaces: RbfTree[] = [];
+ // if the root tx is unknown, remove this tree and return early
+ if (root === txid && !txs.has(txid)) {
+ this.staleCount++;
+ this.removeTree(deflated.key);
+ return;
+ }
+
// check if any transactions in this tree have already been confirmed
mined = mined || treeInfo.mined;
let exists = mined;
@@ -413,7 +432,7 @@ class RbfCache {
this.evict(txid, true);
}
} catch (e) {
- // most transactions do not exist
+ // most transactions only exist in our cache
}
}
diff --git a/backend/src/api/redis-cache.ts b/backend/src/api/redis-cache.ts
index fcde8013a..00b280274 100644
--- a/backend/src/api/redis-cache.ts
+++ b/backend/src/api/redis-cache.ts
@@ -219,7 +219,7 @@ class RedisCache {
await memPool.$setMempool(loadedMempool);
await rbfCache.load({
txs: rbfTxs,
- trees: rbfTrees.map(loadedTree => loadedTree.value),
+ trees: rbfTrees.map(loadedTree => { loadedTree.value.key = loadedTree.key; return loadedTree.value; }),
expiring: rbfExpirations,
});
}
From e3e248d601b03e6175a7fee3a5667ee00119d262 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sat, 11 Nov 2023 05:52:37 +0000
Subject: [PATCH 43/79] Convert RBF disk cache data to match new format
---
backend/src/api/disk-cache.ts | 6 +++++-
backend/src/api/rbf-cache.ts | 32 ++++++++++++++++++--------------
2 files changed, 23 insertions(+), 15 deletions(-)
diff --git a/backend/src/api/disk-cache.ts b/backend/src/api/disk-cache.ts
index 6f603489a..093f07f0d 100644
--- a/backend/src/api/disk-cache.ts
+++ b/backend/src/api/disk-cache.ts
@@ -252,7 +252,11 @@ class DiskCache {
}
if (rbfData?.rbf) {
- rbfCache.load(rbfData.rbf);
+ rbfCache.load({
+ txs: rbfData.rbf.txs.map(([txid, entry]) => ({ value: entry })),
+ trees: rbfData.rbf.trees,
+ expiring: rbfData.rbf.expiring.map(([txid, value]) => ({ key: txid, value })),
+ });
}
} catch (e) {
logger.warn('Failed to parse rbf cache. Skipping. Reason: ' + (e instanceof Error ? e.message : e));
diff --git a/backend/src/api/rbf-cache.ts b/backend/src/api/rbf-cache.ts
index 6ca38eb15..6e1f37afb 100644
--- a/backend/src/api/rbf-cache.ts
+++ b/backend/src/api/rbf-cache.ts
@@ -368,21 +368,25 @@ class RbfCache {
}
public async load({ txs, trees, expiring }): Promise {
- txs.forEach(txEntry => {
- this.txs.set(txEntry.value.txid, txEntry.value);
- });
- this.staleCount = 0;
- for (const deflatedTree of trees) {
- await this.importTree(deflatedTree.root, deflatedTree.root, deflatedTree, this.txs);
- }
- expiring.forEach(expiringEntry => {
- if (this.txs.has(expiringEntry.key)) {
- this.expiring.set(expiringEntry.key, new Date(expiringEntry.value).getTime());
+ try {
+ txs.forEach(txEntry => {
+ this.txs.set(txEntry.value.txid, txEntry.value);
+ });
+ this.staleCount = 0;
+ for (const deflatedTree of trees) {
+ await this.importTree(deflatedTree.root, deflatedTree.root, deflatedTree, this.txs);
}
- });
- logger.debug(`loaded ${txs.length} txs, ${trees.length} trees into rbf cache, ${expiring.length} due to expire, ${this.staleCount} were stale`);
- this.staleCount = 0;
- this.cleanup();
+ expiring.forEach(expiringEntry => {
+ if (this.txs.has(expiringEntry.key)) {
+ this.expiring.set(expiringEntry.key, new Date(expiringEntry.value).getTime());
+ }
+ });
+ logger.debug(`loaded ${txs.length} txs, ${trees.length} trees into rbf cache, ${expiring.length} due to expire, ${this.staleCount} were stale`);
+ this.staleCount = 0;
+ this.cleanup();
+ } catch (e) {
+ logger.err('failed to restore RBF cache: ' + (e instanceof Error ? e.message : e));
+ }
}
exportTree(tree: RbfTree, deflated: any = null) {
From 3f0c3c1952176cf98ea866666637d937aee41d12 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sat, 11 Nov 2023 07:16:59 +0000
Subject: [PATCH 44/79] Add apiService cachedRequest function, apply to
outspends requests
---
.../transactions-list.component.ts | 10 ++++-
.../tx-bowtie-graph.component.ts | 2 +-
frontend/src/app/services/api.service.ts | 44 ++++++++++++++++++-
3 files changed, 52 insertions(+), 4 deletions(-)
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 c49ff0e3c..9541864fc 100644
--- a/frontend/src/app/components/transactions-list/transactions-list.component.ts
+++ b/frontend/src/app/components/transactions-list/transactions-list.component.ts
@@ -6,7 +6,7 @@ import { Outspend, Transaction, Vin, Vout } from '../../interfaces/electrs.inter
import { ElectrsApiService } from '../../services/electrs-api.service';
import { environment } from '../../../environments/environment';
import { AssetsService } from '../../services/assets.service';
-import { filter, map, tap, switchMap, shareReplay } from 'rxjs/operators';
+import { filter, map, tap, switchMap, shareReplay, catchError } from 'rxjs/operators';
import { BlockExtended } from '../../interfaces/node-api.interface';
import { ApiService } from '../../services/api.service';
import { PriceService } from '../../services/price.service';
@@ -53,6 +53,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
private assetsService: AssetsService,
private ref: ChangeDetectorRef,
private priceService: PriceService,
+ private cd: ChangeDetectorRef,
) { }
ngOnInit(): void {
@@ -75,7 +76,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
for (let i = 0; i < txIds.length; i += 50) {
batches.push(txIds.slice(i, i + 50));
}
- return forkJoin(batches.map(batch => this.apiService.getOutspendsBatched$(batch)));
+ return forkJoin(batches.map(batch => { return this.apiService.cachedRequest(this.apiService.getOutspendsBatched$, 5000, batch); }));
} else {
return of([]);
}
@@ -90,6 +91,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
outspends.forEach((outspend, i) => {
transactions[i]._outspends = outspend;
});
+ this.cd.markForCheck();
}),
),
this.stateService.utxoSpent$
@@ -108,6 +110,10 @@ export class TransactionsListComponent implements OnInit, OnChanges {
.pipe(
filter(() => this.stateService.env.LIGHTNING),
switchMap((txIds) => this.apiService.getChannelByTxIds$(txIds)),
+ catchError((error) => {
+ // handle 404
+ return of([]);
+ }),
tap((channels) => {
if (!this.transactions) {
return;
diff --git a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts
index 97e74957e..1dafb327f 100644
--- a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts
+++ b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts
@@ -123,7 +123,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
.pipe(
switchMap((txid) => {
if (!this.cached) {
- return this.apiService.getOutspendsBatched$([txid]);
+ return this.apiService.cachedRequest(this.apiService.getOutspendsBatched$, 5000, [txid]);
} else {
return of(null);
}
diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts
index 744474f9d..046b27812 100644
--- a/frontend/src/app/services/api.service.ts
+++ b/frontend/src/app/services/api.service.ts
@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http';
import { CpfpInfo, OptimizedMempoolStats, AddressInformation, LiquidPegs, ITranslators,
PoolStat, BlockExtended, TransactionStripped, RewardStats, AuditScore, BlockSizesAndWeights, RbfTree, BlockAudit } from '../interfaces/node-api.interface';
-import { Observable, of } from 'rxjs';
+import { BehaviorSubject, Observable, catchError, filter, of, shareReplay, take, tap } from 'rxjs';
import { StateService } from './state.service';
import { IBackendInfo, WebsocketResponse } from '../interfaces/websocket.interface';
import { Outspend, Transaction } from '../interfaces/electrs.interface';
@@ -20,6 +20,8 @@ export class ApiService {
private apiBaseUrl: string; // base URL is protocol, hostname, and port
private apiBasePath: string; // network path is /testnet, etc. or '' for mainnet
+ private requestCache = new Map, expiry: number }>;
+
constructor(
private httpClient: HttpClient,
private stateService: StateService,
@@ -44,6 +46,46 @@ export class ApiService {
}
}
+ private generateCacheKey(functionName: string, params: any[]): string {
+ return functionName + JSON.stringify(params);
+ }
+
+ // delete expired cache entries
+ private cleanExpiredCache(): void {
+ this.requestCache.forEach((value, key) => {
+ if (value.expiry < Date.now()) {
+ this.requestCache.delete(key);
+ }
+ });
+ }
+
+ cachedRequest Observable>(
+ apiFunction: F,
+ expireAfter: number, // in ms
+ ...params: Parameters
+ ): Observable {
+ this.cleanExpiredCache();
+
+ const cacheKey = this.generateCacheKey(apiFunction.name, params);
+ if (!this.requestCache.has(cacheKey)) {
+ const subject = new BehaviorSubject(null);
+ this.requestCache.set(cacheKey, { subject, expiry: Date.now() + expireAfter });
+
+ apiFunction.bind(this)(...params).pipe(
+ tap(data => {
+ subject.next(data as T);
+ }),
+ catchError((error) => {
+ subject.error(error);
+ return of(null);
+ }),
+ shareReplay(1),
+ ).subscribe();
+ }
+
+ return this.requestCache.get(cacheKey).subject.asObservable().pipe(filter(val => val !== null), take(1));
+ }
+
list2HStatistics$(): Observable {
return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/statistics/2h');
}
From 6740ab61f3509ed0d64d11bea5d3a83f3475b8b4 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sat, 11 Nov 2023 07:46:25 +0000
Subject: [PATCH 45/79] Reduce outspend API cache expiry to 250ms
---
.../transactions-list/transactions-list.component.ts | 5 ++---
.../components/tx-bowtie-graph/tx-bowtie-graph.component.ts | 2 +-
2 files changed, 3 insertions(+), 4 deletions(-)
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 9541864fc..05d74a75d 100644
--- a/frontend/src/app/components/transactions-list/transactions-list.component.ts
+++ b/frontend/src/app/components/transactions-list/transactions-list.component.ts
@@ -53,7 +53,6 @@ export class TransactionsListComponent implements OnInit, OnChanges {
private assetsService: AssetsService,
private ref: ChangeDetectorRef,
private priceService: PriceService,
- private cd: ChangeDetectorRef,
) { }
ngOnInit(): void {
@@ -76,7 +75,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
for (let i = 0; i < txIds.length; i += 50) {
batches.push(txIds.slice(i, i + 50));
}
- return forkJoin(batches.map(batch => { return this.apiService.cachedRequest(this.apiService.getOutspendsBatched$, 5000, batch); }));
+ return forkJoin(batches.map(batch => { return this.apiService.cachedRequest(this.apiService.getOutspendsBatched$, 250, batch); }));
} else {
return of([]);
}
@@ -91,7 +90,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
outspends.forEach((outspend, i) => {
transactions[i]._outspends = outspend;
});
- this.cd.markForCheck();
+ this.ref.markForCheck();
}),
),
this.stateService.utxoSpent$
diff --git a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts
index 1dafb327f..3bc352a35 100644
--- a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts
+++ b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts
@@ -123,7 +123,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
.pipe(
switchMap((txid) => {
if (!this.cached) {
- return this.apiService.cachedRequest(this.apiService.getOutspendsBatched$, 5000, [txid]);
+ return this.apiService.cachedRequest(this.apiService.getOutspendsBatched$, 250, [txid]);
} else {
return of(null);
}
From ffd2685922289807fb154ee44bfbb9e6cc0f3d5a Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sun, 15 Oct 2023 23:23:49 +0000
Subject: [PATCH 46/79] Display fee distribution labels to 3 sig figs
---
.../fee-distribution-graph.component.ts | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts
index 010466952..79d89ef46 100644
--- a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts
+++ b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts
@@ -135,7 +135,8 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr
formatter: (value: number): string => {
const unitValue = this.weightMode ? value / 4 : value;
const selectedPowerOfTen = selectPowerOfTen(unitValue);
- const newVal = Math.round(unitValue / selectedPowerOfTen.divider);
+ const scaledValue = unitValue / selectedPowerOfTen.divider;
+ const newVal = scaledValue >= 100 ? Math.round(scaledValue) : scaledValue.toPrecision(3);
return `${newVal}${selectedPowerOfTen.unit}`;
},
},
@@ -155,7 +156,8 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr
const value = label.data[1];
const unitValue = this.weightMode ? value / 4 : value;
const selectedPowerOfTen = selectPowerOfTen(unitValue);
- const newVal = Math.round(unitValue / selectedPowerOfTen.divider);
+ const scaledValue = unitValue / selectedPowerOfTen.divider;
+ const newVal = scaledValue >= 100 ? Math.round(scaledValue) : scaledValue.toPrecision(3);
return `${newVal}${selectedPowerOfTen.unit}`;
}
},
From b5a5f0f6080ba1e139bf47647a5d362e1a12edf1 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sun, 15 Oct 2023 23:33:34 +0000
Subject: [PATCH 47/79] Add small margin above fee distribution graph
---
.../fee-distribution-graph.component.scss | 3 +++
.../fee-distribution-graph/fee-distribution-graph.component.ts | 1 +
2 files changed, 4 insertions(+)
create mode 100644 frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.scss
diff --git a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.scss b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.scss
new file mode 100644
index 000000000..e7150a720
--- /dev/null
+++ b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.scss
@@ -0,0 +1,3 @@
+.fee-distribution-chart {
+ margin-top: 0.75rem;
+}
\ No newline at end of file
diff --git a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts
index 79d89ef46..c73c20237 100644
--- a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts
+++ b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts
@@ -9,6 +9,7 @@ import { Subscription } from 'rxjs';
@Component({
selector: 'app-fee-distribution-graph',
templateUrl: './fee-distribution-graph.component.html',
+ styleUrls: ['./fee-distribution-graph.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestroy {
From 0abf4f415f32049476847fcc149de8cb837e4ab4 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 11 Nov 2023 08:29:45 +0000
Subject: [PATCH 48/79] Bump get-func-name from 2.0.0 to 2.0.2 in /frontend
Bumps [get-func-name](https://github.com/chaijs/get-func-name) from 2.0.0 to 2.0.2.
- [Release notes](https://github.com/chaijs/get-func-name/releases)
- [Commits](https://github.com/chaijs/get-func-name/commits/v2.0.2)
---
updated-dependencies:
- dependency-name: get-func-name
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
---
frontend/package-lock.json | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index c29a0f316..5fc9a7964 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -31,7 +31,6 @@
"bootstrap": "~4.6.2",
"browserify": "^17.0.0",
"clipboard": "^2.0.11",
- "cypress": "^13.5.0",
"domino": "^2.1.6",
"echarts": "~5.4.3",
"lightweight-charts": "~3.8.0",
@@ -9514,9 +9513,9 @@
}
},
"node_modules/get-func-name": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
- "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
+ "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
"optional": true,
"engines": {
"node": "*"
@@ -23940,9 +23939,9 @@
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
},
"get-func-name": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
- "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
+ "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
"optional": true
},
"get-intrinsic": {
From 9ab85ab7999caef3be7d6b53aabafe93ddd3a87e Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 11 Nov 2023 08:39:56 +0000
Subject: [PATCH 49/79] Bump the frontend-angular-dependencies group in
/frontend with 1 update
Bumps the frontend-angular-dependencies group in /frontend with 1 update: [ngx-echarts](https://github.com/xieziyu/ngx-echarts).
- [Release notes](https://github.com/xieziyu/ngx-echarts/releases)
- [Commits](https://github.com/xieziyu/ngx-echarts/commits)
---
updated-dependencies:
- dependency-name: ngx-echarts
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: frontend-angular-dependencies
...
Signed-off-by: dependabot[bot]
---
frontend/package-lock.json | 14 +++++++-------
frontend/package.json | 2 +-
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 5fc9a7964..7054b7385 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -34,7 +34,7 @@
"domino": "^2.1.6",
"echarts": "~5.4.3",
"lightweight-charts": "~3.8.0",
- "ngx-echarts": "~16.0.0",
+ "ngx-echarts": "~16.2.0",
"ngx-infinite-scroll": "^16.0.0",
"qrcode": "1.5.1",
"rxjs": "~7.8.1",
@@ -12442,9 +12442,9 @@
"integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="
},
"node_modules/ngx-echarts": {
- "version": "16.0.0",
- "resolved": "https://registry.npmjs.org/ngx-echarts/-/ngx-echarts-16.0.0.tgz",
- "integrity": "sha512-hdM7/CL29bY3sF3V5ihb7H1NeUsQlhijp8tVxT23+vkNTf9SJrUHPjs9oHOMkbTlr2Q8HB+eVpckYAL/tuK0CQ==",
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/ngx-echarts/-/ngx-echarts-16.2.0.tgz",
+ "integrity": "sha512-yhuDbp6qdkmR4kRVLS06Z0Iumod7xOj5n/Z++clRiKM24OQ4sM8WuOTicdfWy6eeYDNywdGSrri4Y5SUGRD8bg==",
"dependencies": {
"tslib": "^2.3.0"
},
@@ -26109,9 +26109,9 @@
"integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="
},
"ngx-echarts": {
- "version": "16.0.0",
- "resolved": "https://registry.npmjs.org/ngx-echarts/-/ngx-echarts-16.0.0.tgz",
- "integrity": "sha512-hdM7/CL29bY3sF3V5ihb7H1NeUsQlhijp8tVxT23+vkNTf9SJrUHPjs9oHOMkbTlr2Q8HB+eVpckYAL/tuK0CQ==",
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/ngx-echarts/-/ngx-echarts-16.2.0.tgz",
+ "integrity": "sha512-yhuDbp6qdkmR4kRVLS06Z0Iumod7xOj5n/Z++clRiKM24OQ4sM8WuOTicdfWy6eeYDNywdGSrri4Y5SUGRD8bg==",
"requires": {
"tslib": "^2.3.0"
}
diff --git a/frontend/package.json b/frontend/package.json
index 984cba3de..18640c793 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -86,7 +86,7 @@
"domino": "^2.1.6",
"echarts": "~5.4.3",
"lightweight-charts": "~3.8.0",
- "ngx-echarts": "~16.0.0",
+ "ngx-echarts": "~16.2.0",
"ngx-infinite-scroll": "^16.0.0",
"qrcode": "1.5.1",
"rxjs": "~7.8.1",
From 37605d57324fb9ca3910ee185cda79c9d6606820 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sat, 11 Nov 2023 08:57:55 +0000
Subject: [PATCH 50/79] Improve fee distribution legibility on small screens
---
.../fee-distribution-graph.component.ts | 22 ++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts
index c73c20237..178d87897 100644
--- a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts
+++ b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts
@@ -1,4 +1,4 @@
-import { OnChanges, OnDestroy } from '@angular/core';
+import { HostListener, OnChanges, OnDestroy } from '@angular/core';
import { Component, Input, OnInit, ChangeDetectionStrategy } from '@angular/core';
import { TransactionStripped } from '../../interfaces/websocket.interface';
import { StateService } from '../../services/state.service';
@@ -26,6 +26,7 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr
simple: boolean = false;
data: number[][];
labelInterval: number = 50;
+ smallScreen: boolean = window.innerWidth < 450;
rateUnitSub: Subscription;
weightMode: boolean = false;
@@ -96,9 +97,9 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr
this.mempoolVsizeFeesOptions = {
grid: {
height: '210',
- right: '20',
+ right: this.smallScreen ? '10' : '20',
top: '22',
- left: '40',
+ left: this.smallScreen ? '10' : '40',
},
xAxis: {
type: 'category',
@@ -132,7 +133,7 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr
}
},
axisLabel: {
- show: true,
+ show: !this.smallScreen,
formatter: (value: number): string => {
const unitValue = this.weightMode ? value / 4 : value;
const selectedPowerOfTen = selectPowerOfTen(unitValue);
@@ -142,7 +143,7 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr
},
},
axisTick: {
- show: true,
+ show: !this.smallScreen,
}
},
series: [{
@@ -153,6 +154,7 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr
position: 'top',
color: '#ffffff',
textShadowBlur: 0,
+ fontSize: this.smallScreen ? 10 : 12,
formatter: (label: { data: number[] }): string => {
const value = label.data[1];
const unitValue = this.weightMode ? value / 4 : value;
@@ -182,6 +184,16 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr
};
}
+ @HostListener('window:resize', ['$event'])
+ onResize(): void {
+ const isSmallScreen = window.innerWidth < 450;
+ if (this.smallScreen !== isSmallScreen) {
+ this.smallScreen = isSmallScreen;
+ this.prepareChart();
+ this.mountChart();
+ }
+ }
+
ngOnDestroy(): void {
this.rateUnitSub.unsubscribe();
}
From 42732764227af44dea060f61d31112e10273b996 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 11 Nov 2023 09:37:11 +0000
Subject: [PATCH 51/79] Bump mock-socket from 9.2.1 to 9.3.1 in /frontend
Bumps [mock-socket](https://github.com/thoov/mock-socket) from 9.2.1 to 9.3.1.
- [Release notes](https://github.com/thoov/mock-socket/releases)
- [Changelog](https://github.com/thoov/mock-socket/blob/master/CHANGELOG.md)
- [Commits](https://github.com/thoov/mock-socket/commits)
---
updated-dependencies:
- dependency-name: mock-socket
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
---
frontend/package-lock.json | 15 ++++++++-------
frontend/package.json | 2 +-
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 7054b7385..e4cfb1fc4 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -34,6 +34,7 @@
"domino": "^2.1.6",
"echarts": "~5.4.3",
"lightweight-charts": "~3.8.0",
+ "mock-socket": "~9.3.1",
"ngx-echarts": "~16.2.0",
"ngx-infinite-scroll": "^16.0.0",
"qrcode": "1.5.1",
@@ -61,7 +62,7 @@
"cypress": "^13.5.0",
"cypress-fail-on-console-error": "~5.0.0",
"cypress-wait-until": "^2.0.1",
- "mock-socket": "~9.2.1",
+ "mock-socket": "~9.3.1",
"start-server-and-test": "~2.0.0"
}
},
@@ -12191,9 +12192,9 @@
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
},
"node_modules/mock-socket": {
- "version": "9.2.1",
- "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.2.1.tgz",
- "integrity": "sha512-aw9F9T9G2zpGipLLhSNh6ZpgUyUl4frcVmRN08uE1NWPWg43Wx6+sGPDbQ7E5iFZZDJW5b5bypMeAEHqTbIFag==",
+ "version": "9.3.1",
+ "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.3.1.tgz",
+ "integrity": "sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==",
"optional": true,
"engines": {
"node": ">= 8"
@@ -25913,9 +25914,9 @@
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
},
"mock-socket": {
- "version": "9.2.1",
- "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.2.1.tgz",
- "integrity": "sha512-aw9F9T9G2zpGipLLhSNh6ZpgUyUl4frcVmRN08uE1NWPWg43Wx6+sGPDbQ7E5iFZZDJW5b5bypMeAEHqTbIFag==",
+ "version": "9.3.1",
+ "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.3.1.tgz",
+ "integrity": "sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==",
"optional": true
},
"module-deps": {
diff --git a/frontend/package.json b/frontend/package.json
index 18640c793..e549eb122 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -113,7 +113,7 @@
"cypress": "^13.5.0",
"cypress-fail-on-console-error": "~5.0.0",
"cypress-wait-until": "^2.0.1",
- "mock-socket": "~9.2.1",
+ "mock-socket": "~9.3.1",
"start-server-and-test": "~2.0.0"
},
"scarfSettings": {
From 511b827bf56b7d099afdba1db25d047bea24e050 Mon Sep 17 00:00:00 2001
From: junderw
Date: Wed, 16 Aug 2023 00:44:06 -0700
Subject: [PATCH 52/79] Nginx: Ignore all internal-api paths
---
nginx-mempool.conf | 5 +++++
production/nginx/location-api.conf | 5 +++++
2 files changed, 10 insertions(+)
diff --git a/nginx-mempool.conf b/nginx-mempool.conf
index 67cb15939..bc8efc59e 100644
--- a/nginx-mempool.conf
+++ b/nginx-mempool.conf
@@ -39,6 +39,11 @@
try_files $uri $uri/ /$1/index.html =404;
}
+ # any path containing .*/internal-api/.* anywhere is ignored
+ location ~ ^/.*?/internal-api/ {
+ return 404;
+ }
+
# static API docs
location = /api {
try_files $uri $uri/ /en-US/index.html =404;
diff --git a/production/nginx/location-api.conf b/production/nginx/location-api.conf
index 2b2b85411..dba798719 100644
--- a/production/nginx/location-api.conf
+++ b/production/nginx/location-api.conf
@@ -2,6 +2,11 @@
# mempool #
###########
+# any path containing .*/internal-api/.* anywhere is ignored
+location ~ ^/.*?/internal-api/ {
+ return 404;
+}
+
# websocket has special HTTP headers
location /api/v1/ws {
try_files /dev/null @mempool-api-v1-websocket;
From d16773bfa02fa3a8ea2d34c820a95bf9723771a3 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Wed, 16 Aug 2023 17:54:08 +0900
Subject: [PATCH 53/79] Switch backend to use internal-api paths
---
backend/src/api/bitcoin/esplora-api.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts
index 0f3c6290d..368ff1978 100644
--- a/backend/src/api/bitcoin/esplora-api.ts
+++ b/backend/src/api/bitcoin/esplora-api.ts
@@ -214,11 +214,11 @@ class ElectrsApi implements AbstractBitcoinApi {
}
async $getMempoolTransactions(txids: string[]): Promise {
- return this.failoverRouter.$post('/mempool/txs', txids, 'json');
+ return this.failoverRouter.$post('/internal-api/mempool/txs', txids, 'json');
}
async $getAllMempoolTransactions(lastSeenTxid?: string): Promise {
- return this.failoverRouter.$get('/mempool/txs' + (lastSeenTxid ? '/' + lastSeenTxid : ''));
+ return this.failoverRouter.$get('/internal-api/mempool/txs' + (lastSeenTxid ? '/' + lastSeenTxid : ''));
}
$getTransactionHex(txId: string): Promise {
From 502a1c021e9df76aae5ab281d98a5af1cf213a2b Mon Sep 17 00:00:00 2001
From: Jonathan Underwood
Date: Mon, 28 Aug 2023 02:18:59 +0900
Subject: [PATCH 54/79] Add suggestions from wiz
Co-authored-by: wiz
---
backend/src/api/bitcoin/esplora-api.ts | 4 ++--
nginx-mempool.conf | 5 -----
production/nginx/location-api.conf | 7 ++++---
3 files changed, 6 insertions(+), 10 deletions(-)
diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts
index 368ff1978..90da93d7e 100644
--- a/backend/src/api/bitcoin/esplora-api.ts
+++ b/backend/src/api/bitcoin/esplora-api.ts
@@ -214,11 +214,11 @@ class ElectrsApi implements AbstractBitcoinApi {
}
async $getMempoolTransactions(txids: string[]): Promise {
- return this.failoverRouter.$post('/internal-api/mempool/txs', txids, 'json');
+ return this.failoverRouter.$post('/internal/mempool/txs', txids, 'json');
}
async $getAllMempoolTransactions(lastSeenTxid?: string): Promise {
- return this.failoverRouter.$get('/internal-api/mempool/txs' + (lastSeenTxid ? '/' + lastSeenTxid : ''));
+ return this.failoverRouter.$get('/internal/mempool/txs' + (lastSeenTxid ? '/' + lastSeenTxid : ''));
}
$getTransactionHex(txId: string): Promise {
diff --git a/nginx-mempool.conf b/nginx-mempool.conf
index bc8efc59e..67cb15939 100644
--- a/nginx-mempool.conf
+++ b/nginx-mempool.conf
@@ -39,11 +39,6 @@
try_files $uri $uri/ /$1/index.html =404;
}
- # any path containing .*/internal-api/.* anywhere is ignored
- location ~ ^/.*?/internal-api/ {
- return 404;
- }
-
# static API docs
location = /api {
try_files $uri $uri/ /en-US/index.html =404;
diff --git a/production/nginx/location-api.conf b/production/nginx/location-api.conf
index dba798719..333877630 100644
--- a/production/nginx/location-api.conf
+++ b/production/nginx/location-api.conf
@@ -2,11 +2,12 @@
# mempool #
###########
-# any path containing .*/internal-api/.* anywhere is ignored
-location ~ ^/.*?/internal-api/ {
+location /api/internal/ {
+ return 404;
+}
+location /api/v1/internal/ {
return 404;
}
-
# websocket has special HTTP headers
location /api/v1/ws {
try_files /dev/null @mempool-api-v1-websocket;
From 4972f00a9690c639f3b476212e15460e4a605570 Mon Sep 17 00:00:00 2001
From: junderw
Date: Sun, 27 Aug 2023 10:28:51 -0700
Subject: [PATCH 55/79] Add internal endpoint blocking to all Nginx configs
---
production/nginx/location-api.conf | 2 ++
production/nginx/location-liquid-api.conf | 8 ++++++++
production/nginx/location-liquidtestnet-api.conf | 8 ++++++++
production/nginx/location-signet-api.conf | 8 ++++++++
production/nginx/location-testnet-api.conf | 8 ++++++++
5 files changed, 34 insertions(+)
diff --git a/production/nginx/location-api.conf b/production/nginx/location-api.conf
index 333877630..71afa295a 100644
--- a/production/nginx/location-api.conf
+++ b/production/nginx/location-api.conf
@@ -2,12 +2,14 @@
# mempool #
###########
+# Block the internal APIs of esplora
location /api/internal/ {
return 404;
}
location /api/v1/internal/ {
return 404;
}
+
# websocket has special HTTP headers
location /api/v1/ws {
try_files /dev/null @mempool-api-v1-websocket;
diff --git a/production/nginx/location-liquid-api.conf b/production/nginx/location-liquid-api.conf
index e438d1cdc..6c222c469 100644
--- a/production/nginx/location-liquid-api.conf
+++ b/production/nginx/location-liquid-api.conf
@@ -2,6 +2,14 @@
# mempool #
###########
+# Block the internal APIs of esplora
+location /liquid/api/internal/ {
+ return 404;
+}
+location /liquid/api/v1/internal/ {
+ return 404;
+}
+
# websocket has special HTTP headers
location /liquid/api/v1/ws {
rewrite ^/liquid/(.*) /$1 break;
diff --git a/production/nginx/location-liquidtestnet-api.conf b/production/nginx/location-liquidtestnet-api.conf
index 329b7e2e9..5d5be5d43 100644
--- a/production/nginx/location-liquidtestnet-api.conf
+++ b/production/nginx/location-liquidtestnet-api.conf
@@ -2,6 +2,14 @@
# mempool #
###########
+# Block the internal APIs of esplora
+location /liquidtestnet/api/internal/ {
+ return 404;
+}
+location /liquidtestnet/api/v1/internal/ {
+ return 404;
+}
+
# websocket has special HTTP headers
location /liquidtestnet/api/v1/ws {
rewrite ^/liquidtestnet/(.*) /$1 break;
diff --git a/production/nginx/location-signet-api.conf b/production/nginx/location-signet-api.conf
index 54bdc3648..8469043a8 100644
--- a/production/nginx/location-signet-api.conf
+++ b/production/nginx/location-signet-api.conf
@@ -2,6 +2,14 @@
# mempool #
###########
+# Block the internal APIs of esplora
+location /signet/api/internal/ {
+ return 404;
+}
+location /signet/api/v1/internal/ {
+ return 404;
+}
+
# websocket has special HTTP headers
location /signet/api/v1/ws {
rewrite ^/signet/(.*) /$1 break;
diff --git a/production/nginx/location-testnet-api.conf b/production/nginx/location-testnet-api.conf
index 656a705ff..9f0c41147 100644
--- a/production/nginx/location-testnet-api.conf
+++ b/production/nginx/location-testnet-api.conf
@@ -2,6 +2,14 @@
# mempool #
###########
+# Block the internal APIs of esplora
+location /testnet/api/internal/ {
+ return 404;
+}
+location /testnet/api/v1/internal/ {
+ return 404;
+}
+
# websocket has special HTTP headers
location /testnet/api/v1/ws {
rewrite ^/testnet/(.*) /$1 break;
From 2339a0771effdcb7efe446a6785d6a3cf64ed4d1 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Wed, 6 Sep 2023 08:24:30 +0900
Subject: [PATCH 56/79] Use internal /block/:hash/txs endpoint
---
backend/src/api/bitcoin/esplora-api.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts
index 90da93d7e..af021bf2e 100644
--- a/backend/src/api/bitcoin/esplora-api.ts
+++ b/backend/src/api/bitcoin/esplora-api.ts
@@ -238,7 +238,7 @@ class ElectrsApi implements AbstractBitcoinApi {
}
$getTxsForBlock(hash: string): Promise {
- return this.failoverRouter.$get('/block/' + hash + '/txs');
+ return this.failoverRouter.$get('/internal/block/' + hash + '/txs');
}
$getBlockHash(height: number): Promise {
From 38909cfc4253ca0d62e0c4b1a374e4b0769728d6 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sat, 5 Aug 2023 16:08:54 +0900
Subject: [PATCH 57/79] use bulk /txs endpoint to check cached rbf tx status
---
.../bitcoin/bitcoin-api-abstract-factory.ts | 1 +
backend/src/api/bitcoin/bitcoin-api.ts | 4 ++
backend/src/api/bitcoin/esplora-api.ts | 4 ++
backend/src/api/rbf-cache.ts | 53 +++++++++++++++++++
4 files changed, 62 insertions(+)
diff --git a/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts b/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts
index 9407a5441..a76b93e8d 100644
--- a/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts
+++ b/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts
@@ -3,6 +3,7 @@ import { IEsploraApi } from './esplora-api.interface';
export interface AbstractBitcoinApi {
$getRawMempool(): Promise;
$getRawTransaction(txId: string, skipConversion?: boolean, addPrevout?: boolean, lazyPrevouts?: boolean): Promise;
+ $getRawTransactions(txids: string[]): Promise;
$getMempoolTransactions(txids: string[]): Promise;
$getAllMempoolTransactions(lastTxid: string);
$getTransactionHex(txId: string): Promise;
diff --git a/backend/src/api/bitcoin/bitcoin-api.ts b/backend/src/api/bitcoin/bitcoin-api.ts
index 807baae2e..1be7993b8 100644
--- a/backend/src/api/bitcoin/bitcoin-api.ts
+++ b/backend/src/api/bitcoin/bitcoin-api.ts
@@ -60,6 +60,10 @@ class BitcoinApi implements AbstractBitcoinApi {
});
}
+ $getRawTransactions(txids: string[]): Promise {
+ throw new Error('Method getRawTransactions not supported by the Bitcoin RPC API.');
+ }
+
$getMempoolTransactions(txids: string[]): Promise {
throw new Error('Method getMempoolTransactions not supported by the Bitcoin RPC API.');
}
diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts
index af021bf2e..1ebfef8c8 100644
--- a/backend/src/api/bitcoin/esplora-api.ts
+++ b/backend/src/api/bitcoin/esplora-api.ts
@@ -213,6 +213,10 @@ class ElectrsApi implements AbstractBitcoinApi {
return this.failoverRouter.$get('/tx/' + txId);
}
+ async $getRawTransactions(txids: string[]): Promise {
+ return this.$postWrapper(config.ESPLORA.REST_API_URL + '/txs', txids, 'json');
+ }
+
async $getMempoolTransactions(txids: string[]): Promise {
return this.failoverRouter.$post('/internal/mempool/txs', txids, 'json');
}
diff --git a/backend/src/api/rbf-cache.ts b/backend/src/api/rbf-cache.ts
index 6e1f37afb..7d95df27b 100644
--- a/backend/src/api/rbf-cache.ts
+++ b/backend/src/api/rbf-cache.ts
@@ -2,6 +2,7 @@ import config from "../config";
import logger from "../logger";
import { MempoolTransactionExtended, TransactionStripped } from "../mempool.interfaces";
import bitcoinApi from './bitcoin/bitcoin-api-factory';
+import { IEsploraApi } from "./bitcoin/esplora-api.interface";
import { Common } from "./common";
import redisCache from "./redis-cache";
@@ -383,6 +384,7 @@ class RbfCache {
});
logger.debug(`loaded ${txs.length} txs, ${trees.length} trees into rbf cache, ${expiring.length} due to expire, ${this.staleCount} were stale`);
this.staleCount = 0;
+ await this.checkTrees();
this.cleanup();
} catch (e) {
logger.err('failed to restore RBF cache: ' + (e instanceof Error ? e.message : e));
@@ -481,6 +483,57 @@ class RbfCache {
return tree;
}
+ private async checkTrees(): Promise {
+ const found: { [txid: string]: boolean } = {};
+ const txids = Array.from(this.txs.values()).map(tx => tx.txid).filter(txid => {
+ return !this.expiring.has(txid) && !this.getRbfTree(txid)?.mined;
+ });
+
+ const processTxs = (txs: IEsploraApi.Transaction[]): void => {
+ for (const tx of txs) {
+ found[tx.txid] = true;
+ if (tx.status?.confirmed) {
+ const tree = this.getRbfTree(tx.txid);
+ if (tree) {
+ this.setTreeMined(tree, tx.txid);
+ tree.mined = true;
+ this.evict(tx.txid, false);
+ }
+ }
+ }
+ };
+
+ if (config.MEMPOOL.BACKEND === 'esplora') {
+ const sliceLength = 10000;
+ for (let i = 0; i < Math.ceil(txids.length / sliceLength); i++) {
+ const slice = txids.slice(i * sliceLength, (i + 1) * sliceLength);
+ try {
+ const txs = await bitcoinApi.$getRawTransactions(slice);
+ processTxs(txs);
+ } catch (err) {
+ logger.err('failed to fetch some cached rbf transactions');
+ }
+ }
+ } else {
+ const txs: IEsploraApi.Transaction[] = [];
+ for (const txid of txids) {
+ try {
+ const tx = await bitcoinApi.$getRawTransaction(txid, true, false);
+ txs.push(tx);
+ } catch (err) {
+ // some 404s are expected, so continue quietly
+ }
+ }
+ processTxs(txs);
+ }
+
+ for (const txid of txids) {
+ if (!found[txid]) {
+ this.evict(txid, false);
+ }
+ }
+ }
+
public getLatestRbfSummary(): ReplacementInfo[] {
const rbfList = this.getRbfTrees(false);
return rbfList.slice(0, 6).map(rbfTree => {
From 156b5d0b3c33e775eeb158f16a4d4d4be48ed710 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Wed, 16 Aug 2023 18:30:18 +0900
Subject: [PATCH 58/79] Update bulk /txs to use new failover router,
internal-api path
---
backend/src/api/bitcoin/esplora-api.ts | 2 +-
backend/src/api/rbf-cache.ts | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts
index 1ebfef8c8..3264e8725 100644
--- a/backend/src/api/bitcoin/esplora-api.ts
+++ b/backend/src/api/bitcoin/esplora-api.ts
@@ -214,7 +214,7 @@ class ElectrsApi implements AbstractBitcoinApi {
}
async $getRawTransactions(txids: string[]): Promise {
- return this.$postWrapper(config.ESPLORA.REST_API_URL + '/txs', txids, 'json');
+ return this.failoverRouter.$post('/internal-api/txs', txids, 'json');
}
async $getMempoolTransactions(txids: string[]): Promise {
diff --git a/backend/src/api/rbf-cache.ts b/backend/src/api/rbf-cache.ts
index 7d95df27b..b7d6f11a6 100644
--- a/backend/src/api/rbf-cache.ts
+++ b/backend/src/api/rbf-cache.ts
@@ -505,10 +505,13 @@ class RbfCache {
if (config.MEMPOOL.BACKEND === 'esplora') {
const sliceLength = 10000;
+ let count = 0;
for (let i = 0; i < Math.ceil(txids.length / sliceLength); i++) {
const slice = txids.slice(i * sliceLength, (i + 1) * sliceLength);
try {
const txs = await bitcoinApi.$getRawTransactions(slice);
+ count += txs.length;
+ logger.info(`Fetched ${count} of ${txids.length} unknown-status RBF transactions from esplora`);
processTxs(txs);
} catch (err) {
logger.err('failed to fetch some cached rbf transactions');
From 031e14f30277ca74f65abec1bd81bc56b60aea81 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Mon, 28 Aug 2023 16:55:50 +0900
Subject: [PATCH 59/79] Update internal getRawTransactions to use new prefix
---
backend/src/api/bitcoin/esplora-api.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts
index 3264e8725..8f47921c2 100644
--- a/backend/src/api/bitcoin/esplora-api.ts
+++ b/backend/src/api/bitcoin/esplora-api.ts
@@ -214,7 +214,7 @@ class ElectrsApi implements AbstractBitcoinApi {
}
async $getRawTransactions(txids: string[]): Promise {
- return this.failoverRouter.$post('/internal-api/txs', txids, 'json');
+ return this.failoverRouter.$post('/internal/txs', txids, 'json');
}
async $getMempoolTransactions(txids: string[]): Promise {
From 9d60c39aebf638f04b5efa84dce9ea92acd0ebb2 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sun, 12 Nov 2023 06:19:46 +0000
Subject: [PATCH 60/79] Resolve rbf cache merge conflicts
---
backend/src/api/rbf-cache.ts | 31 ++-----------------------------
1 file changed, 2 insertions(+), 29 deletions(-)
diff --git a/backend/src/api/rbf-cache.ts b/backend/src/api/rbf-cache.ts
index b7d6f11a6..950e3a4e5 100644
--- a/backend/src/api/rbf-cache.ts
+++ b/backend/src/api/rbf-cache.ts
@@ -382,10 +382,11 @@ class RbfCache {
this.expiring.set(expiringEntry.key, new Date(expiringEntry.value).getTime());
}
});
- logger.debug(`loaded ${txs.length} txs, ${trees.length} trees into rbf cache, ${expiring.length} due to expire, ${this.staleCount} were stale`);
this.staleCount = 0;
await this.checkTrees();
+ logger.debug(`loaded ${txs.length} txs, ${trees.length} trees into rbf cache, ${expiring.length} due to expire, ${this.staleCount} were stale`);
this.cleanup();
+
} catch (e) {
logger.err('failed to restore RBF cache: ' + (e instanceof Error ? e.message : e));
}
@@ -423,31 +424,6 @@ class RbfCache {
return;
}
- // check if any transactions in this tree have already been confirmed
- mined = mined || treeInfo.mined;
- let exists = mined;
- if (!mined) {
- try {
- const apiTx = await bitcoinApi.$getRawTransaction(txid);
- if (apiTx) {
- exists = true;
- }
- if (apiTx?.status?.confirmed) {
- mined = true;
- treeInfo.txMined = true;
- this.evict(txid, true);
- }
- } catch (e) {
- // most transactions only exist in our cache
- }
- }
-
- // if the root tx is not in the mempool or the blockchain
- // evict this tree as soon as possible
- if (root === txid && !exists) {
- this.evict(txid, true);
- }
-
// recursively reconstruct child trees
for (const childId of treeInfo.replaces) {
const replaced = await this.importTree(root, childId, deflated, txs, mined);
@@ -505,13 +481,10 @@ class RbfCache {
if (config.MEMPOOL.BACKEND === 'esplora') {
const sliceLength = 10000;
- let count = 0;
for (let i = 0; i < Math.ceil(txids.length / sliceLength); i++) {
const slice = txids.slice(i * sliceLength, (i + 1) * sliceLength);
try {
const txs = await bitcoinApi.$getRawTransactions(slice);
- count += txs.length;
- logger.info(`Fetched ${count} of ${txids.length} unknown-status RBF transactions from esplora`);
processTxs(txs);
} catch (err) {
logger.err('failed to fetch some cached rbf transactions');
From 823f06451c9a9ec00c91d6bac0023d3929d400ab Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Mon, 11 Sep 2023 11:04:01 +0900
Subject: [PATCH 61/79] Send correct tx conf status in websocket msgs
---
backend/src/api/blocks.ts | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts
index 73b010b91..64dc1d5ba 100644
--- a/backend/src/api/blocks.ts
+++ b/backend/src/api/blocks.ts
@@ -81,6 +81,7 @@ class Blocks {
private async $getTransactionsExtended(
blockHash: string,
blockHeight: number,
+ blockTime: number,
onlyCoinbase: boolean,
txIds: string[] | null = null,
quiet: boolean = false,
@@ -101,6 +102,12 @@ class Blocks {
if (!onlyCoinbase) {
for (const txid of txIds) {
if (mempool[txid]) {
+ mempool[txid].status = {
+ confirmed: true,
+ block_height: blockHeight,
+ block_hash: blockHash,
+ block_time: blockTime,
+ };
transactionMap[txid] = mempool[txid];
foundInMempool++;
totalFound++;
@@ -608,7 +615,7 @@ class Blocks {
}
const blockHash = await bitcoinApi.$getBlockHash(blockHeight);
const block: IEsploraApi.Block = await bitcoinApi.$getBlock(blockHash);
- const transactions = await this.$getTransactionsExtended(blockHash, block.height, true, null, true);
+ const transactions = await this.$getTransactionsExtended(blockHash, block.height, block.timestamp, true, null, true);
const blockExtended = await this.$getBlockExtended(block, transactions);
newlyIndexed++;
@@ -701,7 +708,7 @@ class Blocks {
const verboseBlock = await bitcoinClient.getBlock(blockHash, 2);
const block = BitcoinApi.convertBlock(verboseBlock);
const txIds: string[] = verboseBlock.tx.map(tx => tx.txid);
- const transactions = await this.$getTransactionsExtended(blockHash, block.height, false, txIds, false, true) as MempoolTransactionExtended[];
+ const transactions = await this.$getTransactionsExtended(blockHash, block.height, block.timestamp, false, txIds, false, true) as MempoolTransactionExtended[];
// fill in missing transaction fee data from verboseBlock
for (let i = 0; i < transactions.length; i++) {
@@ -890,7 +897,7 @@ class Blocks {
const blockHash = await bitcoinApi.$getBlockHash(height);
const block: IEsploraApi.Block = await bitcoinApi.$getBlock(blockHash);
- const transactions = await this.$getTransactionsExtended(blockHash, block.height, true);
+ const transactions = await this.$getTransactionsExtended(blockHash, block.height, block.timestamp, true);
const blockExtended = await this.$getBlockExtended(block, transactions);
if (Common.indexingEnabled()) {
@@ -902,7 +909,7 @@ class Blocks {
public async $indexStaleBlock(hash: string): Promise {
const block: IEsploraApi.Block = await bitcoinApi.$getBlock(hash);
- const transactions = await this.$getTransactionsExtended(hash, block.height, true);
+ const transactions = await this.$getTransactionsExtended(hash, block.height, block.timestamp, true);
const blockExtended = await this.$getBlockExtended(block, transactions);
blockExtended.canonical = await bitcoinApi.$getBlockHash(block.height);
From 8aa51c4e802f8069e285bd496455e07b0472b455 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Wed, 16 Aug 2023 02:25:48 +0900
Subject: [PATCH 62/79] Batch esplora outspends requests
---
backend/src/api/bitcoin/bitcoin.routes.ts | 21 +++++++++++++++++++
backend/src/api/bitcoin/esplora-api.ts | 16 +++++++-------
.../transactions-list.component.ts | 2 +-
.../tx-bowtie-graph.component.ts | 5 +++--
frontend/src/app/services/api.service.ts | 8 -------
.../src/app/services/electrs-api.service.ts | 6 ++++++
6 files changed, 38 insertions(+), 20 deletions(-)
diff --git a/backend/src/api/bitcoin/bitcoin.routes.ts b/backend/src/api/bitcoin/bitcoin.routes.ts
index 240fb07ce..cc912877c 100644
--- a/backend/src/api/bitcoin/bitcoin.routes.ts
+++ b/backend/src/api/bitcoin/bitcoin.routes.ts
@@ -112,6 +112,7 @@ class BitcoinRoutes {
.get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/hex', this.getRawTransaction)
.get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/status', this.getTransactionStatus)
.get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/outspends', this.getTransactionOutspends)
+ .get(config.MEMPOOL.API_URL_PREFIX + 'txs/outspends', this.$getOutspends)
.get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/header', this.getBlockHeader)
.get(config.MEMPOOL.API_URL_PREFIX + 'blocks/tip/hash', this.getBlockTipHash)
.get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/raw', this.getRawBlock)
@@ -198,6 +199,26 @@ class BitcoinRoutes {
}
}
+ private async $getOutspends(req: Request, res: Response) {
+ const txids_csv = req.query.txids;
+ if (!txids_csv || typeof txids_csv !== 'string') {
+ res.status(500).send('Invalid txids format');
+ return;
+ }
+ const txids = txids_csv.split(',');
+ if (txids.length > 50) {
+ res.status(400).send('Too many txids requested');
+ return;
+ }
+
+ try {
+ const batchedOutspends = await bitcoinApi.$getBatchedOutspends(txids);
+ res.json(batchedOutspends);
+ } catch (e) {
+ res.status(500).send(e instanceof Error ? e.message : e);
+ }
+ }
+
private async $getCpfpInfo(req: Request, res: Response) {
if (!/^[a-fA-F0-9]{64}$/.test(req.params.txId)) {
res.status(501).send(`Invalid transaction ID.`);
diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts
index 8f47921c2..3ccb5693d 100644
--- a/backend/src/api/bitcoin/esplora-api.ts
+++ b/backend/src/api/bitcoin/esplora-api.ts
@@ -174,6 +174,9 @@ class FailoverRouter {
axiosConfig = { timeout: config.ESPLORA.REQUEST_TIMEOUT, responseType };
url = host.host + path;
}
+ if (data?.params) {
+ axiosConfig.params = data.params;
+ }
return (method === 'post'
? this.requestConnection.post(url, data, axiosConfig)
: this.requestConnection.get(url, axiosConfig)
@@ -193,8 +196,8 @@ class FailoverRouter {
});
}
- public async $get(path, responseType = 'json'): Promise {
- return this.$query('get', path, null, responseType);
+ public async $get(path, responseType = 'json', params: any = null): Promise {
+ return this.$query('get', path, params ? { params } : null, responseType);
}
public async $post(path, data: any, responseType = 'json'): Promise {
@@ -294,13 +297,8 @@ class ElectrsApi implements AbstractBitcoinApi {
return this.failoverRouter.$get('/tx/' + txId + '/outspends');
}
- async $getBatchedOutspends(txId: string[]): Promise {
- const outspends: IEsploraApi.Outspend[][] = [];
- for (const tx of txId) {
- const outspend = await this.$getOutspends(tx);
- outspends.push(outspend);
- }
- return outspends;
+ async $getBatchedOutspends(txids: string[]): Promise {
+ return this.failoverRouter.$get('/txs/outspends', 'json', { txids: txids.join(',') });
}
public startHealthChecks(): void {
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 05d74a75d..19eb2a6d7 100644
--- a/frontend/src/app/components/transactions-list/transactions-list.component.ts
+++ b/frontend/src/app/components/transactions-list/transactions-list.component.ts
@@ -75,7 +75,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
for (let i = 0; i < txIds.length; i += 50) {
batches.push(txIds.slice(i, i + 50));
}
- return forkJoin(batches.map(batch => { return this.apiService.cachedRequest(this.apiService.getOutspendsBatched$, 250, batch); }));
+ return forkJoin(batches.map(batch => this.electrsApiService.getOutspendsBatched$(batch)));
} else {
return of([]);
}
diff --git a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts
index 3bc352a35..d22f5705b 100644
--- a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts
+++ b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts
@@ -8,6 +8,7 @@ import { ApiService } from '../../services/api.service';
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
import { AssetsService } from '../../services/assets.service';
import { environment } from '../../../environments/environment';
+import { ElectrsApiService } from '../../services/electrs-api.service';
interface SvgLine {
path: string;
@@ -100,7 +101,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
private router: Router,
private relativeUrlPipe: RelativeUrlPipe,
private stateService: StateService,
- private apiService: ApiService,
+ private electrsApiService: ElectrsApiService,
private assetsService: AssetsService,
@Inject(LOCALE_ID) private locale: string,
) {
@@ -123,7 +124,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
.pipe(
switchMap((txid) => {
if (!this.cached) {
- return this.apiService.cachedRequest(this.apiService.getOutspendsBatched$, 250, [txid]);
+ return this.electrsApiService.getOutspendsBatched$([txid]);
} else {
return of(null);
}
diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts
index 046b27812..cd5dd1ae6 100644
--- a/frontend/src/app/services/api.service.ts
+++ b/frontend/src/app/services/api.service.ts
@@ -138,14 +138,6 @@ export class ApiService {
return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/transaction-times', { params });
}
- getOutspendsBatched$(txIds: string[]): Observable {
- let params = new HttpParams();
- txIds.forEach((txId: string) => {
- params = params.append('txId[]', txId);
- });
- return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/outspends', { params });
- }
-
getAboutPageProfiles$(): Observable {
return this.httpClient.get(this.apiBaseUrl + '/api/v1/services/sponsors');
}
diff --git a/frontend/src/app/services/electrs-api.service.ts b/frontend/src/app/services/electrs-api.service.ts
index d63d49f68..c3efcbf46 100644
--- a/frontend/src/app/services/electrs-api.service.ts
+++ b/frontend/src/app/services/electrs-api.service.ts
@@ -54,6 +54,12 @@ export class ElectrsApiService {
return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/tx/' + hash + '/outspends');
}
+ getOutspendsBatched$(txids: string[]): Observable {
+ let params = new HttpParams();
+ params = params.append('txids', txids.join(','));
+ return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/txs/outspends', { params });
+ }
+
getBlockTransactions$(hash: string, index: number = 0): Observable {
return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/block/' + hash + '/txs/' + index);
}
From 09f208484a19512d5d8188f45c382e44dedda2c8 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sun, 12 Nov 2023 06:38:18 +0000
Subject: [PATCH 63/79] Add electrsApiService cachedRequest function, switch
outspends
---
.../transactions-list.component.ts | 2 +-
.../tx-bowtie-graph.component.ts | 2 +-
.../src/app/services/electrs-api.service.ts | 44 ++++++++++++++++++-
3 files changed, 45 insertions(+), 3 deletions(-)
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 19eb2a6d7..d066d3583 100644
--- a/frontend/src/app/components/transactions-list/transactions-list.component.ts
+++ b/frontend/src/app/components/transactions-list/transactions-list.component.ts
@@ -75,7 +75,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
for (let i = 0; i < txIds.length; i += 50) {
batches.push(txIds.slice(i, i + 50));
}
- return forkJoin(batches.map(batch => this.electrsApiService.getOutspendsBatched$(batch)));
+ return forkJoin(batches.map(batch => { return this.electrsApiService.cachedRequest(this.electrsApiService.getOutspendsBatched$, 250, batch); }));
} else {
return of([]);
}
diff --git a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts
index d22f5705b..043c9ea3b 100644
--- a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts
+++ b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts
@@ -124,7 +124,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
.pipe(
switchMap((txid) => {
if (!this.cached) {
- return this.electrsApiService.getOutspendsBatched$([txid]);
+ return this.electrsApiService.cachedRequest(this.electrsApiService.getOutspendsBatched$, 250, [txid]);
} else {
return of(null);
}
diff --git a/frontend/src/app/services/electrs-api.service.ts b/frontend/src/app/services/electrs-api.service.ts
index c3efcbf46..eaa1ab52d 100644
--- a/frontend/src/app/services/electrs-api.service.ts
+++ b/frontend/src/app/services/electrs-api.service.ts
@@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
-import { Observable, from, of, switchMap } from 'rxjs';
+import { BehaviorSubject, Observable, catchError, filter, from, of, shareReplay, switchMap, take, tap } from 'rxjs';
import { Transaction, Address, Outspend, Recent, Asset, ScriptHash } from '../interfaces/electrs.interface';
import { StateService } from './state.service';
import { BlockExtended } from '../interfaces/node-api.interface';
@@ -13,6 +13,8 @@ export class ElectrsApiService {
private apiBaseUrl: string; // base URL is protocol, hostname, and port
private apiBasePath: string; // network path is /testnet, etc. or '' for mainnet
+ private requestCache = new Map, expiry: number }>;
+
constructor(
private httpClient: HttpClient,
private stateService: StateService,
@@ -30,6 +32,46 @@ export class ElectrsApiService {
});
}
+ private generateCacheKey(functionName: string, params: any[]): string {
+ return functionName + JSON.stringify(params);
+ }
+
+ // delete expired cache entries
+ private cleanExpiredCache(): void {
+ this.requestCache.forEach((value, key) => {
+ if (value.expiry < Date.now()) {
+ this.requestCache.delete(key);
+ }
+ });
+ }
+
+ cachedRequest Observable>(
+ apiFunction: F,
+ expireAfter: number, // in ms
+ ...params: Parameters
+ ): Observable {
+ this.cleanExpiredCache();
+
+ const cacheKey = this.generateCacheKey(apiFunction.name, params);
+ if (!this.requestCache.has(cacheKey)) {
+ const subject = new BehaviorSubject(null);
+ this.requestCache.set(cacheKey, { subject, expiry: Date.now() + expireAfter });
+
+ apiFunction.bind(this)(...params).pipe(
+ tap(data => {
+ subject.next(data as T);
+ }),
+ catchError((error) => {
+ subject.error(error);
+ return of(null);
+ }),
+ shareReplay(1),
+ ).subscribe();
+ }
+
+ return this.requestCache.get(cacheKey).subject.asObservable().pipe(filter(val => val !== null), take(1));
+ }
+
getBlock$(hash: string): Observable {
return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/block/' + hash);
}
From 7ec7ae7b955efdf5250b9da942614be41a50693a Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sun, 12 Nov 2023 06:51:48 +0000
Subject: [PATCH 64/79] Remove old batched outspends API
---
backend/src/api/bitcoin/bitcoin.routes.ts | 29 ++---------------------
backend/src/api/bitcoin/esplora-api.ts | 2 +-
2 files changed, 3 insertions(+), 28 deletions(-)
diff --git a/backend/src/api/bitcoin/bitcoin.routes.ts b/backend/src/api/bitcoin/bitcoin.routes.ts
index cc912877c..d62f3da72 100644
--- a/backend/src/api/bitcoin/bitcoin.routes.ts
+++ b/backend/src/api/bitcoin/bitcoin.routes.ts
@@ -24,7 +24,6 @@ class BitcoinRoutes {
public initRoutes(app: Application) {
app
.get(config.MEMPOOL.API_URL_PREFIX + 'transaction-times', this.getTransactionTimes)
- .get(config.MEMPOOL.API_URL_PREFIX + 'outspends', this.$getBatchedOutspends)
.get(config.MEMPOOL.API_URL_PREFIX + 'cpfp/:txId', this.$getCpfpInfo)
.get(config.MEMPOOL.API_URL_PREFIX + 'difficulty-adjustment', this.getDifficultyChange)
.get(config.MEMPOOL.API_URL_PREFIX + 'fees/recommended', this.getRecommendedFees)
@@ -112,7 +111,7 @@ class BitcoinRoutes {
.get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/hex', this.getRawTransaction)
.get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/status', this.getTransactionStatus)
.get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/outspends', this.getTransactionOutspends)
- .get(config.MEMPOOL.API_URL_PREFIX + 'txs/outspends', this.$getOutspends)
+ .get(config.MEMPOOL.API_URL_PREFIX + 'txs/outspends', this.$getBatchedOutspends)
.get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/header', this.getBlockHeader)
.get(config.MEMPOOL.API_URL_PREFIX + 'blocks/tip/hash', this.getBlockTipHash)
.get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/raw', this.getRawBlock)
@@ -175,31 +174,7 @@ class BitcoinRoutes {
res.json(times);
}
- private async $getBatchedOutspends(req: Request, res: Response) {
- if (!Array.isArray(req.query.txId)) {
- res.status(500).send('Not an array');
- return;
- }
- if (req.query.txId.length > 50) {
- res.status(400).send('Too many txids requested');
- return;
- }
- const txIds: string[] = [];
- for (const _txId in req.query.txId) {
- if (typeof req.query.txId[_txId] === 'string') {
- txIds.push(req.query.txId[_txId].toString());
- }
- }
-
- try {
- const batchedOutspends = await bitcoinApi.$getBatchedOutspends(txIds);
- res.json(batchedOutspends);
- } catch (e) {
- res.status(500).send(e instanceof Error ? e.message : e);
- }
- }
-
- private async $getOutspends(req: Request, res: Response) {
+ private async $getBatchedOutspends(req: Request, res: Response): Promise {
const txids_csv = req.query.txids;
if (!txids_csv || typeof txids_csv !== 'string') {
res.status(500).send('Invalid txids format');
diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts
index 3ccb5693d..d400dad7a 100644
--- a/backend/src/api/bitcoin/esplora-api.ts
+++ b/backend/src/api/bitcoin/esplora-api.ts
@@ -298,7 +298,7 @@ class ElectrsApi implements AbstractBitcoinApi {
}
async $getBatchedOutspends(txids: string[]): Promise {
- return this.failoverRouter.$get('/txs/outspends', 'json', { txids: txids.join(',') });
+ throw new Error('Method not implemented.');
}
public startHealthChecks(): void {
From 5bee54a2bf9f5dfdd56ddf3cc7799329319b369e Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Thu, 17 Aug 2023 02:42:59 +0900
Subject: [PATCH 65/79] Use new bulk endpoints to speed up forensics
---
.../bitcoin/bitcoin-api-abstract-factory.ts | 1 +
backend/src/api/bitcoin/bitcoin-api.ts | 17 +-
backend/src/api/bitcoin/esplora-api.ts | 13 ++
.../src/tasks/lightning/forensics.service.ts | 193 ++++++++++++------
4 files changed, 155 insertions(+), 69 deletions(-)
diff --git a/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts b/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts
index a76b93e8d..6f20dad92 100644
--- a/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts
+++ b/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts
@@ -24,6 +24,7 @@ export interface AbstractBitcoinApi {
$getOutspend(txId: string, vout: number): Promise;
$getOutspends(txId: string): Promise;
$getBatchedOutspends(txId: string[]): Promise;
+ $getBatchedOutspendsInternal(txId: string[]): Promise;
startHealthChecks(): void;
}
diff --git a/backend/src/api/bitcoin/bitcoin-api.ts b/backend/src/api/bitcoin/bitcoin-api.ts
index 1be7993b8..9e4cbdd8b 100644
--- a/backend/src/api/bitcoin/bitcoin-api.ts
+++ b/backend/src/api/bitcoin/bitcoin-api.ts
@@ -60,8 +60,17 @@ class BitcoinApi implements AbstractBitcoinApi {
});
}
- $getRawTransactions(txids: string[]): Promise {
- throw new Error('Method getRawTransactions not supported by the Bitcoin RPC API.');
+ async $getRawTransactions(txids: string[]): Promise {
+ const txs: IEsploraApi.Transaction[] = [];
+ for (const txid of txids) {
+ try {
+ const tx = await this.$getRawTransaction(txid, false, true);
+ txs.push(tx);
+ } catch (err) {
+ // skip failures
+ }
+ }
+ return txs;
}
$getMempoolTransactions(txids: string[]): Promise {
@@ -202,6 +211,10 @@ class BitcoinApi implements AbstractBitcoinApi {
return outspends;
}
+ async $getBatchedOutspendsInternal(txId: string[]): Promise {
+ return this.$getBatchedOutspends(txId);
+ }
+
$getEstimatedHashrate(blockHeight: number): Promise {
// 120 is the default block span in Core
return this.bitcoindClient.getNetworkHashPs(120, blockHeight);
diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts
index d400dad7a..574113ae6 100644
--- a/backend/src/api/bitcoin/esplora-api.ts
+++ b/backend/src/api/bitcoin/esplora-api.ts
@@ -301,6 +301,19 @@ class ElectrsApi implements AbstractBitcoinApi {
throw new Error('Method not implemented.');
}
+ async $getBatchedOutspendsInternal(txids: string[]): Promise {
+ const allOutspends: IEsploraApi.Outspend[][] = [];
+ const sliceLength = 50;
+ for (let i = 0; i < Math.ceil(txids.length / sliceLength); i++) {
+ const slice = txids.slice(i * sliceLength, (i + 1) * sliceLength);
+ const sliceOutspends = await this.failoverRouter.$get('/txs/outspends', 'json', { txids: slice.join(',') });
+ for (const outspends of sliceOutspends) {
+ allOutspends.push(outspends);
+ }
+ }
+ return allOutspends;
+ }
+
public startHealthChecks(): void {
this.failoverRouter.startHealthChecks();
}
diff --git a/backend/src/tasks/lightning/forensics.service.ts b/backend/src/tasks/lightning/forensics.service.ts
index 65ea61dc1..8a9bb825f 100644
--- a/backend/src/tasks/lightning/forensics.service.ts
+++ b/backend/src/tasks/lightning/forensics.service.ts
@@ -15,8 +15,6 @@ class ForensicsService {
txCache: { [txid: string]: IEsploraApi.Transaction } = {};
tempCached: string[] = [];
- constructor() {}
-
public async $startService(): Promise {
logger.info('Starting lightning network forensics service');
@@ -66,93 +64,154 @@ class ForensicsService {
*/
public async $runClosedChannelsForensics(onlyNewChannels: boolean = false): Promise {
+ // Only Esplora backend can retrieve spent transaction outputs
if (config.MEMPOOL.BACKEND !== 'esplora') {
return;
}
- let progress = 0;
-
try {
logger.debug(`Started running closed channel forensics...`);
- let channels;
+ let remainingChannels;
if (onlyNewChannels) {
- channels = await channelsApi.$getClosedChannelsWithoutReason();
+ remainingChannels = await channelsApi.$getClosedChannelsWithoutReason();
} else {
- channels = await channelsApi.$getUnresolvedClosedChannels();
+ remainingChannels = await channelsApi.$getUnresolvedClosedChannels();
}
- for (const channel of channels) {
- let reason = 0;
- let resolvedForceClose = false;
- // Only Esplora backend can retrieve spent transaction outputs
- const cached: string[] = [];
+ let progress = 0;
+ const sliceLength = 1000;
+ // process batches of 1000 channels
+ for (let i = 0; i < Math.ceil(remainingChannels.length / sliceLength); i++) {
+ const channels = remainingChannels.slice(i * sliceLength, (i + 1) * sliceLength);
+
+ let allOutspends: IEsploraApi.Outspend[][] = [];
+ const forceClosedChannels: { channel: any, cachedSpends: string[] }[] = [];
+
+ // fetch outspends in bulk
try {
- let outspends: IEsploraApi.Outspend[] | undefined;
- try {
- outspends = await bitcoinApi.$getOutspends(channel.closing_transaction_id);
- await Common.sleep$(config.LIGHTNING.FORENSICS_RATE_LIMIT);
- } catch (e) {
- logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/tx/' + channel.closing_transaction_id + '/outspends'}. Reason ${e instanceof Error ? e.message : e}`);
- continue;
- }
- const lightningScriptReasons: number[] = [];
- for (const outspend of outspends) {
- if (outspend.spent && outspend.txid) {
- let spendingTx = await this.fetchTransaction(outspend.txid);
- if (!spendingTx) {
- continue;
+ const outspendTxids = channels.map(channel => channel.closing_transaction_id);
+ allOutspends = await bitcoinApi.$getBatchedOutspendsInternal(outspendTxids);
+ logger.info(`Fetched outspends for ${allOutspends.length} txs from esplora for lightning forensics`);
+ await Common.sleep$(config.LIGHTNING.FORENSICS_RATE_LIMIT);
+ } catch (e) {
+ logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/txs/outspends'}. Reason ${e instanceof Error ? e.message : e}`);
+ }
+ // fetch spending transactions in bulk and load into txCache
+ try {
+ const newSpendingTxids: { [txid: string]: boolean } = {};
+ for (const outspends of allOutspends) {
+ for (const outspend of outspends) {
+ if (outspend.spent && outspend.txid) {
+ if (!this.txCache[outspend.txid]) {
+ newSpendingTxids[outspend.txid] = true;
+ }
}
- cached.push(spendingTx.txid);
- const lightningScript = this.findLightningScript(spendingTx.vin[outspend.vin || 0]);
- lightningScriptReasons.push(lightningScript);
}
}
- const filteredReasons = lightningScriptReasons.filter((r) => r !== 1);
- if (filteredReasons.length) {
- if (filteredReasons.some((r) => r === 2 || r === 4)) {
- reason = 3;
- } else {
- reason = 2;
- resolvedForceClose = true;
- }
- } else {
- /*
- We can detect a commitment transaction (force close) by reading Sequence and Locktime
- https://github.com/lightning/bolts/blob/master/03-transactions.md#commitment-transaction
- */
- let closingTx = await this.fetchTransaction(channel.closing_transaction_id, true);
- if (!closingTx) {
+ const allOutspendTxs = await bitcoinApi.$getRawTransactions(Object.keys(newSpendingTxids));
+ logger.info(`Fetched ${allOutspendTxs.length} out-spending txs from esplora for lightning forensics`);
+ for (const tx of allOutspendTxs) {
+ this.txCache[tx.txid] = tx;
+ }
+ } catch (e) {
+ logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/txs'}. Reason ${e instanceof Error ? e.message : e}`);
+ }
+
+ // process each outspend
+ for (const [index, channel] of channels.entries()) {
+ let reason = 0;
+ const cached: string[] = [];
+ try {
+ const outspends = allOutspends[index];
+ if (!outspends || !outspends.length) {
+ // outspends are missing
continue;
}
- cached.push(closingTx.txid);
- const sequenceHex: string = closingTx.vin[0].sequence.toString(16);
- const locktimeHex: string = closingTx.locktime.toString(16);
- if (sequenceHex.substring(0, 2) === '80' && locktimeHex.substring(0, 2) === '20') {
- reason = 2; // Here we can't be sure if it's a penalty or not
- } else {
- reason = 1;
+ const lightningScriptReasons: number[] = [];
+ for (const outspend of outspends) {
+ if (outspend.spent && outspend.txid) {
+ const spendingTx = this.txCache[outspend.txid];
+ if (!spendingTx) {
+ continue;
+ }
+ cached.push(spendingTx.txid);
+ const lightningScript = this.findLightningScript(spendingTx.vin[outspend.vin || 0]);
+ lightningScriptReasons.push(lightningScript);
+ }
}
- }
- if (reason) {
- logger.debug('Setting closing reason ' + reason + ' for channel: ' + channel.id + '.');
- await DB.query(`UPDATE channels SET closing_reason = ? WHERE id = ?`, [reason, channel.id]);
- if (reason === 2 && resolvedForceClose) {
- await DB.query(`UPDATE channels SET closing_resolved = ? WHERE id = ?`, [true, channel.id]);
- }
- if (reason !== 2 || resolvedForceClose) {
+ const filteredReasons = lightningScriptReasons.filter((r) => r !== 1);
+ if (filteredReasons.length) {
+ if (filteredReasons.some((r) => r === 2 || r === 4)) {
+ // Force closed with penalty
+ reason = 3;
+ } else {
+ // Force closed without penalty
+ reason = 2;
+ await DB.query(`UPDATE channels SET closing_resolved = ? WHERE id = ?`, [true, channel.id]);
+ }
+ await DB.query(`UPDATE channels SET closing_reason = ? WHERE id = ?`, [reason, channel.id]);
+ // clean up cached transactions
cached.forEach(txid => {
delete this.txCache[txid];
});
+ } else {
+ forceClosedChannels.push({ channel, cachedSpends: cached });
}
+ } catch (e) {
+ logger.err(`$runClosedChannelsForensics() failed for channel ${channel.short_id}. Reason: ${e instanceof Error ? e.message : e}`);
}
- } catch (e) {
- logger.err(`$runClosedChannelsForensics() failed for channel ${channel.short_id}. Reason: ${e instanceof Error ? e.message : e}`);
}
- ++progress;
+ // fetch force-closing transactions in bulk
+ try {
+ const newClosingTxids: { [txid: string]: boolean } = {};
+ for (const { channel } of forceClosedChannels) {
+ if (!this.txCache[channel.closing_transaction_id]) {
+ newClosingTxids[channel.closing_transaction_id] = true;
+ }
+ }
+ const closingTxs = await bitcoinApi.$getRawTransactions(Object.keys(newClosingTxids));
+ logger.info(`Fetched ${closingTxs.length} closing txs from esplora for lightning forensics`);
+ for (const tx of closingTxs) {
+ this.txCache[tx.txid] = tx;
+ }
+ } catch (e) {
+ logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/txs'}. Reason ${e instanceof Error ? e.message : e}`);
+ }
+
+ // process channels with no lightning script reasons
+ for (const { channel, cachedSpends } of forceClosedChannels) {
+ const closingTx = this.txCache[channel.closing_transaction_id];
+ if (!closingTx) {
+ // no channel close transaction found yet
+ continue;
+ }
+ /*
+ We can detect a commitment transaction (force close) by reading Sequence and Locktime
+ https://github.com/lightning/bolts/blob/master/03-transactions.md#commitment-transaction
+ */
+ const sequenceHex: string = closingTx.vin[0].sequence.toString(16);
+ const locktimeHex: string = closingTx.locktime.toString(16);
+ let reason;
+ if (sequenceHex.substring(0, 2) === '80' && locktimeHex.substring(0, 2) === '20') {
+ // Force closed, but we can't be sure if it's a penalty or not
+ reason = 2;
+ } else {
+ // Mutually closed
+ reason = 1;
+ // clean up cached transactions
+ delete this.txCache[closingTx.txid];
+ for (const txid of cachedSpends) {
+ delete this.txCache[txid];
+ }
+ }
+ await DB.query(`UPDATE channels SET closing_reason = ? WHERE id = ?`, [reason, channel.id]);
+ }
+
+ progress += channels.length;
const elapsedSeconds = Math.round((new Date().getTime() / 1000) - this.loggerTimer);
if (elapsedSeconds > 10) {
- logger.debug(`Updating channel closed channel forensics ${progress}/${channels.length}`);
+ logger.debug(`Updating channel closed channel forensics ${progress}/${remainingChannels.length}`);
this.loggerTimer = new Date().getTime() / 1000;
}
}
@@ -221,7 +280,7 @@ class ForensicsService {
const channels = await channelsApi.$getChannelsWithoutSourceChecked();
for (const openChannel of channels) {
- let openTx = await this.fetchTransaction(openChannel.transaction_id, true);
+ const openTx = await this.fetchTransaction(openChannel.transaction_id, true);
if (!openTx) {
continue;
}
@@ -276,7 +335,7 @@ class ForensicsService {
// Check if a channel open tx input spends the result of a swept channel close output
private async $attributeSweptChannelCloses(openChannel: ILightningApi.Channel, input: IEsploraApi.Vin): Promise {
- let sweepTx = await this.fetchTransaction(input.txid, true);
+ const sweepTx = await this.fetchTransaction(input.txid, true);
if (!sweepTx) {
logger.err(`couldn't find input transaction for channel forensics ${openChannel.channel_id} ${input.txid}`);
return;
@@ -335,7 +394,7 @@ class ForensicsService {
if (matched && !ambiguous) {
// fetch closing channel transaction and perform forensics on the outputs
- let prevChannelTx = await this.fetchTransaction(input.txid, true);
+ const prevChannelTx = await this.fetchTransaction(input.txid, true);
let outspends: IEsploraApi.Outspend[] | undefined;
try {
outspends = await bitcoinApi.$getOutspends(input.txid);
@@ -430,7 +489,7 @@ class ForensicsService {
}
await Common.sleep$(config.LIGHTNING.FORENSICS_RATE_LIMIT);
} catch (e) {
- logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/tx/' + txid + '/outspends'}. Reason ${e instanceof Error ? e.message : e}`);
+ logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/tx/' + txid}. Reason ${e instanceof Error ? e.message : e}`);
return null;
}
}
From 995acb238df795d2f041787ddac8a5c8fa809e77 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Fri, 18 Aug 2023 00:19:02 +0900
Subject: [PATCH 66/79] Refactor forensics batching, speed up opened channel
forensics
---
.../src/tasks/lightning/forensics.service.ts | 102 ++++++++++--------
1 file changed, 56 insertions(+), 46 deletions(-)
diff --git a/backend/src/tasks/lightning/forensics.service.ts b/backend/src/tasks/lightning/forensics.service.ts
index 8a9bb825f..c83f1720c 100644
--- a/backend/src/tasks/lightning/forensics.service.ts
+++ b/backend/src/tasks/lightning/forensics.service.ts
@@ -71,18 +71,18 @@ class ForensicsService {
try {
logger.debug(`Started running closed channel forensics...`);
- let remainingChannels;
+ let allChannels;
if (onlyNewChannels) {
- remainingChannels = await channelsApi.$getClosedChannelsWithoutReason();
+ allChannels = await channelsApi.$getClosedChannelsWithoutReason();
} else {
- remainingChannels = await channelsApi.$getUnresolvedClosedChannels();
+ allChannels = await channelsApi.$getUnresolvedClosedChannels();
}
let progress = 0;
const sliceLength = 1000;
// process batches of 1000 channels
- for (let i = 0; i < Math.ceil(remainingChannels.length / sliceLength); i++) {
- const channels = remainingChannels.slice(i * sliceLength, (i + 1) * sliceLength);
+ for (let i = 0; i < Math.ceil(allChannels.length / sliceLength); i++) {
+ const channels = allChannels.slice(i * sliceLength, (i + 1) * sliceLength);
let allOutspends: IEsploraApi.Outspend[][] = [];
const forceClosedChannels: { channel: any, cachedSpends: string[] }[] = [];
@@ -91,31 +91,28 @@ class ForensicsService {
try {
const outspendTxids = channels.map(channel => channel.closing_transaction_id);
allOutspends = await bitcoinApi.$getBatchedOutspendsInternal(outspendTxids);
- logger.info(`Fetched outspends for ${allOutspends.length} txs from esplora for lightning forensics`);
+ logger.info(`Fetched outspends for ${allOutspends.length} txs from esplora for LN forensics`);
await Common.sleep$(config.LIGHTNING.FORENSICS_RATE_LIMIT);
} catch (e) {
logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/txs/outspends'}. Reason ${e instanceof Error ? e.message : e}`);
}
// fetch spending transactions in bulk and load into txCache
- try {
- const newSpendingTxids: { [txid: string]: boolean } = {};
- for (const outspends of allOutspends) {
- for (const outspend of outspends) {
- if (outspend.spent && outspend.txid) {
- if (!this.txCache[outspend.txid]) {
- newSpendingTxids[outspend.txid] = true;
- }
- }
+ const newSpendingTxids: { [txid: string]: boolean } = {};
+ for (const outspends of allOutspends) {
+ for (const outspend of outspends) {
+ if (outspend.spent && outspend.txid) {
+ newSpendingTxids[outspend.txid] = true;
}
}
- const allOutspendTxs = await bitcoinApi.$getRawTransactions(Object.keys(newSpendingTxids));
- logger.info(`Fetched ${allOutspendTxs.length} out-spending txs from esplora for lightning forensics`);
- for (const tx of allOutspendTxs) {
- this.txCache[tx.txid] = tx;
- }
- } catch (e) {
- logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/txs'}. Reason ${e instanceof Error ? e.message : e}`);
}
+ const allOutspendTxs = await this.fetchTransactions(
+ allOutspends.flatMap(outspends =>
+ outspends
+ .filter(outspend => outspend.spent && outspend.txid)
+ .map(outspend => outspend.txid)
+ )
+ );
+ logger.info(`Fetched ${allOutspendTxs.length} out-spending txs from esplora for LN forensics`);
// process each outspend
for (const [index, channel] of channels.entries()) {
@@ -163,21 +160,8 @@ class ForensicsService {
}
// fetch force-closing transactions in bulk
- try {
- const newClosingTxids: { [txid: string]: boolean } = {};
- for (const { channel } of forceClosedChannels) {
- if (!this.txCache[channel.closing_transaction_id]) {
- newClosingTxids[channel.closing_transaction_id] = true;
- }
- }
- const closingTxs = await bitcoinApi.$getRawTransactions(Object.keys(newClosingTxids));
- logger.info(`Fetched ${closingTxs.length} closing txs from esplora for lightning forensics`);
- for (const tx of closingTxs) {
- this.txCache[tx.txid] = tx;
- }
- } catch (e) {
- logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/txs'}. Reason ${e instanceof Error ? e.message : e}`);
- }
+ const closingTxs = await this.fetchTransactions(forceClosedChannels.map(x => x.channel.closing_transaction_id));
+ logger.info(`Fetched ${closingTxs.length} closing txs from esplora for LN forensics`);
// process channels with no lightning script reasons
for (const { channel, cachedSpends } of forceClosedChannels) {
@@ -211,7 +195,7 @@ class ForensicsService {
progress += channels.length;
const elapsedSeconds = Math.round((new Date().getTime() / 1000) - this.loggerTimer);
if (elapsedSeconds > 10) {
- logger.debug(`Updating channel closed channel forensics ${progress}/${remainingChannels.length}`);
+ logger.debug(`Updating channel closed channel forensics ${progress}/${allChannels.length}`);
this.loggerTimer = new Date().getTime() / 1000;
}
}
@@ -279,8 +263,11 @@ class ForensicsService {
logger.debug(`Started running open channel forensics...`);
const channels = await channelsApi.$getChannelsWithoutSourceChecked();
+ // preload open channel transactions
+ await this.fetchTransactions(channels.map(channel => channel.transaction_id), true);
+
for (const openChannel of channels) {
- const openTx = await this.fetchTransaction(openChannel.transaction_id, true);
+ const openTx = this.txCache[openChannel.transaction_id];
if (!openTx) {
continue;
}
@@ -414,17 +401,17 @@ class ForensicsService {
};
});
}
+
+ // preload outspend transactions
+ await this.fetchTransactions(outspends.filter(o => o.spent && o.txid).map(o => o.txid), true);
+
for (let i = 0; i < outspends?.length; i++) {
const outspend = outspends[i];
const output = prevChannel.outputs[i];
if (outspend.spent && outspend.txid) {
- try {
- const spendingTx = await this.fetchTransaction(outspend.txid, true);
- if (spendingTx) {
- output.type = this.findLightningScript(spendingTx.vin[outspend.vin || 0]);
- }
- } catch (e) {
- logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/tx/' + outspend.txid}. Reason ${e instanceof Error ? e.message : e}`);
+ const spendingTx = this.txCache[outspend.txid];
+ if (spendingTx) {
+ output.type = this.findLightningScript(spendingTx.vin[outspend.vin || 0]);
}
} else {
output.type = 0;
@@ -496,6 +483,29 @@ class ForensicsService {
return tx;
}
+ // fetches a batch of transactions and adds them to the txCache
+ // the returned list of txs does *not* preserve ordering or number
+ async fetchTransactions(txids, temp: boolean = false): Promise<(IEsploraApi.Transaction | null)[]> {
+ // deduplicate txids
+ const uniqueTxids = [...new Set(txids)];
+ // filter out any transactions we already have in the cache
+ const needToFetch: string[] = uniqueTxids.filter(txid => !this.txCache[txid]);
+ try {
+ const txs = await bitcoinApi.$getRawTransactions(needToFetch);
+ for (const tx of txs) {
+ this.txCache[tx.txid] = tx;
+ if (temp) {
+ this.tempCached.push(tx.txid);
+ }
+ }
+ await Common.sleep$(config.LIGHTNING.FORENSICS_RATE_LIMIT);
+ } catch (e) {
+ logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/txs'}. Reason ${e instanceof Error ? e.message : e}`);
+ return [];
+ }
+ return txids.map(txid => this.txCache[txid]);
+ }
+
clearTempCache(): void {
for (const txid of this.tempCached) {
delete this.txCache[txid];
From 70badaf4615e3d258a6cd15d4b12a09f085cbd6c Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Fri, 18 Aug 2023 02:47:32 +0900
Subject: [PATCH 67/79] Speed up $scanForClosedChannels, use internal outspends
apis
---
.../bitcoin/bitcoin-api-abstract-factory.ts | 1 +
backend/src/api/bitcoin/bitcoin-api.ts | 9 ++++++
backend/src/api/bitcoin/esplora-api.ts | 15 +++------
.../src/tasks/lightning/forensics.service.ts | 2 +-
.../tasks/lightning/network-sync.service.ts | 32 ++++++++++++-------
5 files changed, 37 insertions(+), 22 deletions(-)
diff --git a/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts b/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts
index 6f20dad92..f008e5ed8 100644
--- a/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts
+++ b/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts
@@ -25,6 +25,7 @@ export interface AbstractBitcoinApi {
$getOutspends(txId: string): Promise;
$getBatchedOutspends(txId: string[]): Promise;
$getBatchedOutspendsInternal(txId: string[]): Promise;
+ $getOutSpendsByOutpoint(outpoints: { txid: string, vout: number }[]): Promise;
startHealthChecks(): void;
}
diff --git a/backend/src/api/bitcoin/bitcoin-api.ts b/backend/src/api/bitcoin/bitcoin-api.ts
index 9e4cbdd8b..1722334df 100644
--- a/backend/src/api/bitcoin/bitcoin-api.ts
+++ b/backend/src/api/bitcoin/bitcoin-api.ts
@@ -215,6 +215,15 @@ class BitcoinApi implements AbstractBitcoinApi {
return this.$getBatchedOutspends(txId);
}
+ async $getOutSpendsByOutpoint(outpoints: { txid: string, vout: number }[]): Promise {
+ const outspends: IEsploraApi.Outspend[] = [];
+ for (const outpoint of outpoints) {
+ const outspend = await this.$getOutspend(outpoint.txid, outpoint.vout);
+ outspends.push(outspend);
+ }
+ return outspends;
+ }
+
$getEstimatedHashrate(blockHeight: number): Promise {
// 120 is the default block span in Core
return this.bitcoindClient.getNetworkHashPs(120, blockHeight);
diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts
index 574113ae6..2beebe270 100644
--- a/backend/src/api/bitcoin/esplora-api.ts
+++ b/backend/src/api/bitcoin/esplora-api.ts
@@ -302,16 +302,11 @@ class ElectrsApi implements AbstractBitcoinApi {
}
async $getBatchedOutspendsInternal(txids: string[]): Promise {
- const allOutspends: IEsploraApi.Outspend[][] = [];
- const sliceLength = 50;
- for (let i = 0; i < Math.ceil(txids.length / sliceLength); i++) {
- const slice = txids.slice(i * sliceLength, (i + 1) * sliceLength);
- const sliceOutspends = await this.failoverRouter.$get('/txs/outspends', 'json', { txids: slice.join(',') });
- for (const outspends of sliceOutspends) {
- allOutspends.push(outspends);
- }
- }
- return allOutspends;
+ return this.failoverRouter.$post('/internal-api/txs/outspends/by-txid', txids, 'json');
+ }
+
+ async $getOutSpendsByOutpoint(outpoints: { txid: string, vout: number }[]): Promise {
+ return this.failoverRouter.$post('/internal-api/txs/outspends/by-outpoint', outpoints.map(out => `${out.txid}:${out.vout}`), 'json');
}
public startHealthChecks(): void {
diff --git a/backend/src/tasks/lightning/forensics.service.ts b/backend/src/tasks/lightning/forensics.service.ts
index c83f1720c..1cbf7d647 100644
--- a/backend/src/tasks/lightning/forensics.service.ts
+++ b/backend/src/tasks/lightning/forensics.service.ts
@@ -94,7 +94,7 @@ class ForensicsService {
logger.info(`Fetched outspends for ${allOutspends.length} txs from esplora for LN forensics`);
await Common.sleep$(config.LIGHTNING.FORENSICS_RATE_LIMIT);
} catch (e) {
- logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/txs/outspends'}. Reason ${e instanceof Error ? e.message : e}`);
+ logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/internal-api/txs/outspends/by-txid'}. Reason ${e instanceof Error ? e.message : e}`);
}
// fetch spending transactions in bulk and load into txCache
const newSpendingTxids: { [txid: string]: boolean } = {};
diff --git a/backend/src/tasks/lightning/network-sync.service.ts b/backend/src/tasks/lightning/network-sync.service.ts
index 963b9e8c2..dc0d609fa 100644
--- a/backend/src/tasks/lightning/network-sync.service.ts
+++ b/backend/src/tasks/lightning/network-sync.service.ts
@@ -288,22 +288,32 @@ class NetworkSyncService {
}
logger.debug(`${log}`, logger.tags.ln);
- const channels = await channelsApi.$getChannelsByStatus([0, 1]);
- for (const channel of channels) {
- const spendingTx = await bitcoinApi.$getOutspend(channel.transaction_id, channel.transaction_vout);
- if (spendingTx.spent === true && spendingTx.status?.confirmed === true) {
- logger.debug(`Marking channel: ${channel.id} as closed.`, logger.tags.ln);
- await DB.query(`UPDATE channels SET status = 2, closing_date = FROM_UNIXTIME(?) WHERE id = ?`,
- [spendingTx.status.block_time, channel.id]);
- if (spendingTx.txid && !channel.closing_transaction_id) {
- await DB.query(`UPDATE channels SET closing_transaction_id = ? WHERE id = ?`, [spendingTx.txid, channel.id]);
+ const allChannels = await channelsApi.$getChannelsByStatus([0, 1]);
+
+ const sliceLength = 5000;
+ // process batches of 5000 channels
+ for (let i = 0; i < Math.ceil(allChannels.length / sliceLength); i++) {
+ const channels = allChannels.slice(i * sliceLength, (i + 1) * sliceLength);
+ const outspends = await bitcoinApi.$getOutSpendsByOutpoint(channels.map(channel => {
+ return { txid: channel.transaction_id, vout: channel.transaction_vout };
+ }));
+
+ for (const [index, channel] of channels.entries()) {
+ const spendingTx = outspends[index];
+ if (spendingTx.spent === true && spendingTx.status?.confirmed === true) {
+ // logger.debug(`Marking channel: ${channel.id} as closed.`, logger.tags.ln);
+ await DB.query(`UPDATE channels SET status = 2, closing_date = FROM_UNIXTIME(?) WHERE id = ?`,
+ [spendingTx.status.block_time, channel.id]);
+ if (spendingTx.txid && !channel.closing_transaction_id) {
+ await DB.query(`UPDATE channels SET closing_transaction_id = ? WHERE id = ?`, [spendingTx.txid, channel.id]);
+ }
}
}
- ++progress;
+ progress += channels.length;
const elapsedSeconds = Math.round((new Date().getTime() / 1000) - this.loggerTimer);
if (elapsedSeconds > config.LIGHTNING.LOGGER_UPDATE_INTERVAL) {
- logger.debug(`Checking if channel has been closed ${progress}/${channels.length}`, logger.tags.ln);
+ logger.debug(`Checking if channel has been closed ${progress}/${allChannels.length}`, logger.tags.ln);
this.loggerTimer = new Date().getTime() / 1000;
}
}
From b9217da45301f3c4d752d9d5214b30fb018cd4cd Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Mon, 28 Aug 2023 16:52:28 +0900
Subject: [PATCH 68/79] Change internal API prefix to "internal"
---
backend/src/api/bitcoin/esplora-api.ts | 4 ++--
backend/src/tasks/lightning/forensics.service.ts | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts
index 2beebe270..dda584ec4 100644
--- a/backend/src/api/bitcoin/esplora-api.ts
+++ b/backend/src/api/bitcoin/esplora-api.ts
@@ -302,11 +302,11 @@ class ElectrsApi implements AbstractBitcoinApi {
}
async $getBatchedOutspendsInternal(txids: string[]): Promise {
- return this.failoverRouter.$post('/internal-api/txs/outspends/by-txid', txids, 'json');
+ return this.failoverRouter.$post('/internal/txs/outspends/by-txid', txids, 'json');
}
async $getOutSpendsByOutpoint(outpoints: { txid: string, vout: number }[]): Promise {
- return this.failoverRouter.$post('/internal-api/txs/outspends/by-outpoint', outpoints.map(out => `${out.txid}:${out.vout}`), 'json');
+ return this.failoverRouter.$post('/internal/txs/outspends/by-outpoint', outpoints.map(out => `${out.txid}:${out.vout}`), 'json');
}
public startHealthChecks(): void {
diff --git a/backend/src/tasks/lightning/forensics.service.ts b/backend/src/tasks/lightning/forensics.service.ts
index 1cbf7d647..584dd3c79 100644
--- a/backend/src/tasks/lightning/forensics.service.ts
+++ b/backend/src/tasks/lightning/forensics.service.ts
@@ -94,7 +94,7 @@ class ForensicsService {
logger.info(`Fetched outspends for ${allOutspends.length} txs from esplora for LN forensics`);
await Common.sleep$(config.LIGHTNING.FORENSICS_RATE_LIMIT);
} catch (e) {
- logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/internal-api/txs/outspends/by-txid'}. Reason ${e instanceof Error ? e.message : e}`);
+ logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/internal/txs/outspends/by-txid'}. Reason ${e instanceof Error ? e.message : e}`);
}
// fetch spending transactions in bulk and load into txCache
const newSpendingTxids: { [txid: string]: boolean } = {};
From fc52514c3163d9c22635bda1b5e24712f66049a0 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sun, 12 Nov 2023 07:59:06 +0000
Subject: [PATCH 69/79] restore incoming tx clearance line, smooth moving avg
---
.../incoming-transactions-graph.component.ts | 72 +++++++------------
frontend/src/app/graphs/echarts.ts | 4 +-
2 files changed, 26 insertions(+), 50 deletions(-)
diff --git a/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts b/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts
index 1b68a5a99..667ad1e28 100644
--- a/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts
+++ b/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts
@@ -63,7 +63,8 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges, On
return;
}
this.windowPreference = this.windowPreferenceOverride ? this.windowPreferenceOverride : this.storageService.getValue('graphWindowPreference');
- this.MA = this.calculateMA(this.data.series[0]);
+ const windowSize = Math.max(10, Math.floor(this.data.series[0].length / 8));
+ this.MA = this.calculateMA(this.data.series[0], windowSize);
this.mountChart();
}
@@ -74,33 +75,22 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges, On
this.isLoading = false;
}
- /// calculate the moving average of maData
- calculateMA(maData): number[][] {
+ /// calculate the moving average of the provided data based on windowSize
+ calculateMA(data: number[][], windowSize: number = 100): number[][] {
//update const variables that are not changed
const ma: number[][] = [];
let sum = 0;
let i = 0;
- const len = maData.length;
-
- //Adjust window length based on the length of the data
- //5% appeared as a good amount from tests
- //TODO: make this a text box in the UI
- const maWindowLen = Math.ceil(len * 0.05);
-
- //calculate the center of the moving average window
- const center = Math.floor(maWindowLen / 2);
//calculate the centered moving average
- for (i = center; i < len - center; i++) {
- sum = 0;
- //build out ma as we loop through the data
- ma[i] = [];
- ma[i].push(maData[i][0]);
- for (let j = i - center; j <= i + center; j++) {
- sum += maData[j][1];
+ for (i = 0; i < data.length; i++) {
+ sum += data[i][1];
+ if (i >= windowSize) {
+ sum -= data[i - windowSize][1];
+ const midpoint = i - Math.floor(windowSize / 2);
+ const avg = sum / windowSize;
+ ma.push([data[midpoint][0], avg]);
}
-
- ma[i].push(sum / maWindowLen);
}
//return the moving average array
@@ -138,36 +128,22 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges, On
}
}],
}
- },
- {
- zlevel: 0,
- name: 'MA',
- data: this.MA,
- type: 'line',
- smooth: false,
- showSymbol: false,
- symbol: 'none',
- lineStyle: {
- width: 1,
- color: "white",
- },
- markLine: {
- silent: true,
+ });
+ if (this.template !== 'widget') {
+ seriesGraph.push({
+ zlevel: 0,
+ name: 'MA',
+ data: this.MA,
+ type: 'line',
+ smooth: false,
+ showSymbol: false,
symbol: 'none',
lineStyle: {
- color: '#fff',
- opacity: 1,
width: 2,
- },
- data: [{
- yAxis: 1667,
- label: {
- show: false,
- color: '#ffffff',
- }
- }],
- }
- });
+ color: "white",
+ }
+ });
+ }
this.mempoolStatsChartOption = {
grid: {
diff --git a/frontend/src/app/graphs/echarts.ts b/frontend/src/app/graphs/echarts.ts
index 588e5e5f1..342867168 100644
--- a/frontend/src/app/graphs/echarts.ts
+++ b/frontend/src/app/graphs/echarts.ts
@@ -1,7 +1,7 @@
// Import tree-shakeable echarts
import * as echarts from 'echarts/core';
import { LineChart, LinesChart, BarChart, TreemapChart, PieChart, ScatterChart } from 'echarts/charts';
-import { TitleComponent, TooltipComponent, GridComponent, LegendComponent, GeoComponent, DataZoomComponent, VisualMapComponent } from 'echarts/components';
+import { TitleComponent, TooltipComponent, GridComponent, LegendComponent, GeoComponent, DataZoomComponent, VisualMapComponent, MarkLineComponent } from 'echarts/components';
import { SVGRenderer, CanvasRenderer } from 'echarts/renderers';
// Typescript interfaces
import { EChartsOption, TreemapSeriesOption, LineSeriesOption, PieSeriesOption } from 'echarts';
@@ -11,7 +11,7 @@ echarts.use([
SVGRenderer, CanvasRenderer,
TitleComponent, TooltipComponent, GridComponent,
LegendComponent, GeoComponent, DataZoomComponent,
- VisualMapComponent,
+ VisualMapComponent, MarkLineComponent,
LineChart, LinesChart, BarChart, TreemapChart, PieChart, ScatterChart
]);
export { echarts, EChartsOption, TreemapSeriesOption, LineSeriesOption, PieSeriesOption };
\ No newline at end of file
From 5998b54fec492da40d85779bd790b656890f03a9 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sun, 12 Nov 2023 09:23:37 +0000
Subject: [PATCH 70/79] more logs, reduce request chunk sizes
---
backend/src/api/bitcoin/esplora-api.ts | 3 ++-
backend/src/api/rbf-cache.ts | 6 ++++--
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts
index 8f47921c2..d980ad980 100644
--- a/backend/src/api/bitcoin/esplora-api.ts
+++ b/backend/src/api/bitcoin/esplora-api.ts
@@ -181,7 +181,8 @@ class FailoverRouter {
.catch((e) => {
let fallbackHost = this.fallbackHost;
if (e?.response?.status !== 404) {
- logger.warn(`esplora request failed ${e?.response?.status || 500} ${host.host}${path}`);
+ logger.warn(`esplora request failed ${e?.response?.status} ${host.host}${path}`);
+ logger.warn(e instanceof Error ? e.message : e);
fallbackHost = this.addFailure(host);
}
if (retry && e?.code === 'ECONNREFUSED' && this.multihost) {
diff --git a/backend/src/api/rbf-cache.ts b/backend/src/api/rbf-cache.ts
index 950e3a4e5..33653a33c 100644
--- a/backend/src/api/rbf-cache.ts
+++ b/backend/src/api/rbf-cache.ts
@@ -480,14 +480,16 @@ class RbfCache {
};
if (config.MEMPOOL.BACKEND === 'esplora') {
- const sliceLength = 10000;
+ const sliceLength = 1000;
for (let i = 0; i < Math.ceil(txids.length / sliceLength); i++) {
const slice = txids.slice(i * sliceLength, (i + 1) * sliceLength);
try {
const txs = await bitcoinApi.$getRawTransactions(slice);
+ logger.debug(`fetched ${slice.length} cached rbf transactions`);
processTxs(txs);
+ logger.debug(`processed ${slice.length} cached rbf transactions`);
} catch (err) {
- logger.err('failed to fetch some cached rbf transactions');
+ logger.err(`failed to fetch or process ${slice.length} cached rbf transactions`);
}
}
} else {
From c0a481acbe1f4cb1c4db40c32810819f4eed9071 Mon Sep 17 00:00:00 2001
From: wiz
Date: Sun, 12 Nov 2023 19:09:36 +0900
Subject: [PATCH 71/79] Reduce /internal/txs RBF cache query chunk size to 250
---
backend/src/api/rbf-cache.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/src/api/rbf-cache.ts b/backend/src/api/rbf-cache.ts
index 33653a33c..c573d3291 100644
--- a/backend/src/api/rbf-cache.ts
+++ b/backend/src/api/rbf-cache.ts
@@ -480,7 +480,7 @@ class RbfCache {
};
if (config.MEMPOOL.BACKEND === 'esplora') {
- const sliceLength = 1000;
+ const sliceLength = 250;
for (let i = 0; i < Math.ceil(txids.length / sliceLength); i++) {
const slice = txids.slice(i * sliceLength, (i + 1) * sliceLength);
try {
From ea2a7e7505799f6e1122212cf935dda4ea3eeb1d Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sat, 16 Sep 2023 02:10:38 +0000
Subject: [PATCH 72/79] Use sigops from mempool/electrs, fix the nodejs sigop
calculation
---
backend/src/api/bitcoin/esplora-api.interface.ts | 1 +
backend/src/api/transaction-utils.ts | 13 +++++++++++--
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/backend/src/api/bitcoin/esplora-api.interface.ts b/backend/src/api/bitcoin/esplora-api.interface.ts
index 55abe1d34..0a0960e46 100644
--- a/backend/src/api/bitcoin/esplora-api.interface.ts
+++ b/backend/src/api/bitcoin/esplora-api.interface.ts
@@ -6,6 +6,7 @@ export namespace IEsploraApi {
size: number;
weight: number;
fee: number;
+ sigops?: number;
vin: Vin[];
vout: Vout[];
status: Status;
diff --git a/backend/src/api/transaction-utils.ts b/backend/src/api/transaction-utils.ts
index ef4a34012..d4f130aa6 100644
--- a/backend/src/api/transaction-utils.ts
+++ b/backend/src/api/transaction-utils.ts
@@ -116,7 +116,10 @@ class TransactionUtils {
public extendMempoolTransaction(transaction: IEsploraApi.Transaction): MempoolTransactionExtended {
const vsize = Math.ceil(transaction.weight / 4);
const fractionalVsize = (transaction.weight / 4);
- const sigops = !Common.isLiquid() ? this.countSigops(transaction) : 0;
+ let sigops = transaction.sigops;
+ if (sigops == null) {
+ sigops = !Common.isLiquid() ? this.countSigops(transaction) : 0;
+ }
// https://github.com/bitcoin/bitcoin/blob/e9262ea32a6e1d364fb7974844fadc36f931f8c6/src/policy/policy.cpp#L295-L298
const adjustedVsize = Math.max(fractionalVsize, sigops * 5); // adjusted vsize = Max(weight, sigops * bytes_per_sigop) / witness_scale_factor
const feePerVbytes = (transaction.fee || 0) / fractionalVsize;
@@ -155,7 +158,7 @@ class TransactionUtils {
sigops += 20 * (script.match(/OP_CHECKMULTISIG/g)?.length || 0);
} else {
// in redeem scripts and witnesses, worth N if preceded by OP_N, 20 otherwise
- const matches = script.matchAll(/(?:OP_(\d+))? OP_CHECKMULTISIG/g);
+ const matches = script.matchAll(/(?:OP_(?:PUSHNUM_)?(\d+))? OP_CHECKMULTISIG/g);
for (const match of matches) {
const n = parseInt(match[1]);
if (Number.isInteger(n)) {
@@ -189,6 +192,12 @@ class TransactionUtils {
sigops += this.countScriptSigops(bitcoinjs.script.toASM(Buffer.from(input.witness[input.witness.length - 1], 'hex')), false, true);
}
break;
+
+ case input.prevout.scriptpubkey_type === 'p2sh':
+ if (input.inner_redeemscript_asm) {
+ sigops += this.countScriptSigops(input.inner_redeemscript_asm);
+ }
+ break;
}
}
}
From 72e19f674ac77421d92569ffab7d0267d7edd7da Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sat, 16 Sep 2023 13:02:07 +0000
Subject: [PATCH 73/79] Clear Liquid sigops
---
backend/src/api/transaction-utils.ts | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/backend/src/api/transaction-utils.ts b/backend/src/api/transaction-utils.ts
index d4f130aa6..6ff1c10b7 100644
--- a/backend/src/api/transaction-utils.ts
+++ b/backend/src/api/transaction-utils.ts
@@ -116,10 +116,7 @@ class TransactionUtils {
public extendMempoolTransaction(transaction: IEsploraApi.Transaction): MempoolTransactionExtended {
const vsize = Math.ceil(transaction.weight / 4);
const fractionalVsize = (transaction.weight / 4);
- let sigops = transaction.sigops;
- if (sigops == null) {
- sigops = !Common.isLiquid() ? this.countSigops(transaction) : 0;
- }
+ let sigops = Common.isLiquid() ? 0 : (transaction.sigops != null ? transaction.sigops : this.countSigops(transaction));
// https://github.com/bitcoin/bitcoin/blob/e9262ea32a6e1d364fb7974844fadc36f931f8c6/src/policy/policy.cpp#L295-L298
const adjustedVsize = Math.max(fractionalVsize, sigops * 5); // adjusted vsize = Max(weight, sigops * bytes_per_sigop) / witness_scale_factor
const feePerVbytes = (transaction.fee || 0) / fractionalVsize;
From a510b4992c14b8e0c086f422b9a4b641da34cfb3 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Sat, 16 Sep 2023 13:02:47 +0000
Subject: [PATCH 74/79] Fix condition to add mempool data to loaded cache txs
---
backend/src/api/mempool.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/src/api/mempool.ts b/backend/src/api/mempool.ts
index 73260dc9e..f5e788f98 100644
--- a/backend/src/api/mempool.ts
+++ b/backend/src/api/mempool.ts
@@ -94,7 +94,7 @@ class Mempool {
logger.debug(`Migrating ${Object.keys(this.mempoolCache).length} transactions from disk cache to Redis cache`);
}
for (const txid of Object.keys(this.mempoolCache)) {
- if (!this.mempoolCache[txid].sigops || this.mempoolCache[txid].effectiveFeePerVsize == null) {
+ if (!this.mempoolCache[txid].adjustedVsize || this.mempoolCache[txid].sigops == null || this.mempoolCache[txid].effectiveFeePerVsize == null) {
this.mempoolCache[txid] = transactionUtils.extendMempoolTransaction(this.mempoolCache[txid]);
}
if (this.mempoolCache[txid].order == null) {
From 4ac0a6dad2556749c5542d1c359bc489eee3331a Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Tue, 19 Sep 2023 00:18:52 +0000
Subject: [PATCH 75/79] Display sigops on all transactions
---
.../transaction/transaction.component.html | 8 ++++----
.../components/transaction/transaction.component.ts | 12 ++++++++++++
frontend/src/app/interfaces/electrs.interface.ts | 1 +
3 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/frontend/src/app/components/transaction/transaction.component.html b/frontend/src/app/components/transaction/transaction.component.html
index 006870864..f062662dc 100644
--- a/frontend/src/app/components/transaction/transaction.component.html
+++ b/frontend/src/app/components/transaction/transaction.component.html
@@ -292,9 +292,9 @@
Virtual size
- (tx.weight / 4)">
+
Adjusted vsize
-
+
Weight
@@ -314,9 +314,9 @@
Locktime
- (tx.weight / 4)">
+
Sigops
-
+
Transaction hex
diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts
index 4743e5cd6..5260cd668 100644
--- a/frontend/src/app/components/transaction/transaction.component.ts
+++ b/frontend/src/app/components/transaction/transaction.component.ts
@@ -62,6 +62,8 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
rbfReplaces: string[];
rbfInfo: RbfTree;
cpfpInfo: CpfpInfo | null;
+ sigops: number | null;
+ adjustedVsize: number | null;
showCpfpDetails = false;
fetchCpfp$ = new Subject();
fetchRbfHistory$ = new Subject();
@@ -343,6 +345,10 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
if (tx.fee === undefined) {
this.tx.fee = 0;
}
+ if (this.tx.sigops != null) {
+ this.sigops = this.tx.sigops;
+ this.adjustedVsize = Math.max(this.tx.weight / 4, this.sigops * 5);
+ }
this.tx.feePerVsize = tx.fee / (tx.weight / 4);
this.isLoadingTx = false;
this.error = undefined;
@@ -543,6 +549,10 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
}
this.cpfpInfo = cpfpInfo;
+ if (this.cpfpInfo.adjustedVsize && this.cpfpInfo.sigops != null) {
+ this.sigops = this.cpfpInfo.sigops;
+ this.adjustedVsize = this.cpfpInfo.adjustedVsize;
+ }
this.hasEffectiveFeeRate = hasRelatives || (this.tx.effectiveFeePerVsize && (Math.abs(this.tx.effectiveFeePerVsize - this.tx.feePerVsize) > 0.01));
}
@@ -569,6 +579,8 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
this.replaced = false;
this.transactionTime = -1;
this.cpfpInfo = null;
+ this.adjustedVsize = null;
+ this.sigops = null;
this.hasEffectiveFeeRate = false;
this.rbfInfo = null;
this.rbfReplaces = [];
diff --git a/frontend/src/app/interfaces/electrs.interface.ts b/frontend/src/app/interfaces/electrs.interface.ts
index 2d604a9de..58a02ad79 100644
--- a/frontend/src/app/interfaces/electrs.interface.ts
+++ b/frontend/src/app/interfaces/electrs.interface.ts
@@ -26,6 +26,7 @@ export interface Transaction {
_outspends?: Outspend[];
_channels?: TransactionChannels;
price?: Price;
+ sigops?: number;
}
export interface TransactionChannels {
From 29299e622ec8cd7a96703900fcdbf2f6014b5b4d Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Mon, 13 Nov 2023 03:42:12 +0000
Subject: [PATCH 76/79] Calculate sigops in /api/v1/tx/:txid for mined txs
---
backend/src/api/bitcoin/bitcoin.routes.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/src/api/bitcoin/bitcoin.routes.ts b/backend/src/api/bitcoin/bitcoin.routes.ts
index 240fb07ce..105b0be14 100644
--- a/backend/src/api/bitcoin/bitcoin.routes.ts
+++ b/backend/src/api/bitcoin/bitcoin.routes.ts
@@ -251,7 +251,7 @@ class BitcoinRoutes {
private async getTransaction(req: Request, res: Response) {
try {
- const transaction = await transactionUtils.$getTransactionExtended(req.params.txId, true);
+ const transaction = await transactionUtils.$getTransactionExtended(req.params.txId, true, false, false, true);
res.json(transaction);
} catch (e) {
let statusCode = 500;
From 3639dcc92aef898fd9ede92a8e8aa8a87ea421e9 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Fri, 10 Nov 2023 07:45:02 +0000
Subject: [PATCH 77/79] Recover from stale PID file
---
backend/src/database.ts | 32 +++++++++++++++++++++++++-------
1 file changed, 25 insertions(+), 7 deletions(-)
diff --git a/backend/src/database.ts b/backend/src/database.ts
index c27f28d23..655dad47c 100644
--- a/backend/src/database.ts
+++ b/backend/src/database.ts
@@ -4,6 +4,7 @@ import config from './config';
import { createPool, Pool, PoolConnection } from 'mysql2/promise';
import logger from './logger';
import { FieldPacket, OkPacket, PoolOptions, ResultSetHeader, RowDataPacket } from 'mysql2/typings/mysql';
+import { execSync } from 'child_process';
class DB {
constructor() {
@@ -105,18 +106,34 @@ import { FieldPacket, OkPacket, PoolOptions, ResultSetHeader, RowDataPacket } fr
public getPidLock(): boolean {
const filePath = path.join(config.DATABASE.PID_DIR || __dirname, `/mempool-${config.DATABASE.DATABASE}.pid`);
+ this.enforcePidLock(filePath);
+ fs.writeFileSync(filePath, `${process.pid}`);
+ return true;
+ }
+
+ private enforcePidLock(filePath: string): void {
if (fs.existsSync(filePath)) {
- const pid = fs.readFileSync(filePath).toString();
- if (pid !== `${process.pid}`) {
- const msg = `Already running on PID ${pid} (or pid file '${filePath}' is stale)`;
+ const pid = parseInt(fs.readFileSync(filePath, 'utf-8'));
+ if (pid === process.pid) {
+ logger.warn('PID file already exists for this process');
+ return;
+ }
+
+ let cmd;
+ try {
+ cmd = execSync(`ps -p ${pid} -o args=`);
+ } catch (e) {
+ logger.warn(`Stale PID file at ${filePath}, but no process running on that PID ${pid}`);
+ return;
+ }
+
+ if (cmd && cmd.toString()?.includes('node')) {
+ const msg = `Another mempool nodejs process is already running on PID ${pid}`;
logger.err(msg);
throw new Error(msg);
} else {
- return true;
+ logger.warn(`Stale PID file at ${filePath}, but the PID ${pid} does not belong to a running mempool instance`);
}
- } else {
- fs.writeFileSync(filePath, `${process.pid}`);
- return true;
}
}
@@ -124,6 +141,7 @@ import { FieldPacket, OkPacket, PoolOptions, ResultSetHeader, RowDataPacket } fr
const filePath = path.join(config.DATABASE.PID_DIR || __dirname, `/mempool-${config.DATABASE.DATABASE}.pid`);
if (fs.existsSync(filePath)) {
const pid = fs.readFileSync(filePath).toString();
+ // only release our own pid file
if (pid === `${process.pid}`) {
fs.unlinkSync(filePath);
}
From 8c4b488251cc2aae70d142a78715b33e2ad3431c Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Mon, 13 Nov 2023 07:33:53 +0000
Subject: [PATCH 78/79] handle SIGHUP exit code
---
backend/src/index.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/src/index.ts b/backend/src/index.ts
index e7e1afa3d..59c92fbf3 100644
--- a/backend/src/index.ts
+++ b/backend/src/index.ts
@@ -92,7 +92,7 @@ class Server {
logger.notice(`Starting Mempool Server${worker ? ' (worker)' : ''}... (${backendInfo.getShortCommitHash()})`);
// Register cleanup listeners for exit events
- ['exit', 'SIGINT', 'SIGTERM', 'SIGUSR1', 'SIGUSR2', 'uncaughtException', 'unhandledRejection'].forEach(event => {
+ ['exit', 'SIGHUP', 'SIGINT', 'SIGTERM', 'SIGUSR1', 'SIGUSR2', 'uncaughtException', 'unhandledRejection'].forEach(event => {
process.on(event, () => { this.onExit(event); });
});
From c6a92083a8621e50a7b5410ea9909d4e4233da0a Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Mon, 13 Nov 2023 07:53:13 +0000
Subject: [PATCH 79/79] Fix pid parsing on release lock
---
backend/src/database.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/backend/src/database.ts b/backend/src/database.ts
index 655dad47c..0638aa319 100644
--- a/backend/src/database.ts
+++ b/backend/src/database.ts
@@ -140,9 +140,9 @@ import { execSync } from 'child_process';
public releasePidLock(): void {
const filePath = path.join(config.DATABASE.PID_DIR || __dirname, `/mempool-${config.DATABASE.DATABASE}.pid`);
if (fs.existsSync(filePath)) {
- const pid = fs.readFileSync(filePath).toString();
+ const pid = parseInt(fs.readFileSync(filePath, 'utf-8'));
// only release our own pid file
- if (pid === `${process.pid}`) {
+ if (pid === process.pid) {
fs.unlinkSync(filePath);
}
}