From f8787e525b90d1667c334964e03646fe21a50f50 Mon Sep 17 00:00:00 2001 From: wiz Date: Sat, 12 Mar 2022 10:34:17 +0000 Subject: [PATCH 01/29] Add production frontend configurations --- production/mempool-frontend-config.bisq.json | 14 ++++++++++++++ production/mempool-frontend-config.json | 13 ------------- production/mempool-frontend-config.liquid.json | 17 +++++++++++++++++ production/mempool-frontend-config.mainnet.json | 14 ++++++++++++++ 4 files changed, 45 insertions(+), 13 deletions(-) create mode 100644 production/mempool-frontend-config.bisq.json delete mode 100644 production/mempool-frontend-config.json create mode 100644 production/mempool-frontend-config.liquid.json create mode 100644 production/mempool-frontend-config.mainnet.json diff --git a/production/mempool-frontend-config.bisq.json b/production/mempool-frontend-config.bisq.json new file mode 100644 index 000000000..3ddb807f9 --- /dev/null +++ b/production/mempool-frontend-config.bisq.json @@ -0,0 +1,14 @@ +{ + "BASE_MODULE": "bisq", + "OFFICIAL_MEMPOOL_SPACE": true, + "TESTNET_ENABLED": true, + "LIQUID_ENABLED": true, + "LIQUID_TESTNET_ENABLED": true, + "BISQ_ENABLED": true, + "BISQ_SEPARATE_BACKEND": true, + "SIGNET_ENABLED": true, + "MEMPOOL_WEBSITE_URL": "https://mempool.space", + "LIQUID_WEBSITE_URL": "https://liquid.network", + "BISQ_WEBSITE_URL": "https://bisq.markets", + "ITEMS_PER_PAGE": 25 +} diff --git a/production/mempool-frontend-config.json b/production/mempool-frontend-config.json deleted file mode 100644 index 1a5849f52..000000000 --- a/production/mempool-frontend-config.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "TESTNET_ENABLED": true, - "LIQUID_ENABLED": true, - "LIQUID_TESTNET_ENABLED": true, - "BISQ_ENABLED": true, - "BISQ_SEPARATE_BACKEND": true, - "SIGNET_ENABLED": true, - "ITEMS_PER_PAGE": 25, - "KEEP_BLOCKS_AMOUNT": 8, - "NGINX_PROTOCOL": "http", - "NGINX_HOSTNAME": "127.0.0.1", - "NGINX_PORT": "80" -} diff --git a/production/mempool-frontend-config.liquid.json b/production/mempool-frontend-config.liquid.json new file mode 100644 index 000000000..6a7c79d52 --- /dev/null +++ b/production/mempool-frontend-config.liquid.json @@ -0,0 +1,17 @@ +{ + "BASE_MODULE": "liquid", + "OFFICIAL_MEMPOOL_SPACE": true, + "TESTNET_ENABLED": true, + "LIQUID_ENABLED": true, + "LIQUID_TESTNET_ENABLED": true, + "BISQ_ENABLED": true, + "BISQ_SEPARATE_BACKEND": true, + "SIGNET_ENABLED": true, + "MEMPOOL_WEBSITE_URL": "https://mempool.space", + "LIQUID_WEBSITE_URL": "https://liquid.network", + "BISQ_WEBSITE_URL": "https://bisq.markets", + "ITEMS_PER_PAGE": 25, + "BLOCK_WEIGHT_UNITS": 300000, + "MEMPOOL_BLOCKS_AMOUNT": 2, + "KEEP_BLOCKS_AMOUNT": 16 +} diff --git a/production/mempool-frontend-config.mainnet.json b/production/mempool-frontend-config.mainnet.json new file mode 100644 index 000000000..83b9fc65e --- /dev/null +++ b/production/mempool-frontend-config.mainnet.json @@ -0,0 +1,14 @@ +{ + "OFFICIAL_MEMPOOL_SPACE": true, + "TESTNET_ENABLED": true, + "LIQUID_ENABLED": true, + "LIQUID_TESTNET_ENABLED": true, + "BISQ_ENABLED": true, + "BISQ_SEPARATE_BACKEND": true, + "SIGNET_ENABLED": true, + "MEMPOOL_WEBSITE_URL": "https://mempool.space", + "LIQUID_WEBSITE_URL": "https://liquid.network", + "BISQ_WEBSITE_URL": "https://bisq.markets", + "ITEMS_PER_PAGE": 25, + "INDEXING_BLOCKS_AMOUNT": -1 +} From 597c62ede34f4aceabc247c2a97c58be580919c7 Mon Sep 17 00:00:00 2001 From: wiz Date: Sat, 12 Mar 2022 10:39:28 +0000 Subject: [PATCH 02/29] Remove INDEXING_BLOCKS_AMOUNT from mainnet frontend configuration --- production/mempool-frontend-config.mainnet.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/production/mempool-frontend-config.mainnet.json b/production/mempool-frontend-config.mainnet.json index 83b9fc65e..525cdb115 100644 --- a/production/mempool-frontend-config.mainnet.json +++ b/production/mempool-frontend-config.mainnet.json @@ -9,6 +9,5 @@ "MEMPOOL_WEBSITE_URL": "https://mempool.space", "LIQUID_WEBSITE_URL": "https://liquid.network", "BISQ_WEBSITE_URL": "https://bisq.markets", - "ITEMS_PER_PAGE": 25, - "INDEXING_BLOCKS_AMOUNT": -1 + "ITEMS_PER_PAGE": 25 } From 9786f1794f12ad88bb8c3d525a8609979be9c1b5 Mon Sep 17 00:00:00 2001 From: wiz Date: Sat, 12 Mar 2022 10:53:37 +0000 Subject: [PATCH 03/29] Install production backend/frontend configurations from master --- production/mempool-install-all | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/production/mempool-install-all b/production/mempool-install-all index 6fc302dcd..1295de36c 100755 --- a/production/mempool-install-all +++ b/production/mempool-install-all @@ -7,7 +7,7 @@ do mkdir -p "${HOME}/public_html/${site}/" cd "${HOME}/${site}/backend/" - cp "../production/mempool-config.${site}.json" "mempool-config.json" + cp "${HOME}/mempool/production/mempool-config.${site}.json" "mempool-config.json" npm install npm run build @@ -15,6 +15,7 @@ do if [ "${site}" = "mainnet" ] then cd "${HOME}/${site}/frontend/" + cp "${HOME}/mempool/production/mempool-frontend-config.${site}.json" "mempool-frontend-config.json" npm install npm run build rsync -av ./dist/mempool/browser/* "${HOME}/public_html/${site}/" From ed488a763d3dea33281286826c5f3aa1971b903e Mon Sep 17 00:00:00 2001 From: wiz Date: Sat, 12 Mar 2022 11:11:12 +0000 Subject: [PATCH 04/29] Remove old install script, merge remaining stuff into upgrade script --- production/mempool-config.bisq.json | 10 ++--- production/mempool-config.liquid.json | 14 +++---- production/mempool-config.liquidtestnet.json | 8 ++-- production/mempool-config.mainnet.json | 8 ++-- production/mempool-config.signet.json | 10 ++--- production/mempool-config.testnet.json | 10 ++--- production/mempool-install-all | 23 ----------- production/mempool-upgrade-all | 40 +++++++++++++++++--- 8 files changed, 65 insertions(+), 58 deletions(-) delete mode 100755 production/mempool-install-all diff --git a/production/mempool-config.bisq.json b/production/mempool-config.bisq.json index f4b2e1480..6eef30192 100644 --- a/production/mempool-config.bisq.json +++ b/production/mempool-config.bisq.json @@ -12,8 +12,8 @@ "MIN_PRIORITY": "debug" }, "CORE_RPC": { - "USERNAME": "foo", - "PASSWORD": "bar" + "USERNAME": "__BITCOIN_RPC_USER__", + "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { "REST_API_URL": "http://127.0.0.1:4000" @@ -22,9 +22,9 @@ "ENABLED": false, "HOST": "127.0.0.1", "PORT": 3306, - "USERNAME": "bmempool", - "PASSWORD": "bmempool", - "DATABASE": "bmempool" + "USERNAME": "mempool_bisq", + "PASSWORD": "mempool_bisq", + "DATABASE": "mempool_bisq" }, "STATISTICS": { "ENABLED": true, diff --git a/production/mempool-config.liquid.json b/production/mempool-config.liquid.json index dc29af452..1d3e30731 100644 --- a/production/mempool-config.liquid.json +++ b/production/mempool-config.liquid.json @@ -13,13 +13,13 @@ }, "CORE_RPC": { "PORT": 7041, - "USERNAME": "foo", - "PASSWORD": "bar" + "USERNAME": "__ELEMENTS_RPC_USER__", + "PASSWORD": "__ELEMENTS_RPC_PASS__" }, "SECOND_CORE_RPC": { "PORT": 8332, - "USERNAME": "foo", - "PASSWORD": "bar" + "USERNAME": "__BITCOIN_RPC_USER__", + "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { "REST_API_URL": "http://127.0.0.1:4001" @@ -28,9 +28,9 @@ "ENABLED": true, "HOST": "127.0.0.1", "PORT": 3306, - "USERNAME": "lmempool", - "PASSWORD": "lmempool", - "DATABASE": "lmempool" + "USERNAME": "mempool_liquid", + "PASSWORD": "mempool_liquid", + "DATABASE": "mempool_liquid" }, "STATISTICS": { "ENABLED": true, diff --git a/production/mempool-config.liquidtestnet.json b/production/mempool-config.liquidtestnet.json index 17081a8ea..8805f4045 100644 --- a/production/mempool-config.liquidtestnet.json +++ b/production/mempool-config.liquidtestnet.json @@ -13,13 +13,13 @@ }, "CORE_RPC": { "PORT": 7040, - "USERNAME": "foo", - "PASSWORD": "bar" + "USERNAME": "__ELEMENTS_RPC_USER__", + "PASSWORD": "__ELEMENTS_RPC_PASS__" }, "SECOND_CORE_RPC": { "PORT": 8332, - "USERNAME": "foo", - "PASSWORD": "bar" + "USERNAME": "__BITCOIN_RPC_USER__", + "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { "REST_API_URL": "http://127.0.0.1:4004" diff --git a/production/mempool-config.mainnet.json b/production/mempool-config.mainnet.json index 49ce69479..2be5c565c 100644 --- a/production/mempool-config.mainnet.json +++ b/production/mempool-config.mainnet.json @@ -15,13 +15,13 @@ }, "CORE_RPC": { "PORT": 8332, - "USERNAME": "foo", - "PASSWORD": "bar" + "USERNAME": "__BITCOIN_RPC_USER__", + "PASSWORD": "__BITCOIN_RPC_PASS__" }, "SECOND_CORE_RPC": { "PORT": 8302, - "USERNAME": "foo", - "PASSWORD": "bar" + "USERNAME": "__BITCOIN_RPC_USER__", + "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { "REST_API_URL": "http://127.0.0.1:4000" diff --git a/production/mempool-config.signet.json b/production/mempool-config.signet.json index 57246160c..5fb395dbe 100644 --- a/production/mempool-config.signet.json +++ b/production/mempool-config.signet.json @@ -13,8 +13,8 @@ }, "CORE_RPC": { "PORT": 38332, - "USERNAME": "foo", - "PASSWORD": "bar" + "USERNAME": "__BITCOIN_RPC_USER__", + "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { "REST_API_URL": "http://127.0.0.1:4003" @@ -23,9 +23,9 @@ "ENABLED": true, "HOST": "127.0.0.1", "PORT": 3306, - "USERNAME": "smempool", - "PASSWORD": "smempool", - "DATABASE": "smempool" + "USERNAME": "mempool_signet", + "PASSWORD": "mempool_signet", + "DATABASE": "mempool_signet" }, "STATISTICS": { "ENABLED": true, diff --git a/production/mempool-config.testnet.json b/production/mempool-config.testnet.json index e96689d06..b17fcd98e 100644 --- a/production/mempool-config.testnet.json +++ b/production/mempool-config.testnet.json @@ -13,8 +13,8 @@ }, "CORE_RPC": { "PORT": 18332, - "USERNAME": "foo", - "PASSWORD": "bar" + "USERNAME": "__BITCOIN_RPC_USER__", + "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { "REST_API_URL": "http://127.0.0.1:4002" @@ -23,9 +23,9 @@ "ENABLED": true, "HOST": "127.0.0.1", "PORT": 3306, - "USERNAME": "tmempool", - "PASSWORD": "tmempool", - "DATABASE": "tmempool" + "USERNAME": "mempool_testnet", + "PASSWORD": "mempool_testnet", + "DATABASE": "mempool_testnet" }, "STATISTICS": { "ENABLED": true, diff --git a/production/mempool-install-all b/production/mempool-install-all deleted file mode 100755 index 1295de36c..000000000 --- a/production/mempool-install-all +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/local/bin/zsh -export NVM_DIR="$HOME/.nvm" -source "$NVM_DIR/nvm.sh" -for site in mainnet liquid testnet bisq signet liquidtestnet -do - #git clone https://github.com/mempool/mempool "${HOME}/${site}" - mkdir -p "${HOME}/public_html/${site}/" - - cd "${HOME}/${site}/backend/" - cp "${HOME}/mempool/production/mempool-config.${site}.json" "mempool-config.json" - - npm install - npm run build - - if [ "${site}" = "mainnet" ] - then - cd "${HOME}/${site}/frontend/" - cp "${HOME}/mempool/production/mempool-frontend-config.${site}.json" "mempool-frontend-config.json" - npm install - npm run build - rsync -av ./dist/mempool/browser/* "${HOME}/public_html/${site}/" - fi -done diff --git a/production/mempool-upgrade-all b/production/mempool-upgrade-all index 3aecdbd93..75cd03313 100755 --- a/production/mempool-upgrade-all +++ b/production/mempool-upgrade-all @@ -4,6 +4,12 @@ HOSTNAME=$(hostname) LOCKFILE="${HOME}/lock" REF=$(echo "${1:=origin/master}"|sed -e 's!:!/!') +# get rpc credentials +BITCOIN_RPC_USER=$(grep '^rpcuser' /bitcoin/bitcoin.conf | cut -d '=' -f2) +BITCOIN_RPC_PASS=$(grep '^rpcpassword' /bitcoin/bitcoin.conf | cut -d '=' -f2) +ELEMENTS_RPC_USER=$(grep '^rpcuser' /elements/elements.conf | cut -d '=' -f2) +ELEMENTS_RPC_PASS=$(grep '^rpcpassword' /elements/elements.conf | cut -d '=' -f2) + if [ -f "${LOCKFILE}" ];then echo "upgrade already running? check lockfile ${LOCKFILE}" exit 1 @@ -42,6 +48,9 @@ build_frontend() echo "[*] Building frontend for ${site}" [ -z "${HASH}" ] && exit 1 cd "$HOME/${site}/frontend" || exit 1 + if [ ! -e "mempool-frontend-config.json" ];then + cp "${HOME}/mempool/production/mempool-frontend-config.${site}.json" "mempool-frontend-config.json" + fi npm install --no-optional || exit 1 npm run build || exit 1 } @@ -52,6 +61,15 @@ build_backend() echo "[*] Building backend for ${site}" [ -z "${HASH}" ] && exit 1 cd "$HOME/${site}/backend" || exit 1 + if [ ! -e "mempool-config.json" ];then + cp "${HOME}/mempool/production/mempool-config.${site}.json" "mempool-config.json" + sed -i .orig \ + -e "s!__BITCOIN_RPC_USER__!${BITCOIN_RPC_USER}!" \ + -e "s!__BITCOIN_RPC_PASS__!${BITCOIN_RPC_PASS}!" \ + -e "s!__ELEMENTS_RPC_USER__!${ELEMENTS_RPC_USER}!" \ + -e "s!__ELEMENTS_RPC_PASS__!${ELEMENTS_RPC_PASS}!" \ + "mempool-config.json" + fi npm install --no-optional || exit 1 npm run build || exit 1 } @@ -60,16 +78,28 @@ ship_frontend() { local site="$1" cd "$HOME/${site}/frontend" || exit 1 - rsync -av ./dist/mempool/browser/* "${HOME}/public_html/${site}/" || exit 1 + mkdir -p "${HOME}/public_html/${site}/" + rsync -av "./dist/mempool/browser/" "${HOME}/public_html/${site}/" || exit 1 } export NVM_DIR="${HOME}/.nvm" source "${NVM_DIR}/nvm.sh" -for target in mainnet testnet signet liquid liquidtestnet bisq;do update_repo "${target}";done -for target in mainnet testnet signet liquid liquidtestnet bisq;do build_backend "${target}";done -for target in mainnet liquid bisq;do build_frontend "${target}";done -for target in mainnet liquid bisq;do ship_frontend "${target}";done +for target in mainnet testnet signet liquid liquidtestnet bisq;do + update_repo "${target}" +done + +for target in mainnet testnet signet liquid liquidtestnet bisq;do + build_backend "${target}" +done + +for target in mainnet liquid bisq;do + build_frontend "${target}" +done + +for target in mainnet liquid bisq;do + ship_frontend "${target}" +done echo "${HOSTNAME} updated to \`${REF}\` @ \`${HASH}\`" | /usr/local/bin/keybase chat send --nonblock --channel general mempool.dev echo "${HOSTNAME} updated to \`${REF}\` @ \`${HASH}\`" | /usr/local/bin/keybase chat send --nonblock --channel general mempool.ops From 0daf49b8ad0aa59d31f6e720b00b5851a30cf304 Mon Sep 17 00:00:00 2001 From: wiz Date: Sat, 12 Mar 2022 12:19:49 +0000 Subject: [PATCH 05/29] Add mariadb-server and mysql db creation to install script --- production/install | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/production/install b/production/install index ad2eca9a4..b203a3bf6 100755 --- a/production/install +++ b/production/install @@ -269,7 +269,7 @@ ELEMENTS_ELECTRS_HOME=${ELEMENTS_HOME}/electrs MEMPOOL_REPO_URL=https://github.com/mempool/mempool MEMPOOL_REPO_NAME=mempool -MEMPOOL_REPO_BRANCH=wiz/installer2 +MEMPOOL_REPO_BRANCH=master MEMPOOL_LATEST_RELEASE=v2.3.1 BITCOIN_REPO_URL=https://github.com/bitcoin/bitcoin @@ -326,7 +326,7 @@ FREEBSD_PKG=() FREEBSD_PKG+=(zsh sudo git screen curl wget calc neovim) FREEBSD_PKG+=(openssh-portable py38-pip rust llvm90) FREEBSD_PKG+=(boost-libs autoconf automake gmake gcc libevent libtool pkgconf) -FREEBSD_PKG+=(nginx rsync py38-certbot-nginx ) +FREEBSD_PKG+=(nginx rsync py38-certbot-nginx mariadb105-server) ############################# ##### utility functions ##### @@ -1256,6 +1256,48 @@ if [ "${ELEMENTS_LIQUIDTESTNET_ENABLE}" = ON ];then osSudo "${MEMPOOL_USER}" sh -c "cd ${MEMPOOL_HOME}/${MEMPOOL_REPO_NAME} && git checkout ${MEMPOOL_LATEST_RELEASE}" fi +if [ "${BISQ_ENABLE}" = ON ];then + echo "[*] Creating Mempool instance for Bisq" + osSudo "${MEMPOOL_USER}" git config --global advice.detachedHead false + osSudo "${MEMPOOL_USER}" git clone --branch "${MEMPOOL_REPO_BRANCH}" "${MEMPOOL_REPO_URL}" "${MEMPOOL_HOME}/bisq" + + echo "[*] Checking out Mempool ${MEMPOOL_LATEST_RELEASE} for Bisq" + osSudo "${MEMPOOL_USER}" sh -c "cd ${MEMPOOL_HOME}/${MEMPOOL_REPO_NAME} && git checkout ${MEMPOOL_LATEST_RELEASE}" +fi + +##### mariadb + +echo "[*] Adding MySQL configuration" +case $OS in + + FreeBSD) + osSudo "${ROOT_USER}" service mysql-server start + ;; + Debian) + osSudo "${ROOT_USER}" service mysql start + ;; +esac + +mysql << _EOF_ +create database mempool; +grant all on mempool.* to 'mempool'@'localhost' identified by 'mempool'; + +create database mempool_testnet; +grant all on mempool_testnet.* to 'mempool_testnet'@'localhost' identified by 'mempool_testnet'; + +create database mempool_signet; +grant all on mempool_signet.* to 'mempool_signet'@'localhost' identified by 'mempool_signet'; + +create database mempool_liquid; +grant all on mempool_liquid.* to 'mempool_liquid'@'localhost' identified by 'mempool_liquid'; + +create database mempool_liquidtestnet; +grant all on mempool_liquidtestnet.* to 'mempool_liquidtestnet'@'localhost' identified by 'mempool_liquidtestnet'; + +create database mempool_bisq; +grant all on mempool_bisq.* to 'mempool_bisq'@'localhost' identified by 'mempool_bisq'; +_EOF_ + ##### nginx echo "[*] Adding Nginx configuration" From 03faa18bfcacb93ef91dee9894eaa8002daf158e Mon Sep 17 00:00:00 2001 From: wiz Date: Sat, 12 Mar 2022 12:27:24 +0000 Subject: [PATCH 06/29] Set git to always rebase from install script --- production/install | 1 + 1 file changed, 1 insertion(+) diff --git a/production/install b/production/install index ad2eca9a4..f6794b134 100755 --- a/production/install +++ b/production/install @@ -819,6 +819,7 @@ osSudo "${ROOT_USER}" chown -R "${MEMPOOL_USER}:${MEMPOOL_GROUP}" "${MEMPOOL_HOM osSudo "${MEMPOOL_USER}" touch "${MEMPOOL_HOME}/.zshrc" echo "[*] Cloning Mempool repo from ${MEMPOOL_REPO_URL}" +osSudo "${MEMPOOL_USER}" git config --global pull.rebase true osSudo "${MEMPOOL_USER}" git config --global advice.detachedHead false osSudo "${MEMPOOL_USER}" git clone --branch "${MEMPOOL_REPO_BRANCH}" "${MEMPOOL_REPO_URL}" "${MEMPOOL_HOME}/${MEMPOOL_REPO_NAME}" From 1ea9c13a2672731c3b291318029a315b7a882968 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Fri, 11 Mar 2022 19:26:04 +0100 Subject: [PATCH 07/29] Fix empty diff adjust table --- .../difficulty-adjustments-table.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.component.html b/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.component.html index a04c60f6a..fd881016a 100644 --- a/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.component.html +++ b/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.component.html @@ -1,5 +1,5 @@ -
- +
+
From 6073d4559b0a2e3448fdc8de86ee2c1aee0c71f6 Mon Sep 17 00:00:00 2001 From: wiz Date: Sat, 12 Mar 2022 12:41:33 +0000 Subject: [PATCH 08/29] Create symlinks for mempool scripts in installation script --- production/install | 4 ++++ production/{mempool-upgrade-all => mempool-build-all} | 0 2 files changed, 4 insertions(+) rename production/{mempool-upgrade-all => mempool-build-all} (100%) diff --git a/production/install b/production/install index ad2eca9a4..f9827804d 100755 --- a/production/install +++ b/production/install @@ -821,6 +821,10 @@ osSudo "${MEMPOOL_USER}" touch "${MEMPOOL_HOME}/.zshrc" echo "[*] Cloning Mempool repo from ${MEMPOOL_REPO_URL}" osSudo "${MEMPOOL_USER}" git config --global advice.detachedHead false osSudo "${MEMPOOL_USER}" git clone --branch "${MEMPOOL_REPO_BRANCH}" "${MEMPOOL_REPO_URL}" "${MEMPOOL_HOME}/${MEMPOOL_REPO_NAME}" +osSudo "${MEMPOOL_USER}" ln -s mempool/production/mempool-build-all upgrade +osSudo "${MEMPOOL_USER}" ln -s mempool/production/mempool-kill-all stop +osSudo "${MEMPOOL_USER}" ln -s mempool/production/mempool-start-all start +osSudo "${MEMPOOL_USER}" ln -s mempool/production/mempool-restart-all restart echo "[*] Installing nvm.sh from GitHub" osSudo "${MEMPOOL_USER}" sh -c 'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | zsh' diff --git a/production/mempool-upgrade-all b/production/mempool-build-all similarity index 100% rename from production/mempool-upgrade-all rename to production/mempool-build-all From 87405ec4a561add9c28342eaace0790fd920e88b Mon Sep 17 00:00:00 2001 From: nymkappa Date: Fri, 11 Mar 2022 21:09:56 +0100 Subject: [PATCH 09/29] Don't try to reset hashrates states if not bitcoin --- backend/src/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/src/index.ts b/backend/src/index.ts index c2de54521..0a6080b16 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -97,8 +97,10 @@ class Server { await databaseMigration.$truncateIndexedData(tables); } await databaseMigration.$initializeOrMigrateDatabase(); - await this.$resetHashratesIndexingState(); - await poolsParser.migratePoolsJson(); + if (Common.indexingEnabled()) { + await this.$resetHashratesIndexingState(); + await poolsParser.migratePoolsJson(); + } } catch (e) { throw new Error(e instanceof Error ? e.message : 'Error'); } From cd12e9bde970517d13087ef9b39948d475d1a4f6 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Fri, 11 Mar 2022 21:58:25 +0100 Subject: [PATCH 10/29] Only insert hashrate states for bitcoin --- backend/src/api/database-migration.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/src/api/database-migration.ts b/backend/src/api/database-migration.ts index 14d23a477..4f99ba603 100644 --- a/backend/src/api/database-migration.ts +++ b/backend/src/api/database-migration.ts @@ -293,6 +293,7 @@ class DatabaseMigration { */ private getMigrationQueriesFromVersion(version: number): string[] { const queries: string[] = []; + const isBitcoin = ['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK); if (version < 1) { if (config.MEMPOOL.NETWORK !== 'liquid' && config.MEMPOOL.NETWORK !== 'liquidtestnet') { @@ -300,11 +301,11 @@ class DatabaseMigration { } } - if (version < 7) { + if (version < 7 && isBitcoin === true) { queries.push(`INSERT INTO state(name, number, string) VALUES ('last_hashrates_indexing', 0, NULL)`); } - if (version < 9) { + if (version < 9 && isBitcoin === true) { queries.push(`INSERT INTO state(name, number, string) VALUES ('last_weekly_hashrates_indexing', 0, NULL)`); } From 0dbc725c39b56259c2b2407c9608354d5a28f38d Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sat, 12 Mar 2022 11:06:37 +0100 Subject: [PATCH 11/29] int -> bigint for all satoshis related indexed data --- backend/src/api/database-migration.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/backend/src/api/database-migration.ts b/backend/src/api/database-migration.ts index 4f99ba603..bdad06961 100644 --- a/backend/src/api/database-migration.ts +++ b/backend/src/api/database-migration.ts @@ -6,7 +6,7 @@ import logger from '../logger'; const sleep = (ms: number) => new Promise(res => setTimeout(res, ms)); class DatabaseMigration { - private static currentVersion = 12; + private static currentVersion = 13; private queryTimeout = 120000; private statisticsAddedIndexed = false; @@ -161,6 +161,13 @@ class DatabaseMigration { await this.$executeQuery(connection, 'ALTER TABLE blocks MODIFY `fees` BIGINT UNSIGNED NOT NULL DEFAULT "0"'); } + if (databaseSchemaVersion < 13 && isBitcoin === true) { + await this.$executeQuery(connection, 'ALTER TABLE blocks MODIFY `difficulty` DOUBLE UNSIGNED NOT NULL DEFAULT "0"'); + await this.$executeQuery(connection, 'ALTER TABLE blocks MODIFY `median_fee` BIGINT UNSIGNED NOT NULL DEFAULT "0"'); + await this.$executeQuery(connection, 'ALTER TABLE blocks MODIFY `avg_fee` BIGINT UNSIGNED NOT NULL DEFAULT "0"'); + await this.$executeQuery(connection, 'ALTER TABLE blocks MODIFY `avg_fee_rate` BIGINT UNSIGNED NOT NULL DEFAULT "0"'); + } + connection.release(); } catch (e) { connection.release(); From 0e0331d8ab02d5fa6f83f51ff663ed5a67069324 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Thu, 10 Mar 2022 18:35:37 +0100 Subject: [PATCH 12/29] Create working template for the new blocks page --- backend/src/api/blocks.ts | 4 +- backend/src/routes.ts | 2 +- frontend/src/app/app-routing.module.ts | 15 ++- frontend/src/app/app.module.ts | 2 + .../blocks-list/blocks-list.component.html | 100 ++++++++++++++++++ .../blocks-list/blocks-list.component.scss | 74 +++++++++++++ .../blocks-list/blocks-list.component.ts | 48 +++++++++ frontend/src/app/services/api.service.ts | 7 ++ 8 files changed, 248 insertions(+), 4 deletions(-) create mode 100644 frontend/src/app/components/blocks-list/blocks-list.component.html create mode 100644 frontend/src/app/components/blocks-list/blocks-list.component.scss create mode 100644 frontend/src/app/components/blocks-list/blocks-list.component.ts diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index 40687060f..aed2d0004 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -339,7 +339,7 @@ class Blocks { return blockExtended; } - public async $getBlocksExtras(fromHeight: number): Promise { + public async $getBlocksExtras(fromHeight: number, limit: number = 15): Promise { try { loadingIndicators.setProgress('blocks', 0); @@ -360,7 +360,7 @@ class Blocks { } let nextHash = startFromHash; - for (let i = 0; i < 10 && currentHeight >= 0; i++) { + for (let i = 0; i < limit && currentHeight >= 0; i++) { let block = this.getBlocks().find((b) => b.height === currentHeight); if (!block && Common.indexingEnabled()) { block = this.prepareBlock(await this.$indexBlock(currentHeight)); diff --git a/backend/src/routes.ts b/backend/src/routes.ts index 710cd8378..c6b3656e7 100644 --- a/backend/src/routes.ts +++ b/backend/src/routes.ts @@ -658,7 +658,7 @@ class Routes { public async getBlocksExtras(req: Request, res: Response) { try { - res.json(await blocks.$getBlocksExtras(parseInt(req.params.height, 10))) + res.json(await blocks.$getBlocksExtras(parseInt(req.params.height, 10), 15)); } catch (e) { res.status(500).send(e instanceof Error ? e.message : e); } diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 19285fc8f..1ef7e5fe0 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -31,6 +31,7 @@ import { MiningDashboardComponent } from './components/mining-dashboard/mining-d import { HashrateChartComponent } from './components/hashrate-chart/hashrate-chart.component'; import { HashrateChartPoolsComponent } from './components/hashrates-chart-pools/hashrate-chart-pools.component'; import { MiningStartComponent } from './components/mining-start/mining-start.component'; +import { BlocksList } from './components/blocks-list/blocks-list.component'; let routes: Routes = [ { @@ -75,6 +76,10 @@ let routes: Routes = [ path: 'mining', component: MiningStartComponent, children: [ + { + path: 'blocks', + component: BlocksList, + }, { path: 'hashrate', component: HashrateChartComponent, @@ -190,6 +195,10 @@ let routes: Routes = [ path: 'mining', component: MiningStartComponent, children: [ + { + path: 'blocks', + component: BlocksList, + }, { path: 'hashrate', component: HashrateChartComponent, @@ -299,6 +308,10 @@ let routes: Routes = [ path: 'mining', component: MiningStartComponent, children: [ + { + path: 'blocks', + component: BlocksList, + }, { path: 'hashrate', component: HashrateChartComponent, @@ -630,7 +643,7 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') { initialNavigation: 'enabled', scrollPositionRestoration: 'enabled', anchorScrolling: 'enabled' -})], + })], exports: [RouterModule] }) export class AppRoutingModule { } diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 0dfc853cc..3affdc7ba 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -76,6 +76,7 @@ import { MiningStartComponent } from './components/mining-start/mining-start.com import { AmountShortenerPipe } from './shared/pipes/amount-shortener.pipe'; import { ShortenStringPipe } from './shared/pipes/shorten-string-pipe/shorten-string.pipe'; import { DifficultyAdjustmentsTable } from './components/difficulty-adjustments-table/difficulty-adjustments-table.components'; +import { BlocksList } from './components/blocks-list/blocks-list.component'; @NgModule({ declarations: [ @@ -133,6 +134,7 @@ import { DifficultyAdjustmentsTable } from './components/difficulty-adjustments- MiningStartComponent, AmountShortenerPipe, DifficultyAdjustmentsTable, + BlocksList, ], imports: [ BrowserModule.withServerTransition({ appId: 'serverApp' }), diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.html b/frontend/src/app/components/blocks-list/blocks-list.component.html new file mode 100644 index 000000000..480df9f3f --- /dev/null +++ b/frontend/src/app/components/blocks-list/blocks-list.component.html @@ -0,0 +1,100 @@ +
+

Blocks

+
+ +
+ +
Height
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HeightTimestampMinedPoolRewardFeesTxsSize
+ {{ block.height + }} + + ‎{{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }} + + + + + {{ + block.extras.pool.name }} + + + + + + {{ block.tx_count | number }} + +
+
+
+
+
+ + + + + + + + + + + + + + + +
+ + + +
\ No newline at end of file diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.scss b/frontend/src/app/components/blocks-list/blocks-list.component.scss new file mode 100644 index 000000000..3d7ffe631 --- /dev/null +++ b/frontend/src/app/components/blocks-list/blocks-list.component.scss @@ -0,0 +1,74 @@ +.container-xl { + max-width: 1400px; +} + +.container { + max-width: 100%; +} + +.row { + padding-top: 15px; + padding-bottom: 15px; +} + +.pool-name { + display: inline-block; + vertical-align: text-top; + padding-left: 10px; +} + +.height { + width: 12%; + @media (max-width: 1100px) { + width: 10%; + } +} + +.timestamp { + @media (max-width: 900px) { + display: none; + } +} + +.mined { + @media (max-width: 576px) { + display: none; + } +} + +.txs { + padding-right: 40px; + @media (max-width: 1100px) { + padding-right: 10px; + } + @media (max-width: 800px) { + display: none; + } +} + +.fees { + @media (max-width: 650px) { + display: none; + } +} + +.pool { + width: 12%; +} + +.reward { + @media (max-width: 576px) { + width: 7%; + padding-right: 30px; + } +} + +.size { + width: 12%; + @media (max-width: 1000px) { + width: 15%; + } + @media (max-width: 650px) { + width: 20%; + } +} \ No newline at end of file diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.ts b/frontend/src/app/components/blocks-list/blocks-list.component.ts new file mode 100644 index 000000000..56563d7e6 --- /dev/null +++ b/frontend/src/app/components/blocks-list/blocks-list.component.ts @@ -0,0 +1,48 @@ +import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; +import { Observable } from 'rxjs'; +import { map, repeat, tap } from 'rxjs/operators'; +import { BlockExtended } from 'src/app/interfaces/node-api.interface'; +import { ApiService } from 'src/app/services/api.service'; +import { StateService } from 'src/app/services/state.service'; + +@Component({ + selector: 'app-blocks-list', + templateUrl: './blocks-list.component.html', + styleUrls: ['./blocks-list.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class BlocksList implements OnInit { + blocks$: Observable = undefined + isLoading = true; + oldestBlockHeight = undefined; + + constructor( + private apiService: ApiService, + public stateService: StateService + ) { + + } + + ngOnInit(): void { + this.blocks$ = this.apiService.getBlocks$(this.oldestBlockHeight) + .pipe( + tap(blocks => { + this.isLoading = false; + }), + map(blocks => { + for (const block of blocks) { + // @ts-ignore + block.extras.pool.logo = `./resources/mining-pools/` + + block.extras.pool.name.toLowerCase().replace(' ', '').replace('.', '') + '.svg'; + this.oldestBlockHeight = block.height; + } + return blocks; + }), + repeat(2), + ); + } + + trackByBlock(index: number, block: BlockExtended) { + return block.height; + } +} \ No newline at end of file diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts index 858da3273..142f26807 100644 --- a/frontend/src/app/services/api.service.ts +++ b/frontend/src/app/services/api.service.ts @@ -151,6 +151,13 @@ export class ApiService { ); } + getBlocks$(from: number): Observable { + return this.httpClient.get( + this.apiBasePath + this.apiBasePath + `/api/v1/blocks-extras` + + (from !== undefined ? `/${from}` : ``) + ); + } + getHistoricalDifficulty$(interval: string | undefined): Observable { return this.httpClient.get( this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/difficulty` + From d8e986996f0a01ca84c32cbd21bb52ca9dbaa1cb Mon Sep 17 00:00:00 2001 From: nymkappa Date: Fri, 11 Mar 2022 14:54:34 +0100 Subject: [PATCH 13/29] Add pagination on /mining/blocks --- backend/src/api/blocks.ts | 61 +++++++----- backend/src/repositories/BlocksRepository.ts | 5 +- .../blocks-list/blocks-list.component.html | 92 +++++++++---------- .../blocks-list/blocks-list.component.scss | 17 +++- .../blocks-list/blocks-list.component.ts | 59 ++++++++---- 5 files changed, 135 insertions(+), 99 deletions(-) diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index aed2d0004..7a9589348 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -108,14 +108,23 @@ class Blocks { blockExtended.extras.reward = transactions[0].vout.reduce((acc, curr) => acc + curr.value, 0); blockExtended.extras.coinbaseTx = transactionUtils.stripCoinbaseTransaction(transactions[0]); - const stats = await bitcoinClient.getBlockStats(block.id); const coinbaseRaw: IEsploraApi.Transaction = await bitcoinApi.$getRawTransaction(transactions[0].txid, true); blockExtended.extras.coinbaseRaw = coinbaseRaw.hex; - blockExtended.extras.medianFee = stats.feerate_percentiles[2]; // 50th percentiles - blockExtended.extras.feeRange = [stats.minfeerate, stats.feerate_percentiles, stats.maxfeerate].flat(); - blockExtended.extras.totalFees = stats.totalfee; - blockExtended.extras.avgFee = stats.avgfee; - blockExtended.extras.avgFeeRate = stats.avgfeerate; + + if (block.height === 0) { + blockExtended.extras.medianFee = 0; // 50th percentiles + blockExtended.extras.feeRange = [0, 0, 0, 0, 0, 0, 0]; + blockExtended.extras.totalFees = 0; + blockExtended.extras.avgFee = 0; + blockExtended.extras.avgFeeRate = 0; + } else { + const stats = await bitcoinClient.getBlockStats(block.id); + blockExtended.extras.medianFee = stats.feerate_percentiles[2]; // 50th percentiles + blockExtended.extras.feeRange = [stats.minfeerate, stats.feerate_percentiles, stats.maxfeerate].flat(); + blockExtended.extras.totalFees = stats.totalfee; + blockExtended.extras.avgFee = stats.avgfee; + blockExtended.extras.avgFeeRate = stats.avgfeerate; + } if (Common.indexingEnabled()) { let pool: PoolTag; @@ -336,10 +345,13 @@ class Blocks { await blocksRepository.$saveBlockInDatabase(blockExtended); - return blockExtended; + return this.prepareBlock(blockExtended); } public async $getBlocksExtras(fromHeight: number, limit: number = 15): Promise { + // Note - This API is breaking if indexing is not available. For now it is okay because we only + // use it for the mining pages, and mining pages should not be available if indexing is turned off. + // I'll need to fix it before we refactor the block(s) related pages try { loadingIndicators.setProgress('blocks', 0); @@ -363,7 +375,7 @@ class Blocks { for (let i = 0; i < limit && currentHeight >= 0; i++) { let block = this.getBlocks().find((b) => b.height === currentHeight); if (!block && Common.indexingEnabled()) { - block = this.prepareBlock(await this.$indexBlock(currentHeight)); + block = await this.$indexBlock(currentHeight); } else if (!block) { block = this.prepareBlock(await bitcoinApi.$getBlock(nextHash)); } @@ -383,24 +395,25 @@ class Blocks { private prepareBlock(block: any): BlockExtended { return { id: block.id ?? block.hash, // hash for indexed block - timestamp: block?.timestamp ?? block?.blockTimestamp, // blockTimestamp for indexed block - height: block?.height, - version: block?.version, - bits: block?.bits, - nonce: block?.nonce, - difficulty: block?.difficulty, - merkle_root: block?.merkle_root, - tx_count: block?.tx_count, - size: block?.size, - weight: block?.weight, - previousblockhash: block?.previousblockhash, + timestamp: block.timestamp ?? block.blockTimestamp, // blockTimestamp for indexed block + height: block.height, + version: block.version, + bits: block.bits, + nonce: block.nonce, + difficulty: block.difficulty, + merkle_root: block.merkle_root, + tx_count: block.tx_count, + size: block.size, + weight: block.weight, + previousblockhash: block.previousblockhash, extras: { - medianFee: block?.medianFee, - feeRange: block?.feeRange ?? [], // TODO - reward: block?.reward, + medianFee: block.medianFee ?? block.median_fee ?? block.extras?.medianFee, + feeRange: block.feeRange ?? block.fee_range ?? block?.extras?.feeSpan, + reward: block.reward ?? block?.extras?.reward, + totalFees: block.totalFees ?? block?.fees ?? block?.extras.totalFees, pool: block?.extras?.pool ?? (block?.pool_id ? { - id: block?.pool_id, - name: block?.pool_name, + id: block.pool_id, + name: block.pool_name, } : undefined), } }; diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index 0cab3c0db..041086f73 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -277,7 +277,10 @@ class BlocksRepository { const connection = await DB.pool.getConnection(); try { const [rows]: any[] = await connection.query(` - SELECT *, UNIX_TIMESTAMP(blocks.blockTimestamp) as blockTimestamp, pools.id as pool_id, pools.name as pool_name, pools.link as pool_link, pools.addresses as pool_addresses, pools.regexes as pool_regexes + SELECT *, UNIX_TIMESTAMP(blocks.blockTimestamp) as blockTimestamp, + pools.id as pool_id, pools.name as pool_name, pools.link as pool_link, + pools.addresses as pool_addresses, pools.regexes as pool_regexes, + previous_block_hash as previousblockhash FROM blocks JOIN pools ON blocks.pool_id = pools.id WHERE height = ${height}; diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.html b/frontend/src/app/components/blocks-list/blocks-list.component.html index 480df9f3f..2a4818c4f 100644 --- a/frontend/src/app/components/blocks-list/blocks-list.component.html +++ b/frontend/src/app/components/blocks-list/blocks-list.component.html @@ -7,32 +7,32 @@ + - - + - - + + @@ -50,51 +50,41 @@ - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - + +
HeightPool Timestamp MinedPool Reward Fees Txs Size
{{ block.height }} - ‎{{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }} - - - {{ block.extras.pool.name }} + ‎{{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }} + + +
+ + + + + + + + + + + + + + + +
- - - - - - - - - - - - - - - -
- + + \ No newline at end of file diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.scss b/frontend/src/app/components/blocks-list/blocks-list.component.scss index 3d7ffe631..71d96323c 100644 --- a/frontend/src/app/components/blocks-list/blocks-list.component.scss +++ b/frontend/src/app/components/blocks-list/blocks-list.component.scss @@ -1,5 +1,6 @@ .container-xl { max-width: 1400px; + padding-bottom: 0; } .container { @@ -11,6 +12,15 @@ padding-bottom: 15px; } +.disabled { + pointer-events: none; + opacity: 0.5; +} + +.progress { + background-color: #2d3348; +} + .pool-name { display: inline-block; vertical-align: text-top; @@ -18,7 +28,7 @@ } .height { - width: 12%; + width: 10%; @media (max-width: 1100px) { width: 10%; } @@ -31,6 +41,7 @@ } .mined { + width: 13%; @media (max-width: 576px) { display: none; } @@ -53,7 +64,7 @@ } .pool { - width: 12%; + width: 17%; } .reward { @@ -71,4 +82,4 @@ @media (max-width: 650px) { width: 20%; } -} \ No newline at end of file +} diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.ts b/frontend/src/app/components/blocks-list/blocks-list.component.ts index 56563d7e6..3143b4f61 100644 --- a/frontend/src/app/components/blocks-list/blocks-list.component.ts +++ b/frontend/src/app/components/blocks-list/blocks-list.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; -import { Observable } from 'rxjs'; -import { map, repeat, tap } from 'rxjs/operators'; +import { BehaviorSubject, Observable, timer } from 'rxjs'; +import { delayWhen, map, retryWhen, switchMap, tap } from 'rxjs/operators'; import { BlockExtended } from 'src/app/interfaces/node-api.interface'; import { ApiService } from 'src/app/services/api.service'; import { StateService } from 'src/app/services/state.service'; @@ -13,33 +13,52 @@ import { StateService } from 'src/app/services/state.service'; }) export class BlocksList implements OnInit { blocks$: Observable = undefined + isLoading = true; - oldestBlockHeight = undefined; + fromBlockHeight = undefined; + paginationMaxSize: number; + page = 1; + blocksCount: number; + fromHeightSubject: BehaviorSubject = new BehaviorSubject(this.fromBlockHeight); constructor( private apiService: ApiService, - public stateService: StateService + public stateService: StateService, ) { } ngOnInit(): void { - this.blocks$ = this.apiService.getBlocks$(this.oldestBlockHeight) - .pipe( - tap(blocks => { - this.isLoading = false; - }), - map(blocks => { - for (const block of blocks) { - // @ts-ignore - block.extras.pool.logo = `./resources/mining-pools/` + - block.extras.pool.name.toLowerCase().replace(' ', '').replace('.', '') + '.svg'; - this.oldestBlockHeight = block.height; - } - return blocks; - }), - repeat(2), - ); + this.paginationMaxSize = window.matchMedia('(max-width: 670px)').matches ? 3 : 5; + + this.blocks$ = this.fromHeightSubject.pipe( + switchMap(() => { + this.isLoading = true; + return this.apiService.getBlocks$(this.fromBlockHeight) + .pipe( + tap(blocks => { + if (this.blocksCount === undefined) { + this.blocksCount = blocks[0].height; + } + this.isLoading = false; + }), + map(blocks => { + for (const block of blocks) { + // @ts-ignore: Need to add an extra field for the template + block.extras.pool.logo = `./resources/mining-pools/` + + block.extras.pool.name.toLowerCase().replace(' ', '').replace('.', '') + '.svg'; + } + return blocks; + }), + retryWhen(errors => errors.pipe(delayWhen(() => timer(1000)))) + ) + }) + ); + } + + pageChange(page: number) { + this.fromBlockHeight = this.blocksCount - (page - 1) * 15; + this.fromHeightSubject.next(this.fromBlockHeight); } trackByBlock(index: number, block: BlockExtended) { From 123af53de246bcf3a18f382cff63fb57838180aa Mon Sep 17 00:00:00 2001 From: nymkappa Date: Fri, 11 Mar 2022 17:09:13 +0100 Subject: [PATCH 14/29] Added latest block on mining dashboard --- .../blocks-list/blocks-list.component.html | 66 ++++++++++--------- .../blocks-list/blocks-list.component.scss | 49 ++++++++++++-- .../blocks-list/blocks-list.component.ts | 12 +++- .../mining-dashboard.component.html | 18 ++++- 4 files changed, 102 insertions(+), 43 deletions(-) diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.html b/frontend/src/app/components/blocks-list/blocks-list.component.html index 2a4818c4f..d1327653b 100644 --- a/frontend/src/app/components/blocks-list/blocks-list.component.html +++ b/frontend/src/app/components/blocks-list/blocks-list.component.html @@ -1,48 +1,50 @@ -
-

Blocks

-
+
+

Blocks

- - - - - - - - + + + + + + + + - - - - - - - - - - + - - - - - - - @@ -83,8 +86,9 @@
HeightPoolTimestampMinedRewardFeesTxsSizeHeight + PoolTimestampMined + RewardFeesTxsSize
+ {{ block.height }} + - {{ + {{ block.extras.pool.name }} + ‎{{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }} + + + + {{ block.tx_count | number }} +
@@ -53,29 +55,30 @@
+
+ + + + + + + +
- +
\ No newline at end of file diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.scss b/frontend/src/app/components/blocks-list/blocks-list.component.scss index 71d96323c..ba64fd6ed 100644 --- a/frontend/src/app/components/blocks-list/blocks-list.component.scss +++ b/frontend/src/app/components/blocks-list/blocks-list.component.scss @@ -2,14 +2,21 @@ max-width: 1400px; padding-bottom: 0; } +.container-xl.widget { + padding-left: 0px; +} .container { max-width: 100%; } -.row { - padding-top: 15px; - padding-bottom: 15px; +td { + padding-top: 0.7rem !important; + padding-bottom: 0.7rem !important; +} + +.clear-link { + color: white; } .disabled { @@ -21,6 +28,16 @@ background-color: #2d3348; } +.pool { + width: 17%; +} +.pool.widget { + width: 40%; + @media (max-width: 576px) { + padding-left: 30px; + width: 60%; + } +} .pool-name { display: inline-block; vertical-align: text-top; @@ -33,6 +50,12 @@ width: 10%; } } +.height.widget { + width: 20%; + @media (max-width: 576px) { + width: 10%; + } +} .timestamp { @media (max-width: 900px) { @@ -52,7 +75,13 @@ @media (max-width: 1100px) { padding-right: 10px; } - @media (max-width: 800px) { + @media (max-width: 875px) { + display: none; + } +} +.txs.widget { + padding-right: 0; + @media (max-width: 650px) { display: none; } } @@ -62,9 +91,8 @@ display: none; } } - -.pool { - width: 17%; +.fees.widget { + width: 20%; } .reward { @@ -73,6 +101,13 @@ padding-right: 30px; } } +.reward.widget { + width: 20%; + @media (max-width: 576px) { + width: 30%; + padding-right: 0; + } +} .size { width: 12%; diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.ts b/frontend/src/app/components/blocks-list/blocks-list.component.ts index 3143b4f61..3606cc122 100644 --- a/frontend/src/app/components/blocks-list/blocks-list.component.ts +++ b/frontend/src/app/components/blocks-list/blocks-list.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; +import { Component, OnInit, ChangeDetectionStrategy, Input } from '@angular/core'; import { BehaviorSubject, Observable, timer } from 'rxjs'; import { delayWhen, map, retryWhen, switchMap, tap } from 'rxjs/operators'; import { BlockExtended } from 'src/app/interfaces/node-api.interface'; @@ -12,6 +12,8 @@ import { StateService } from 'src/app/services/state.service'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class BlocksList implements OnInit { + @Input() widget: boolean = false; + blocks$: Observable = undefined isLoading = true; @@ -20,17 +22,18 @@ export class BlocksList implements OnInit { page = 1; blocksCount: number; fromHeightSubject: BehaviorSubject = new BehaviorSubject(this.fromBlockHeight); + skeletonLines: number[] = []; constructor( private apiService: ApiService, public stateService: StateService, ) { - } ngOnInit(): void { + this.skeletonLines = this.widget === true ? [...Array(5).keys()] : [...Array(15).keys()]; this.paginationMaxSize = window.matchMedia('(max-width: 670px)').matches ? 3 : 5; - + this.blocks$ = this.fromHeightSubject.pipe( switchMap(() => { this.isLoading = true; @@ -48,6 +51,9 @@ export class BlocksList implements OnInit { block.extras.pool.logo = `./resources/mining-pools/` + block.extras.pool.name.toLowerCase().replace(' ', '').replace('.', '') + '.svg'; } + if (this.widget) { + return blocks.slice(0, 5); + } return blocks; }), retryWhen(errors => errors.pipe(delayWhen(() => timer(1000)))) diff --git a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html index 68209fed0..1c8fb2c9d 100644 --- a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html +++ b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html @@ -95,7 +95,7 @@
-
+ + + +
+
+
+
+ Latest blocks +
+ + +
+
@@ -115,7 +129,7 @@ Adjustments -
From d6a0d84d7114baaa881f02f4efeeb47746f46eef Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sat, 12 Mar 2022 15:55:19 +0100 Subject: [PATCH 15/29] Update mining/blocks in real time --- .../blocks-list/blocks-list.component.html | 2 +- .../blocks-list/blocks-list.component.ts | 91 ++++++++++++------- 2 files changed, 59 insertions(+), 34 deletions(-) diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.html b/frontend/src/app/components/blocks-list/blocks-list.component.html index d1327653b..f14261190 100644 --- a/frontend/src/app/components/blocks-list/blocks-list.component.html +++ b/frontend/src/app/components/blocks-list/blocks-list.component.html @@ -19,7 +19,7 @@ - {{ block.height + {{ block.height }} diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.ts b/frontend/src/app/components/blocks-list/blocks-list.component.ts index 3606cc122..72727b734 100644 --- a/frontend/src/app/components/blocks-list/blocks-list.component.ts +++ b/frontend/src/app/components/blocks-list/blocks-list.component.ts @@ -1,9 +1,10 @@ import { Component, OnInit, ChangeDetectionStrategy, Input } from '@angular/core'; -import { BehaviorSubject, Observable, timer } from 'rxjs'; -import { delayWhen, map, retryWhen, switchMap, tap } from 'rxjs/operators'; +import { BehaviorSubject, combineLatest, Observable, timer } from 'rxjs'; +import { delayWhen, map, retryWhen, scan, skip, switchMap, tap } from 'rxjs/operators'; import { BlockExtended } from 'src/app/interfaces/node-api.interface'; import { ApiService } from 'src/app/services/api.service'; import { StateService } from 'src/app/services/state.service'; +import { WebsocketService } from 'src/app/services/websocket.service'; @Component({ selector: 'app-blocks-list', @@ -14,57 +15,81 @@ import { StateService } from 'src/app/services/state.service'; export class BlocksList implements OnInit { @Input() widget: boolean = false; - blocks$: Observable = undefined + blocks$: Observable = undefined; isLoading = true; fromBlockHeight = undefined; paginationMaxSize: number; page = 1; + lastPage = 1; blocksCount: number; fromHeightSubject: BehaviorSubject = new BehaviorSubject(this.fromBlockHeight); skeletonLines: number[] = []; constructor( private apiService: ApiService, + private websocketService: WebsocketService, public stateService: StateService, ) { } ngOnInit(): void { - this.skeletonLines = this.widget === true ? [...Array(5).keys()] : [...Array(15).keys()]; + this.websocketService.want(['blocks']); + + this.skeletonLines = this.widget === true ? [...Array(5).keys()] : [...Array(15).keys()]; this.paginationMaxSize = window.matchMedia('(max-width: 670px)').matches ? 3 : 5; - - this.blocks$ = this.fromHeightSubject.pipe( - switchMap(() => { - this.isLoading = true; - return this.apiService.getBlocks$(this.fromBlockHeight) - .pipe( - tap(blocks => { - if (this.blocksCount === undefined) { - this.blocksCount = blocks[0].height; - } - this.isLoading = false; - }), - map(blocks => { - for (const block of blocks) { - // @ts-ignore: Need to add an extra field for the template - block.extras.pool.logo = `./resources/mining-pools/` + - block.extras.pool.name.toLowerCase().replace(' ', '').replace('.', '') + '.svg'; - } - if (this.widget) { - return blocks.slice(0, 5); - } - return blocks; - }), - retryWhen(errors => errors.pipe(delayWhen(() => timer(1000)))) - ) - }) - ); + + this.blocks$ = combineLatest([ + this.fromHeightSubject.pipe( + switchMap((fromBlockHeight) => { + this.isLoading = true; + return this.apiService.getBlocks$(this.page === 1 ? undefined : fromBlockHeight) + .pipe( + tap(blocks => { + if (this.blocksCount === undefined) { + this.blocksCount = blocks[0].height; + } + this.isLoading = false; + }), + map(blocks => { + for (const block of blocks) { + // @ts-ignore: Need to add an extra field for the template + block.extras.pool.logo = `./resources/mining-pools/` + + block.extras.pool.name.toLowerCase().replace(' ', '').replace('.', '') + '.svg'; + } + if (this.widget) { + return blocks.slice(0, 5); + } + return blocks; + }), + retryWhen(errors => errors.pipe(delayWhen(() => timer(1000)))) + ) + }) + ), + this.stateService.blocks$ + .pipe( + skip(this.stateService.env.MEMPOOL_BLOCKS_AMOUNT - 1), + ), + ]) + .pipe( + scan((acc, blocks) => { + if (this.page > 1 || acc.length === 0 || (this.page === 1 && this.lastPage !== 1)) { + this.lastPage = this.page; + return blocks[0]; + } + this.blocksCount = Math.max(this.blocksCount, blocks[1][0].height); + // @ts-ignore: Need to add an extra field for the template + blocks[1][0].extras.pool.logo = `./resources/mining-pools/` + + blocks[1][0].extras.pool.name.toLowerCase().replace(' ', '').replace('.', '') + '.svg'; + acc.unshift(blocks[1][0]); + acc = acc.slice(0, this.widget ? 5 : 15); + return acc; + }, []) + ); } pageChange(page: number) { - this.fromBlockHeight = this.blocksCount - (page - 1) * 15; - this.fromHeightSubject.next(this.fromBlockHeight); + this.fromHeightSubject.next(this.blocksCount - (page - 1) * 15); } trackByBlock(index: number, block: BlockExtended) { From 11de94cf905247e9e95fc6e2cda160daf8817751 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sat, 12 Mar 2022 16:44:21 +0100 Subject: [PATCH 16/29] Pool icon clickable - blocks list pagination margin --- .../components/blocks-list/blocks-list.component.html | 10 +++++----- .../components/blocks-list/blocks-list.component.scss | 7 +++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.html b/frontend/src/app/components/blocks-list/blocks-list.component.html index f14261190..7cc7b2e17 100644 --- a/frontend/src/app/components/blocks-list/blocks-list.component.html +++ b/frontend/src/app/components/blocks-list/blocks-list.component.html @@ -23,11 +23,11 @@ }} - + - {{ - block.extras.pool.name }} + {{ block.extras.pool.name }} + ‎{{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }} @@ -86,7 +86,7 @@ - diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.scss b/frontend/src/app/components/blocks-list/blocks-list.component.scss index ba64fd6ed..b9a19f927 100644 --- a/frontend/src/app/components/blocks-list/blocks-list.component.scss +++ b/frontend/src/app/components/blocks-list/blocks-list.component.scss @@ -118,3 +118,10 @@ td { width: 20%; } } + +.pagination-container { + margin-bottom: 40px; + @media (max-width: 992px) { + margin-bottom: 80px; + } +} \ No newline at end of file From a893e8734765537f139b9f15c04f696ff1cd8118 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sat, 12 Mar 2022 17:33:07 +0100 Subject: [PATCH 17/29] Add more padding to the blocks list page --- .../blocks-list/blocks-list.component.html | 142 +++++++++--------- .../blocks-list/blocks-list.component.scss | 13 +- 2 files changed, 77 insertions(+), 78 deletions(-) diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.html b/frontend/src/app/components/blocks-list/blocks-list.component.html index 7cc7b2e17..f50a5fff2 100644 --- a/frontend/src/app/components/blocks-list/blocks-list.component.html +++ b/frontend/src/app/components/blocks-list/blocks-list.component.html @@ -3,92 +3,94 @@
- - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + +
Height - PoolTimestampMined - RewardFeesTxsSize
- {{ block.height - }} - - - - {{ block.extras.pool.name }} - - - ‎{{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }} - - - - - - - - {{ block.tx_count | number }} - -
-
-
-
-
- +
+ + + + + + + + + + + + + + - -
Height + PoolTimestampMined + RewardFeesTxsSize
+ {{ block.height + }} - - + + + {{ block.extras.pool.name }} + - + ‎{{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }} - + - + - + - + {{ block.tx_count | number }} - +
+
+
+
- - - + +
+ + + + + + + + + + + + + + + + +
+ + +
+ \ No newline at end of file diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.scss b/frontend/src/app/components/blocks-list/blocks-list.component.scss index b9a19f927..9414348c1 100644 --- a/frontend/src/app/components/blocks-list/blocks-list.component.scss +++ b/frontend/src/app/components/blocks-list/blocks-list.component.scss @@ -1,9 +1,10 @@ .container-xl { max-width: 1400px; - padding-bottom: 0; + padding-bottom: 100px; } .container-xl.widget { padding-left: 0px; + padding-bottom: 0px; } .container { @@ -117,11 +118,7 @@ td { @media (max-width: 650px) { width: 20%; } -} - -.pagination-container { - margin-bottom: 40px; - @media (max-width: 992px) { - margin-bottom: 80px; + @media (max-width: 450px) { + display: none; } -} \ No newline at end of file +} From 9f5d64cf4ae09606268baf166e50e34ce2643722 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sat, 12 Mar 2022 17:56:00 +0100 Subject: [PATCH 18/29] Fix font size in reward stat widget --- .../mining-dashboard/mining-dashboard.component.html | 6 +++--- .../mining-dashboard/mining-dashboard.component.scss | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html index 1c8fb2c9d..0e9ffb14d 100644 --- a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html +++ b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html @@ -9,14 +9,14 @@
-
Miners Reward
+
Miners Reward
in the last 8 blocks
-
Reward Per Tx
+
Reward Per Tx
{{ rewardStats.rewardPerTx | amountShortener }} sats/tx @@ -24,7 +24,7 @@
-
Average Fee
+
Average Fee
{{ rewardStats.feePerTx | amountShortener}} sats/tx diff --git a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.scss b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.scss index fb2663812..148d589c6 100644 --- a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.scss +++ b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.scss @@ -28,6 +28,9 @@ .card-body.pool-ranking { padding: 1.25rem 0.25rem 0.75rem 0.25rem; } +.card-text { + font-size: 22px; +} #blockchain-container { position: relative; From b8e30ad91fbe5e1c92c4953a7fe08bda6ba71f1f Mon Sep 17 00:00:00 2001 From: softsimon Date: Sun, 13 Mar 2022 14:02:40 +0100 Subject: [PATCH 19/29] Reorganizing community integrations --- .../app/components/about/about.component.html | 21 +++++++++++++----- frontend/src/resources/profile/start9.png | Bin 0 -> 14008 bytes 2 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 frontend/src/resources/profile/start9.png diff --git a/frontend/src/app/components/about/about.component.html b/frontend/src/app/components/about/about.component.html index b0a440b61..c03a3a00a 100644 --- a/frontend/src/app/components/about/about.component.html +++ b/frontend/src/app/components/about/about.component.html @@ -170,13 +170,8 @@
-

Community Integrations

- +

Self-Hosted Integrations

+
+ +
+

Wallet Integrations

+
+ + + Bisq + Electrum diff --git a/frontend/src/resources/profile/start9.png b/frontend/src/resources/profile/start9.png new file mode 100644 index 0000000000000000000000000000000000000000..2cfe19ded9b1372494b8b11836ac62e5e9c90ad4 GIT binary patch literal 14008 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 literal 0 HcmV?d00001 From 81984e9df54ae99dc5b4b4f1ac25463834fa5e07 Mon Sep 17 00:00:00 2001 From: wiz Date: Sun, 13 Mar 2022 13:57:20 +0000 Subject: [PATCH 20/29] Increase default INDEXING_BLOCKS_AMOUNT by 10x to 11000 blocks --- backend/mempool-config.sample.json | 2 +- backend/src/config.ts | 2 +- docker/backend/start.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index 5c45838ee..bfee600b1 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -12,7 +12,7 @@ "BLOCK_WEIGHT_UNITS": 4000000, "INITIAL_BLOCKS_AMOUNT": 8, "MEMPOOL_BLOCKS_AMOUNT": 8, - "INDEXING_BLOCKS_AMOUNT": 1100, + "INDEXING_BLOCKS_AMOUNT": 11000, "PRICE_FEED_UPDATE_INTERVAL": 600, "USE_SECOND_NODE_FOR_MINFEE": false, "EXTERNAL_ASSETS": [ diff --git a/backend/src/config.ts b/backend/src/config.ts index 97c3bb32a..42584b119 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -90,7 +90,7 @@ const defaults: IConfig = { 'BLOCK_WEIGHT_UNITS': 4000000, 'INITIAL_BLOCKS_AMOUNT': 8, 'MEMPOOL_BLOCKS_AMOUNT': 8, - 'INDEXING_BLOCKS_AMOUNT': 1100, // 0 = disable indexing, -1 = index all blocks + 'INDEXING_BLOCKS_AMOUNT': 11000, // 0 = disable indexing, -1 = index all blocks 'PRICE_FEED_UPDATE_INTERVAL': 600, 'USE_SECOND_NODE_FOR_MINFEE': false, 'EXTERNAL_ASSETS': [ diff --git a/docker/backend/start.sh b/docker/backend/start.sh index d26a93b08..46fceb97e 100644 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -13,7 +13,7 @@ __MEMPOOL_RECOMMENDED_FEE_PERCENTILE__=${MEMPOOL_RECOMMENDED_FEE_PERCENTILE:=50} __MEMPOOL_BLOCK_WEIGHT_UNITS__=${MEMPOOL_BLOCK_WEIGHT_UNITS:=4000000} __MEMPOOL_INITIAL_BLOCKS_AMOUNT__=${MEMPOOL_INITIAL_BLOCKS_AMOUNT:=8} __MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__=${MEMPOOL_MEMPOOL_BLOCKS_AMOUNT:=8} -__MEMPOOL_INDEXING_BLOCKS_AMOUNT__=${MEMPOOL_INDEXING_BLOCKS_AMOUNT:=1100} +__MEMPOOL_INDEXING_BLOCKS_AMOUNT__=${MEMPOOL_INDEXING_BLOCKS_AMOUNT:=11000} __MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__=${MEMPOOL_PRICE_FEED_UPDATE_INTERVAL:=600} __MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__=${MEMPOOL_USE_SECOND_NODE_FOR_MINFEE:=false} __MEMPOOL_EXTERNAL_ASSETS__=${MEMPOOL_EXTERNAL_ASSETS:=[\"https://mempool.space/resources/pools.json\"]} From 33897b029f414b8d89ba3c3c81060f035244820f Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sat, 12 Mar 2022 14:47:33 +0100 Subject: [PATCH 21/29] Set db connection to UTC - Fix hashrate indexing --- backend/src/api/database-migration.ts | 25 ++++++++++------- backend/src/api/liquid/elements-parser.ts | 8 +++--- backend/src/api/mining.ts | 13 +++++---- backend/src/api/pools-parser.ts | 4 +-- backend/src/api/statistics.ts | 24 ++++++++--------- backend/src/database.ts | 17 +++++++++--- backend/src/index.ts | 6 ++--- backend/src/repositories/BlocksRepository.ts | 20 +++++++------- .../src/repositories/HashratesRepository.ts | 27 ++++++++++--------- backend/src/repositories/PoolsRepository.ts | 10 +++---- 10 files changed, 86 insertions(+), 68 deletions(-) diff --git a/backend/src/api/database-migration.ts b/backend/src/api/database-migration.ts index bdad06961..c9c1da8e8 100644 --- a/backend/src/api/database-migration.ts +++ b/backend/src/api/database-migration.ts @@ -6,7 +6,7 @@ import logger from '../logger'; const sleep = (ms: number) => new Promise(res => setTimeout(res, ms)); class DatabaseMigration { - private static currentVersion = 13; + private static currentVersion = 14; private queryTimeout = 120000; private statisticsAddedIndexed = false; @@ -77,7 +77,7 @@ class DatabaseMigration { await this.$setStatisticsAddedIndexedFlag(databaseSchemaVersion); const isBitcoin = ['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK); - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { await this.$executeQuery(connection, this.getCreateElementsTableQuery(), await this.$checkIfTableExists('elements_pegs')); await this.$executeQuery(connection, this.getCreateStatisticsQuery(), await this.$checkIfTableExists('statistics')); @@ -168,6 +168,13 @@ class DatabaseMigration { await this.$executeQuery(connection, 'ALTER TABLE blocks MODIFY `avg_fee_rate` BIGINT UNSIGNED NOT NULL DEFAULT "0"'); } + if (databaseSchemaVersion < 14 && isBitcoin === true) { + logger.warn(`'hashrates' table has been truncated. Re-indexing from scratch.`); + await this.$executeQuery(connection, 'TRUNCATE hashrates;'); // Need to re-index + await this.$executeQuery(connection, 'ALTER TABLE `hashrates` DROP FOREIGN KEY `hashrates_ibfk_1`'); + await this.$executeQuery(connection, 'ALTER TABLE `hashrates` MODIFY `pool_id` SMALLINT UNSIGNED NOT NULL DEFAULT "0"'); + } + connection.release(); } catch (e) { connection.release(); @@ -187,7 +194,7 @@ class DatabaseMigration { return; } - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { // We don't use "CREATE INDEX IF NOT EXISTS" because it is not supported on old mariadb version 5.X @@ -225,7 +232,7 @@ class DatabaseMigration { * Check if 'table' exists in the database */ private async $checkIfTableExists(table: string): Promise { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const query = `SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = '${config.DATABASE.DATABASE}' AND TABLE_NAME = '${table}'`; const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); @@ -236,7 +243,7 @@ class DatabaseMigration { * Get current database version */ private async $getSchemaVersionFromDatabase(): Promise { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const query = `SELECT number FROM state WHERE name = 'schema_version';`; const [rows] = await this.$executeQuery(connection, query, true); connection.release(); @@ -247,7 +254,7 @@ class DatabaseMigration { * Create the `state` table */ private async $createMigrationStateTable(): Promise { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { const query = `CREATE TABLE IF NOT EXISTS state ( @@ -279,7 +286,7 @@ class DatabaseMigration { } transactionQueries.push(this.getUpdateToLatestSchemaVersionQuery()); - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { await this.$executeQuery(connection, 'START TRANSACTION;'); for (const query of transactionQueries) { @@ -330,7 +337,7 @@ class DatabaseMigration { * Print current database version */ private async $printDatabaseVersion() { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { const [rows] = await this.$executeQuery(connection, 'SELECT VERSION() as version;', true); logger.debug(`MIGRATIONS: Database engine version '${rows[0].version}'`); @@ -474,7 +481,7 @@ class DatabaseMigration { public async $truncateIndexedData(tables: string[]) { const allowedTables = ['blocks', 'hashrates']; - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { for (const table of tables) { if (!allowedTables.includes(table)) { diff --git a/backend/src/api/liquid/elements-parser.ts b/backend/src/api/liquid/elements-parser.ts index a2d4e1546..24c7ab949 100644 --- a/backend/src/api/liquid/elements-parser.ts +++ b/backend/src/api/liquid/elements-parser.ts @@ -33,7 +33,7 @@ class ElementsParser { } public async $getPegDataByMonth(): Promise { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const query = `SELECT SUM(amount) AS amount, DATE_FORMAT(FROM_UNIXTIME(datetime), '%Y-%m-01') AS date FROM elements_pegs GROUP BY DATE_FORMAT(FROM_UNIXTIME(datetime), '%Y%m')`; const [rows] = await connection.query(query); connection.release(); @@ -79,7 +79,7 @@ class ElementsParser { protected async $savePegToDatabase(height: number, blockTime: number, amount: number, txid: string, txindex: number, bitcoinaddress: string, bitcointxid: string, bitcoinindex: number, final_tx: number): Promise { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const query = `INSERT INTO elements_pegs( block, datetime, amount, txid, txindex, bitcoinaddress, bitcointxid, bitcoinindex, final_tx ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`; @@ -93,7 +93,7 @@ class ElementsParser { } protected async $getLatestBlockHeightFromDatabase(): Promise { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const query = `SELECT number FROM state WHERE name = 'last_elements_block'`; const [rows] = await connection.query(query); connection.release(); @@ -101,7 +101,7 @@ class ElementsParser { } protected async $saveLatestBlockToDatabase(blockHeight: number) { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const query = `UPDATE state SET number = ? WHERE name = 'last_elements_block'`; await connection.query(query, [blockHeight]); connection.release(); diff --git a/backend/src/api/mining.ts b/backend/src/api/mining.ts index afcc89220..512388b36 100644 --- a/backend/src/api/mining.ts +++ b/backend/src/api/mining.ts @@ -80,8 +80,8 @@ class Mining { // We only run this once a week const latestTimestamp = await HashratesRepository.$getLatestRunTimestamp('last_weekly_hashrates_indexing'); - const now = new Date().getTime() / 1000; - if (now - latestTimestamp < 604800) { + const now = new Date(); + if ((now.getTime() / 1000) - latestTimestamp < 604800) { return; } @@ -94,7 +94,6 @@ class Mining { const hashrates: any[] = []; const genesisTimestamp = 1231006505; // bitcoin-cli getblock 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f - const now = new Date(); const lastMonday = new Date(now.setDate(now.getDate() - (now.getDay() + 6) % 7)); const lastMondayMidnight = this.getDateMidnight(lastMonday); let toTimestamp = Math.round((lastMondayMidnight.getTime() - 604800) / 1000); @@ -108,7 +107,7 @@ class Mining { const fromTimestamp = toTimestamp - 604800; // Skip already indexed weeks - if (indexedTimestamp.includes(toTimestamp + 1)) { + if (indexedTimestamp.includes(toTimestamp)) { toTimestamp -= 604800; ++totalIndexed; continue; @@ -133,7 +132,7 @@ class Mining { for (const pool of pools) { hashrates.push({ - hashrateTimestamp: toTimestamp + 1, + hashrateTimestamp: toTimestamp, avgHashrate: pool['hashrate'], poolId: pool.poolId, share: pool['share'], @@ -202,7 +201,7 @@ class Mining { const fromTimestamp = toTimestamp - 86400; // Skip already indexed weeks - if (indexedTimestamp.includes(fromTimestamp)) { + if (indexedTimestamp.includes(toTimestamp)) { toTimestamp -= 86400; ++totalIndexed; continue; @@ -220,7 +219,7 @@ class Mining { hashrates.push({ hashrateTimestamp: toTimestamp, avgHashrate: lastBlockHashrate, - poolId: null, + poolId: 0, share: 1, type: 'daily', }); diff --git a/backend/src/api/pools-parser.ts b/backend/src/api/pools-parser.ts index 194ce0dd9..ff70c3cb9 100644 --- a/backend/src/api/pools-parser.ts +++ b/backend/src/api/pools-parser.ts @@ -66,7 +66,7 @@ class PoolsParser { logger.debug(`Found ${poolNames.length} unique mining pools`); // Get existing pools from the db - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); let existingPools; try { [existingPools] = await connection.query({ sql: 'SELECT * FROM pools;', timeout: 120000 }); @@ -152,7 +152,7 @@ class PoolsParser { * Manually add the 'unknown pool' */ private async insertUnknownPool() { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { const [rows]: any[] = await connection.query({ sql: 'SELECT name from pools where name="Unknown"', timeout: 120000 }); if (rows.length === 0) { diff --git a/backend/src/api/statistics.ts b/backend/src/api/statistics.ts index 886ad78ba..3d99adcb7 100644 --- a/backend/src/api/statistics.ts +++ b/backend/src/api/statistics.ts @@ -155,7 +155,7 @@ class Statistics { } private async $createZeroedStatistic(): Promise { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { const query = `INSERT INTO statistics( added, @@ -216,7 +216,7 @@ class Statistics { } private async $create(statistics: Statistic): Promise { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { const query = `INSERT INTO statistics( added, @@ -421,7 +421,7 @@ class Statistics { private async $get(id: number): Promise { try { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics WHERE id = ?`; const [rows] = await connection.query(query, [id]); connection.release(); @@ -435,7 +435,7 @@ class Statistics { public async $list2H(): Promise { try { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics ORDER BY statistics.added DESC LIMIT 120`; const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); @@ -448,7 +448,7 @@ class Statistics { public async $list24H(): Promise { try { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics ORDER BY statistics.added DESC LIMIT 1440`; const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); @@ -461,7 +461,7 @@ class Statistics { public async $list1W(): Promise { try { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const query = this.getQueryForDaysAvg(300, '1 WEEK'); // 5m interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); @@ -474,7 +474,7 @@ class Statistics { public async $list1M(): Promise { try { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const query = this.getQueryForDaysAvg(1800, '1 MONTH'); // 30m interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); @@ -487,7 +487,7 @@ class Statistics { public async $list3M(): Promise { try { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const query = this.getQueryForDaysAvg(7200, '3 MONTH'); // 2h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); @@ -500,7 +500,7 @@ class Statistics { public async $list6M(): Promise { try { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const query = this.getQueryForDaysAvg(10800, '6 MONTH'); // 3h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); @@ -513,7 +513,7 @@ class Statistics { public async $list1Y(): Promise { try { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const query = this.getQueryForDays(28800, '1 YEAR'); // 8h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); @@ -526,7 +526,7 @@ class Statistics { public async $list2Y(): Promise { try { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const query = this.getQueryForDays(28800, "2 YEAR"); // 8h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); @@ -539,7 +539,7 @@ class Statistics { public async $list3Y(): Promise { try { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const query = this.getQueryForDays(43200, "3 YEAR"); // 12h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); diff --git a/backend/src/database.ts b/backend/src/database.ts index 9f2655016..596ce2364 100644 --- a/backend/src/database.ts +++ b/backend/src/database.ts @@ -1,5 +1,5 @@ import config from './config'; -import { createPool } from 'mysql2/promise'; +import { createPool, PoolConnection } from 'mysql2/promise'; import logger from './logger'; export class DB { @@ -11,13 +11,24 @@ export class DB { password: config.DATABASE.PASSWORD, connectionLimit: 10, supportBigNumbers: true, - timezone: '+00:00', }); + + static connectionsReady: number[] = []; + + static async getConnection() { + const connection: PoolConnection = await DB.pool.getConnection(); + const connectionId = connection['connection'].connectionId; + if (!DB.connectionsReady.includes(connectionId)) { + await connection.query(`SET time_zone='+00:00';`); + this.connectionsReady.push(connectionId); + } + return connection; + } } export async function checkDbConnection() { try { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); logger.info('Database connection established.'); connection.release(); } catch (e) { diff --git a/backend/src/index.ts b/backend/src/index.ts index 0a6080b16..d4b55e078 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -5,7 +5,7 @@ import * as WebSocket from 'ws'; import * as cluster from 'cluster'; import axios from 'axios'; -import { checkDbConnection } from './database'; +import { checkDbConnection, DB } from './database'; import config from './config'; import routes from './routes'; import blocks from './api/blocks'; @@ -180,8 +180,8 @@ class Server { try { blocks.$generateBlockDatabase(); - mining.$generateNetworkHashrateHistory(); - mining.$generatePoolHashrateHistory(); + await mining.$generateNetworkHashrateHistory(); + await mining.$generatePoolHashrateHistory(); } catch (e) { logger.err(`Unable to run indexing right now, trying again later. ` + e); } diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index 041086f73..0af5e2252 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -8,7 +8,7 @@ class BlocksRepository { * Save indexed block data in the database */ public async $saveBlockInDatabase(block: BlockExtended) { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { const query = `INSERT INTO blocks( @@ -70,7 +70,7 @@ class BlocksRepository { return []; } - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { const [rows]: any[] = await connection.query(` SELECT height @@ -116,7 +116,7 @@ class BlocksRepository { query += ` GROUP by pools.id`; - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { const [rows] = await connection.query(query, params); connection.release(); @@ -154,7 +154,7 @@ class BlocksRepository { } // logger.debug(query); - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { const [rows] = await connection.query(query, params); connection.release(); @@ -194,7 +194,7 @@ class BlocksRepository { query += ` blockTimestamp BETWEEN FROM_UNIXTIME('${from}') AND FROM_UNIXTIME('${to}')`; // logger.debug(query); - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { const [rows] = await connection.query(query, params); connection.release(); @@ -217,7 +217,7 @@ class BlocksRepository { LIMIT 1;`; // logger.debug(query); - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { const [rows]: any[] = await connection.query(query); connection.release(); @@ -253,7 +253,7 @@ class BlocksRepository { LIMIT 10`; // logger.debug(query); - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { const [rows] = await connection.query(query, params); connection.release(); @@ -274,7 +274,7 @@ class BlocksRepository { * Get one block by height */ public async $getBlockByHeight(height: number): Promise { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { const [rows]: any[] = await connection.query(` SELECT *, UNIX_TIMESTAMP(blocks.blockTimestamp) as blockTimestamp, @@ -305,7 +305,7 @@ class BlocksRepository { public async $getBlocksDifficulty(interval: string | null): Promise { interval = Common.getSqlInterval(interval); - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); // :D ... Yeah don't ask me about this one https://stackoverflow.com/a/40303162 // Basically, using temporary user defined fields, we are able to extract all @@ -356,7 +356,7 @@ class BlocksRepository { } public async $getOldestIndexedBlockHeight(): Promise { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { const [rows]: any[] = await connection.query(`SELECT MIN(height) as minHeight FROM blocks`); connection.release(); diff --git a/backend/src/repositories/HashratesRepository.ts b/backend/src/repositories/HashratesRepository.ts index 749d3cb57..5237e6cb7 100644 --- a/backend/src/repositories/HashratesRepository.ts +++ b/backend/src/repositories/HashratesRepository.ts @@ -20,9 +20,9 @@ class HashratesRepository { } query = query.slice(0, -1); - const connection = await DB.pool.getConnection(); + let connection; try { - // logger.debug(query); + connection = await DB.getConnection(); await connection.query(query); connection.release(); } catch (e: any) { @@ -35,18 +35,16 @@ class HashratesRepository { public async $getNetworkDailyHashrate(interval: string | null): Promise { interval = Common.getSqlInterval(interval); - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); let query = `SELECT UNIX_TIMESTAMP(hashrate_timestamp) as timestamp, avg_hashrate as avgHashrate FROM hashrates`; if (interval) { query += ` WHERE hashrate_timestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW() - AND hashrates.type = 'daily' - AND pool_id IS NULL`; + AND hashrates.type = 'daily'`; } else { - query += ` WHERE hashrates.type = 'daily' - AND pool_id IS NULL`; + query += ` WHERE hashrates.type = 'daily'`; } query += ` ORDER by hashrate_timestamp`; @@ -64,9 +62,12 @@ class HashratesRepository { } public async $getWeeklyHashrateTimestamps(): Promise { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); - const query = `SELECT UNIX_TIMESTAMP(hashrate_timestamp) as timestamp FROM hashrates where type = 'weekly' GROUP BY hashrate_timestamp`; + const query = `SELECT UNIX_TIMESTAMP(hashrate_timestamp) as timestamp + FROM hashrates + WHERE type = 'weekly' + GROUP BY hashrate_timestamp`; try { const [rows]: any[] = await connection.query(query); @@ -86,7 +87,7 @@ class HashratesRepository { public async $getPoolsWeeklyHashrate(interval: string | null): Promise { interval = Common.getSqlInterval(interval); - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const topPoolsId = (await PoolsRepository.$getPoolsInfo('1w')).map((pool) => pool.poolId); let query = `SELECT UNIX_TIMESTAMP(hashrate_timestamp) as timestamp, avg_hashrate as avgHashrate, share, pools.name as poolName @@ -120,7 +121,7 @@ class HashratesRepository { * Returns a pool hashrate history */ public async $getPoolWeeklyHashrate(poolId: number): Promise { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); // Find hashrate boundaries let query = `SELECT MIN(hashrate_timestamp) as firstTimestamp, MAX(hashrate_timestamp) as lastTimestamp @@ -163,7 +164,7 @@ class HashratesRepository { } public async $setLatestRunTimestamp(key: string, val: any = null) { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const query = `UPDATE state SET number = ? WHERE name = ?`; try { @@ -175,7 +176,7 @@ class HashratesRepository { } public async $getLatestRunTimestamp(key: string): Promise { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const query = `SELECT number FROM state WHERE name = ?`; try { diff --git a/backend/src/repositories/PoolsRepository.ts b/backend/src/repositories/PoolsRepository.ts index 3f904888d..4c3fd67ce 100644 --- a/backend/src/repositories/PoolsRepository.ts +++ b/backend/src/repositories/PoolsRepository.ts @@ -8,7 +8,7 @@ class PoolsRepository { * Get all pools tagging info */ public async $getPools(): Promise { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const [rows] = await connection.query('SELECT id, name, addresses, regexes FROM pools;'); connection.release(); return rows; @@ -18,7 +18,7 @@ class PoolsRepository { * Get unknown pool tagging info */ public async $getUnknownPool(): Promise { - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); const [rows] = await connection.query('SELECT id, name FROM pools where name = "Unknown"'); connection.release(); return rows[0]; @@ -42,7 +42,7 @@ class PoolsRepository { ORDER BY COUNT(height) DESC`; // logger.debug(query); - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { const [rows] = await connection.query(query); connection.release(); @@ -64,7 +64,7 @@ class PoolsRepository { LEFT JOIN blocks on pools.id = blocks.pool_id AND blocks.blockTimestamp BETWEEN FROM_UNIXTIME(?) AND FROM_UNIXTIME(?) GROUP BY pools.id`; - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { const [rows] = await connection.query(query, [from, to]); connection.release(); @@ -87,7 +87,7 @@ class PoolsRepository { WHERE pools.id = ?`; // logger.debug(query); - const connection = await DB.pool.getConnection(); + const connection = await DB.getConnection(); try { const [rows] = await connection.query(query, [poolId]); connection.release(); From ab486bfe6e1c124bdc965b1e080f13f7b280bf24 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sun, 13 Mar 2022 11:37:56 +0100 Subject: [PATCH 22/29] Use correct url for blocks-extras API - Fix amountShortner pipe --- ...ifficulty-adjustments-table.component.html | 2 +- ...difficulty-adjustments-table.components.ts | 2 +- frontend/src/app/services/api.service.ts | 2 +- .../app/shared/pipes/amount-shortener.pipe.ts | 45 +++++++++++++------ 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.component.html b/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.component.html index fd881016a..51872c932 100644 --- a/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.component.html +++ b/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.component.html @@ -17,7 +17,7 @@ {{ diffChange.difficultyShorten }} - {{ diffChange.change >= 0 ? '+' : '' }}{{ formatNumber(diffChange.change, locale, '1.2-2') }}% + {{ diffChange.change >= 0 ? '+' : '' }}{{ diffChange.change | amountShortener }}% diff --git a/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.components.ts b/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.components.ts index 24c44fe05..5e8b3ded7 100644 --- a/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.components.ts +++ b/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.components.ts @@ -43,7 +43,7 @@ export class DifficultyAdjustmentsTable implements OnInit { const change = (data.difficulty[i].difficulty / data.difficulty[i - 1].difficulty - 1) * 100; tableData.push(Object.assign(data.difficulty[i], { - change: change, + change: Math.round(change * 100) / 100, difficultyShorten: formatNumber( data.difficulty[i].difficulty / selectedPowerOfTen.divider, this.locale, '1.2-2') + selectedPowerOfTen.unit diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts index 142f26807..da228a833 100644 --- a/frontend/src/app/services/api.service.ts +++ b/frontend/src/app/services/api.service.ts @@ -153,7 +153,7 @@ export class ApiService { getBlocks$(from: number): Observable { return this.httpClient.get( - this.apiBasePath + this.apiBasePath + `/api/v1/blocks-extras` + + this.apiBaseUrl + this.apiBasePath + `/api/v1/blocks-extras` + (from !== undefined ? `/${from}` : ``) ); } diff --git a/frontend/src/app/shared/pipes/amount-shortener.pipe.ts b/frontend/src/app/shared/pipes/amount-shortener.pipe.ts index 49b452cd9..5c58b7513 100644 --- a/frontend/src/app/shared/pipes/amount-shortener.pipe.ts +++ b/frontend/src/app/shared/pipes/amount-shortener.pipe.ts @@ -1,22 +1,39 @@ import { Pipe, PipeTransform } from '@angular/core'; +// https://medium.com/@thunderroid/angular-short-number-suffix-pipe-1k-2m-3b-dded4af82fb4 + @Pipe({ name: 'amountShortener' }) export class AmountShortenerPipe implements PipeTransform { - transform(num: number, ...args: number[]): unknown { - const digits = args[0] || 1; - const lookup = [ - { value: 1, symbol: '' }, - { value: 1e3, symbol: 'k' }, - { value: 1e6, symbol: 'M' }, - { value: 1e9, symbol: 'G' }, - { value: 1e12, symbol: 'T' }, - { value: 1e15, symbol: 'P' }, - { value: 1e18, symbol: 'E' } + transform(number: number, args?: any): any { + if (isNaN(number)) return null; // will only work value is a number + if (number === null) return null; + if (number === 0) return null; + let abs = Math.abs(number); + const rounder = Math.pow(10, 1); + const isNegative = number < 0; // will also work for Negetive numbers + let key = ''; + + const powers = [ + { key: 'E', value: 10e18 }, + { key: 'P', value: 10e15 }, + { key: 'T', value: 10e12 }, + { key: 'B', value: 10e9 }, + { key: 'M', value: 10e6 }, + { key: 'K', value: 1000 } ]; - const rx = /\.0+$|(\.[0-9]*[1-9])0+$/; - var item = lookup.slice().reverse().find((item) => num >= item.value); - return item ? (num / item.value).toFixed(digits).replace(rx, '$1') + item.symbol : '0'; + + for (let i = 0; i < powers.length; i++) { + let reduced = abs / powers[i].value; + reduced = Math.round(reduced * rounder) / rounder; + if (reduced >= 1) { + abs = reduced; + key = powers[i].key; + break; + } + } + + return (isNegative ? '-' : '') + abs + key; } -} +} \ No newline at end of file From bec3f214b55b315338021b9f04c9f249b8dfe429 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sun, 13 Mar 2022 11:38:33 +0100 Subject: [PATCH 23/29] Make sure to set avg_hashrate field to double unsigned --- backend/src/api/database-migration.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/backend/src/api/database-migration.ts b/backend/src/api/database-migration.ts index c9c1da8e8..f68f7f17d 100644 --- a/backend/src/api/database-migration.ts +++ b/backend/src/api/database-migration.ts @@ -6,7 +6,7 @@ import logger from '../logger'; const sleep = (ms: number) => new Promise(res => setTimeout(res, ms)); class DatabaseMigration { - private static currentVersion = 14; + private static currentVersion = 15; private queryTimeout = 120000; private statisticsAddedIndexed = false; @@ -175,6 +175,12 @@ class DatabaseMigration { await this.$executeQuery(connection, 'ALTER TABLE `hashrates` MODIFY `pool_id` SMALLINT UNSIGNED NOT NULL DEFAULT "0"'); } + if (databaseSchemaVersion < 15 && isBitcoin === true) { + logger.warn(`'hashrates' table has been truncated. Re-indexing from scratch.`); + await this.$executeQuery(connection, 'TRUNCATE hashrates;'); // Need to re-index + await this.$executeQuery(connection, 'ALTER TABLE `hashrates` MODIFY `avg_hashrate` DOUBLE UNSIGNED NOT NULL DEFAULT "0"'); + } + connection.release(); } catch (e) { connection.release(); From 0730053d5d3c1ae66e5b40e888450248123a96eb Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sun, 13 Mar 2022 11:38:45 +0100 Subject: [PATCH 24/29] Use bitcoin RPC getblock because esplora returns int for difficulty - Fix some css in mining dashboard --- backend/src/api/bitcoin/bitcoin-api.ts | 4 +- backend/src/api/blocks.ts | 37 +++++----- .../mining-dashboard.component.html | 62 ++++++++-------- .../mining-dashboard.component.scss | 71 ++++++++++--------- .../mining-dashboard.component.ts | 4 +- 5 files changed, 94 insertions(+), 84 deletions(-) diff --git a/backend/src/api/bitcoin/bitcoin-api.ts b/backend/src/api/bitcoin/bitcoin-api.ts index 97a428c23..8d66f82ef 100644 --- a/backend/src/api/bitcoin/bitcoin-api.ts +++ b/backend/src/api/bitcoin/bitcoin-api.ts @@ -70,7 +70,7 @@ class BitcoinApi implements AbstractBitcoinApi { } return this.bitcoindClient.getBlock(hash) - .then((block: IBitcoinApi.Block) => this.convertBlock(block)); + .then((block: IBitcoinApi.Block) => BitcoinApi.convertBlock(block)); } $getAddress(address: string): Promise { @@ -186,7 +186,7 @@ class BitcoinApi implements AbstractBitcoinApi { return esploraTransaction; } - private convertBlock(block: IBitcoinApi.Block): IEsploraApi.Block { + static convertBlock(block: IBitcoinApi.Block): IEsploraApi.Block { return { id: block.hash, height: block.height, diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index 7a9589348..8f066b5a4 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -11,6 +11,7 @@ import { IEsploraApi } from './bitcoin/esplora-api.interface'; import poolsRepository from '../repositories/PoolsRepository'; import blocksRepository from '../repositories/BlocksRepository'; import loadingIndicators from './loading-indicators'; +import BitcoinApi from './bitcoin/bitcoin-api'; class Blocks { private blocks: BlockExtended[] = []; @@ -103,8 +104,8 @@ class Blocks { * @param transactions * @returns BlockExtended */ - private async $getBlockExtended(block: IEsploraApi.Block, transactions: TransactionExtended[]): Promise { - const blockExtended: BlockExtended = Object.assign({extras: {}}, block); + private async $getBlockExtended(block: IEsploraApi.Block, transactions: TransactionExtended[]): Promise { + const blockExtended: BlockExtended = Object.assign({ extras: {} }, block); blockExtended.extras.reward = transactions[0].vout.reduce((acc, curr) => acc + curr.value, 0); blockExtended.extras.coinbaseTx = transactionUtils.stripCoinbaseTransaction(transactions[0]); @@ -112,19 +113,19 @@ class Blocks { blockExtended.extras.coinbaseRaw = coinbaseRaw.hex; if (block.height === 0) { - blockExtended.extras.medianFee = 0; // 50th percentiles - blockExtended.extras.feeRange = [0, 0, 0, 0, 0, 0, 0]; - blockExtended.extras.totalFees = 0; - blockExtended.extras.avgFee = 0; - blockExtended.extras.avgFeeRate = 0; - } else { + blockExtended.extras.medianFee = 0; // 50th percentiles + blockExtended.extras.feeRange = [0, 0, 0, 0, 0, 0, 0]; + blockExtended.extras.totalFees = 0; + blockExtended.extras.avgFee = 0; + blockExtended.extras.avgFeeRate = 0; + } else { const stats = await bitcoinClient.getBlockStats(block.id); blockExtended.extras.medianFee = stats.feerate_percentiles[2]; // 50th percentiles - blockExtended.extras.feeRange = [stats.minfeerate, stats.feerate_percentiles, stats.maxfeerate].flat(); - blockExtended.extras.totalFees = stats.totalfee; - blockExtended.extras.avgFee = stats.avgfee; - blockExtended.extras.avgFeeRate = stats.avgfeerate; - } + blockExtended.extras.feeRange = [stats.minfeerate, stats.feerate_percentiles, stats.maxfeerate].flat(); + blockExtended.extras.totalFees = stats.totalfee; + blockExtended.extras.avgFee = stats.avgfee; + blockExtended.extras.avgFeeRate = stats.avgfeerate; + } if (Common.indexingEnabled()) { let pool: PoolTag; @@ -239,7 +240,7 @@ class Blocks { indexedThisRun = 0; } const blockHash = await bitcoinApi.$getBlockHash(blockHeight); - const block = await bitcoinApi.$getBlock(blockHash); + const block = BitcoinApi.convertBlock(await bitcoinClient.getBlock(blockHash)); const transactions = await this.$getTransactionsExtended(blockHash, block.height, true, true); const blockExtended = await this.$getBlockExtended(block, transactions); await blocksRepository.$saveBlockInDatabase(blockExtended); @@ -276,7 +277,7 @@ class Blocks { if (blockchainInfo.blocks === blockchainInfo.headers) { const heightDiff = blockHeightTip % 2016; const blockHash = await bitcoinApi.$getBlockHash(blockHeightTip - heightDiff); - const block = await bitcoinApi.$getBlock(blockHash); + const block = BitcoinApi.convertBlock(await bitcoinClient.getBlock(blockHash)); this.lastDifficultyAdjustmentTime = block.timestamp; this.currentDifficulty = block.difficulty; @@ -300,7 +301,7 @@ class Blocks { } const blockHash = await bitcoinApi.$getBlockHash(this.currentBlockHeight); - const block = await bitcoinApi.$getBlock(blockHash); + const block = BitcoinApi.convertBlock(await bitcoinClient.getBlock(blockHash)); const txIds: string[] = await bitcoinApi.$getTxIdsForBlock(blockHash); const transactions = await this.$getTransactionsExtended(blockHash, block.height, false); const blockExtended: BlockExtended = await this.$getBlockExtended(block, transactions); @@ -332,14 +333,14 @@ class Blocks { /** * Index a block if it's missing from the database. Returns the block after indexing */ - public async $indexBlock(height: number): Promise { + public async $indexBlock(height: number): Promise { const dbBlock = await blocksRepository.$getBlockByHeight(height); if (dbBlock != null) { return this.prepareBlock(dbBlock); } const blockHash = await bitcoinApi.$getBlockHash(height); - const block = await bitcoinApi.$getBlock(blockHash); + const block = BitcoinApi.convertBlock(await bitcoinClient.getBlock(blockHash)); const transactions = await this.$getTransactionsExtended(blockHash, block.height, true); const blockExtended = await this.$getBlockExtended(block, transactions); diff --git a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html index 0e9ffb14d..63a93a3e4 100644 --- a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html +++ b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html @@ -5,30 +5,32 @@
Reward stats
-
-
-
-
-
Miners Reward
-
- -
in the last 8 blocks
+
+
+
+
+
+
Miners Reward
+
+ +
in the last 8 blocks
+
-
-
-
Reward Per Tx
-
- {{ rewardStats.rewardPerTx | amountShortener }} - sats/tx -
in the last 8 blocks
+
+
Reward Per Tx
+
+ {{ rewardStats.rewardPerTx | amountShortener }} + sats/tx +
in the last 8 blocks
+
-
-
-
Average Fee
-
- {{ rewardStats.feePerTx | amountShortener}} - sats/tx -
in the last 8 blocks
+
+
Average Fee
+
+ {{ rewardStats.feePerTx | amountShortener}} + sats/tx +
in the last 8 blocks
+
@@ -36,24 +38,24 @@
-
+
-
Miners Reward
-
+
Miners Reward
+
-
Reward Per Tx
-
+
Reward Per Tx
+
-
Average Fee
-
+
Average Fee
+
@@ -136,4 +138,4 @@
-
+
\ No newline at end of file diff --git a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.scss b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.scss index 148d589c6..a345be972 100644 --- a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.scss +++ b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.scss @@ -59,50 +59,57 @@ padding-bottom: 3px; } -.fee-estimation-container { +.reward-container { display: flex; - justify-content: space-between; - @media (min-width: 376px) { - flex-direction: row; + flex-direction: row; + justify-content: space-around; + height: 76px; + .shared-block { + color: #ffffff66; + font-size: 12px; } .item { - max-width: 150px; - margin: 0; - width: -webkit-fill-available; - @media (min-width: 376px) { - margin: 0 auto 0px; - } - &:first-child{ + display: table-cell; + padding: 0 5px; + width: 100%; + &:nth-child(1) { display: none; @media (min-width: 485px) { - display: block; + display: table-cell; } @media (min-width: 768px) { display: none; } @media (min-width: 992px) { - display: block; + display: table-cell; } } - &:last-child { - margin-bottom: 0; - } - .card-text span { - color: #ffffff66; - font-size: 12px; - top: 0px; - } - .fee-text{ - border-bottom: 1px solid #ffffff1c; - width: fit-content; - margin: auto; - line-height: 1.45; - padding: 0px 2px; - } - .fiat { - display: block; - font-size: 14px !important; - } + } + .card-text { + font-size: 22px; + margin-top: -9px; + position: relative; + } + .card-text.skeleton { + margin-top: 0px; + } +} + +.more-padding { + padding: 18px; +} + +.card-wrapper { + .card { + height: auto !important; + } + .card-body { + display: flex; + flex: inherit; + text-align: center; + flex-direction: column; + justify-content: space-around; + padding: 22px 20px; } } diff --git a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.ts b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.ts index 606bac5f1..c05c951b3 100644 --- a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.ts +++ b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.ts @@ -36,8 +36,8 @@ export class MiningDashboardComponent implements OnInit { return { 'totalReward': totalReward, - 'rewardPerTx': totalReward / totalTx, - 'feePerTx': totalFee / totalTx, + 'rewardPerTx': Math.round(totalReward / totalTx), + 'feePerTx': Math.round(totalFee / totalTx), } }) ); From edddf25917816a837b8281cd834385903a01c348 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sun, 13 Mar 2022 16:04:49 +0100 Subject: [PATCH 25/29] Remove unnecessary migration version 15 --- backend/src/api/database-migration.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/backend/src/api/database-migration.ts b/backend/src/api/database-migration.ts index f68f7f17d..c9c1da8e8 100644 --- a/backend/src/api/database-migration.ts +++ b/backend/src/api/database-migration.ts @@ -6,7 +6,7 @@ import logger from '../logger'; const sleep = (ms: number) => new Promise(res => setTimeout(res, ms)); class DatabaseMigration { - private static currentVersion = 15; + private static currentVersion = 14; private queryTimeout = 120000; private statisticsAddedIndexed = false; @@ -175,12 +175,6 @@ class DatabaseMigration { await this.$executeQuery(connection, 'ALTER TABLE `hashrates` MODIFY `pool_id` SMALLINT UNSIGNED NOT NULL DEFAULT "0"'); } - if (databaseSchemaVersion < 15 && isBitcoin === true) { - logger.warn(`'hashrates' table has been truncated. Re-indexing from scratch.`); - await this.$executeQuery(connection, 'TRUNCATE hashrates;'); // Need to re-index - await this.$executeQuery(connection, 'ALTER TABLE `hashrates` MODIFY `avg_hashrate` DOUBLE UNSIGNED NOT NULL DEFAULT "0"'); - } - connection.release(); } catch (e) { connection.release(); From 7fd9e27cc28e35b3656ed4ceac4ceb27d4d3493a Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 13 Mar 2022 14:57:17 +0100 Subject: [PATCH 26/29] Add MySQL socket support --- backend/src/config.ts | 2 ++ backend/src/database.ts | 30 +++++++++++++++++++++--------- docker/backend/mempool-config.json | 1 + docker/backend/start.sh | 3 +++ 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/backend/src/config.ts b/backend/src/config.ts index 97c3bb32a..7bb99b429 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -43,6 +43,7 @@ interface IConfig { DATABASE: { ENABLED: boolean; HOST: string, + SOCKET: string | undefined, PORT: number; DATABASE: string; USERNAME: string; @@ -121,6 +122,7 @@ const defaults: IConfig = { 'DATABASE': { 'ENABLED': true, 'HOST': '127.0.0.1', + 'SOCKET': undefined, 'PORT': 3306, 'DATABASE': 'mempool', 'USERNAME': 'mempool', diff --git a/backend/src/database.ts b/backend/src/database.ts index 596ce2364..4f73a1b7d 100644 --- a/backend/src/database.ts +++ b/backend/src/database.ts @@ -1,17 +1,29 @@ import config from './config'; import { createPool, PoolConnection } from 'mysql2/promise'; import logger from './logger'; +import { PoolOptions } from 'mysql2/typings/mysql'; export class DB { - static pool = createPool({ - host: config.DATABASE.HOST, - port: config.DATABASE.PORT, - database: config.DATABASE.DATABASE, - user: config.DATABASE.USERNAME, - password: config.DATABASE.PASSWORD, - connectionLimit: 10, - supportBigNumbers: true, - }); + static poolConfig = ():PoolOptions => { + let poolConfig:PoolOptions = { + port: config.DATABASE.PORT, + database: config.DATABASE.DATABASE, + user: config.DATABASE.USERNAME, + password: config.DATABASE.PASSWORD, + connectionLimit: 10, + supportBigNumbers: true, + timezone: '+00:00', + } + + if (config.DATABASE.SOCKET) + poolConfig.socketPath = config.DATABASE.SOCKET + else + poolConfig.host = config.DATABASE.HOST + + return poolConfig; + } + + static pool = createPool(DB.poolConfig()); static connectionsReady: number[] = []; diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json index 6b2319a59..39d0e5fad 100644 --- a/docker/backend/mempool-config.json +++ b/docker/backend/mempool-config.json @@ -41,6 +41,7 @@ "DATABASE": { "ENABLED": __DATABASE_ENABLED__, "HOST": "__DATABASE_HOST__", + "SOCKET": "__DATABASE_SOCKET__", "PORT": __DATABASE_PORT__, "DATABASE": "__DATABASE_DATABASE__", "USERNAME": "__DATABASE_USERNAME__", diff --git a/docker/backend/start.sh b/docker/backend/start.sh index d26a93b08..db610a362 100644 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -42,6 +42,7 @@ __SECOND_CORE_RPC_PASSWORD__=${SECOND_CORE_RPC_PASSWORD:=mempool} # DATABASE __DATABASE_ENABLED__=${DATABASE_ENABLED:=true} __DATABASE_HOST__=${DATABASE_HOST:=127.0.0.1} +__DATABASE_SOCKET__=${DATABASE_SOCKET:=""} __DATABASE_PORT__=${DATABASE_PORT:=3306} __DATABASE_DATABASE__=${DATABASE_DATABASE:=mempool} __DATABASE_USERNAME__=${DATABASE_USERNAME:=mempool} @@ -111,6 +112,8 @@ sed -i "s/__SECOND_CORE_RPC_PASSWORD__/${__SECOND_CORE_RPC_PASSWORD__}/g" mempoo sed -i "s/__DATABASE_ENABLED__/${__DATABASE_ENABLED__}/g" mempool-config.json sed -i "s/__DATABASE_HOST__/${__DATABASE_HOST__}/g" mempool-config.json +sed -i "s/__DATABASE_SOCKET__/${__DATABASE_SOCKET__}/g" mempool-config.json + sed -i "s/__DATABASE_PORT__/${__DATABASE_PORT__}/g" mempool-config.json sed -i "s/__DATABASE_DATABASE__/${__DATABASE_DATABASE__}/g" mempool-config.json sed -i "s/__DATABASE_USERNAME__/${__DATABASE_USERNAME__}/g" mempool-config.json From 465529b03f518feabfc5abbfc7c2762e9b84a7bf Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 13 Mar 2022 15:09:16 +0100 Subject: [PATCH 27/29] sed and config fix for MySQL socket, accept CLA for @dsbaars --- backend/src/database.ts | 2 +- contributors/dsbaars.txt | 3 +++ docker/backend/start.sh | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 contributors/dsbaars.txt diff --git a/backend/src/database.ts b/backend/src/database.ts index 4f73a1b7d..b106c6ec9 100644 --- a/backend/src/database.ts +++ b/backend/src/database.ts @@ -15,7 +15,7 @@ export class DB { timezone: '+00:00', } - if (config.DATABASE.SOCKET) + if (config.DATABASE.SOCKET && config.DATABASE.SOCKET != "") poolConfig.socketPath = config.DATABASE.SOCKET else poolConfig.host = config.DATABASE.HOST diff --git a/contributors/dsbaars.txt b/contributors/dsbaars.txt new file mode 100644 index 000000000..8e4dcbb9a --- /dev/null +++ b/contributors/dsbaars.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 January 25, 2022. + +Signed: dsbaars \ No newline at end of file diff --git a/docker/backend/start.sh b/docker/backend/start.sh index db610a362..1d8c0d1fc 100644 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -112,7 +112,7 @@ sed -i "s/__SECOND_CORE_RPC_PASSWORD__/${__SECOND_CORE_RPC_PASSWORD__}/g" mempoo sed -i "s/__DATABASE_ENABLED__/${__DATABASE_ENABLED__}/g" mempool-config.json sed -i "s/__DATABASE_HOST__/${__DATABASE_HOST__}/g" mempool-config.json -sed -i "s/__DATABASE_SOCKET__/${__DATABASE_SOCKET__}/g" mempool-config.json +sed -i "s!__DATABASE_SOCKET__!${__DATABASE_SOCKET__}!g" mempool-config.json sed -i "s/__DATABASE_PORT__/${__DATABASE_PORT__}/g" mempool-config.json sed -i "s/__DATABASE_DATABASE__/${__DATABASE_DATABASE__}/g" mempool-config.json From 2023d366036cc7b3a3249008d662559a6c0190ba Mon Sep 17 00:00:00 2001 From: wiz Date: Mon, 14 Mar 2022 13:11:04 +0000 Subject: [PATCH 28/29] Cleanup MySQL unix socket code and add to sample config --- backend/mempool-config.sample.json | 1 + backend/src/config.ts | 4 ++-- backend/src/database.ts | 9 +++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index 5c45838ee..b5c4b8d53 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -44,6 +44,7 @@ "ENABLED": true, "HOST": "127.0.0.1", "PORT": 3306, + "SOCKET": "/var/run/mysql/mysql.sock", "DATABASE": "mempool", "USERNAME": "mempool", "PASSWORD": "mempool" diff --git a/backend/src/config.ts b/backend/src/config.ts index 7bb99b429..9ceb66e59 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -43,7 +43,7 @@ interface IConfig { DATABASE: { ENABLED: boolean; HOST: string, - SOCKET: string | undefined, + SOCKET: string, PORT: number; DATABASE: string; USERNAME: string; @@ -122,7 +122,7 @@ const defaults: IConfig = { 'DATABASE': { 'ENABLED': true, 'HOST': '127.0.0.1', - 'SOCKET': undefined, + 'SOCKET': '', 'PORT': 3306, 'DATABASE': 'mempool', 'USERNAME': 'mempool', diff --git a/backend/src/database.ts b/backend/src/database.ts index b106c6ec9..55be0ffc3 100644 --- a/backend/src/database.ts +++ b/backend/src/database.ts @@ -15,10 +15,11 @@ export class DB { timezone: '+00:00', } - if (config.DATABASE.SOCKET && config.DATABASE.SOCKET != "") - poolConfig.socketPath = config.DATABASE.SOCKET - else - poolConfig.host = config.DATABASE.HOST + if (config.DATABASE.SOCKET !== "") { + poolConfig.socketPath = config.DATABASE.SOCKET; + } else { + poolConfig.host = config.DATABASE.HOST; + } return poolConfig; } From f466498988174fc5beb4ab07aa5ffc12cc04fa71 Mon Sep 17 00:00:00 2001 From: softsimon Date: Sun, 6 Mar 2022 13:50:01 +0100 Subject: [PATCH 29/29] Address page highlight and transfer value --- .../components/address/address.component.html | 2 +- .../components/amount/amount.component.html | 4 ++-- .../app/components/amount/amount.component.ts | 1 + .../transactions-list.component.html | 24 +++++++++++++------ .../transactions-list.component.scss | 12 +++++++++- .../transactions-list.component.ts | 24 +++++++++++++++---- .../src/app/interfaces/electrs.interface.ts | 2 +- 7 files changed, 53 insertions(+), 16 deletions(-) diff --git a/frontend/src/app/components/address/address.component.html b/frontend/src/app/components/address/address.component.html index c61680ff4..0c030f5de 100644 --- a/frontend/src/app/components/address/address.component.html +++ b/frontend/src/app/components/address/address.component.html @@ -62,7 +62,7 @@
- +
diff --git a/frontend/src/app/components/amount/amount.component.html b/frontend/src/app/components/amount/amount.component.html index 07f669a81..c4946ddf8 100644 --- a/frontend/src/app/components/amount/amount.component.html +++ b/frontend/src/app/components/amount/amount.component.html @@ -1,12 +1,12 @@ - {{ conversions.USD * (satoshis / 100000000) | currency:'USD':'symbol':'1.2-2' }} + {{ addPlus && satoshis >= 0 ? '+' : '' }}{{ conversions.USD * (satoshis / 100000000) | currency:'USD':'symbol':'1.2-2' }} Confidential - ‎{{ satoshis / 100000000 | number : digitsInfo }} + ‎{{ addPlus && satoshis >= 0 ? '+' : '' }}{{ satoshis / 100000000 | number : digitsInfo }} L- tL- t diff --git a/frontend/src/app/components/amount/amount.component.ts b/frontend/src/app/components/amount/amount.component.ts index 068acf1a7..f9bba4318 100644 --- a/frontend/src/app/components/amount/amount.component.ts +++ b/frontend/src/app/components/amount/amount.component.ts @@ -18,6 +18,7 @@ export class AmountComponent implements OnInit, OnDestroy { @Input() satoshis: number; @Input() digitsInfo = '1.8-8'; @Input() noFiat = false; + @Input() addPlus = false; constructor( private stateService: StateService, 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 1470e6211..790f38cfc 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.html +++ b/frontend/src/app/components/transactions-list/transactions-list.component.html @@ -21,7 +21,10 @@ - +
@@ -143,7 +146,10 @@ - +
{{ vout.scriptpubkey_address | shortenString : 16 }} @@ -242,13 +248,13 @@ -
+
{{ tx.fee / (tx.weight / 4) | feeRounding }} sat/vB  – {{ tx.fee | number }} sat
- + -   - - + + +
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 5a96d2d3c..4f20be835 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.scss +++ b/frontend/src/app/components/transactions-list/transactions-list.component.scss @@ -1,10 +1,12 @@ .arrow-td { width: 20px; + padding-top: 0; + padding-bottom: 0; } .green, .grey, .red { font-size: 16px; - top: -2px; + top: 1px; position: relative; @media( min-width: 576px){ font-size: 19px; @@ -119,3 +121,11 @@ h2 { line-height: 1; } + +.highlight { + background-color: #181b2d; +} + +.summary { + margin-top: 10px; +} 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 7d3c5d0e4..63c5c7367 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.ts +++ b/frontend/src/app/components/transactions-list/transactions-list.component.ts @@ -1,11 +1,11 @@ import { Component, OnInit, Input, ChangeDetectionStrategy, OnChanges, Output, EventEmitter, ChangeDetectorRef } from '@angular/core'; import { StateService } from '../../services/state.service'; -import { Observable, forkJoin, ReplaySubject, BehaviorSubject, merge, of, Subject, Subscription } from 'rxjs'; -import { Outspend, Transaction } from '../../interfaces/electrs.interface'; +import { Observable, forkJoin, ReplaySubject, BehaviorSubject, merge, Subscription } from 'rxjs'; +import { Outspend, Transaction, Vin, Vout } from '../../interfaces/electrs.interface'; import { ElectrsApiService } from '../../services/electrs-api.service'; import { environment } from 'src/environments/environment'; import { AssetsService } from 'src/app/services/assets.service'; -import { map, share, switchMap, tap } from 'rxjs/operators'; +import { map, switchMap } from 'rxjs/operators'; import { BlockExtended } from 'src/app/interfaces/node-api.interface'; @Component({ @@ -23,6 +23,7 @@ export class TransactionsListComponent implements OnInit, OnChanges { @Input() transactionPage = false; @Input() errorUnblinded = false; @Input() outputIndex: number; + @Input() address: string = ''; @Output() loadMore = new EventEmitter(); @@ -98,6 +99,21 @@ export class TransactionsListComponent implements OnInit, OnChanges { if (this.outspends[i]) { return; } + + if (this.address) { + const addressIn = tx.vout + .filter((v: Vout) => v.scriptpubkey_address === this.address) + .map((v: Vout) => v.value || 0) + .reduce((a: number, b: number) => a + b, 0); + + const addressOut = tx.vin + .filter((v: Vin) => v.prevout && v.prevout.scriptpubkey_address === this.address) + .map((v: Vin) => v.prevout.value || 0) + .reduce((a: number, b: number) => a + b, 0); + + tx['addressValue'] = addressIn || -addressOut; + } + observableObject[i] = this.electrsApiService.getOutspends$(tx.txid); }); this.refreshOutspends$.next(observableObject); @@ -119,7 +135,7 @@ export class TransactionsListComponent implements OnInit, OnChanges { } getTotalTxOutput(tx: Transaction) { - return tx.vout.map((v: any) => v.value || 0).reduce((a: number, b: number) => a + b); + return tx.vout.map((v: Vout) => v.value || 0).reduce((a: number, b: number) => a + b); } switchCurrency() { diff --git a/frontend/src/app/interfaces/electrs.interface.ts b/frontend/src/app/interfaces/electrs.interface.ts index 803a7227e..ecd0ac598 100644 --- a/frontend/src/app/interfaces/electrs.interface.ts +++ b/frontend/src/app/interfaces/electrs.interface.ts @@ -72,7 +72,7 @@ export interface Vout { scriptpubkey: string; scriptpubkey_asm: string; scriptpubkey_type: string; - scriptpubkey_address: string; + scriptpubkey_address?: string; value: number; // Elements valuecommitment?: number;