diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 23df91b1e..7a43cd5ef 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,6 +1,6 @@ # These are supported funding model platforms -github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +github: ['mempool'] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username diff --git a/.github/workflows/on-tag.yml b/.github/workflows/on-tag.yml index cde388972..c45e453c7 100644 --- a/.github/workflows/on-tag.yml +++ b/.github/workflows/on-tag.yml @@ -34,6 +34,9 @@ jobs: - name: Checkout project uses: actions/checkout@v2 + - name: Init repo for Dockerization + run: docker/init.sh "$TAG" + - name: Set up QEMU uses: docker/setup-qemu-action@v1 id: qemu diff --git a/backend/docker/master b/backend/docker/master deleted file mode 100644 index 7cfb44686..000000000 --- a/backend/docker/master +++ /dev/null @@ -1 +0,0 @@ -9d02ab1eb5ffb60d38128df903e47e11b95f13d5 diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index fe9122572..e53df38f2 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -48,12 +48,5 @@ "BISQ_MARKETS": { "ENABLED": false, "DATA_PATH": "/bisq/statsnode-data/btc_mainnet/db" - }, - "SPONSORS": { - "ENABLED": false, - "BTCPAY_URL": "", - "BTCPAY_AUTH": "", - "BTCPAY_WEBHOOK_URL": "", - "TWITTER_BEARER_AUTH": "" } } diff --git a/backend/src/api/donations.ts b/backend/src/api/donations.ts deleted file mode 100644 index 32700baae..000000000 --- a/backend/src/api/donations.ts +++ /dev/null @@ -1,198 +0,0 @@ -import config from '../config'; -import axios from 'axios'; -import { DB } from '../database'; -import logger from '../logger'; - -class Donations { - private notifyDonationStatusCallback: ((invoiceId: string) => void) | undefined; - private options = { - baseURL: config.SPONSORS.BTCPAY_URL, - headers: { - 'Content-Type': 'application/json', - 'Authorization': config.SPONSORS.BTCPAY_AUTH, - }, - timeout: 10000, - }; - - sponsorsCache: any[] = []; - - constructor() {} - - public async $updateCache() { - try { - this.sponsorsCache = await this.$getDonationsFromDatabase('handle, image'); - } catch (e) { - logger.warn('Setting sponsorsCache failed ' + e.message || e); - } - } - - setNotfyDonationStatusCallback(fn: any): void { - this.notifyDonationStatusCallback = fn; - } - - async $createRequest(amount: number, orderId: string): Promise { - logger.notice('New invoice request. Handle: ' + orderId + ' Amount: ' + amount + ' BTC'); - - const postData = { - 'price': amount, - 'orderId': orderId, - 'currency': 'BTC', - 'itemDesc': 'Sponsor mempool.space', - 'notificationUrl': config.SPONSORS.BTCPAY_WEBHOOK_URL, - 'redirectURL': 'https://mempool.space/about', - }; - const response = await axios.post('/invoices', postData, this.options); - return { - id: response.data.data.id, - amount: parseFloat(response.data.data.btcPrice), - addresses: response.data.data.addresses, - }; - } - - async $handleWebhookRequest(data: any): Promise { - if (!data || !data.id) { - return; - } - const response = await this.$getStatus(data.id); - logger.notice(`Received BTCPayServer webhook. Invoice ID: ${data.id} Status: ${response.status} BTC Paid: ${response.btcPaid}`); - if (response.status !== 'complete' && response.status !== 'confirmed' && response.status !== 'paid') { - return; - } - - if (this.notifyDonationStatusCallback) { - this.notifyDonationStatusCallback(data.id); - } - - if (parseFloat(response.btcPaid) < 0.01) { - return; - } - - if (response.orderId !== '') { - try { - const userData = await this.$getTwitterUserData(response.orderId); - const imageUrl = userData.profile_image_url.replace('normal', '200x200'); - const imageBlob = await this.$downloadProfileImageBlob(imageUrl); - - logger.debug('Creating database entry for donation with invoice id: ' + response.id); - await this.$addDonationToDatabase(response.btcPaid, userData.screen_name, userData.id, response.id, imageUrl, imageBlob); - this.$updateCache(); - } catch (e) { - logger.err(`Error fetching twitter data for handle ${response.orderId}: ${e.message}`); - } - } - } - - getSponsorImage(id: string): any | undefined { - const sponsor = this.sponsorsCache.find((s) => s.handle === id); - if (sponsor) { - return sponsor.image; - } - } - - async $getDonationsFromDatabase(fields: string): Promise { - try { - const connection = await DB.pool.getConnection(); - const query = `SELECT ${fields} FROM donations ORDER BY id DESC`; - const [rows] = await connection.query(query); - connection.release(); - return rows; - } catch (e) { - logger.err('$getDonationsFromDatabase() error: ' + e.message || e); - return []; - } - } - - private async $getOldDonations(): Promise { - try { - const connection = await DB.pool.getConnection(); - const query = `SELECT * FROM donations WHERE twitter_id IS NULL AND handle != ''`; - const [rows] = await connection.query(query); - connection.release(); - return rows; - } catch (e) { - logger.err('$getLegacyDonations() error' + e.message || e); - return []; - } - } - - private async $getStatus(id: string): Promise { - logger.debug('Fetching status for invoice: ' + id); - const response = await axios.get('/invoices/' + id, this.options); - logger.debug('Invoice status received: ' + JSON.stringify(response.data)); - return response.data.data; - } - - private async $addDonationToDatabase(btcPaid: number, handle: string, twitter_id: number | null, - orderId: string, imageUrl: string, image: string): Promise { - try { - const connection = await DB.pool.getConnection(); - const query = `INSERT IGNORE INTO donations(added, amount, handle, twitter_id, order_id, imageUrl, image) VALUES (NOW(), ?, ?, ?, ?, ?, FROM_BASE64(?))`; - const params: (string | number | null)[] = [ - btcPaid, - handle, - twitter_id, - orderId, - imageUrl, - image, - ]; - const [result]: any = await connection.query(query, params); - connection.release(); - } catch (e) { - logger.err('$addDonationToDatabase() error' + e.message || e); - } - } - - private async $updateDonation(id: number, handle: string, twitterId: number, imageUrl: string, image: string): Promise { - try { - const connection = await DB.pool.getConnection(); - const query = `UPDATE donations SET handle = ?, twitter_id = ?, imageUrl = ?, image = FROM_BASE64(?) WHERE id = ?`; - const params: (string | number)[] = [ - handle, - twitterId, - imageUrl, - image, - id, - ]; - const [result]: any = await connection.query(query, params); - connection.release(); - } catch (e) { - logger.err('$updateDonation() error' + e.message || e); - } - } - - private async $getTwitterUserData(handle: string): Promise { - logger.debug('Fetching Twitter API data...'); - const res = await axios.get(`https://api.twitter.com/1.1/users/show.json?screen_name=${handle}`, { - headers: { - Authorization: 'Bearer ' + config.SPONSORS.TWITTER_BEARER_AUTH - }, - timeout: 10000, - }); - logger.debug('Twitter user data fetched:' + JSON.stringify(res.data)); - return res.data; - } - - private async $downloadProfileImageBlob(url: string): Promise { - logger.debug('Fetching image blob...'); - const res = await axios.get(url, { responseType: 'arraybuffer', timeout: 10000 }); - logger.debug('Image downloaded.'); - return Buffer.from(res.data, 'utf8').toString('base64'); - } - - private async refreshSponsors(): Promise { - const oldDonations = await this.$getOldDonations(); - oldDonations.forEach(async (donation: any) => { - logger.debug('Migrating donation for handle: ' + donation.handle); - try { - const twitterData = await this.$getTwitterUserData(donation.handle); - const imageUrl = twitterData.profile_image_url.replace('normal', '200x200'); - const imageBlob = await this.$downloadProfileImageBlob(imageUrl); - await this.$updateDonation(donation.id, twitterData.screen_name, twitterData.id, imageUrl, imageBlob); - } catch (e) { - logger.err('Failed to migrate donation for handle: ' + donation.handle + '. ' + (e.message || e)); - } - }); - } -} - -export default new Donations(); diff --git a/backend/src/config.ts b/backend/src/config.ts index d98b1b1ec..1d46ccfcb 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -51,13 +51,6 @@ interface IConfig { ENABLED: boolean; DATA_PATH: string; }; - SPONSORS: { - ENABLED: boolean; - BTCPAY_URL: string; - BTCPAY_AUTH: string; - BTCPAY_WEBHOOK_URL: string; - TWITTER_BEARER_AUTH: string; - }; } const defaults: IConfig = { @@ -111,13 +104,6 @@ const defaults: IConfig = { 'ENABLED': false, 'DATA_PATH': '/bisq/statsnode-data/btc_mainnet/db' }, - 'SPONSORS': { - 'ENABLED': false, - 'BTCPAY_URL': '', - 'BTCPAY_AUTH': '', - 'BTCPAY_WEBHOOK_URL': '', - 'TWITTER_BEARER_AUTH': '' - } }; class Config implements IConfig { @@ -130,7 +116,6 @@ class Config implements IConfig { STATISTICS: IConfig['STATISTICS']; BISQ_BLOCKS: IConfig['BISQ_BLOCKS']; BISQ_MARKETS: IConfig['BISQ_MARKETS']; - SPONSORS: IConfig['SPONSORS']; constructor() { const configs = this.merge(configFile, defaults); @@ -143,7 +128,6 @@ class Config implements IConfig { this.STATISTICS = configs.STATISTICS; this.BISQ_BLOCKS = configs.BISQ_BLOCKS; this.BISQ_MARKETS = configs.BISQ_MARKETS; - this.SPONSORS = configs.SPONSORS; } merge = (...objects: object[]): IConfig => { diff --git a/backend/src/index.ts b/backend/src/index.ts index e78691aed..2389d38b5 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -1,7 +1,6 @@ import { Express, Request, Response, NextFunction } from 'express'; import * as express from 'express'; import * as http from 'http'; -import * as https from 'https'; import * as WebSocket from 'ws'; import * as cluster from 'cluster'; import axios from 'axios'; @@ -17,7 +16,6 @@ import websocketHandler from './api/websocket-handler'; import fiatConversion from './api/fiat-conversion'; import bisq from './api/bisq/bisq'; import bisqMarkets from './api/bisq/markets'; -import donations from './api/donations'; import logger from './logger'; import backendInfo from './api/backend-info'; import loadingIndicators from './api/loading-indicators'; @@ -25,7 +23,7 @@ import mempool from './api/mempool'; class Server { private wss: WebSocket.Server | undefined; - private server: https.Server | http.Server | undefined; + private server: http.Server | undefined; private app: Express; private currentBackendRetryInterval = 5; @@ -87,10 +85,6 @@ class Server { fiatConversion.startService(); - if (config.SPONSORS.ENABLED) { - donations.$updateCache(); - } - this.setUpHttpApiRoutes(); this.setUpWebsocketHandling(); this.runMainUpdateLoop(); @@ -144,7 +138,6 @@ class Server { statistics.setNewStatisticsEntryCallback(websocketHandler.handleNewStatistic.bind(websocketHandler)); blocks.setNewBlockCallback(websocketHandler.handleNewBlock.bind(websocketHandler)); memPool.setMempoolChangedCallback(websocketHandler.handleMempoolChange.bind(websocketHandler)); - donations.setNotfyDonationStatusCallback(websocketHandler.handleNewDonation.bind(websocketHandler)); fiatConversion.setProgressChangedCallback(websocketHandler.handleNewConversionRates.bind(websocketHandler)); loadingIndicators.setProgressChangedCallback(websocketHandler.handleLoadingChanged.bind(websocketHandler)); } @@ -156,6 +149,24 @@ class Server { .get(config.MEMPOOL.API_URL_PREFIX + 'fees/mempool-blocks', routes.getMempoolBlocks) .get(config.MEMPOOL.API_URL_PREFIX + 'backend-info', routes.getBackendInfo) .get(config.MEMPOOL.API_URL_PREFIX + 'init-data', routes.getInitData) + .get(config.MEMPOOL.API_URL_PREFIX + 'donations', async (req, res) => { + try { + const response = await axios.get('https://mempool.space/api/v1/donations', { responseType: 'stream', timeout: 10000 }); + response.data.pipe(res); + } catch (e) { + res.status(500).end(); + } + }) + .get(config.MEMPOOL.API_URL_PREFIX + 'donations/images/:id', async (req, res) => { + try { + const response = await axios.get('https://mempool.space/api/v1/donations/images/' + req.params.id, { + responseType: 'stream', timeout: 10000 + }); + response.data.pipe(res); + } catch (e) { + res.status(500).end(); + } + }) ; if (config.STATISTICS.ENABLED && config.DATABASE.ENABLED) { @@ -195,35 +206,6 @@ class Server { ; } - if (config.SPONSORS.ENABLED) { - this.app - .get(config.MEMPOOL.API_URL_PREFIX + 'donations', routes.getDonations.bind(routes)) - .get(config.MEMPOOL.API_URL_PREFIX + 'donations/images/:id', routes.getSponsorImage.bind(routes)) - .post(config.MEMPOOL.API_URL_PREFIX + 'donations', routes.createDonationRequest.bind(routes)) - .post(config.MEMPOOL.API_URL_PREFIX + 'donations-webhook', routes.donationWebhook.bind(routes)) - ; - } else { - this.app - .get(config.MEMPOOL.API_URL_PREFIX + 'donations', async (req, res) => { - try { - const response = await axios.get('https://mempool.space/api/v1/donations', { responseType: 'stream', timeout: 10000 }); - response.data.pipe(res); - } catch (e) { - res.status(500).end(); - } - }) - .get(config.MEMPOOL.API_URL_PREFIX + 'donations/images/:id', async (req, res) => { - try { - const response = await axios.get('https://mempool.space/api/v1/donations/images/' + req.params.id, { - responseType: 'stream', timeout: 10000 - }); - response.data.pipe(res); - } catch (e) { - res.status(500).end(); - } - }); - } - if (config.MEMPOOL.BACKEND !== 'esplora') { this.app .get(config.MEMPOOL.API_URL_PREFIX + 'mempool', routes.getMempool) diff --git a/backend/src/routes.ts b/backend/src/routes.ts index f451d914d..c03c08b75 100644 --- a/backend/src/routes.ts +++ b/backend/src/routes.ts @@ -8,10 +8,9 @@ import mempool from './api/mempool'; import bisq from './api/bisq/bisq'; import websocketHandler from './api/websocket-handler'; import bisqMarket from './api/bisq/markets-api'; -import { OptimizedStatistic, RequiredSpec, TransactionExtended } from './mempool.interfaces'; +import { RequiredSpec, TransactionExtended } from './mempool.interfaces'; import { MarketsApiError } from './api/bisq/interfaces'; import { IEsploraApi } from './api/bitcoin/esplora-api.interface'; -import donations from './api/donations'; import logger from './logger'; import bitcoinApi from './api/bitcoin/bitcoin-api-factory'; import transactionUtils from './api/transaction-utils'; @@ -99,79 +98,6 @@ class Routes { res.json(backendInfo.getBackendInfo()); } - public async createDonationRequest(req: Request, res: Response) { - const constraints: RequiredSpec = { - 'amount': { - required: true, - types: ['@float'] - }, - 'orderId': { - required: true, - types: ['@string'] - } - }; - - const p = this.parseRequestParameters(req.body, constraints); - if (p.error) { - res.status(400).send(p.error); - return; - } - - if (p.orderId !== '' && !/^(@|)[a-zA-Z0-9_]{1,15}$/.test(p.orderId)) { - res.status(400).send('Invalid Twitter handle'); - return; - } - - if (p.amount < 0.001) { - res.status(400).send('Amount needs to be at least 0.001'); - return; - } - - if (p.amount > 1000) { - res.status(400).send('Amount too large'); - return; - } - - try { - const result = await donations.$createRequest(p.amount, p.orderId); - res.json(result); - } catch (e) { - res.status(500).send(e.message); - } - } - - public async getDonations(req: Request, res: Response) { - try { - const result = await donations.$getDonationsFromDatabase('handle, imageUrl'); - res.json(result); - } catch (e) { - res.status(500).send(e.message); - } - } - - public async getSponsorImage(req: Request, res: Response) { - try { - const result = await donations.getSponsorImage(req.params.id); - if (result) { - res.set('Content-Type', 'image/jpeg'); - res.send(result); - } else { - res.status(404).end(); - } - } catch (e) { - res.status(500).send(e.message); - } - } - - public async donationWebhook(req: Request, res: Response) { - try { - donations.$handleWebhookRequest(req.body); - res.end(); - } catch (e) { - res.status(500).send(e); - } - } - public getBisqStats(req: Request, res: Response) { const result = bisq.getStats(); res.json(result); diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 000000000..0a65eba0b --- /dev/null +++ b/docker/README.md @@ -0,0 +1,99 @@ +# Docker + +## Initialization + +In an empty dir create 2 sub-dirs + +```bash +mkdir -p data mysql/data mysql/db-scripts +``` + +In the mysql/db-scripts sub-dir add the mariadb-structure.sql file from the mempool repo + +Your dir should now look like that: + +```bash +$ls -R +.: +data mysql + +./data: + +./mysql: +data db-scripts + +./mysql/data: + +./mysql/db-scripts: +mariadb-structure.sql +``` + +In the main dir add the following docker-compose.yml + +```bash +version: "3.7" + +services: + web: + image: mempool/frontend:latest + user: "1000:1000" + restart: on-failure + stop_grace_period: 1m + command: "./wait-for db:3306 --timeout=720 -- nginx -g 'daemon off;'" + ports: + - 80:8080 + environment: + FRONTEND_HTTP_PORT: "8080" + BACKEND_MAINNET_HTTP_HOST: "api" + api: + image: mempool/backend:latest + user: "1000:1000" + restart: on-failure + stop_grace_period: 1m + command: "./wait-for-it.sh db:3306 --timeout=720 --strict -- ./start.sh" + volumes: + - ./data:/backend/cache + environment: + RPC_HOST: "127.0.0.1" + RPC_PORT: "8332" + RPC_USER: "mempool" + RPC_PASS: "mempool" + ELECTRS_HOST: "127.0.0.1" + ELECTRS_PORT: "50002" + MYSQL_HOST: "db" + MYSQL_PORT: "3306" + MYSQL_DATABASE: "mempool" + MYSQL_USER: "mempool" + MYSQL_PASS: "mempool" + BACKEND_MAINNET_HTTP_PORT: "8999" + CACHE_DIR: "/backend/cache/" + db: + image: mariadb:10.5.8 + user: "1000:1000" + restart: on-failure + stop_grace_period: 1m + volumes: + - ./mysql/data:/var/lib/mysql + - ./mysql/db-scripts:/docker-entrypoint-initdb.d + environment: + MYSQL_DATABASE: "mempool" + MYSQL_USER: "mempool" + MYSQL_PASSWORD: "mempool" + MYSQL_ROOT_PASSWORD: "admin" + +``` + +You can update all the environment variables inside the API container, especially the RPC and ELECTRS ones + +## Run it + +To run our docker-compose use the following cmd: + +```bash +docker-compose up +``` + +If everything went okay you should see the beautiful mempool :grin: + +If you get stuck on "loading blocks", this means the websocket can't connect. +Check your nginx proxy setup, firewalls, etc. and open an issue if you need help. diff --git a/backend/Dockerfile b/docker/backend/Dockerfile similarity index 74% rename from backend/Dockerfile rename to docker/backend/Dockerfile index 4ac5e2c97..a0edee986 100644 --- a/backend/Dockerfile +++ b/docker/backend/Dockerfile @@ -3,17 +3,12 @@ FROM node:12-buster-slim AS builder WORKDIR /build COPY . . -RUN sed -i "s!../.git/refs/heads/master!master!g" ./src/api/backend-info.ts - RUN apt-get update RUN apt-get install -y build-essential python3 pkg-config RUN npm ci --production RUN npm i typescript RUN npm run build -RUN mv ./docker/* . -RUN mv ./mempool-config-docker.json ./mempool-config.json - FROM node:12-buster-slim WORKDIR /backend diff --git a/backend/docker/mempool-config-docker.json b/docker/backend/mempool-config.json similarity index 88% rename from backend/docker/mempool-config-docker.json rename to docker/backend/mempool-config.json index 3bd9d64a0..7f3ae6729 100644 --- a/backend/docker/mempool-config-docker.json +++ b/docker/backend/mempool-config.json @@ -27,9 +27,9 @@ "ENABLED": true, "HOST": "__MYSQL_HOST__", "PORT": __MYSQL_PORT__, - "DATABASE": "mempool", - "USERNAME": "mempool", - "PASSWORD": "mempool" + "DATABASE": "__MYSQL_DATABASE__", + "USERNAME": "__MYSQL_USERNAME__", + "PASSWORD": "__MYSQL_PASSWORD__" }, "STATISTICS": { "ENABLED": true, diff --git a/backend/docker/start.sh b/docker/backend/start.sh similarity index 81% rename from backend/docker/start.sh rename to docker/backend/start.sh index e17d337fb..6b01c2632 100644 --- a/backend/docker/start.sh +++ b/docker/backend/start.sh @@ -14,6 +14,9 @@ __ELECTRS_MAINNET_HTTP_PORT__=${ELECTRS_PORT:=50002} # MYSQL __MYSQL_HOST__=${MYSQL_HOST:=127.0.0.1} __MYSQL_PORT__=${MYSQL_PORT:=3306} +__MYSQL_DATABASE__=${MYSQL_DATABASE:=mempool} +__MYSQL_USERNAME__=${MYSQL_USER:=mempool} +__MYSQL_PASSWORD__=${MYSQL_PASS:=mempool} mkdir -p "${__MEMPOOL_BACKEND_MAINNET_CACHE_DIR__}" @@ -25,6 +28,9 @@ sed -i "s/__ELECTRS_MAINNET_HTTP_HOST__/${__ELECTRS_MAINNET_HTTP_HOST__}/g" memp sed -i "s/__ELECTRS_MAINNET_HTTP_PORT__/${__ELECTRS_MAINNET_HTTP_PORT__}/g" mempool-config.json sed -i "s/__MYSQL_HOST__/${__MYSQL_HOST__}/g" mempool-config.json sed -i "s/__MYSQL_PORT__/${__MYSQL_PORT__}/g" mempool-config.json +sed -i "s/__MYSQL_DATABASE__/${__MYSQL_DATABASE__}/g" mempool-config.json +sed -i "s/__MYSQL_USERNAME__/${__MYSQL_USERNAME__}/g" mempool-config.json +sed -i "s/__MYSQL_PASSWORD__/${__MYSQL_PASSWORD__}/g" mempool-config.json sed -i "s!__MEMPOOL_BACKEND_MAINNET_CACHE_DIR__!${__MEMPOOL_BACKEND_MAINNET_CACHE_DIR__}!g" mempool-config.json sed -i "s/__MEMPOOL_BACKEND_MAINNET_HTTP_PORT__/${__MEMPOOL_BACKEND_MAINNET_HTTP_PORT__}/g" mempool-config.json diff --git a/backend/docker/wait-for-it.sh b/docker/backend/wait-for-it.sh similarity index 100% rename from backend/docker/wait-for-it.sh rename to docker/backend/wait-for-it.sh diff --git a/frontend/Dockerfile b/docker/frontend/Dockerfile similarity index 94% rename from frontend/Dockerfile rename to docker/frontend/Dockerfile index e71cccf8c..a9ed8d674 100644 --- a/frontend/Dockerfile +++ b/docker/frontend/Dockerfile @@ -7,8 +7,6 @@ RUN apt-get install -y build-essential rsync RUN npm i RUN npm run build -RUN mv ./docker/* . - FROM nginx:1.17.8-alpine WORKDIR /patch @@ -25,13 +23,12 @@ RUN chmod +x /patch/wait-for RUN chown -R 1000:1000 /patch && chmod -R 755 /patch && \ chown -R 1000:1000 /var/cache/nginx && \ chown -R 1000:1000 /var/log/nginx && \ + chown -R 1000:1000 /etc/nginx/nginx.conf && \ chown -R 1000:1000 /etc/nginx/conf.d RUN touch /var/run/nginx.pid && \ chown -R 1000:1000 /var/run/nginx.pid USER 1000 -EXPOSE 8080 - ENTRYPOINT ["/patch/entrypoint.sh"] CMD ["nginx", "-g", "daemon off;"] diff --git a/frontend/docker/entrypoint.sh b/docker/frontend/entrypoint.sh similarity index 63% rename from frontend/docker/entrypoint.sh rename to docker/frontend/entrypoint.sh index 04085121b..7ebe5632c 100644 --- a/frontend/docker/entrypoint.sh +++ b/docker/frontend/entrypoint.sh @@ -1,8 +1,13 @@ #!/bin/sh __MEMPOOL_BACKEND_MAINNET_HTTP_HOST__=${BACKEND_MAINNET_HTTP_HOST:=127.0.0.1} __MEMPOOL_BACKEND_MAINNET_HTTP_PORT__=${BACKEND_MAINNET_HTTP_PORT:=8999} +__MEMPOOL_FRONTEND_HTTP_PORT__=${FRONTEND_HTTP_PORT:=8080} sed -i "s/__MEMPOOL_BACKEND_MAINNET_HTTP_HOST__/${__MEMPOOL_BACKEND_MAINNET_HTTP_HOST__}/g" /etc/nginx/conf.d/nginx-mempool.conf sed -i "s/__MEMPOOL_BACKEND_MAINNET_HTTP_PORT__/${__MEMPOOL_BACKEND_MAINNET_HTTP_PORT__}/g" /etc/nginx/conf.d/nginx-mempool.conf +cp /etc/nginx/nginx.conf /patch/nginx.conf +sed -i "s/__MEMPOOL_FRONTEND_HTTP_PORT__/${__MEMPOOL_FRONTEND_HTTP_PORT__}/g" /patch/nginx.conf +cat /patch/nginx.conf > /etc/nginx/nginx.conf + exec "$@" diff --git a/frontend/docker/wait-for b/docker/frontend/wait-for similarity index 100% rename from frontend/docker/wait-for rename to docker/frontend/wait-for diff --git a/docker/init.sh b/docker/init.sh new file mode 100755 index 000000000..722df3700 --- /dev/null +++ b/docker/init.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +#backend +gitMaster="\.\.\/\.git\/refs\/heads\/master" +git ls-remote https://github.com/mempool/mempool.git $1 | awk '{ print $1}' > ./backend/master +cp ./docker/backend/* ./backend/ +sed -i "s/${gitMaster}/master/g" ./backend/src/api/backend-info.ts + +#frontend +localhostIP="127.0.0.1" +cp ./docker/frontend/* ./frontend +cp ./nginx.conf ./frontend/ +cp ./nginx-mempool.conf ./frontend/ +sed -i "s/${localhostIP}:80/0.0.0.0:__MEMPOOL_FRONTEND_HTTP_PORT__/g" ./frontend/nginx.conf +sed -i "s/${localhostIP}/0.0.0.0/g" ./frontend/nginx.conf +sed -i "s/user nobody;//g" ./frontend/nginx.conf +sed -i "s!/etc/nginx/nginx-mempool.conf!/etc/nginx/conf.d/nginx-mempool.conf!g" ./frontend/nginx.conf +sed -i "s/${localhostIP}:8999/__MEMPOOL_BACKEND_MAINNET_HTTP_HOST__:__MEMPOOL_BACKEND_MAINNET_HTTP_PORT__/g" ./frontend/nginx-mempool.conf diff --git a/frontend/docker/nginx-mempool.conf b/frontend/docker/nginx-mempool.conf deleted file mode 100644 index 5fb0b46e0..000000000 --- a/frontend/docker/nginx-mempool.conf +++ /dev/null @@ -1,62 +0,0 @@ - access_log /var/log/nginx/access_mempool.log; - error_log /var/log/nginx/error_mempool.log; - - root /var/www/mempool/browser; - - index index.html; - - # fallback for all URLs i.e. /address/foo /tx/foo /block/000 - location / { - try_files /$lang/$uri /$lang/$uri/ $uri $uri/ /en-US/$uri @index-redirect; - } - location @index-redirect { - add_header vary accept-language; - rewrite (.*) /$lang/index.html; - } - - # location block using regex are matched in order - - # used to rewrite resources from // to /en-US/ - location ~ ^/(ar|bg|bs|ca|cs|da|de|et|el|es|eo|eu|fa|fr|gl|ko|hr|id|it|he|ka|lv|lt|hu|mk|ms|nl|ja|ka|no|nb|nn|pl|pt|pt-BR|ro|ru|sk|sl|sr|sh|fi|sv|th|tr|uk|vi|zh)/resources/ { - rewrite ^/[a-zA-Z-]*/resources/(.*) /en-US/resources/$1; - } - # used for cookie override - location ~ ^/(ar|bg|bs|ca|cs|da|de|et|el|es|eo|eu|fa|fr|gl|ko|hr|id|it|he|ka|lv|lt|hu|mk|ms|nl|ja|ka|no|nb|nn|pl|pt|pt-BR|ro|ru|sk|sl|sr|sh|fi|sv|th|tr|uk|vi|zh)/ { - try_files $uri $uri/ /$1/index.html =404; - } - - # static API docs - location = /api { - try_files $uri $uri/ /en-US/index.html =404; - } - location = /api/ { - try_files $uri $uri/ /en-US/index.html =404; - } - - # mainnet API - location /api/v1/donations { - proxy_pass https://mempool.space; - } - location /api/v1/donations/images { - proxy_pass https://mempool.space; - } - location /api/v1/ws { - proxy_pass http://__MEMPOOL_BACKEND_MAINNET_HTTP_HOST__:__MEMPOOL_BACKEND_MAINNET_HTTP_PORT__/; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - } - location /api/v1 { - proxy_pass http://__MEMPOOL_BACKEND_MAINNET_HTTP_HOST__:__MEMPOOL_BACKEND_MAINNET_HTTP_PORT__/api/v1; - } - location /api/ { - proxy_pass http://__MEMPOOL_BACKEND_MAINNET_HTTP_HOST__:__MEMPOOL_BACKEND_MAINNET_HTTP_PORT__/api/v1/; - } - - # mainnet API - location /ws { - proxy_pass http://__MEMPOOL_BACKEND_MAINNET_HTTP_HOST__:__MEMPOOL_BACKEND_MAINNET_HTTP_PORT__/; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - } diff --git a/frontend/docker/nginx.conf b/frontend/docker/nginx.conf deleted file mode 100644 index aa3b8a6c9..000000000 --- a/frontend/docker/nginx.conf +++ /dev/null @@ -1,128 +0,0 @@ - -pid /var/run/nginx.pid; - -worker_processes auto; -worker_rlimit_nofile 100000; - -events { - worker_connections 9000; - multi_accept on; -} - -http { - sendfile on; - tcp_nopush on; - tcp_nodelay on; - - server_tokens off; - server_name_in_redirect off; - - include /etc/nginx/mime.types; - default_type application/octet-stream; - - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log; - - # reset timed out connections freeing ram - reset_timedout_connection on; - # maximum time between packets the client can pause when sending nginx any data - client_body_timeout 10s; - # maximum time the client has to send the entire header to nginx - client_header_timeout 10s; - # timeout which a single keep-alive client connection will stay open - keepalive_timeout 69s; - # maximum time between packets nginx is allowed to pause when sending the client data - send_timeout 10s; - - # number of requests per connection, does not affect SPDY - keepalive_requests 100; - - # enable gzip compression - gzip on; - gzip_vary on; - gzip_comp_level 6; - gzip_min_length 1000; - gzip_proxied expired no-cache no-store private auth; - # text/html is always compressed by gzip module - gzip_types application/javascript application/json application/ld+json application/manifest+json application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard; - - # limit request body size - client_max_body_size 10m; - - # proxy cache - proxy_cache off; - proxy_cache_path /var/cache/nginx keys_zone=cache:20m levels=1:2 inactive=600s max_size=500m; - types_hash_max_size 2048; - - # exempt localhost from rate limit - geo $limited_ip { - default 1; - 0.0.0.0 0; - } - map $limited_ip $limited_ip_key { - 1 $binary_remote_addr; - 0 ''; - } - - # rate limit requests - limit_req_zone $limited_ip_key zone=api:5m rate=200r/m; - limit_req_zone $limited_ip_key zone=electrs:5m rate=2000r/m; - limit_req_status 429; - - # rate limit connections - limit_conn_zone $limited_ip_key zone=websocket:10m; - limit_conn_status 429; - - map $http_accept_language $header_lang { - default en-US; - ~*^en-US en-US; - ~*^en en-US; - ~*^ar ar; - ~*^cs cs; - ~*^de de; - ~*^es es; - ~*^fa fa; - ~*^fr fr; - ~*^ja ja; - ~*^ka ka; - ~*^hu hu; - ~*^nl nl; - ~*^nn nn; - ~*^pt pt; - ~*^sl sl; - ~*^sv sv; - ~*^tr tr; - ~*^uk uk; - ~*^vi vi; - ~*^zh zh; - } - - map $cookie_lang $lang { - default $header_lang; - ~*^en-US en-US; - ~*^en en-US; - ~*^ar ar; - ~*^cs cs; - ~*^de de; - ~*^es es; - ~*^fa fa; - ~*^fr fr; - ~*^ja ja; - ~*^ka ka; - ~*^hu hu; - ~*^nl nl; - ~*^nn nn; - ~*^pt pt; - ~*^sl sl; - ~*^sv sv; - ~*^tr tr; - ~*^uk uk; - ~*^vi vi; - ~*^zh zh; - } - - server { - listen 0.0.0.0:8080; - include /etc/nginx/conf.d/nginx-mempool.conf; - } -} diff --git a/frontend/proxy.conf.json b/frontend/proxy.conf.json index 5886ff104..d109b50ec 100644 --- a/frontend/proxy.conf.json +++ b/frontend/proxy.conf.json @@ -1,4 +1,8 @@ { + "/api/v1/donations": { + "target": "http://localhost:9000/", + "secure": false + }, "/api/v1": { "target": "http://localhost:8999/", "secure": false diff --git a/frontend/src/app/bisq/bisq-stats/bisq-stats.component.html b/frontend/src/app/bisq/bisq-stats/bisq-stats.component.html index 4b4e99984..7b38b8b0a 100644 --- a/frontend/src/app/bisq/bisq-stats/bisq-stats.component.html +++ b/frontend/src/app/bisq/bisq-stats/bisq-stats.component.html @@ -38,7 +38,7 @@ Market cap - + @@ -83,4 +83,4 @@ - \ No newline at end of file + diff --git a/frontend/src/app/components/about/about.component.html b/frontend/src/app/components/about/about.component.html index 81fb96cf2..80579f206 100644 --- a/frontend/src/app/components/about/about.component.html +++ b/frontend/src/app/components/about/about.component.html @@ -5,7 +5,7 @@
- v2.1.0 + v2.1-SNAPSHOT ({{ gitCommit$ | async }})

@@ -173,10 +173,9 @@

Donation confirmed!
Thank you!

-

If you specified a Twitter handle, the profile photo should now be visible on this page when you reload.

-



+


diff --git a/frontend/src/app/components/about/about.component.ts b/frontend/src/app/components/about/about.component.ts index 04681d95a..4e598e693 100644 --- a/frontend/src/app/components/about/about.component.ts +++ b/frontend/src/app/components/about/about.component.ts @@ -1,19 +1,19 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { WebsocketService } from '../../services/websocket.service'; import { SeoService } from 'src/app/services/seo.service'; import { StateService } from 'src/app/services/state.service'; -import { Observable } from 'rxjs'; +import { Observable, Subscription } from 'rxjs'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { ApiService } from 'src/app/services/api.service'; import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; -import { map } from 'rxjs/operators'; +import { delay, map, retryWhen, switchMap, tap } from 'rxjs/operators'; @Component({ selector: 'app-about', templateUrl: './about.component.html', styleUrls: ['./about.component.scss'], }) -export class AboutComponent implements OnInit { +export class AboutComponent implements OnInit, OnDestroy { gitCommit$: Observable; donationForm: FormGroup; paymentForm: FormGroup; @@ -22,6 +22,7 @@ export class AboutComponent implements OnInit { donationObj: any; sponsorsEnabled = this.stateService.env.SPONSORS_ENABLED; sponsors = null; + requestSubscription: Subscription | undefined; constructor( private websocketService: WebsocketService, @@ -50,23 +51,37 @@ export class AboutComponent implements OnInit { .subscribe((sponsors) => { this.sponsors = sponsors; }); + } - this.apiService.getDonation$() - this.stateService.donationConfirmed$.subscribe(() => this.donationStatus = 4); + ngOnDestroy() { + if (this.requestSubscription) { + this.requestSubscription.unsubscribe(); + } } submitDonation() { if (this.donationForm.invalid) { return; } - this.apiService.requestDonation$( + this.requestSubscription = this.apiService.requestDonation$( this.donationForm.get('amount').value, this.donationForm.get('handle').value ) - .subscribe((response) => { - this.websocketService.trackDonation(response.id); - this.donationObj = response; - this.donationStatus = 3; + .pipe( + tap((response) => { + this.donationObj = response; + this.donationStatus = 3; + }), + switchMap(() => this.apiService.checkDonation$(this.donationObj.id) + .pipe( + retryWhen((errors) => errors.pipe(delay(2000))) + ) + ) + ).subscribe(() => { + this.donationStatus = 4; + if (this.donationForm.get('handle').value) { + this.sponsors.unshift({ handle: this.donationForm.get('handle').value }); + } }); } diff --git a/frontend/src/app/components/address-labels/address-labels.component.ts b/frontend/src/app/components/address-labels/address-labels.component.ts index 4f4cbf7fa..bde749025 100644 --- a/frontend/src/app/components/address-labels/address-labels.component.ts +++ b/frontend/src/app/components/address-labels/address-labels.component.ts @@ -43,19 +43,23 @@ export class AddressLabelsComponent implements OnInit { } else { this.liquid = 'Emergency Peg Out'; } + return; } [ - {regexp: /^OP_DUP OP_HASH160/, label: 'HTLC'}, + // {regexp: /^OP_DUP OP_HASH160/, label: 'HTLC'}, {regexp: /^OP_IF OP_PUSHBYTES_33 \w{33} OP_ELSE OP_PUSHBYTES_2 \w{2} OP_CSV OP_DROP/, label: 'Force Close'} ].forEach((item) => { if (item.regexp.test(this.vin.inner_witnessscript_asm)) { this.lightning = item.label; - return; } } ); + if (this.lightning) { + return; + } + if (this.vin.inner_witnessscript_asm.indexOf('OP_CHECKMULTISIG') > -1) { const matches = this.getMatches(this.vin.inner_witnessscript_asm, /OP_PUSHNUM_([0-9])/g, 1); this.multisig = true; diff --git a/frontend/src/app/interfaces/websocket.interface.ts b/frontend/src/app/interfaces/websocket.interface.ts index e96c6e3c2..2a753b91f 100644 --- a/frontend/src/app/interfaces/websocket.interface.ts +++ b/frontend/src/app/interfaces/websocket.interface.ts @@ -15,13 +15,11 @@ export interface WebsocketResponse { tx?: Transaction; rbfTransaction?: Transaction; transactions?: TransactionStripped[]; - donationConfirmed?: boolean; loadingIndicators?: ILoadingIndicators; 'track-tx'?: string; 'track-address'?: string; 'track-asset'?: string; 'watch-mempool'?: boolean; - 'track-donation'?: string; } export interface MempoolBlock { diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts index 2b2fa6525..b31bb24f3 100644 --- a/frontend/src/app/services/api.service.ts +++ b/frontend/src/app/services/api.service.ts @@ -77,6 +77,10 @@ export class ApiService { return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/donations'); } + checkDonation$(orderId: string): Observable { + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/donations/check?order_id=' + orderId); + } + getInitData$(): Observable { return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/init-data'); } diff --git a/frontend/src/app/services/state.service.ts b/frontend/src/app/services/state.service.ts index 8b66862fc..be0191e2c 100644 --- a/frontend/src/app/services/state.service.ts +++ b/frontend/src/app/services/state.service.ts @@ -64,7 +64,6 @@ export class StateService { vbytesPerSecond$ = new ReplaySubject(1); lastDifficultyAdjustment$ = new ReplaySubject(1); gitCommit$ = new ReplaySubject(1); - donationConfirmed$ = new Subject(); loadingIndicators$ = new ReplaySubject(1); live2Chart$ = new Subject(); diff --git a/frontend/src/app/services/websocket.service.ts b/frontend/src/app/services/websocket.service.ts index 66bb70b54..7c35e040d 100644 --- a/frontend/src/app/services/websocket.service.ts +++ b/frontend/src/app/services/websocket.service.ts @@ -126,10 +126,6 @@ export class WebsocketService { this.isTrackingTx = true; } - trackDonation(id: string) { - this.websocketSubject.next({ 'track-donation': id }); - } - stopTrackingTransaction() { if (!this.isTrackingTx) { return; @@ -289,9 +285,5 @@ export class WebsocketService { if (response['git-commit']) { this.stateService.gitCommit$.next(response['git-commit']); } - - if (response.donationConfirmed) { - this.stateService.donationConfirmed$.next(true); - } } } diff --git a/frontend/src/locale/messages.xlf b/frontend/src/locale/messages.xlf index e875d4f58..4140d8340 100644 --- a/frontend/src/locale/messages.xlf +++ b/frontend/src/locale/messages.xlf @@ -46,7 +46,7 @@ src/app/components/transactions-list/transactions-list.component.html - 205 + 208 src/app/bisq/bisq-transfers/bisq-transfers.component.html @@ -67,7 +67,7 @@ src/app/components/transactions-list/transactions-list.component.html - 206 + 209 src/app/bisq/bisq-transfers/bisq-transfers.component.html @@ -88,7 +88,7 @@ src/app/components/transactions-list/transactions-list.component.html - 209 + 212 Transaction unconfirmed state transaction.unconfirmed @@ -242,7 +242,7 @@ src/app/components/transactions-list/transactions-list.component.html - 198 + 201 src/app/components/block/block.component.html @@ -468,7 +468,7 @@ nSequence src/app/components/transactions-list/transactions-list.component.html - 92 + 95 transactions-list.nsequence @@ -476,7 +476,7 @@ ScriptSig (ASM) src/app/components/transactions-list/transactions-list.component.html - 71 + 74 ScriptSig (ASM) transactions-list.scriptsig.asm @@ -485,7 +485,7 @@ ScriptSig (HEX) src/app/components/transactions-list/transactions-list.component.html - 75 + 78 ScriptSig (HEX) transactions-list.scriptsig.hex @@ -494,7 +494,7 @@ Witness src/app/components/transactions-list/transactions-list.component.html - 80 + 83 transactions-list.witness @@ -502,7 +502,7 @@ P2SH redeem script src/app/components/transactions-list/transactions-list.component.html - 84 + 87 transactions-list.p2sh-redeem-script @@ -510,7 +510,7 @@ P2WSH witness script src/app/components/transactions-list/transactions-list.component.html - 88 + 91 transactions-list.p2wsh-witness-script @@ -518,7 +518,7 @@ Previous output script src/app/components/transactions-list/transactions-list.component.html - 96 + 99 transactions-list.previous-output-script @@ -526,11 +526,11 @@ Load all src/app/components/transactions-list/transactions-list.component.html - 106 + 109 src/app/components/transactions-list/transactions-list.component.html - 188 + 191 transactions-list.load-all @@ -538,7 +538,7 @@ Peg-out to src/app/components/transactions-list/transactions-list.component.html - 125 + 128 transactions-list.peg-out-to @@ -546,7 +546,7 @@ ScriptPubKey (ASM) src/app/components/transactions-list/transactions-list.component.html - 170 + 173 ScriptPubKey (ASM) transactions-list.scriptpubkey.asm @@ -555,7 +555,7 @@ ScriptPubKey (HEX) src/app/components/transactions-list/transactions-list.component.html - 174 + 177 ScriptPubKey (HEX) transactions-list.scriptpubkey.hex @@ -564,7 +564,7 @@ Type src/app/components/transactions-list/transactions-list.component.html - 166 + 169 src/app/bisq/bisq-transaction-details/bisq-transaction-details.component.html @@ -580,7 +580,7 @@ data src/app/components/transactions-list/transactions-list.component.html - 178 + 181 transactions-list.vout.scriptpubkey-type.data @@ -588,7 +588,7 @@ sat src/app/components/transactions-list/transactions-list.component.html - 198 + 201 sat shared.sat @@ -597,7 +597,7 @@ Confidential src/app/components/transactions-list/transactions-list.component.html - 214 + 217 src/app/components/amount/amount.component.html @@ -605,7 +605,7 @@ src/app/components/address/address.component.html - 132 + 134 src/app/components/asset/asset.component.html @@ -841,11 +841,23 @@ shared.address + + Balance + + src/app/components/address/address.component.html + 30 + + + src/app/bisq/bisq-address/bisq-address.component.html + 28 + + address.balance + Total received src/app/components/address/address.component.html - 20 + 21 src/app/bisq/bisq-address/bisq-address.component.html @@ -857,7 +869,7 @@ Total sent src/app/components/address/address.component.html - 24 + 25 src/app/bisq/bisq-address/bisq-address.component.html @@ -869,23 +881,11 @@ address.total-sent - - Balance - - src/app/components/address/address.component.html - 28 - - - src/app/bisq/bisq-address/bisq-address.component.html - 28 - - address.balance - of transaction src/app/components/address/address.component.html - 48 + 50 X of X Address Transaction @@ -893,7 +893,7 @@ of transactions src/app/components/address/address.component.html - 49 + 51 X of X Address Transactions (Plural) @@ -901,7 +901,7 @@ Error loading address data. src/app/components/address/address.component.html - 113 + 115 address.error.loading-address-data @@ -1020,15 +1020,23 @@ multisig of src/app/components/address-labels/address-labels.component.html - 1 + 5 address-labels.multisig - - Layer Peg-out + + Lightning src/app/components/address-labels/address-labels.component.html - 2 + 11 + + address-labels.upper-layer-peg-out + + + Liquid + + src/app/components/address-labels/address-labels.component.html + 17 address-labels.upper-layer-peg-out @@ -1052,7 +1060,7 @@ src/app/components/about/about.component.ts - 37 + 38 master-page.about @@ -1199,7 +1207,7 @@ Terms of Service src/app/components/about/about.component.html - 206 + 205 src/app/dashboard/dashboard.component.html @@ -1268,14 +1276,6 @@ about.sponsor.thank-you - - If you specified a Twitter handle, the profile photo should now be visible on this page when you reload. - - src/app/components/about/about.component.html - 176 - - about.sponsor.sponsor-completed - Loading graphs... diff --git a/frontend/src/resources/screenshots/v2.1.0-dashboard.png b/frontend/src/resources/screenshots/v2.1.0-dashboard.png new file mode 100644 index 000000000..768d99918 Binary files /dev/null and b/frontend/src/resources/screenshots/v2.1.0-dashboard.png differ diff --git a/mariadb-structure.sql b/mariadb-structure.sql index d045b3ce3..4d567ed91 100644 --- a/mariadb-structure.sql +++ b/mariadb-structure.sql @@ -84,24 +84,3 @@ ALTER TABLE `transactions` ALTER TABLE `statistics` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; - - -CREATE TABLE `donations` ( - `id` int(11) NOT NULL, - `added` datetime NOT NULL, - `amount` float NOT NULL, - `handle` varchar(250) NOT NULL, - `order_id` varchar(25) NOT NULL, - `imageUrl` varchar(250) NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -ALTER TABLE `donations` - ADD PRIMARY KEY (`id`); - -ALTER TABLE `donations` - MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; - -ALTER TABLE `donations` ADD UNIQUE(`order_id`); - -ALTER TABLE `donations` ADD `image` MEDIUMBLOB NULL AFTER `imageUrl`; -ALTER TABLE `donations` ADD `twitter_id` VARCHAR(250) NULL AFTER `handle`; diff --git a/mysql-mempool.cnf b/mysql-mempool.cnf deleted file mode 100644 index f4a7fb3bb..000000000 --- a/mysql-mempool.cnf +++ /dev/null @@ -1,2 +0,0 @@ -[mysqld] -sql_mode="NO_AUTO_VALUE_ON_ZERO" diff --git a/production/electrs-start-mainnet b/production/electrs-start-mainnet index 75172bf33..06129e9b7 100755 --- a/production/electrs-start-mainnet +++ b/production/electrs-start-mainnet @@ -1,5 +1,5 @@ #!/usr/local/bin/zsh -cd /electrs +cd $HOME/electrs source $HOME/.cargo/env export PATH=$HOME/.cargo/bin:$PATH @@ -11,9 +11,11 @@ do -- \ -vvvv \ --address-search \ - --daemon-dir /bitcoin \ + --db-dir /electrs \ + --daemon-dir $HOME \ --http-addr '[::]:3000' \ --cookie 'user:pass' \ - --precache-scripts /electrs/contrib/popular-scripts.txt - sleep 1 + --precache-scripts $HOME/electrs/contrib/popular-scripts.txt + + sleep 3 done diff --git a/production/electrs-start-testnet b/production/electrs-start-testnet index b6a66263a..82a6c23b7 100755 --- a/production/electrs-start-testnet +++ b/production/electrs-start-testnet @@ -1,5 +1,5 @@ #!/usr/local/bin/zsh -cd /electrs +cd $HOME/electrs source $HOME/.cargo/env export PATH=$HOME/.cargo/bin:$PATH @@ -9,11 +9,13 @@ do --release \ --bin electrs \ -- \ - -vv \ + -vvvv \ --network testnet \ - --daemon-dir /bitcoin \ + --db-dir /electrs \ + --daemon-dir $HOME \ --http-addr '[::]:3002' \ --cookie 'user:pass' \ - --precache-scripts /electrs/contrib/popular-scripts.txt - sleep 1 + --precache-scripts $HOME/electrs/contrib/popular-scripts.txt + + sleep 3 done