Compare commits

..

5 Commits

Author SHA1 Message Date
wiz
541555051b
Merge branch 'master' into knorrium/update-node-matrix 2025-01-20 19:26:56 +09:00
Felipe Knorr Kuhn
5f5e96984a
Merge branch 'master' into knorrium/update-node-matrix 2025-01-19 23:41:46 -08:00
Felipe Knorr Kuhn
f5a54ae62b
Update the local nvmrc to node 22 2025-01-15 21:52:54 -08:00
Felipe Knorr Kuhn
4da145ff5c
Update the node version to run e2e tests 2025-01-15 21:52:38 -08:00
Felipe Knorr Kuhn
a898701830
Update node matrix to v20 and v22 2025-01-15 21:33:25 -08:00
62 changed files with 353 additions and 765 deletions

View File

@ -9,7 +9,7 @@ jobs:
if: "!contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')" if: "!contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')"
strategy: strategy:
matrix: matrix:
node: ["20", "21"] node: ["20", "22"]
flavor: ["dev", "prod"] flavor: ["dev", "prod"]
fail-fast: false fail-fast: false
runs-on: "ubuntu-latest" runs-on: "ubuntu-latest"
@ -160,7 +160,7 @@ jobs:
if: "!contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')" if: "!contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')"
strategy: strategy:
matrix: matrix:
node: ["20", "21"] node: ["20", "22"]
flavor: ["dev", "prod"] flavor: ["dev", "prod"]
fail-fast: false fail-fast: false
runs-on: "ubuntu-latest" runs-on: "ubuntu-latest"
@ -263,7 +263,7 @@ jobs:
- name: Setup node - name: Setup node
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 20 node-version: 22
cache: "npm" cache: "npm"
cache-dependency-path: ${{ matrix.module }}/frontend/package-lock.json cache-dependency-path: ${{ matrix.module }}/frontend/package-lock.json

2
.nvmrc
View File

@ -1 +1 @@
v20.8.0 v22.13.0

View File

@ -7,7 +7,7 @@ const config: Config.InitialOptions = {
automock: false, automock: false,
collectCoverage: true, collectCoverage: true,
collectCoverageFrom: ["./src/**/**.ts"], collectCoverageFrom: ["./src/**/**.ts"],
coverageProvider: "v8", coverageProvider: "babel",
coverageThreshold: { coverageThreshold: {
global: { global: {
lines: 1 lines: 1

View File

@ -10,6 +10,7 @@
"hasInstallScript": true, "hasInstallScript": true,
"license": "GNU Affero General Public License v3.0", "license": "GNU Affero General Public License v3.0",
"dependencies": { "dependencies": {
"@babel/core": "^7.25.2",
"@mempool/electrum-client": "1.1.9", "@mempool/electrum-client": "1.1.9",
"@types/node": "^18.15.3", "@types/node": "^18.15.3",
"axios": "1.7.2", "axios": "1.7.2",
@ -17,7 +18,7 @@
"crypto-js": "~4.2.0", "crypto-js": "~4.2.0",
"express": "~4.21.1", "express": "~4.21.1",
"maxmind": "~4.3.11", "maxmind": "~4.3.11",
"mysql2": "~3.12.0", "mysql2": "~3.11.0",
"redis": "^4.7.0", "redis": "^4.7.0",
"rust-gbt": "file:./rust-gbt", "rust-gbt": "file:./rust-gbt",
"socks-proxy-agent": "~7.0.0", "socks-proxy-agent": "~7.0.0",
@ -25,6 +26,8 @@
"ws": "~8.18.0" "ws": "~8.18.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/code-frame": "^7.18.6",
"@babel/core": "^7.25.2",
"@types/compression": "^1.7.2", "@types/compression": "^1.7.2",
"@types/crypto-js": "^4.1.1", "@types/crypto-js": "^4.1.1",
"@types/express": "^4.17.17", "@types/express": "^4.17.17",
@ -5997,21 +6000,6 @@
"yallist": "^3.0.2" "yallist": "^3.0.2"
} }
}, },
"node_modules/lru.min": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.1.tgz",
"integrity": "sha512-FbAj6lXil6t8z4z3j0E5mfRlPzxkySotzUHwRXjlpRh10vc6AI6WN62ehZj82VG7M20rqogJ0GLwar2Xa05a8Q==",
"license": "MIT",
"engines": {
"bun": ">=1.0.0",
"deno": ">=1.30.0",
"node": ">=8.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wellwelwel"
}
},
"node_modules/make-dir": { "node_modules/make-dir": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
@ -6173,17 +6161,16 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}, },
"node_modules/mysql2": { "node_modules/mysql2": {
"version": "3.12.0", "version": "3.11.0",
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.12.0.tgz", "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.11.0.tgz",
"integrity": "sha512-C8fWhVysZoH63tJbX8d10IAoYCyXy4fdRFz2Ihrt9jtPILYynFEKUUzpp1U7qxzDc3tMbotvaBH+sl6bFnGZiw==", "integrity": "sha512-J9phbsXGvTOcRVPR95YedzVSxJecpW5A5+cQ57rhHIFXteTP10HCs+VBjS7DHIKfEaI1zQ5tlVrquCd64A6YvA==",
"license": "MIT",
"dependencies": { "dependencies": {
"aws-ssl-profiles": "^1.1.1", "aws-ssl-profiles": "^1.1.1",
"denque": "^2.1.0", "denque": "^2.1.0",
"generate-function": "^2.3.1", "generate-function": "^2.3.1",
"iconv-lite": "^0.6.3", "iconv-lite": "^0.6.3",
"long": "^5.2.1", "long": "^5.2.1",
"lru.min": "^1.0.0", "lru-cache": "^8.0.0",
"named-placeholders": "^1.1.3", "named-placeholders": "^1.1.3",
"seq-queue": "^0.0.5", "seq-queue": "^0.0.5",
"sqlstring": "^2.3.2" "sqlstring": "^2.3.2"
@ -6203,6 +6190,14 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/mysql2/node_modules/lru-cache": {
"version": "8.0.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz",
"integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==",
"engines": {
"node": ">=16.14"
}
},
"node_modules/named-placeholders": { "node_modules/named-placeholders": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz",
@ -12218,11 +12213,6 @@
"yallist": "^3.0.2" "yallist": "^3.0.2"
} }
}, },
"lru.min": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.1.tgz",
"integrity": "sha512-FbAj6lXil6t8z4z3j0E5mfRlPzxkySotzUHwRXjlpRh10vc6AI6WN62ehZj82VG7M20rqogJ0GLwar2Xa05a8Q=="
},
"make-dir": { "make-dir": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
@ -12337,16 +12327,16 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}, },
"mysql2": { "mysql2": {
"version": "3.12.0", "version": "3.11.0",
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.12.0.tgz", "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.11.0.tgz",
"integrity": "sha512-C8fWhVysZoH63tJbX8d10IAoYCyXy4fdRFz2Ihrt9jtPILYynFEKUUzpp1U7qxzDc3tMbotvaBH+sl6bFnGZiw==", "integrity": "sha512-J9phbsXGvTOcRVPR95YedzVSxJecpW5A5+cQ57rhHIFXteTP10HCs+VBjS7DHIKfEaI1zQ5tlVrquCd64A6YvA==",
"requires": { "requires": {
"aws-ssl-profiles": "^1.1.1", "aws-ssl-profiles": "^1.1.1",
"denque": "^2.1.0", "denque": "^2.1.0",
"generate-function": "^2.3.1", "generate-function": "^2.3.1",
"iconv-lite": "^0.6.3", "iconv-lite": "^0.6.3",
"long": "^5.2.1", "long": "^5.2.1",
"lru.min": "^1.0.0", "lru-cache": "^8.0.0",
"named-placeholders": "^1.1.3", "named-placeholders": "^1.1.3",
"seq-queue": "^0.0.5", "seq-queue": "^0.0.5",
"sqlstring": "^2.3.2" "sqlstring": "^2.3.2"
@ -12359,6 +12349,11 @@
"requires": { "requires": {
"safer-buffer": ">= 2.1.2 < 3.0.0" "safer-buffer": ">= 2.1.2 < 3.0.0"
} }
},
"lru-cache": {
"version": "8.0.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz",
"integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA=="
} }
} }
}, },

View File

@ -39,6 +39,7 @@
"prettier": "./node_modules/.bin/prettier --write \"src/**/*.{js,ts}\"" "prettier": "./node_modules/.bin/prettier --write \"src/**/*.{js,ts}\""
}, },
"dependencies": { "dependencies": {
"@babel/core": "^7.25.2",
"@mempool/electrum-client": "1.1.9", "@mempool/electrum-client": "1.1.9",
"@types/node": "^18.15.3", "@types/node": "^18.15.3",
"axios": "1.7.2", "axios": "1.7.2",
@ -46,7 +47,7 @@
"crypto-js": "~4.2.0", "crypto-js": "~4.2.0",
"express": "~4.21.1", "express": "~4.21.1",
"maxmind": "~4.3.11", "maxmind": "~4.3.11",
"mysql2": "~3.12.0", "mysql2": "~3.11.0",
"rust-gbt": "file:./rust-gbt", "rust-gbt": "file:./rust-gbt",
"redis": "^4.7.0", "redis": "^4.7.0",
"socks-proxy-agent": "~7.0.0", "socks-proxy-agent": "~7.0.0",
@ -54,6 +55,8 @@
"ws": "~8.18.0" "ws": "~8.18.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/code-frame": "^7.18.6",
"@babel/core": "^7.25.2",
"@types/compression": "^1.7.2", "@types/compression": "^1.7.2",
"@types/crypto-js": "^4.1.1", "@types/crypto-js": "^4.1.1",
"@types/express": "^4.17.17", "@types/express": "^4.17.17",

View File

@ -21,7 +21,6 @@ import transactionRepository from '../../repositories/TransactionRepository';
import rbfCache from '../rbf-cache'; import rbfCache from '../rbf-cache';
import { calculateMempoolTxCpfp } from '../cpfp'; import { calculateMempoolTxCpfp } from '../cpfp';
import { handleError } from '../../utils/api'; import { handleError } from '../../utils/api';
import poolsUpdater from '../../tasks/pools-updater';
const TXID_REGEX = /^[a-f0-9]{64}$/i; const TXID_REGEX = /^[a-f0-9]{64}$/i;
const BLOCK_HASH_REGEX = /^[a-f0-9]{64}$/i; const BLOCK_HASH_REGEX = /^[a-f0-9]{64}$/i;
@ -57,10 +56,6 @@ class BitcoinRoutes {
.get(config.MEMPOOL.API_URL_PREFIX + 'blocks-bulk/:from/:to', this.getBlocksByBulk.bind(this)) .get(config.MEMPOOL.API_URL_PREFIX + 'blocks-bulk/:from/:to', this.getBlocksByBulk.bind(this))
// Temporarily add txs/package endpoint for all backends until esplora supports it // Temporarily add txs/package endpoint for all backends until esplora supports it
.post(config.MEMPOOL.API_URL_PREFIX + 'txs/package', this.$submitPackage) .post(config.MEMPOOL.API_URL_PREFIX + 'txs/package', this.$submitPackage)
// Internal routes
.get(config.MEMPOOL.API_URL_PREFIX + 'internal/blocks/definition/list', this.getBlockDefinitionHashes)
.get(config.MEMPOOL.API_URL_PREFIX + 'internal/blocks/definition/current', this.getCurrentBlockDefinitionHash)
.get(config.MEMPOOL.API_URL_PREFIX + 'internal/blocks/:definitionHash', this.getBlocksByDefinitionHash)
; ;
if (config.MEMPOOL.BACKEND !== 'esplora') { if (config.MEMPOOL.BACKEND !== 'esplora') {
@ -744,52 +739,6 @@ class BitcoinRoutes {
} }
} }
private async getBlockDefinitionHashes(req: Request, res: Response): Promise<void> {
try {
const result = await blocks.$getBlockDefinitionHashes();
if (!result) {
handleError(req, res, 503, `Service Temporarily Unavailable`);
return;
}
res.setHeader('content-type', 'application/json');
res.send(result);
} catch (e) {
handleError(req, res, 500, e instanceof Error ? e.message : e);
}
}
private async getCurrentBlockDefinitionHash(req: Request, res: Response): Promise<void> {
try {
const currentSha = await poolsUpdater.getShaFromDb();
if (!currentSha) {
handleError(req, res, 503, `Service Temporarily Unavailable`);
return;
}
res.setHeader('content-type', 'text/plain');
res.send(currentSha);
} catch (e) {
handleError(req, res, 500, e instanceof Error ? e.message : e);
}
}
private async getBlocksByDefinitionHash(req: Request, res: Response): Promise<void> {
try {
if (typeof(req.params.definitionHash) !== 'string') {
res.status(400).send('Parameter "hash" must be a valid string');
return;
}
const blocksHash = await blocks.$getBlocksByDefinitionHash(req.params.definitionHash as string);
if (!blocksHash) {
handleError(req, res, 503, `Service Temporarily Unavailable`);
return;
}
res.setHeader('content-type', 'application/json');
res.send(blocksHash);
} catch (e) {
handleError(req, res, 500, e instanceof Error ? e.message : e);
}
}
private getBlockTipHeight(req: Request, res: Response) { private getBlockTipHeight(req: Request, res: Response) {
try { try {
const result = blocks.getCurrentBlockHeight(); const result = blocks.getCurrentBlockHeight();

View File

@ -33,8 +33,8 @@ import AccelerationRepository from '../repositories/AccelerationRepository';
import { calculateFastBlockCpfp, calculateGoodBlockCpfp } from './cpfp'; import { calculateFastBlockCpfp, calculateGoodBlockCpfp } from './cpfp';
import mempool from './mempool'; import mempool from './mempool';
import CpfpRepository from '../repositories/CpfpRepository'; import CpfpRepository from '../repositories/CpfpRepository';
import accelerationApi from './services/acceleration';
import { parseDATUMTemplateCreator } from '../utils/bitcoin-script'; import { parseDATUMTemplateCreator } from '../utils/bitcoin-script';
import database from '../database';
class Blocks { class Blocks {
private blocks: BlockExtended[] = []; private blocks: BlockExtended[] = [];
@ -1462,36 +1462,6 @@ class Blocks {
// not a fatal error, we'll try again next time the indexer runs // not a fatal error, we'll try again next time the indexer runs
} }
} }
public async $getBlockDefinitionHashes(): Promise<string[] | null> {
try {
const [rows]: any = await database.query(`SELECT DISTINCT(definition_hash) FROM blocks`);
if (rows && Array.isArray(rows)) {
return rows.map(r => r.definition_hash);
} else {
logger.debug(`Unable to retreive list of blocks.definition_hash from db (no result)`);
return null;
}
} catch (e) {
logger.debug(`Unable to retreive list of blocks.definition_hash from db (exception: ${e})`);
return null;
}
}
public async $getBlocksByDefinitionHash(definitionHash: string): Promise<string[] | null> {
try {
const [rows]: any = await database.query(`SELECT hash FROM blocks WHERE definition_hash = ?`, [definitionHash]);
if (rows && Array.isArray(rows)) {
return rows.map(r => r.hash);
} else {
logger.debug(`Unable to retreive list of blocks for definition hash ${definitionHash} from db (no result)`);
return null;
}
} catch (e) {
logger.debug(`Unable to retreive list of blocks for definition hash ${definitionHash} from db (exception: ${e})`);
return null;
}
}
} }
export default new Blocks(); export default new Blocks();

View File

@ -7,7 +7,7 @@ import cpfpRepository from '../repositories/CpfpRepository';
import { RowDataPacket } from 'mysql2'; import { RowDataPacket } from 'mysql2';
class DatabaseMigration { class DatabaseMigration {
private static currentVersion = 95; private static currentVersion = 94;
private queryTimeout = 3600_000; private queryTimeout = 3600_000;
private statisticsAddedIndexed = false; private statisticsAddedIndexed = false;
private uniqueLogs: string[] = []; private uniqueLogs: string[] = [];
@ -1118,18 +1118,6 @@ class DatabaseMigration {
} }
await this.updateToSchemaVersion(94); await this.updateToSchemaVersion(94);
} }
// blocks pools-v2.json hash
if (databaseSchemaVersion < 95) {
let poolJsonSha = 'f737d86571d190cf1a1a3cf5fd86b33ba9624254';
const [poolJsonShaDb]: any[] = await DB.query(`SELECT string FROM state WHERE name = 'pools_json_sha'`);
if (poolJsonShaDb?.length > 0) {
poolJsonSha = poolJsonShaDb[0].string;
}
await this.$executeQuery(`ALTER TABLE blocks ADD definition_hash varchar(255) NOT NULL DEFAULT "${poolJsonSha}"`);
await this.$executeQuery('ALTER TABLE blocks ADD INDEX `definition_hash` (`definition_hash`)');
await this.updateToSchemaVersion(95);
}
} }
/** /**

View File

@ -19,6 +19,15 @@ class PoolsParser {
'addresses': '[]', 'addresses': '[]',
'slug': 'unknown' 'slug': 'unknown'
}; };
private uniqueLogs: string[] = [];
private uniqueLog(loggerFunction: any, msg: string): void {
if (this.uniqueLogs.includes(msg)) {
return;
}
this.uniqueLogs.push(msg);
loggerFunction(msg);
}
public setMiningPools(pools): void { public setMiningPools(pools): void {
for (const pool of pools) { for (const pool of pools) {

View File

@ -325,8 +325,6 @@ export interface BlockExtension {
// Requires coinstatsindex, will be set to NULL otherwise // Requires coinstatsindex, will be set to NULL otherwise
utxoSetSize: number | null; utxoSetSize: number | null;
totalInputAmt: number | null; totalInputAmt: number | null;
// pools-v2.json git hash
definitionHash: string | undefined;
} }
/** /**

View File

@ -15,7 +15,6 @@ import blocks from '../api/blocks';
import BlocksAuditsRepository from './BlocksAuditsRepository'; import BlocksAuditsRepository from './BlocksAuditsRepository';
import transactionUtils from '../api/transaction-utils'; import transactionUtils from '../api/transaction-utils';
import { parseDATUMTemplateCreator } from '../utils/bitcoin-script'; import { parseDATUMTemplateCreator } from '../utils/bitcoin-script';
import poolsUpdater from '../tasks/pools-updater';
interface DatabaseBlock { interface DatabaseBlock {
id: string; id: string;
@ -124,7 +123,7 @@ class BlocksRepository {
coinbase_signature, utxoset_size, utxoset_change, avg_tx_size, coinbase_signature, utxoset_size, utxoset_change, avg_tx_size,
total_inputs, total_outputs, total_input_amt, total_output_amt, total_inputs, total_outputs, total_input_amt, total_output_amt,
fee_percentiles, segwit_total_txs, segwit_total_size, segwit_total_weight, fee_percentiles, segwit_total_txs, segwit_total_size, segwit_total_weight,
median_fee_amt, coinbase_signature_ascii, definition_hash median_fee_amt, coinbase_signature_ascii
) VALUE ( ) VALUE (
?, ?, FROM_UNIXTIME(?), ?, ?, ?, FROM_UNIXTIME(?), ?,
?, ?, ?, ?, ?, ?, ?, ?,
@ -135,7 +134,7 @@ class BlocksRepository {
?, ?, ?, ?, ?, ?, ?, ?,
?, ?, ?, ?, ?, ?, ?, ?,
?, ?, ?, ?, ?, ?, ?, ?,
?, ?, ? ?, ?
)`; )`;
const poolDbId = await PoolsRepository.$getPoolByUniqueId(block.extras.pool.id); const poolDbId = await PoolsRepository.$getPoolByUniqueId(block.extras.pool.id);
@ -182,7 +181,6 @@ class BlocksRepository {
block.extras.segwitTotalWeight, block.extras.segwitTotalWeight,
block.extras.medianFeeAmt, block.extras.medianFeeAmt,
truncatedCoinbaseSignatureAscii, truncatedCoinbaseSignatureAscii,
poolsUpdater.currentSha
]; ];
await DB.query(query, params); await DB.query(query, params);
@ -1015,9 +1013,9 @@ class BlocksRepository {
public async $savePool(id: string, poolId: number): Promise<void> { public async $savePool(id: string, poolId: number): Promise<void> {
try { try {
await DB.query(` await DB.query(`
UPDATE blocks SET pool_id = ?, definition_hash = ? UPDATE blocks SET pool_id = ?
WHERE hash = ?`, WHERE hash = ?`,
[poolId, poolsUpdater.currentSha, id] [poolId, id]
); );
} catch (e) { } catch (e) {
logger.err(`Cannot update block pool. Reason: ` + (e instanceof Error ? e.message : e)); logger.err(`Cannot update block pool. Reason: ` + (e instanceof Error ? e.message : e));

View File

@ -88,8 +88,8 @@ class PoolsUpdater {
try { try {
await DB.query('START TRANSACTION;'); await DB.query('START TRANSACTION;');
await this.updateDBSha(githubSha);
await poolsParser.migratePoolsJson(); await poolsParser.migratePoolsJson();
await this.updateDBSha(githubSha);
await DB.query('COMMIT;'); await DB.query('COMMIT;');
} catch (e) { } catch (e) {
logger.err(`Could not migrate mining pools, rolling back. Exception: ${JSON.stringify(e)}`, this.tag); logger.err(`Could not migrate mining pools, rolling back. Exception: ${JSON.stringify(e)}`, this.tag);
@ -121,7 +121,7 @@ class PoolsUpdater {
/** /**
* Fetch our latest pools-v2.json sha from the db * Fetch our latest pools-v2.json sha from the db
*/ */
public async getShaFromDb(): Promise<string | null> { private async getShaFromDb(): Promise<string | null> {
try { try {
const [rows]: any[] = await DB.query('SELECT string FROM state WHERE name="pools_json_sha"'); const [rows]: any[] = await DB.query('SELECT string FROM state WHERE name="pools_json_sha"');
return (rows.length > 0 ? rows[0].string : null); return (rows.length > 0 ? rows[0].string : null);

View File

@ -11,14 +11,10 @@ services:
stop_grace_period: 1m stop_grace_period: 1m
command: "./wait-for db:3306 --timeout=720 -- nginx -g 'daemon off;'" command: "./wait-for db:3306 --timeout=720 -- nginx -g 'daemon off;'"
ports: ports:
- 8080:8080 - 80:8080
api: api:
environment: environment:
MEMPOOL_BACKEND: "electrum" MEMPOOL_BACKEND: "none"
ELECTRUM_HOST: "172.27.0.1"
ELECTRUM_PORT: "50001"
ELECTRUM_TLS_ENABLED: "false"
CORE_RPC_HOST: "172.27.0.1" CORE_RPC_HOST: "172.27.0.1"
CORE_RPC_PORT: "8332" CORE_RPC_PORT: "8332"
CORE_RPC_USERNAME: "mempool" CORE_RPC_USERNAME: "mempool"

View File

@ -45,7 +45,6 @@ __SERVICES_API__=${SERVICES_API:=https://mempool.space/api/v1/services}
__PUBLIC_ACCELERATIONS__=${PUBLIC_ACCELERATIONS:=false} __PUBLIC_ACCELERATIONS__=${PUBLIC_ACCELERATIONS:=false}
__HISTORICAL_PRICE__=${HISTORICAL_PRICE:=true} __HISTORICAL_PRICE__=${HISTORICAL_PRICE:=true}
__ADDITIONAL_CURRENCIES__=${ADDITIONAL_CURRENCIES:=false} __ADDITIONAL_CURRENCIES__=${ADDITIONAL_CURRENCIES:=false}
__STRATUM_ENABLED__=${STRATUM_ENABLED:=false}
# Export as environment variables to be used by envsubst # Export as environment variables to be used by envsubst
export __MAINNET_ENABLED__ export __MAINNET_ENABLED__
@ -77,7 +76,6 @@ export __SERVICES_API__
export __PUBLIC_ACCELERATIONS__ export __PUBLIC_ACCELERATIONS__
export __HISTORICAL_PRICE__ export __HISTORICAL_PRICE__
export __ADDITIONAL_CURRENCIES__ export __ADDITIONAL_CURRENCIES__
export __STRATUM_ENABLED__
folder=$(find /var/www/mempool -name "config.js" | xargs dirname) folder=$(find /var/www/mempool -name "config.js" | xargs dirname)
echo ${folder} echo ${folder}

View File

@ -13,8 +13,8 @@ localhostIP="127.0.0.1"
cp ./docker/frontend/* ./frontend cp ./docker/frontend/* ./frontend
cp ./nginx.conf ./frontend/ cp ./nginx.conf ./frontend/
cp ./nginx-mempool.conf ./frontend/ cp ./nginx-mempool.conf ./frontend/
# sed -i"" -e "s/${localhostIP}:80/0.0.0.0:__MEMPOOL_FRONTEND_HTTP_PORT__/g" ./frontend/nginx.conf sed -i"" -e "s/${localhostIP}:80/0.0.0.0:__MEMPOOL_FRONTEND_HTTP_PORT__/g" ./frontend/nginx.conf
# sed -i"" -e "s/${localhostIP}/0.0.0.0/g" ./frontend/nginx.conf sed -i"" -e "s/${localhostIP}/0.0.0.0/g" ./frontend/nginx.conf
sed -i"" -e "s/user nobody;//g" ./frontend/nginx.conf sed -i"" -e "s/user nobody;//g" ./frontend/nginx.conf
sed -i"" -e "s!/etc/nginx/nginx-mempool.conf!/etc/nginx/conf.d/nginx-mempool.conf!g" ./frontend/nginx.conf sed -i"" -e "s!/etc/nginx/nginx-mempool.conf!/etc/nginx/conf.d/nginx-mempool.conf!g" ./frontend/nginx.conf
sed -i"" -e "s/${localhostIP}:8999/__MEMPOOL_BACKEND_MAINNET_HTTP_HOST__:__MEMPOOL_BACKEND_MAINNET_HTTP_PORT__/g" ./frontend/nginx-mempool.conf sed -i"" -e "s/${localhostIP}:8999/__MEMPOOL_BACKEND_MAINNET_HTTP_HOST__:__MEMPOOL_BACKEND_MAINNET_HTTP_PORT__/g" ./frontend/nginx-mempool.conf

View File

@ -33,7 +33,7 @@
"browserify": "^17.0.0", "browserify": "^17.0.0",
"clipboard": "^2.0.11", "clipboard": "^2.0.11",
"domino": "^2.1.6", "domino": "^2.1.6",
"echarts": "~5.6.0", "echarts": "~5.5.0",
"esbuild": "^0.24.0", "esbuild": "^0.24.0",
"ngx-echarts": "~17.2.0", "ngx-echarts": "~17.2.0",
"ngx-infinite-scroll": "^17.0.0", "ngx-infinite-scroll": "^17.0.0",
@ -8724,12 +8724,12 @@
} }
}, },
"node_modules/echarts": { "node_modules/echarts": {
"version": "5.6.0", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz", "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.5.0.tgz",
"integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==", "integrity": "sha512-rNYnNCzqDAPCr4m/fqyUFv7fD9qIsd50S6GDFgO1DxZhncCsNsG7IfUlAlvZe5oSEQxtsjnHiUuppzccry93Xw==",
"dependencies": { "dependencies": {
"tslib": "2.3.0", "tslib": "2.3.0",
"zrender": "5.6.1" "zrender": "5.5.0"
} }
}, },
"node_modules/echarts/node_modules/tslib": { "node_modules/echarts/node_modules/tslib": {
@ -18366,9 +18366,9 @@
} }
}, },
"node_modules/zrender": { "node_modules/zrender": {
"version": "5.6.1", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz", "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.5.0.tgz",
"integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==", "integrity": "sha512-O3MilSi/9mwoovx77m6ROZM7sXShR/O/JIanvzTwjN3FORfLSr81PsUGd7jlaYOeds9d8tw82oP44+3YucVo+w==",
"dependencies": { "dependencies": {
"tslib": "2.3.0" "tslib": "2.3.0"
} }
@ -24485,12 +24485,12 @@
} }
}, },
"echarts": { "echarts": {
"version": "5.6.0", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz", "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.5.0.tgz",
"integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==", "integrity": "sha512-rNYnNCzqDAPCr4m/fqyUFv7fD9qIsd50S6GDFgO1DxZhncCsNsG7IfUlAlvZe5oSEQxtsjnHiUuppzccry93Xw==",
"requires": { "requires": {
"tslib": "2.3.0", "tslib": "2.3.0",
"zrender": "5.6.1" "zrender": "5.5.0"
}, },
"dependencies": { "dependencies": {
"tslib": { "tslib": {
@ -31485,9 +31485,9 @@
} }
}, },
"zrender": { "zrender": {
"version": "5.6.1", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz", "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.5.0.tgz",
"integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==", "integrity": "sha512-O3MilSi/9mwoovx77m6ROZM7sXShR/O/JIanvzTwjN3FORfLSr81PsUGd7jlaYOeds9d8tw82oP44+3YucVo+w==",
"requires": { "requires": {
"tslib": "2.3.0" "tslib": "2.3.0"
}, },

View File

@ -86,7 +86,7 @@
"browserify": "^17.0.0", "browserify": "^17.0.0",
"clipboard": "^2.0.11", "clipboard": "^2.0.11",
"domino": "^2.1.6", "domino": "^2.1.6",
"echarts": "~5.6.0", "echarts": "~5.5.0",
"ngx-echarts": "~17.2.0", "ngx-echarts": "~17.2.0",
"ngx-infinite-scroll": "^17.0.0", "ngx-infinite-scroll": "^17.0.0",
"qrcode": "1.5.1", "qrcode": "1.5.1",

View File

@ -217,7 +217,7 @@
<ng-container> <ng-container>
<ng-template ngFor let-sponsor [ngForOf]="profiles.whales"> <ng-template ngFor let-sponsor [ngForOf]="profiles.whales">
<a [href]="'https://x.com/' + sponsor.username" target="_blank" rel="sponsored" [title]="sponsor.username"> <a [href]="'https://x.com/' + sponsor.username" target="_blank" rel="sponsored" [title]="sponsor.username">
<img class="image" [src]="'/api/v1/services/account/images/' + sponsor.username" onError="this.src = '/resources/profile/grumpy.svg'; this.className = 'image unknown'"/> <img class="image" [src]="'/api/v1/services/account/images/' + sponsor.username + '/md5=' + sponsor.imageMd5" onError="this.src = '/resources/profile/grumpy.svg'; this.className = 'image unknown'"/>
</a> </a>
</ng-template> </ng-template>
</ng-container> </ng-container>
@ -229,7 +229,7 @@
<div class="wrapper"> <div class="wrapper">
<ng-template ngFor let-sponsor [ngForOf]="profiles.chads"> <ng-template ngFor let-sponsor [ngForOf]="profiles.chads">
<a [href]="'https://x.com/' + sponsor.username" target="_blank" rel="sponsored" [title]="sponsor.username"> <a [href]="'https://x.com/' + sponsor.username" target="_blank" rel="sponsored" [title]="sponsor.username">
<img class="image" [src]="'/api/v1/services/account/images/' + sponsor.username" onError="this.src = '/resources/profile/grumpy.svg'; this.className = 'image unknown'"/> <img class="image" [src]="'/api/v1/services/account/images/' + sponsor.username + '/md5=' + sponsor.imageMd5" onError="this.src = '/resources/profile/grumpy.svg'; this.className = 'image unknown'"/>
</a> </a>
</ng-template> </ng-template>
</div> </div>

View File

@ -365,9 +365,9 @@
<app-active-acceleration-box [miningStats]="miningStats" [pools]="estimate.pools" [chartOnly]="true" class="ml-2"></app-active-acceleration-box> <app-active-acceleration-box [miningStats]="miningStats" [pools]="estimate.pools" [chartOnly]="true" class="ml-2"></app-active-acceleration-box>
</div> </div>
</div> </div>
<div class="payment-area" style="font-size: 14px;"> <div class="payment-area mt-2 p-2" style="font-size: 14px;">
<div class="row text-center justify-content-center mx-2"> <div class="row text-center justify-content-center mx-2">
<span i18n="accelerator.payment-to-mempool-space">Payment to mempool.space for acceleration of txid <a [routerLink]="'/tx/' + tx.txid" target="_blank">{{ tx.txid.substr(0, 10) }}..{{ tx.txid.substr(-10) }}</a></span> <p i18n="accelerator.payment-to-mempool-space">Payment to mempool.space for acceleration of txid <a [routerLink]="'/tx/' + tx.txid" target="_blank">{{ tx.txid.substr(0, 10) }}..{{ tx.txid.substr(-10) }}</a></p>
</div> </div>
@if (canPayWithBalance || !(canPayWithBitcoin || canPayWithCashapp || canPayWithApplePay || canPayWithGooglePay)) { @if (canPayWithBalance || !(canPayWithBitcoin || canPayWithCashapp || canPayWithApplePay || canPayWithGooglePay)) {
<div class="row"> <div class="row">
@ -386,12 +386,9 @@
<p><ng-container i18n="transaction.pay|Pay button label">Pay</ng-container>&nbsp;<span><small style="font-family: monospace;">{{ ((invoice.btcDue * 100_000_000) || cost) | number }}</small>&nbsp;<span class="symbol" i18n="shared.sats">sats</span></span></p> <p><ng-container i18n="transaction.pay|Pay button label">Pay</ng-container>&nbsp;<span><small style="font-family: monospace;">{{ ((invoice.btcDue * 100_000_000) || cost) | number }}</small>&nbsp;<span class="symbol" i18n="shared.sats">sats</span></span></p>
<app-bitcoin-invoice style="width: 100%;" [invoice]="invoice" [minimal]="true" (completed)="bitcoinPaymentCompleted()"></app-bitcoin-invoice> <app-bitcoin-invoice style="width: 100%;" [invoice]="invoice" [minimal]="true" (completed)="bitcoinPaymentCompleted()"></app-bitcoin-invoice>
} @else if (btcpayInvoiceFailed) { } @else if (btcpayInvoiceFailed) {
<div class="btcpay-invoice"> <p i18n="accelerator.failed-to-load-invoice">Failed to load invoice</p>
<fa-icon style="font-size: 20px; color: var(--red)" [icon]="['fas', 'circle-xmark']"></fa-icon> <div class="d-flex flex-column align-items-center justify-content-center" style="width: 100%; height: 292px;">
<span i18n="accelerator.failed-to-load-invoice">Failed to load invoice</span> <fa-icon style="font-size: 24px; color: var(--red)" [icon]="['fas', 'circle-xmark']"></fa-icon>
@if (!loadingBtcpayInvoice) {
<button class="btn btn-sm btn-secondary mt-0 mt-md-1" (click)="requestBTCPayInvoice()">Retry ↻</button>
}
</div> </div>
} @else { } @else {
<p i18n="accelerator.loading-invoice">Loading invoice...</p> <p i18n="accelerator.loading-invoice">Loading invoice...</p>
@ -400,13 +397,13 @@
</div> </div>
} }
</div> </div>
@if (canPayWithCashapp || canPayWithApplePay || canPayWithGooglePay || canPayWithCardOnFile) { @if (canPayWithCashapp || canPayWithApplePay || canPayWithGooglePay) {
<div class="col-sm text-center flex-grow-0 d-flex flex-column justify-content-center align-items-center"> <div class="col-sm text-center flex-grow-0 d-flex flex-column justify-content-center align-items-center">
<p class="text-nowrap">&mdash;&mdash;<span i18n="or"> OR </span>&mdash;&mdash;</p> <p class="text-nowrap">&mdash;<span i18n="or">OR</span>&mdash;</p>
</div> </div>
} }
} }
@if (canPayWithCashapp || canPayWithApplePay || canPayWithGooglePay || canPayWithCardOnFile) { @if (canPayWithCashapp || canPayWithApplePay || canPayWithGooglePay) {
<div class="col-sm text-center d-flex flex-column justify-content-center align-items-center"> <div class="col-sm text-center d-flex flex-column justify-content-center align-items-center">
<p><ng-container i18n="transaction.pay|Pay button label">Pay</ng-container>&nbsp;<app-fiat [value]="cost"></app-fiat> with</p> <p><ng-container i18n="transaction.pay|Pay button label">Pay</ng-container>&nbsp;<app-fiat [value]="cost"></app-fiat> with</p>
@if (canPayWithCashapp) { @if (canPayWithCashapp) {
@ -424,17 +421,6 @@
<img src="/resources/google-pay.png" height=37> <img src="/resources/google-pay.png" height=37>
</div> </div>
} }
@if (canPayWithCardOnFile) {
@if (canPayWithCashapp || canPayWithApplePay || canPayWithGooglePay) { <span class="mt-1 mb-1"></span> }
<div class="paymentMethod mx-2 d-flex justify-content-center align-items-center" style="width: 200px; height: 55px" (click)="moveToStep('cardonfile')">
@if (['VISA', 'MASTERCARD', 'JCB', 'DISCOVER', 'DISCOVER_DINERS', 'AMERICAN_EXPRESS'].includes(estimate?.availablePaymentMethods?.cardOnFile?.card?.brand)) {
<app-svg-images [name]="estimate?.availablePaymentMethods?.cardOnFile?.card?.brand" height="33" class="mr-2"></app-svg-images>
} @else {
<app-svg-images name="OTHER_BRAND" height="33" class="mr-2"></app-svg-images>
}
<span style="font-size: 22px; padding-bottom: 3px">{{ estimate?.availablePaymentMethods?.cardOnFile?.card?.last_4 }}</span>
</div>
}
</div> </div>
} }
</div> </div>
@ -457,7 +443,7 @@
<button type="button" class="mt-1 btn btn-secondary btn-sm rounded-pill align-self-center" style="width: 200px" (click)="moveToStep('summary')" i18n="go-back">Go back</button> <button type="button" class="mt-1 btn btn-secondary btn-sm rounded-pill align-self-center" style="width: 200px" (click)="moveToStep('summary')" i18n="go-back">Go back</button>
</div> </div>
</div> </div>
} @else if (step === 'cashapp' || step === 'applepay' || step === 'googlepay' || step === 'cardonfile') { } @else if (step === 'cashapp' || step === 'applepay' || step === 'googlepay') {
<!-- Show checkout page --> <!-- Show checkout page -->
<div class="row mb-md-1 text-center" id="confirm-title"> <div class="row mb-md-1 text-center" id="confirm-title">
<div class="col-sm" id="confirm-payment-title"> <div class="col-sm" id="confirm-payment-title">
@ -473,7 +459,7 @@
</div> </div>
</div> </div>
@if (step === 'cashapp' && !loadingCashapp || step === 'applepay' && !loadingApplePay || step === 'googlepay' && !loadingGooglePay || step === 'cardonfile' && !loadingCardOnFile) { @if (step === 'cashapp' && !loadingCashapp || step === 'applepay' && !loadingApplePay || step === 'googlepay' && !loadingGooglePay) {
<div class="row text-center mt-1"> <div class="row text-center mt-1">
<div class="col-sm"> <div class="col-sm">
<div class="form-group w-100"> <div class="form-group w-100">
@ -498,13 +484,8 @@
<div id="cash-app-pay" class="d-inline-block" style="height: 50px" [style]="loadingCashapp ? 'opacity: 0; width: 0px; height: 0px; pointer-events: none;' : ''"></div> <div id="cash-app-pay" class="d-inline-block" style="height: 50px" [style]="loadingCashapp ? 'opacity: 0; width: 0px; height: 0px; pointer-events: none;' : ''"></div>
} @else if (step === 'googlepay') { } @else if (step === 'googlepay') {
<div id="google-pay-button" class="d-inline-block" style="height: 50px" [style]="loadingGooglePay ? 'opacity: 0; width: 0px; height: 0px; pointer-events: none;' : ''"></div> <div id="google-pay-button" class="d-inline-block" style="height: 50px" [style]="loadingGooglePay ? 'opacity: 0; width: 0px; height: 0px; pointer-events: none;' : ''"></div>
} @else if (step === 'cardonfile') {
<div class="paymentMethod mx-2 d-flex justify-content-center align-items-center ml-auto mr-auto" style="width: 200px; height: 55px" (click)="requestCardOnFilePayment()" [style]="loadingCardOnFile ? 'opacity: 0; width: 0px; height: 0px; pointer-events: none;' : ''">
<fa-icon style="font-size: 24px; color: white" [icon]="['fas', 'credit-card']"></fa-icon>
<span class="ml-2" style="font-size: 22px">{{ estimate?.availablePaymentMethods?.cardOnFile?.card?.brand }} {{ estimate?.availablePaymentMethods?.cardOnFile?.card?.last_4 }}</span>
</div>
} }
@if (loadingCashapp || loadingApplePay || loadingGooglePay || loadingCardOnFile) { @if (loadingCashapp || loadingApplePay || loadingGooglePay) {
<div display="d-flex flex-row justify-content-center"> <div display="d-flex flex-row justify-content-center">
<span i18n="accelerator.loading-payment-method">Loading payment method...</span> <span i18n="accelerator.loading-payment-method">Loading payment method...</span>
<div class="ml-2 spinner-border text-light" style="width: 25px; height: 25px"></div> <div class="ml-2 spinner-border text-light" style="width: 25px; height: 25px"></div>

View File

@ -153,11 +153,6 @@
.payment-area { .payment-area {
background: var(--bg); background: var(--bg);
margin-top: 0.5rem;
padding: 0.5rem;
@media (max-width: 575px) {
padding-bottom: 1.25rem;
}
} }
.col.pie { .col.pie {
@ -225,16 +220,3 @@
.apple-pay-button-white-with-line { .apple-pay-button-white-with-line {
-apple-pay-button-style: white-outline; -apple-pay-button-style: white-outline;
} }
.btcpay-invoice {
display: flex;
height: 292px;
flex-direction: column;
justify-content: center;
align-items: center;
@media (max-width: 575px) {
height: 75px;
flex-direction: row;
gap: 5px;
}
}

View File

@ -13,7 +13,7 @@ import { EnterpriseService } from '@app/services/enterprise.service';
import { ApiService } from '@app/services/api.service'; import { ApiService } from '@app/services/api.service';
import { isDevMode } from '@angular/core'; import { isDevMode } from '@angular/core';
export type PaymentMethod = 'balance' | 'bitcoin' | 'cashapp' | 'applePay' | 'googlePay' | 'cardOnFile'; export type PaymentMethod = 'balance' | 'bitcoin' | 'cashapp' | 'applePay' | 'googlePay';
export type AccelerationEstimate = { export type AccelerationEstimate = {
hasAccess: boolean; hasAccess: boolean;
@ -26,7 +26,7 @@ export type AccelerationEstimate = {
mempoolBaseFee: number; mempoolBaseFee: number;
vsizeFee: number; vsizeFee: number;
pools: number[]; pools: number[];
availablePaymentMethods: Record<PaymentMethod, {min: number, max: number, card?: {card_id: string, last_4: string, brand: string, name: string, billing: any}}>; availablePaymentMethods: Record<PaymentMethod, {min: number, max: number}>;
unavailable?: boolean; unavailable?: boolean;
options: { // recommended bid options options: { // recommended bid options
fee: number; // recommended userBid in sats fee: number; // recommended userBid in sats
@ -49,7 +49,7 @@ export const MIN_BID_RATIO = 1;
export const DEFAULT_BID_RATIO = 2; export const DEFAULT_BID_RATIO = 2;
export const MAX_BID_RATIO = 4; export const MAX_BID_RATIO = 4;
type CheckoutStep = 'quote' | 'summary' | 'checkout' | 'cashapp' | 'applepay' | 'googlepay' | 'cardonfile' | 'processing' | 'paid' | 'success'; type CheckoutStep = 'quote' | 'summary' | 'checkout' | 'cashapp' | 'applepay' | 'googlepay' | 'processing' | 'paid' | 'success';
@Component({ @Component({
selector: 'app-accelerate-checkout', selector: 'app-accelerate-checkout',
@ -62,9 +62,9 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
@Input() miningStats: MiningStats; @Input() miningStats: MiningStats;
@Input() eta: ETA; @Input() eta: ETA;
@Input() scrollEvent: boolean; @Input() scrollEvent: boolean;
@Input() cashappEnabled: boolean = true;
@Input() applePayEnabled: boolean = false; @Input() applePayEnabled: boolean = false;
@Input() googlePayEnabled: boolean = true; @Input() googlePayEnabled: boolean = true;
@Input() cardOnFileEnabled: boolean = true;
@Input() advancedEnabled: boolean = false; @Input() advancedEnabled: boolean = false;
@Input() forceMobile: boolean = false; @Input() forceMobile: boolean = false;
@Input() showDetails: boolean = false; @Input() showDetails: boolean = false;
@ -117,7 +117,6 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
loadingCashapp = false; loadingCashapp = false;
loadingApplePay = false; loadingApplePay = false;
loadingGooglePay = false; loadingGooglePay = false;
loadingCardOnFile = false;
payments: any; payments: any;
cashAppPay: any; cashAppPay: any;
applePay: any; applePay: any;
@ -211,7 +210,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
if (this.timeoutTimer) { if (this.timeoutTimer) {
clearTimeout(this.timeoutTimer); clearTimeout(this.timeoutTimer);
} }
if (!this.estimate && ['quote', 'summary', 'checkout', 'processing'].includes(this.step)) { if (!this.estimate && ['quote', 'summary', 'checkout'].includes(this.step)) {
this.fetchEstimate(); this.fetchEstimate();
} }
if (this._step === 'checkout') { if (this._step === 'checkout') {
@ -220,9 +219,10 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
} }
if (this._step === 'checkout' && this.canPayWithBitcoin) { if (this._step === 'checkout' && this.canPayWithBitcoin) {
this.btcpayInvoiceFailed = false; this.btcpayInvoiceFailed = false;
this.loadingBtcpayInvoice = true;
this.invoice = null; this.invoice = null;
this.requestBTCPayInvoice(); this.requestBTCPayInvoice();
} else if (this._step === 'cashapp') { } else if (this._step === 'cashapp' && this.cashappEnabled) {
this.loadingCashapp = true; this.loadingCashapp = true;
this.setupSquare(); this.setupSquare();
this.scrollToElementWithTimeout('confirm-title', 'center', 100); this.scrollToElementWithTimeout('confirm-title', 'center', 100);
@ -234,10 +234,6 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
this.loadingGooglePay = true; this.loadingGooglePay = true;
this.setupSquare(); this.setupSquare();
this.scrollToElementWithTimeout('confirm-title', 'center', 100); this.scrollToElementWithTimeout('confirm-title', 'center', 100);
} else if (this._step === 'cardonfile' && this.cardOnFileEnabled) {
this.loadingCardOnFile = true;
this.setupSquare();
this.scrollToElementWithTimeout('confirm-title', 'center', 100);
} else if (this._step === 'paid') { } else if (this._step === 'paid') {
this.timePaid = Date.now(); this.timePaid = Date.now();
this.timeoutTimer = setTimeout(() => { this.timeoutTimer = setTimeout(() => {
@ -332,6 +328,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
} }
if (this.step === 'checkout' && this.canPayWithBitcoin && !this.loadingBtcpayInvoice) { if (this.step === 'checkout' && this.canPayWithBitcoin && !this.loadingBtcpayInvoice) {
this.loadingBtcpayInvoice = true;
this.requestBTCPayInvoice(); this.requestBTCPayInvoice();
} }
@ -457,8 +454,6 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
await this.requestApplePayPayment(); await this.requestApplePayPayment();
} else if (this._step === 'googlepay') { } else if (this._step === 'googlepay') {
await this.requestGooglePayPayment(); await this.requestGooglePayPayment();
} else if (this._step === 'cardonfile') {
this.loadingCardOnFile = false;
} }
}, },
error: () => { error: () => {
@ -715,109 +710,6 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
); );
} }
/**
* Card On File
*/
async requestCardOnFilePayment(): Promise<void> {
if (this.processing) {
return;
}
if (this.conversionsSubscription) {
this.conversionsSubscription.unsubscribe();
}
this.processing = true;
this.conversionsSubscription = this.stateService.conversions$.subscribe(
async (conversions) => {
this.conversions = conversions;
const costUSD = this.cost / 100_000_000 * conversions.USD;
if (this.isCheckoutLocked > 0) {
return;
}
const cardOnFile = this.estimate?.availablePaymentMethods?.cardOnFile;
if (!cardOnFile?.card) {
this.accelerateError = 'card_on_file_not_found';
return;
}
this.loadingCardOnFile = false;
try {
this.isCheckoutLocked += 2;
this.isTokenizing += 2;
const nameParts = cardOnFile.card.name.split(' ');
const assumedGivenName = nameParts[0];
const assumedFamilyName = nameParts.length > 1 ? nameParts[1] : undefined;
const verificationDetails = {
card: {
billing: {
givenName: assumedGivenName,
familyName: assumedFamilyName,
addressLines: [cardOnFile.card.billing.addressLine1 ?? ''],
city: cardOnFile.card.billing.locality ?? '',
state: cardOnFile.card.billing.administrativeDistrictLevel1 ?? '',
countyCode: cardOnFile.card.billing.country,
}
}
};
const verificationToken = await this.$verifyBuyer(this.payments, cardOnFile.card.card_id, verificationDetails, costUSD.toFixed(2));
if (!verificationToken || !verificationToken.token) {
console.error(`SCA verification failed`);
this.accelerateError = 'SCA Verification Failed. Payment Declined.';
this.processing = false;
return;
}
this.servicesApiService.accelerateWithCardOnFile$(
this.tx.txid,
cardOnFile.card.card_id,
verificationToken.token,
`accelerator-${this.tx.txid.substring(0, 15)}-${Math.round(new Date().getTime() / 1000)}`,
costUSD,
verificationToken.userChallenged
).subscribe({
next: () => {
this.processing = false;
this.apiService.logAccelerationRequest$(this.tx.txid).subscribe();
this.audioService.playSound('ascend-chime-cartoon');
setTimeout(() => {
this.isCheckoutLocked--;
this.isTokenizing--;
this.moveToStep('paid', true);
}, 1000);
},
error: (response) => {
this.processing = false;
this.accelerateError = response.error;
this.isCheckoutLocked--;
this.isTokenizing--;
if (!(response.status === 403 && response.error === 'not_available')) {
setTimeout(() => {
// Reset everything by reloading the page :D, can be improved
const urlParams = new URLSearchParams(window.location.search);
window.location.assign(window.location.toString().replace(`?cash_request_id=${urlParams.get('cash_request_id')}`, ``));
}, 3000);
}
}
});
} catch (e) {
console.log(e);
this.isCheckoutLocked--;
this.isTokenizing--;
this.processing = false;
this.accelerateError = e.message;
} finally {
// always unlock the checkout once we're finished
this.isCheckoutLocked--;
this.isTokenizing--;
}
}
);
}
/** /**
* CASHAPP * CASHAPP
*/ */
@ -838,7 +730,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
} }
const redirectHostname = document.location.hostname === 'localhost' ? `http://localhost:4200`: `https://${document.location.hostname}`; const redirectHostname = document.location.hostname === 'localhost' ? `http://localhost:4200`: `https://${document.location.hostname}`;
const costUSD = this.cost / 100_000_000 * conversions.USD; const costUSD = this.step === 'processing' ? 69.69 : (this.cost / 100_000_000 * conversions.USD); // When we're redirected to this component, the payment data is already linked to the payment token, so does not matter what amonut we put in there, therefore it's 69.69
const paymentRequest = this.payments.paymentRequest({ const paymentRequest = this.payments.paymentRequest({
countryCode: 'US', countryCode: 'US',
currencyCode: 'USD', currencyCode: 'USD',
@ -933,19 +825,16 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
* BTCPay * BTCPay
*/ */
async requestBTCPayInvoice(): Promise<void> { async requestBTCPayInvoice(): Promise<void> {
this.loadingBtcpayInvoice = true;
this.servicesApiService.generateBTCPayAcceleratorInvoice$(this.tx.txid, this.userBid).pipe( this.servicesApiService.generateBTCPayAcceleratorInvoice$(this.tx.txid, this.userBid).pipe(
switchMap(response => { switchMap(response => {
return this.servicesApiService.retreiveInvoice$(response.btcpayInvoiceId); return this.servicesApiService.retreiveInvoice$(response.btcpayInvoiceId);
}), }),
catchError(error => { catchError(error => {
console.log(error); console.log(error);
this.loadingBtcpayInvoice = false;
this.btcpayInvoiceFailed = true; this.btcpayInvoiceFailed = true;
return of(null); return of(null);
}) })
).subscribe((invoice) => { ).subscribe((invoice) => {
this.loadingBtcpayInvoice = false;
this.invoice = invoice; this.invoice = invoice;
this.cd.markForCheck(); this.cd.markForCheck();
}); });
@ -982,6 +871,9 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
} }
get couldPayWithCashapp(): boolean { get couldPayWithCashapp(): boolean {
if (!this.cashappEnabled) {
return false;
}
return !!this.estimate?.availablePaymentMethods?.cashapp; return !!this.estimate?.availablePaymentMethods?.cashapp;
} }
@ -1016,7 +908,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
} }
get canPayWithCashapp(): boolean { get canPayWithCashapp(): boolean {
if (!this.conversions || (!this.isProdDomain && !isDevMode())) { if (!this.cashappEnabled || !this.conversions || (!this.isProdDomain && !isDevMode())) {
return false; return false;
} }
@ -1063,22 +955,6 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
return false; return false;
} }
get canPayWithCardOnFile(): boolean {
if (!this.cardOnFileEnabled || !this.conversions || (!this.isProdDomain && !isDevMode())) {
return false;
}
const paymentMethod = this.estimate?.availablePaymentMethods?.cardOnFile;
if (paymentMethod) {
const costUSD = (this.cost / 100_000_000 * this.conversions.USD);
if (costUSD >= paymentMethod.min && costUSD <= paymentMethod.max) {
return true;
}
}
return false;
}
get canPayWithBalance(): boolean { get canPayWithBalance(): boolean {
if (!this.hasAccessToBalanceMode) { if (!this.hasAccessToBalanceMode) {
return false; return false;

View File

@ -14,7 +14,7 @@
<th class="time text-right" i18n="accelerator.requested">Requested</th> <th class="time text-right" i18n="accelerator.requested">Requested</th>
</ng-container> </ng-container>
<ng-container *ngIf="!pending"> <ng-container *ngIf="!pending">
<th class="fee text-right text-truncate" i18n="transaction.bid-boost|Bid Boost">Bid Boost</th> <th class="fee text-right" i18n="transaction.bid-boost|Bid Boost">Bid Boost</th>
<th class="block text-right" i18n="shared.block-title">Block</th> <th class="block text-right" i18n="shared.block-title">Block</th>
<th class="pool text-right" i18n="mining.pool-name" *ngIf="!this.widget">Pool</th> <th class="pool text-right" i18n="mining.pool-name" *ngIf="!this.widget">Pool</th>
<th class="status text-right" i18n="transaction.status|Transaction Status">Status</th> <th class="status text-right" i18n="transaction.status|Transaction Status">Status</th>
@ -64,8 +64,7 @@
<span *ngIf="acceleration.status === 'accelerating'" class="badge badge-warning" i18n="accelerator.pending">Pending</span> <span *ngIf="acceleration.status === 'accelerating'" class="badge badge-warning" i18n="accelerator.pending">Pending</span>
<span *ngIf="acceleration.status.includes('completed') && acceleration.minedByPoolUniqueId && pools[acceleration.minedByPoolUniqueId]" class="badge badge-success"><ng-container i18n="accelerator.completed">Completed</ng-container><span *ngIf="acceleration.status === 'completed_provisional'">&nbsp;</span></span> <span *ngIf="acceleration.status.includes('completed') && acceleration.minedByPoolUniqueId && pools[acceleration.minedByPoolUniqueId]" class="badge badge-success"><ng-container i18n="accelerator.completed">Completed</ng-container><span *ngIf="acceleration.status === 'completed_provisional'">&nbsp;</span></span>
<span *ngIf="acceleration.status.includes('completed') && (!acceleration.minedByPoolUniqueId || !pools[acceleration.minedByPoolUniqueId])" class="badge badge-success"><ng-container i18n="transaction.rbf.mined">Mined</ng-container><span *ngIf="acceleration.status === 'completed_provisional'">&nbsp;</span></span> <span *ngIf="acceleration.status.includes('completed') && (!acceleration.minedByPoolUniqueId || !pools[acceleration.minedByPoolUniqueId])" class="badge badge-success"><ng-container i18n="transaction.rbf.mined">Mined</ng-container><span *ngIf="acceleration.status === 'completed_provisional'">&nbsp;</span></span>
<span *ngIf="acceleration.status.includes('failed') && acceleration.canceled" class="badge badge-danger"><ng-container i18n="accelerator.canceled">Canceled</ng-container><span *ngIf="acceleration.status === 'failed_provisional'">&nbsp;</span></span> <span *ngIf="acceleration.status.includes('failed')" class="badge badge-danger"><ng-container i18n="accelerator.canceled">Canceled</ng-container><span *ngIf="acceleration.status === 'failed_provisional'">&nbsp;</span></span>
<span *ngIf="acceleration.status.includes('failed') && !acceleration.canceled" class="badge badge-danger"><ng-container i18n="accelerator.canceled">Failed</ng-container><span *ngIf="acceleration.status === 'failed_provisional'">&nbsp;</span></span>
</td> </td>
<td class="date text-right" *ngIf="!this.widget"> <td class="date text-right" *ngIf="!this.widget">
<app-time kind="since" [time]="acceleration.added" [fastRender]="true" [showTooltip]="true"></app-time> <app-time kind="since" [time]="acceleration.added" [fastRender]="true" [showTooltip]="true"></app-time>

View File

@ -10,10 +10,6 @@
</span> </span>
} }
<div class="d-flex justify-content-center">
<app-mempool-error *ngIf="paymentErrorMessage" [error]="paymentErrorMessage"></app-mempool-error>
</div>
<div *ngIf="paymentStatus === 2"> <div *ngIf="paymentStatus === 2">
<form [formGroup]="paymentForm"> <form [formGroup]="paymentForm">

View File

@ -1,8 +1,9 @@
import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms'; import { FormBuilder, FormGroup } from '@angular/forms';
import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
import { Subscription, of, catchError } from 'rxjs'; import { ActivatedRoute } from '@angular/router';
import { retry, tap } from 'rxjs/operators'; import { Subscription, of, timer } from 'rxjs';
import { filter, repeat, retry, switchMap, take, tap } from 'rxjs/operators';
import { ServicesApiServices } from '@app/services/services-api.service'; import { ServicesApiServices } from '@app/services/services-api.service';
@Component({ @Component({
@ -17,17 +18,30 @@ export class BitcoinInvoiceComponent implements OnInit, OnChanges, OnDestroy {
@Output() completed = new EventEmitter(); @Output() completed = new EventEmitter();
paymentForm: FormGroup; paymentForm: FormGroup;
requestSubscription: Subscription | undefined;
paymentStatusSubscription: Subscription | undefined; paymentStatusSubscription: Subscription | undefined;
paymentStatus = 1; // 1 - Waiting for invoice | 2 - Pending payment | 3 - Payment completed paymentStatus = 1; // 1 - Waiting for invoice | 2 - Pending payment | 3 - Payment completed
paymentErrorMessage: string = ''; paramMapSubscription: Subscription | undefined;
invoiceSubscription: Subscription | undefined;
invoiceTimeout; // Wait for angular to load all the things before making a request
constructor( constructor(
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private apiService: ServicesApiServices, private apiService: ServicesApiServices,
private sanitizer: DomSanitizer private sanitizer: DomSanitizer,
private activatedRoute: ActivatedRoute
) { } ) { }
ngOnDestroy() { ngOnDestroy() {
if (this.requestSubscription) {
this.requestSubscription.unsubscribe();
}
if (this.paramMapSubscription) {
this.paramMapSubscription.unsubscribe();
}
if (this.invoiceSubscription) {
this.invoiceSubscription.unsubscribe();
}
if (this.paymentStatusSubscription) { if (this.paymentStatusSubscription) {
this.paymentStatusSubscription.unsubscribe(); this.paymentStatusSubscription.unsubscribe();
} }
@ -58,39 +72,15 @@ export class BitcoinInvoiceComponent implements OnInit, OnChanges, OnDestroy {
} else { } else {
this.paymentStatus = 4; this.paymentStatus = 4;
} }
this.monitorPendingInvoice();
}
monitorPendingInvoice(): void {
if (!this.invoice) {
return;
}
if (this.paymentStatusSubscription) {
this.paymentStatusSubscription.unsubscribe();
}
this.paymentStatusSubscription = this.apiService.getPaymentStatus$(this.invoice.btcpayInvoiceId).pipe( this.paymentStatusSubscription = this.apiService.getPaymentStatus$(this.invoice.btcpayInvoiceId).pipe(
tap(result => { retry({ delay: () => timer(2000)}),
if (result.status === 204) { // Manually trigger an error in that case so we can retry repeat({delay: 2000}),
throw result; filter((response) => response.status !== 204 && response.status !== 404),
} else if (result.status === 200) { // Invoice settled take(1),
).subscribe(() => {
this.paymentStatus = 3; this.paymentStatus = 3;
this.completed.emit(); this.completed.emit();
} });
}),
catchError(err => {
if (err.status === 204 || err.status === 504) {
throw err; // Will trigger the retry
} else if (err.status === 400) {
this.paymentErrorMessage = 'Invoice has expired';
} else if (err.status === 404) {
this.paymentErrorMessage = 'Invoice is no longer valid';
}
this.paymentStatus = -1;
return of(null);
}),
retry({ delay: 1000 }),
).subscribe();
} }
get availableMethods(): string[] { get availableMethods(): string[] {

View File

@ -19,10 +19,12 @@
} @else if (!user) { } @else if (!user) {
<!-- User not logged in --> <!-- User not logged in -->
<div class="alert alert-mempool d-block text-center w-100"> <div class="alert alert-mempool d-block text-center w-100">
<div class="d-inline align-middle pr-2"> <div class="d-inline align-middle">
<span>To use the faucet, please</span> <span>To use the faucet, please&nbsp;</span>
<a routerLink="/login" [queryParams]="{'redirectTo': '/testnet4/faucet'}">login</a>
<span class="mr-2">&nbsp;or</span>
</div> </div>
<app-github-login customClass="btn btn-sm" width="150px" redirectTo="/testnet4/faucet" buttonString="Sign up with"></app-github-login> <app-twitter-login customClass="btn btn-sm" width="220px" redirectTo="/testnet4/faucet" buttonString="Sign up with Twitter"></app-twitter-login>
</div> </div>
} }
@else if (user && user.status === 'pending' && !user.email && user.snsId) { @else if (user && user.status === 'pending' && !user.email && user.snsId) {
@ -34,18 +36,18 @@
</div> </div>
} }
@else if (error === 'not_available') { @else if (error === 'not_available') {
<!-- User logged in but not a paid user or did not link its Github account --> <!-- User logged in but not a paid user or did not link its Twitter account -->
<div class="alert alert-mempool d-block text-center w-100"> <div class="alert alert-mempool d-block text-center w-100">
<div class="d-inline align-middle"> <div class="d-inline align-middle">
<span class="mb-2 mr-2">To use the faucet, please</span> <span class="mb-2 mr-2">To use the faucet, please</span>
</div> </div>
<app-github-login customClass="btn btn-sm" width="180px" redirectTo="/testnet4/faucet" buttonString="Link your"></app-github-login> <app-twitter-login customClass="btn btn-sm" width="180px" redirectTo="/testnet4/faucet" buttonString="Link your Twitter"></app-twitter-login>
</div> </div>
} }
@else if (error === 'account_limited') { @else if (error === 'account_limited') {
<div class="alert alert-mempool d-block text-center w-100"> <div class="alert alert-mempool d-block text-center w-100">
<div class="d-inline align-middle"> <div class="d-inline align-middle">
<span class="mb-2 mr-2">Your account does not allow you to access the faucet</span> <span class="mb-2 mr-2">Your Twitter account does not allow you to access the faucet</span>
</div> </div>
</div> </div>
} }

View File

@ -24,7 +24,7 @@ export class FaucetComponent implements OnInit, OnDestroy {
min: number; // minimum amount to request at once (in sats) min: number; // minimum amount to request at once (in sats)
max: number; // maximum amount to request at once max: number; // maximum amount to request at once
address?: string; // faucet address address?: string; // faucet address
code: 'ok' | 'faucet_not_available' | 'faucet_maximum_reached' | 'faucet_too_soon' | 'faucet_not_available_no_utxo'; code: 'ok' | 'faucet_not_available' | 'faucet_maximum_reached' | 'faucet_too_soon';
} | null = null; } | null = null;
faucetForm: FormGroup; faucetForm: FormGroup;

View File

@ -1,6 +0,0 @@
<a href="#" (click)="githubLogin()" [class]="(disabled ? 'disabled': '') + (customClass ? customClass : 'w-100 btn mt-1 d-flex justify-content-center align-items-center')" style="background-color: rgb(31, 35, 40)" [style]="width ? 'width: ' + width : ''">
<span class="ml-2 text-light align-middle">{{ buttonString }}</span>
<svg height="32" viewBox="0 0 18 16" width="32" style="fill: white; padding-left: 5px">
<path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/>
</svg>
</a>

View File

@ -1,25 +0,0 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'app-github-login',
templateUrl: './github-login.component.html',
})
export class GithubLogin {
@Input() width: string | null = null;
@Input() customClass: string | null = null;
@Input() buttonString: string= 'unset';
@Input() redirectTo: string | null = null;
@Output() clicked = new EventEmitter<boolean>();
@Input() disabled: boolean = false;
constructor() {}
githubLogin() {
this.clicked.emit(true);
if (this.redirectTo) {
location.replace(`/api/v1/services/auth/login/github?redirectTo=${encodeURIComponent(this.redirectTo)}`);
} else {
location.replace(`/api/v1/services/auth/login/github?redirectTo=${location.href}`);
}
return false;
}
}

View File

@ -4,8 +4,9 @@
<nav class="navbar navbar-expand-md navbar-dark"> <nav class="navbar navbar-expand-md navbar-dark">
<!-- Hamburger --> <!-- Hamburger -->
<ng-container *ngIf="servicesEnabled"> <ng-container *ngIf="servicesEnabled">
<div *ngIf="user" class="profile_image_container" (click)="hamburgerClick($event)"> <div *ngIf="user" class="profile_image_container" [class]="{'anon': !user.imageMd5}" (click)="hamburgerClick($event)">
<img [src]="'/api/v1/services/account/images/' + user.username" class="profile_image" onError="this.src = '/resources/anon.svg'; this.className = 'anon'" /> <img *ngIf="user.imageMd5" [src]="'/api/v1/services/account/images/' + user.username + '/md5=' + user.imageMd5" class="profile_image">
<app-svg-images style="color: lightgrey; fill: lightgray" *ngIf="!user.imageMd5" name="anon"></app-svg-images>
</div> </div>
<div *ngIf="false && user === null" class="profile_image_container" (click)="hamburgerClick($event)"> <div *ngIf="false && user === null" class="profile_image_container" (click)="hamburgerClick($event)">
<app-svg-images name="hamburger" height="40"></app-svg-images> <app-svg-images name="hamburger" height="40"></app-svg-images>
@ -22,7 +23,7 @@
} @else { } @else {
<ng-template [ngIf]="subdomain && enterpriseInfo"> <ng-template [ngIf]="subdomain && enterpriseInfo">
<div class="subdomain_container"> <div class="subdomain_container">
<img [src]="enterpriseInfo.img || '/api/v1/services/enterprise/images/' + subdomain + '/logo'" class="subdomain_logo" [class]="{'rounded': enterpriseInfo.rounded_corner}"> <img [src]="enterpriseInfo.img || '/api/v1/services/enterprise/images/' + subdomain + '/logo?imageMd5=' + enterpriseInfo.imageMd5" class="subdomain_logo" [class]="{'rounded': enterpriseInfo.rounded_corner}">
</div> </div>
<div class="vertical-line"></div> <div class="vertical-line"></div>
</ng-template> </ng-template>
@ -42,7 +43,7 @@
} @else { } @else {
<ng-template [ngIf]="subdomain && enterpriseInfo"> <ng-template [ngIf]="subdomain && enterpriseInfo">
<div class="subdomain_container"> <div class="subdomain_container">
<img [src]="enterpriseInfo.img || '/api/v1/services/enterprise/images/' + subdomain + '/logo'" class="subdomain_logo" [class]="{'rounded': enterpriseInfo.rounded_corner}"> <img [src]="enterpriseInfo.img || '/api/v1/services/enterprise/images/' + subdomain + '/logo?imageMd5=' + enterpriseInfo.imageMd5" class="subdomain_logo" [class]="{'rounded': enterpriseInfo.rounded_corner}">
</div> </div>
<div class="vertical-line"></div> <div class="vertical-line"></div>
</ng-template> </ng-template>

View File

@ -269,7 +269,7 @@ nav {
text-align: center; text-align: center;
align-self: center; align-self: center;
cursor: pointer; cursor: pointer;
.anon { &.anon {
border: 1.5px solid lightgrey; border: 1.5px solid lightgrey;
color: lightgrey; color: lightgrey;
border-radius: 5px; border-radius: 5px;

View File

@ -267,13 +267,7 @@
<tbody> <tbody>
<tr> <tr>
@for (branch of job.merkleBranches; track $index) { @for (branch of job.merkleBranches; track $index) {
<td class="merkle" [style.background-color]="branch ? '#' + branch.slice(0, 6) : ''"> <td class="merkle" [style.background-color]="branch ? '#' + branch.slice(0, 6) : ''"></td>
@if ($index === 0 && branch) {
<a [routerLink]="['/tx' | relativeUrl, reverseHash(branch)]" class="cell-link">
<fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: text-top; font-size: 14px; color: white"></fa-icon>
</a>
}
</td>
} }
@for (_ of [].constructor(Math.max(0, 12 - job.merkleBranches.length)); track $index) { @for (_ of [].constructor(Math.max(0, 12 - job.merkleBranches.length)); track $index) {
<td class="merkle empty-branch"></td> <td class="merkle empty-branch"></td>

View File

@ -220,7 +220,6 @@ div.scrollable {
.merkle { .merkle {
width: 100px; width: 100px;
text-align: center;
} }
.empty-branch { .empty-branch {
@ -241,19 +240,6 @@ div.scrollable {
td { td {
position: relative; position: relative;
height: 2em; height: 2em;
.cell-link {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
color: inherit;
text-decoration: none;
display: flex;
justify-content: center;
align-items: center;
}
} }
} }

View File

@ -361,10 +361,6 @@ export class PoolComponent implements OnInit {
return block.height; return block.height;
} }
reverseHash(hash: string) {
return hash.match(/../g).reverse().join('');
}
ngOnDestroy(): void { ngOnDestroy(): void {
this.slugSubscription.unsubscribe(); this.slugSubscription.unsubscribe();
} }

View File

@ -82,10 +82,6 @@ export class ServerHealthComponent implements OnInit {
return '🇺🇸'; return '🇺🇸';
} else if (host.includes('.va1.')) { } else if (host.includes('.va1.')) {
return '🇺🇸'; return '🇺🇸';
} else if (host.includes('.sg1.')) {
return '🇸🇬';
} else if (host.includes('.hnl.')) {
return '🤙';
} else { } else {
return ''; return '';
} }

View File

@ -7,27 +7,30 @@
<table *ngIf="poolsReady && (rows$ | async) as rows;" class="stratum-table"> <table *ngIf="poolsReady && (rows$ | async) as rows;" class="stratum-table">
<thead> <thead>
<tr> <tr>
<td class="height">Height</td>
<td class="reward">Reward</td>
<td class="tag">Coinbase Tag</td>
<td class="merkle" [attr.colspan]="rows[0]?.merkleCells?.length || 4"> <td class="merkle" [attr.colspan]="rows[0]?.merkleCells?.length || 4">
Merkle Branches Merkle Branches
</td> </td>
<td class="pool">Pool</td> <td class="pool">Pool</td>
<td class="tag">Coinbase Tag</td>
<td class="reward">Reward</td>
<td class="height">Height</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@for (row of rows; track row.job.pool) { @for (row of rows; track row.job.pool) {
<tr> <tr>
<td class="height">
{{ row.job.height }}
</td>
<td class="reward">
<app-amount [satoshis]="row.job.reward"></app-amount>
</td>
<td class="tag">
{{ row.job.tag }}
</td>
@for (cell of row.merkleCells; track $index) { @for (cell of row.merkleCells; track $index) {
<td class="merkle" [style.background-color]="cell.hash ? '#' + cell.hash.slice(0, 6) : ''"> <td class="merkle" [style.background-color]="cell.hash ? '#' + cell.hash.slice(0, 6) : ''">
@if ($index === 0 && cell.hash) {
<a [routerLink]="['/tx' | relativeUrl, reverseHash(cell.hash)]" class="cell-link">
<div class="pipe-segment" [class]="pipeToClass(cell.type)"></div> <div class="pipe-segment" [class]="pipeToClass(cell.type)"></div>
</a>
} @else {
<div class="pipe-segment" [class]="pipeToClass(cell.type)"></div>
}
</td> </td>
} }
<td class="pool"> <td class="pool">
@ -38,15 +41,6 @@
</a> </a>
} }
</td> </td>
<td class="tag">
{{ row.job.tag }}
</td>
<td class="reward">
<app-amount [satoshis]="row.job.reward"></app-amount>
</td>
<td class="height">
{{ row.job.height }}
</td>
</tr> </tr>
} }
</tbody> </tbody>

View File

@ -92,36 +92,6 @@ td {
} }
} }
} }
.cell-link {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
color: inherit;
text-decoration: none;
}
}
@media (max-width: 800px) {
.stratum-table {
td {
&.tag {
display: none;
}
}
}
}
@media (max-width: 650px) {
.stratum-table {
td {
&.reward {
display: none;
}
}
}
} }
.badge { .badge {

View File

@ -48,16 +48,14 @@ function parseTag(scriptSig: string): string {
return (ascii.match(/\/.*\//)?.[0] || ascii).trim(); return (ascii.match(/\/.*\//)?.[0] || ascii).trim();
} }
function getMerkleBranchIds(merkleBranches: string[], numBranches: number, poolId: number): string[] { function getMerkleBranchIds(merkleBranches: string[], numBranches: number): string[] {
let lastHash = ''; let lastHash = '';
const ids: string[] = []; const ids: string[] = [];
for (let i = 0; i < numBranches; i++) { for (let i = 0; i < numBranches; i++) {
if (merkleBranches[i]) { if (merkleBranches[i]) {
lastHash = merkleBranches[i]; lastHash = merkleBranches[i];
ids.push(`${i}-${lastHash}`);
} else {
ids.push(`${i}-${lastHash}-${poolId}`);
} }
ids.push(`${i}-${lastHash}`);
} }
return ids; return ids;
} }
@ -100,7 +98,7 @@ export class StratumList implements OnInit, OnDestroy {
const numBranches = Math.max(...Object.values(rawJobs).map(job => job.merkleBranches.length)); const numBranches = Math.max(...Object.values(rawJobs).map(job => job.merkleBranches.length));
const jobs: Record<string, TaggedStratumJob> = {}; const jobs: Record<string, TaggedStratumJob> = {};
for (const [id, job] of Object.entries(rawJobs)) { for (const [id, job] of Object.entries(rawJobs)) {
jobs[id] = { ...job, tag: parseTag(job.scriptsig), merkleBranchIds: getMerkleBranchIds(job.merkleBranches, numBranches, job.pool) }; jobs[id] = { ...job, tag: parseTag(job.scriptsig), merkleBranchIds: getMerkleBranchIds(job.merkleBranches, numBranches) };
} }
if (Object.keys(jobs).length === 0) { if (Object.keys(jobs).length === 0) {
return []; return [];
@ -198,10 +196,6 @@ export class StratumList implements OnInit, OnDestroy {
}[type]; }[type];
} }
reverseHash(hash: string) {
return hash.match(/../g).reverse().join('');
}
ngOnDestroy(): void { ngOnDestroy(): void {
this.websocketService.stopTrackStratum(); this.websocketService.stopTrackStratum();
} }

View File

@ -1,47 +1,4 @@
<ng-container [ngSwitch]="name"> <ng-container [ngSwitch]="name">
<ng-container *ngSwitchCase="'VISA'">
<svg xmlns="http://www.w3.org/2000/svg" [attr.width]="width" [attr.height]="height" viewBox="0 0 576 512" fill="white" xmlns="http://www.w3.org/2000/svg">
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
<path d="M470.1 231.3s7.6 37.2 9.3 45H446c3.3-8.9 16-43.5 16-43.5-.2 .3 3.3-9.1 5.3-14.9l2.8 13.4zM576 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h480c26.5 0 48 21.5 48 48zM152.5 331.2L215.7 176h-42.5l-39.3 106-4.3-21.5-14-71.4c-2.3-9.9-9.4-12.7-18.2-13.1H32.7l-.7 3.1c15.8 4 29.9 9.8 42.2 17.1l35.8 135h42.5zm94.4 .2L272.1 176h-40.2l-25.1 155.4h40.1zm139.9-50.8c.2-17.7-10.6-31.2-33.7-42.3-14.1-7.1-22.7-11.9-22.7-19.2 .2-6.6 7.3-13.4 23.1-13.4 13.1-.3 22.7 2.8 29.9 5.9l3.6 1.7 5.5-33.6c-7.9-3.1-20.5-6.6-36-6.6-39.7 0-67.6 21.2-67.8 51.4-.3 22.3 20 34.7 35.2 42.2 15.5 7.6 20.8 12.6 20.8 19.3-.2 10.4-12.6 15.2-24.1 15.2-16 0-24.6-2.5-37.7-8.3l-5.3-2.5-5.6 34.9c9.4 4.3 26.8 8.1 44.8 8.3 42.2 .1 69.7-20.8 70-53zM528 331.4L495.6 176h-31.1c-9.6 0-16.9 2.8-21 12.9l-59.7 142.5H426s6.9-19.2 8.4-23.3H486c1.2 5.5 4.8 23.3 4.8 23.3H528z"/>
</svg>
</ng-container>
<ng-container *ngSwitchCase="'MASTERCARD'">
<svg xmlns="http://www.w3.org/2000/svg" [attr.width]="width" [attr.height]="height" viewBox="0 0 576 512" fill="white" xmlns="http://www.w3.org/2000/svg">
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M482.9 410.3c0 6.8-4.6 11.7-11.2 11.7-6.8 0-11.2-5.2-11.2-11.7 0-6.5 4.4-11.7 11.2-11.7 6.6 0 11.2 5.2 11.2 11.7zm-310.8-11.7c-7.1 0-11.2 5.2-11.2 11.7 0 6.5 4.1 11.7 11.2 11.7 6.5 0 10.9-4.9 10.9-11.7-.1-6.5-4.4-11.7-10.9-11.7zm117.5-.3c-5.4 0-8.7 3.5-9.5 8.7h19.1c-.9-5.7-4.4-8.7-9.6-8.7zm107.8 .3c-6.8 0-10.9 5.2-10.9 11.7 0 6.5 4.1 11.7 10.9 11.7 6.8 0 11.2-4.9 11.2-11.7 0-6.5-4.4-11.7-11.2-11.7zm105.9 26.1c0 .3 .3 .5 .3 1.1 0 .3-.3 .5-.3 1.1-.3 .3-.3 .5-.5 .8-.3 .3-.5 .5-1.1 .5-.3 .3-.5 .3-1.1 .3-.3 0-.5 0-1.1-.3-.3 0-.5-.3-.8-.5-.3-.3-.5-.5-.5-.8-.3-.5-.3-.8-.3-1.1 0-.5 0-.8 .3-1.1 0-.5 .3-.8 .5-1.1 .3-.3 .5-.3 .8-.5 .5-.3 .8-.3 1.1-.3 .5 0 .8 0 1.1 .3 .5 .3 .8 .3 1.1 .5s.2 .6 .5 1.1zm-2.2 1.4c.5 0 .5-.3 .8-.3 .3-.3 .3-.5 .3-.8 0-.3 0-.5-.3-.8-.3 0-.5-.3-1.1-.3h-1.6v3.5h.8V426h.3l1.1 1.4h.8l-1.1-1.3zM576 81v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V81c0-26.5 21.5-48 48-48h480c26.5 0 48 21.5 48 48zM64 220.6c0 76.5 62.1 138.5 138.5 138.5 27.2 0 53.9-8.2 76.5-23.1-72.9-59.3-72.4-171.2 0-230.5-22.6-15-49.3-23.1-76.5-23.1-76.4-.1-138.5 62-138.5 138.2zm224 108.8c70.5-55 70.2-162.2 0-217.5-70.2 55.3-70.5 162.6 0 217.5zm-142.3 76.3c0-8.7-5.7-14.4-14.7-14.7-4.6 0-9.5 1.4-12.8 6.5-2.4-4.1-6.5-6.5-12.2-6.5-3.8 0-7.6 1.4-10.6 5.4V392h-8.2v36.7h8.2c0-18.9-2.5-30.2 9-30.2 10.2 0 8.2 10.2 8.2 30.2h7.9c0-18.3-2.5-30.2 9-30.2 10.2 0 8.2 10 8.2 30.2h8.2v-23zm44.9-13.7h-7.9v4.4c-2.7-3.3-6.5-5.4-11.7-5.4-10.3 0-18.2 8.2-18.2 19.3 0 11.2 7.9 19.3 18.2 19.3 5.2 0 9-1.9 11.7-5.4v4.6h7.9V392zm40.5 25.6c0-15-22.9-8.2-22.9-15.2 0-5.7 11.9-4.8 18.5-1.1l3.3-6.5c-9.4-6.1-30.2-6-30.2 8.2 0 14.3 22.9 8.3 22.9 15 0 6.3-13.5 5.8-20.7 .8l-3.5 6.3c11.2 7.6 32.6 6 32.6-7.5zm35.4 9.3l-2.2-6.8c-3.8 2.1-12.2 4.4-12.2-4.1v-16.6h13.1V392h-13.1v-11.2h-8.2V392h-7.6v7.3h7.6V416c0 17.6 17.3 14.4 22.6 10.9zm13.3-13.4h27.5c0-16.2-7.4-22.6-17.4-22.6-10.6 0-18.2 7.9-18.2 19.3 0 20.5 22.6 23.9 33.8 14.2l-3.8-6c-7.8 6.4-19.6 5.8-21.9-4.9zm59.1-21.5c-4.6-2-11.6-1.8-15.2 4.4V392h-8.2v36.7h8.2V408c0-11.6 9.5-10.1 12.8-8.4l2.4-7.6zm10.6 18.3c0-11.4 11.6-15.1 20.7-8.4l3.8-6.5c-11.6-9.1-32.7-4.1-32.7 15 0 19.8 22.4 23.8 32.7 15l-3.8-6.5c-9.2 6.5-20.7 2.6-20.7-8.6zm66.7-18.3H408v4.4c-8.3-11-29.9-4.8-29.9 13.9 0 19.2 22.4 24.7 29.9 13.9v4.6h8.2V392zm33.7 0c-2.4-1.2-11-2.9-15.2 4.4V392h-7.9v36.7h7.9V408c0-11 9-10.3 12.8-8.4l2.4-7.6zm40.3-14.9h-7.9v19.3c-8.2-10.9-29.9-5.1-29.9 13.9 0 19.4 22.5 24.6 29.9 13.9v4.6h7.9v-51.7zm7.6-75.1v4.6h.8V302h1.9v-.8h-4.6v.8h1.9zm6.6 123.8c0-.5 0-1.1-.3-1.6-.3-.3-.5-.8-.8-1.1-.3-.3-.8-.5-1.1-.8-.5 0-1.1-.3-1.6-.3-.3 0-.8 .3-1.4 .3-.5 .3-.8 .5-1.1 .8-.5 .3-.8 .8-.8 1.1-.3 .5-.3 1.1-.3 1.6 0 .3 0 .8 .3 1.4 0 .3 .3 .8 .8 1.1 .3 .3 .5 .5 1.1 .8 .5 .3 1.1 .3 1.4 .3 .5 0 1.1 0 1.6-.3 .3-.3 .8-.5 1.1-.8 .3-.3 .5-.8 .8-1.1 .3-.6 .3-1.1 .3-1.4zm3.2-124.7h-1.4l-1.6 3.5-1.6-3.5h-1.4v5.4h.8v-4.1l1.6 3.5h1.1l1.4-3.5v4.1h1.1v-5.4zm4.4-80.5c0-76.2-62.1-138.3-138.5-138.3-27.2 0-53.9 8.2-76.5 23.1 72.1 59.3 73.2 171.5 0 230.5 22.6 15 49.5 23.1 76.5 23.1 76.4 .1 138.5-61.9 138.5-138.4z"/>
</svg>
</ng-container>
<ng-container *ngSwitchCase="'JCB'">
<svg xmlns="http://www.w3.org/2000/svg" [attr.width]="width" [attr.height]="height" viewBox="0 0 576 512" fill="white" xmlns="http://www.w3.org/2000/svg">
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M431.5 244.3V212c41.2 0 38.5 .2 38.5 .2 7.3 1.3 13.3 7.3 13.3 16 0 8.8-6 14.5-13.3 15.8-1.2 .4-3.3 .3-38.5 .3zm42.8 20.2c-2.8-.7-3.3-.5-42.8-.5v35c39.6 0 40 .2 42.8-.5 7.5-1.5 13.5-8 13.5-17 0-8.7-6-15.5-13.5-17zM576 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h480c26.5 0 48 21.5 48 48zM182 192.3h-57c0 67.1 10.7 109.7-35.8 109.7-19.5 0-38.8-5.7-57.2-14.8v28c30 8.3 68 8.3 68 8.3 97.9 0 82-47.7 82-131.2zm178.5 4.5c-63.4-16-165-14.9-165 59.3 0 77.1 108.2 73.6 165 59.2V287C312.9 311.7 253 309 253 256s59.8-55.6 107.5-31.2v-28zM544 286.5c0-18.5-16.5-30.5-38-32v-.8c19.5-2.7 30.3-15.5 30.3-30.2 0-19-15.7-30-37-31 0 0 6.3-.3-120.3-.3v127.5h122.7c24.3 .1 42.3-12.9 42.3-33.2z"/>
</svg>
</ng-container>
<ng-container *ngSwitchCase="'DISCOVER'">
<svg xmlns="http://www.w3.org/2000/svg" [attr.width]="width" [attr.height]="height" viewBox="0 0 576 512" fill="white" xmlns="http://www.w3.org/2000/svg">
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M520.4 196.1c0-7.9-5.5-12.1-15.6-12.1h-4.9v24.9h4.7c10.3 0 15.8-4.4 15.8-12.8zM528 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h480c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-44.1 138.9c22.6 0 52.9-4.1 52.9 24.4 0 12.6-6.6 20.7-18.7 23.2l25.8 34.4h-19.6l-22.2-32.8h-2.2v32.8h-16zm-55.9 .1h45.3v14H444v18.2h28.3V217H444v22.2h29.3V253H428zm-68.7 0l21.9 55.2 22.2-55.2h17.5l-35.5 84.2h-8.6l-35-84.2zm-55.9-3c24.7 0 44.6 20 44.6 44.6 0 24.7-20 44.6-44.6 44.6-24.7 0-44.6-20-44.6-44.6 0-24.7 20-44.6 44.6-44.6zm-49.3 6.1v19c-20.1-20.1-46.8-4.7-46.8 19 0 25 27.5 38.5 46.8 19.2v19c-29.7 14.3-63.3-5.7-63.3-38.2 0-31.2 33.1-53 63.3-38zm-97.2 66.3c11.4 0 22.4-15.3-3.3-24.4-15-5.5-20.2-11.4-20.2-22.7 0-23.2 30.6-31.4 49.7-14.3l-8.4 10.8c-10.4-11.6-24.9-6.2-24.9 2.5 0 4.4 2.7 6.9 12.3 10.3 18.2 6.6 23.6 12.5 23.6 25.6 0 29.5-38.8 37.4-56.6 11.3l10.3-9.9c3.7 7.1 9.9 10.8 17.5 10.8zM55.4 253H32v-82h23.4c26.1 0 44.1 17 44.1 41.1 0 18.5-13.2 40.9-44.1 40.9zm67.5 0h-16v-82h16zM544 433c0 8.2-6.8 15-15 15H128c189.6-35.6 382.7-139.2 416-160zM74.1 191.6c-5.2-4.9-11.6-6.6-21.9-6.6H48v54.2h4.2c10.3 0 17-2 21.9-6.4 5.7-5.2 8.9-12.8 8.9-20.7s-3.2-15.5-8.9-20.5z"/>
</svg>
</ng-container>
<ng-container *ngSwitchCase="'DISCOVER_DINERS'">
<svg xmlns="http://www.w3.org/2000/svg" [attr.width]="width" [attr.height]="height" viewBox="0 0 576 512" fill="white" xmlns="http://www.w3.org/2000/svg">
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M239.7 79.9c-96.9 0-175.8 78.6-175.8 175.8 0 96.9 78.9 175.8 175.8 175.8 97.2 0 175.8-78.9 175.8-175.8 0-97.2-78.6-175.8-175.8-175.8zm-39.9 279.6c-41.7-15.9-71.4-56.4-71.4-103.8s29.7-87.9 71.4-104.1v207.9zm79.8 .3V151.6c41.7 16.2 71.4 56.7 71.4 104.1s-29.7 87.9-71.4 104.1zM528 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h480c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zM329.7 448h-90.3c-106.2 0-193.8-85.5-193.8-190.2C45.6 143.2 133.2 64 239.4 64h90.3c105 0 200.7 79.2 200.7 193.8 0 104.7-95.7 190.2-200.7 190.2z"/>
</svg>
</ng-container>
<ng-container *ngSwitchCase="'AMERICAN_EXPRESS'">
<svg xmlns="http://www.w3.org/2000/svg" [attr.width]="width" [attr.height]="height" viewBox="0 0 576 512" fill="white" xmlns="http://www.w3.org/2000/svg">
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M0 432c0 26.5 21.5 48 48 48H528c26.5 0 48-21.5 48-48v-1.1H514.3l-31.9-35.1-31.9 35.1H246.8V267.1H181L262.7 82.4h78.6l28.1 63.2V82.4h97.2L483.5 130l17-47.6H576V80c0-26.5-21.5-48-48-48H48C21.5 32 0 53.5 0 80V432zm440.4-21.7L482.6 364l42 46.3H576l-68-72.1 68-72.1H525.4l-42 46.7-41.5-46.7H390.5L458 338.6l-67.4 71.6V377.1h-83V354.9h80.9V322.6H307.6V300.2h83V267.1h-122V410.3H440.4zm96.3-72L576 380.2V296.9l-39.3 41.4zm-36.3-92l36.9-100.6V246.3H576V103H515.8l-32.2 89.3L451.7 103H390.5V246.1L327.3 103H276.1L213.7 246.3h43l11.9-28.7h65.9l12 28.7h82.7V146L466 246.3h34.4zM282 185.4l19.5-46.9 19.4 46.9H282z"/>
</svg>
</ng-container>
<ng-container *ngSwitchCase="'OTHER_BRAND'">
<svg xmlns="http://www.w3.org/2000/svg" [attr.width]="width" [attr.height]="height" viewBox="0 0 576 512" fill="white" xmlns="http://www.w3.org/2000/svg">
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M512 80c8.8 0 16 7.2 16 16l0 32L48 128l0-32c0-8.8 7.2-16 16-16l448 0zm16 144l0 192c0 8.8-7.2 16-16 16L64 432c-8.8 0-16-7.2-16-16l0-192 480 0zM64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l448 0c35.3 0 64-28.7 64-64l0-320c0-35.3-28.7-64-64-64L64 32zm56 304c-13.3 0-24 10.7-24 24s10.7 24 24 24l48 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-48 0zm128 0c-13.3 0-24 10.7-24 24s10.7 24 24 24l112 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-112 0z"/>
</svg>
</ng-container>
<ng-container *ngSwitchCase="'officialMempoolSpace'"> <ng-container *ngSwitchCase="'officialMempoolSpace'">
<svg [class]="class" [style]="style" [attr.width]="width" [attr.height]="height" [attr.viewBox]="viewBox" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg [class]="class" [style]="style" [attr.width]="width" [attr.height]="height" [attr.viewBox]="viewBox" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M163.658 113.263C161.089 113.263 158.992 111.146 158.992 108.535C158.992 105.966 161.048 103.951 163.658 103.951C166.269 103.951 168.325 105.966 168.325 108.535C168.325 111.125 166.228 113.263 163.658 113.263Z" fill="#9857FF"/> <path d="M163.658 113.263C161.089 113.263 158.992 111.146 158.992 108.535C158.992 105.966 161.048 103.951 163.658 103.951C166.269 103.951 168.325 105.966 168.325 108.535C168.325 111.125 166.228 113.263 163.658 113.263Z" fill="#9857FF"/>

View File

@ -8,7 +8,7 @@
</a> </a>
} @else if (enterpriseInfo?.img || enterpriseInfo?.imageMd5) { } @else if (enterpriseInfo?.img || enterpriseInfo?.imageMd5) {
<a [routerLink]="['/' | relativeUrl]"> <a [routerLink]="['/' | relativeUrl]">
<img [src]="enterpriseInfo.img || '/api/v1/services/enterprise/images/' + enterpriseInfo.name + '/logo'" class="subdomain_logo" [class]="{'rounded': enterpriseInfo.rounded_corner}"> <img [src]="enterpriseInfo.img || '/api/v1/services/enterprise/images/' + enterpriseInfo.name + '/logo?imageMd5=' + enterpriseInfo.imageMd5" class="subdomain_logo" [class]="{'rounded': enterpriseInfo.rounded_corner}">
</a> </a>
<div class="vertical-line"></div> <div class="vertical-line"></div>
} }
@ -124,6 +124,7 @@
<ng-container *ngIf="(ETA$ | async) as eta;"> <ng-container *ngIf="(ETA$ | async) as eta;">
<app-accelerate-checkout <app-accelerate-checkout
*ngIf="(da$ | async) as da;" *ngIf="(da$ | async) as da;"
[cashappEnabled]="cashappEligible"
[advancedEnabled]="false" [advancedEnabled]="false"
[forceMobile]="true" [forceMobile]="true"
[tx]="tx" [tx]="tx"

View File

@ -756,6 +756,10 @@ export class TrackerComponent implements OnInit, OnDestroy {
} }
} }
get cashappEligible(): boolean {
return this.mempoolPosition?.block > 0 && this.tx.weight < 4000;
}
get showAccelerationSummary(): boolean { get showAccelerationSummary(): boolean {
return ( return (
this.tx this.tx

View File

@ -139,6 +139,7 @@
<app-accelerate-checkout <app-accelerate-checkout
*ngIf="(da$ | async) as da;" *ngIf="(da$ | async) as da;"
[cashappEnabled]="cashappEligible"
[advancedEnabled]="true" [advancedEnabled]="true"
[tx]="tx" [tx]="tx"
[accelerating]="isAcceleration" [accelerating]="isAcceleration"

View File

@ -156,6 +156,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
showAccelerationDetails = false; showAccelerationDetails = false;
hasAccelerationDetails = false; hasAccelerationDetails = false;
scrollIntoAccelPreview = false; scrollIntoAccelPreview = false;
cashappEligible = false;
auditEnabled: boolean = this.stateService.env.AUDIT && this.stateService.env.BASE_MODULE === 'mempool' && this.stateService.env.MINING_DASHBOARD === true; auditEnabled: boolean = this.stateService.env.AUDIT && this.stateService.env.BASE_MODULE === 'mempool' && this.stateService.env.MINING_DASHBOARD === true;
isMempoolSpaceBuild = this.stateService.isMempoolSpaceBuild; isMempoolSpaceBuild = this.stateService.isMempoolSpaceBuild;
@ -527,6 +528,9 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
this.miningStats = stats; this.miningStats = stats;
}); });
} }
if (txPosition.position?.block > 0 && this.tx.weight < 4000) {
this.cashappEligible = true;
}
if (!this.gotInitialPosition && txPosition.position?.block === 0 && txPosition.position?.vsize < 750_000) { if (!this.gotInitialPosition && txPosition.position?.block === 0 && txPosition.position?.vsize < 750_000) {
this.accelerationFlowCompleted = true; this.accelerationFlowCompleted = true;
} }
@ -1032,6 +1036,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
this.showAccelerationDetails = false; this.showAccelerationDetails = false;
this.accelerationFlowCompleted = false; this.accelerationFlowCompleted = false;
this.accelerationInfo = null; this.accelerationInfo = null;
this.cashappEligible = false;
this.txInBlockIndex = null; this.txInBlockIndex = null;
this.mempoolPosition = null; this.mempoolPosition = null;
this.pool = null; this.pool = null;

View File

@ -1,6 +1,6 @@
<a href="#" (click)="twitterLogin()" <a href="#" (click)="twitterLogin()"
[class]="(disabled ? 'disabled': '') + (customClass ? customClass : 'w-100 btn mt-1 d-flex justify-content-center align-items-center')" [class]="(disabled ? 'disabled': '') + (customClass ? customClass : 'w-100 btn mt-1 d-flex justify-content-center align-items-center')"
style="background-color: rgb(31, 35, 40)" [style]="width ? 'width: ' + width : ''"> style="background-color: #1DA1F2" [style]="width ? 'width: ' + width : ''">
<img src="./resources/twitter.svg" height="25" style="padding: 2px" [alt]="buttonString + ' with Twitter'" />
<span class="ml-2 text-light align-middle">{{ buttonString }}</span> <span class="ml-2 text-light align-middle">{{ buttonString }}</span>
<img src="./resources/x.svg" height="25" style="padding: 2px; padding-left: 5px" [alt]="buttonString + ' with Twitter'" />
</a> </a>

View File

@ -412,13 +412,13 @@ export interface Acceleration {
feeDelta: number; feeDelta: number;
blockHash: string; blockHash: string;
blockHeight: number; blockHeight: number;
acceleratedFeeRate?: number; acceleratedFeeRate?: number;
boost?: number; boost?: number;
bidBoost?: number; bidBoost?: number;
boostCost?: number; boostCost?: number;
boostRate?: number; boostRate?: number;
minedByPoolUniqueId?: number; minedByPoolUniqueId?: number;
canceled?: number;
} }
export interface AccelerationHistoryParams { export interface AccelerationHistoryParams {

View File

@ -58,7 +58,6 @@ export class AuthServiceMempool {
setAuth(auth: any) { setAuth(auth: any) {
if (!auth) { if (!auth) {
localStorage.removeItem('auth'); localStorage.removeItem('auth');
localStorage.removeItem('authenticatorStatus');
} else { } else {
localStorage.setItem('auth', JSON.stringify(auth)); localStorage.setItem('auth', JSON.stringify(auth));
} }

View File

@ -146,10 +146,6 @@ export class ServicesApiServices {
return this.httpClient.post<any>(`${this.stateService.env.SERVICES_API}/accelerator/accelerate/googlePay`, { txInput: txInput, cardTag: cardTag, token: token, verificationToken: verificationToken, referenceId: referenceId, userApprovedUSD: userApprovedUSD, userChallenged: userChallenged }); return this.httpClient.post<any>(`${this.stateService.env.SERVICES_API}/accelerator/accelerate/googlePay`, { txInput: txInput, cardTag: cardTag, token: token, verificationToken: verificationToken, referenceId: referenceId, userApprovedUSD: userApprovedUSD, userChallenged: userChallenged });
} }
accelerateWithCardOnFile$(txInput: string, token: string, verificationToken: string, referenceId: string, userApprovedUSD: number, userChallenged: boolean) {
return this.httpClient.post<any>(`${this.stateService.env.SERVICES_API}/accelerator/accelerate/cardOnFile`, { txInput: txInput, token: token, verificationToken: verificationToken, referenceId: referenceId, userApprovedUSD: userApprovedUSD, userChallenged: userChallenged });
}
getAccelerations$(): Observable<Acceleration[]> { getAccelerations$(): Observable<Acceleration[]> {
return this.httpClient.get<Acceleration[]>(`${this.stateService.env.SERVICES_API}/accelerator/accelerations`); return this.httpClient.get<Acceleration[]>(`${this.stateService.env.SERVICES_API}/accelerator/accelerations`);
} }

View File

@ -26,7 +26,6 @@ export const MempoolErrors = {
'unauthorized': `You are not authorized to do this`, 'unauthorized': `You are not authorized to do this`,
'faucet_too_soon': `You cannot request any more coins right now. Try again later.`, 'faucet_too_soon': `You cannot request any more coins right now. Try again later.`,
'faucet_not_available': `The faucet is not available right now. Try again later.`, 'faucet_not_available': `The faucet is not available right now. Try again later.`,
'faucet_not_available_no_utxo': `The faucet is not available right now. Please try again once a new block has been mined.`,
'faucet_maximum_reached': `You are not allowed to request more coins`, 'faucet_maximum_reached': `You are not allowed to request more coins`,
'faucet_address_not_allowed': `You cannot use this address`, 'faucet_address_not_allowed': `You cannot use this address`,
'faucet_below_minimum': `Requested amount is too small`, 'faucet_below_minimum': `Requested amount is too small`,

View File

@ -7,7 +7,7 @@ import { faFilter, faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, fa
faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft, faArrowsRotate, faCircleLeft, faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft, faArrowsRotate, faCircleLeft,
faFastForward, faWallet, faUserClock, faWrench, faUserFriends, faQuestionCircle, faHistory, faSignOutAlt, faKey, faSuitcase, faIdCardAlt, faNetworkWired, faUserCheck, faFastForward, faWallet, faUserClock, faWrench, faUserFriends, faQuestionCircle, faHistory, faSignOutAlt, faKey, faSuitcase, faIdCardAlt, faNetworkWired, faUserCheck,
faCircleCheck, faUserCircle, faCheck, faRocket, faScaleBalanced, faHourglassStart, faHourglassHalf, faHourglassEnd, faWandMagicSparkles, faFaucetDrip, faTimeline, faCircleCheck, faUserCircle, faCheck, faRocket, faScaleBalanced, faHourglassStart, faHourglassHalf, faHourglassEnd, faWandMagicSparkles, faFaucetDrip, faTimeline,
faCircleXmark, faCalendarCheck, faMoneyBillTrendUp, faRobot, faShareNodes, faCreditCard } from '@fortawesome/free-solid-svg-icons'; faCircleXmark, faCalendarCheck, faMoneyBillTrendUp, faRobot, faShareNodes } from '@fortawesome/free-solid-svg-icons';
import { InfiniteScrollModule } from 'ngx-infinite-scroll'; import { InfiniteScrollModule } from 'ngx-infinite-scroll';
import { MenuComponent } from '@components/menu/menu.component'; import { MenuComponent } from '@components/menu/menu.component';
import { PreviewTitleComponent } from '@components/master-page-preview/preview-title.component'; import { PreviewTitleComponent } from '@components/master-page-preview/preview-title.component';
@ -125,7 +125,6 @@ import { TwitterLogin } from '@components/twitter-login/twitter-login.component'
import { BitcoinInvoiceComponent } from '@components/bitcoin-invoice/bitcoin-invoice.component'; import { BitcoinInvoiceComponent } from '@components/bitcoin-invoice/bitcoin-invoice.component';
import { OnlyVsizeDirective, OnlyWeightDirective } from '@app/shared/components/weight-directives/weight-directives'; import { OnlyVsizeDirective, OnlyWeightDirective } from '@app/shared/components/weight-directives/weight-directives';
import { GithubLogin } from '../components/github-login.component/github-login.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -243,7 +242,6 @@ import { GithubLogin } from '../components/github-login.component/github-login.c
TwitterWidgetComponent, TwitterWidgetComponent,
FaucetComponent, FaucetComponent,
TwitterLogin, TwitterLogin,
GithubLogin,
BitcoinInvoiceComponent, BitcoinInvoiceComponent,
], ],
imports: [ imports: [
@ -378,7 +376,6 @@ import { GithubLogin } from '../components/github-login.component/github-login.c
HttpErrorComponent, HttpErrorComponent,
TwitterWidgetComponent, TwitterWidgetComponent,
TwitterLogin, TwitterLogin,
GithubLogin,
BitcoinInvoiceComponent, BitcoinInvoiceComponent,
BitcoinsatoshisPipe, BitcoinsatoshisPipe,
@ -463,6 +460,5 @@ export class SharedModule {
library.addIcons(faMoneyBillTrendUp); library.addIcons(faMoneyBillTrendUp);
library.addIcons(faRobot); library.addIcons(faRobot);
library.addIcons(faShareNodes); library.addIcons(faShareNodes);
library.addIcons(faCreditCard);
} }
} }

View File

@ -150,8 +150,7 @@ http {
} }
server { server {
listen 80; listen 127.0.0.1:80;
listen [::]:80
include /etc/nginx/nginx-mempool.conf; include /etc/nginx/nginx-mempool.conf;
} }
} }

View File

@ -15,7 +15,6 @@ whitelist=127.0.0.1
whitelist=103.99.168.0/22 whitelist=103.99.168.0/22
whitelist=2401:b140::/32 whitelist=2401:b140::/32
blocksxor=0 blocksxor=0
logtimemicros=1
#uacomment=@wiz #uacomment=@wiz
[main] [main]

View File

@ -26,14 +26,12 @@
"ESPLORA": { "ESPLORA": {
"UNIX_SOCKET_PATH": "/elements/socket/esplora-elements-liquid", "UNIX_SOCKET_PATH": "/elements/socket/esplora-elements-liquid",
"FALLBACK": [ "FALLBACK": [
"http://node201.hnl.mempool.space:3001", "http://node201.fmt.mempool.space:3001",
"http://node202.hnl.mempool.space:3001", "http://node202.fmt.mempool.space:3001",
"http://node203.hnl.mempool.space:3001", "http://node203.fmt.mempool.space:3001",
"http://node204.hnl.mempool.space:3001", "http://node204.fmt.mempool.space:3001",
"http://node201.sg1.mempool.space:3001", "http://node205.fmt.mempool.space:3001",
"http://node202.sg1.mempool.space:3001", "http://node206.fmt.mempool.space:3001",
"http://node203.sg1.mempool.space:3001",
"http://node204.sg1.mempool.space:3001",
"http://node201.va1.mempool.space:3001", "http://node201.va1.mempool.space:3001",
"http://node202.va1.mempool.space:3001", "http://node202.va1.mempool.space:3001",
"http://node203.va1.mempool.space:3001", "http://node203.va1.mempool.space:3001",

View File

@ -26,14 +26,12 @@
"ESPLORA": { "ESPLORA": {
"UNIX_SOCKET_PATH": "/elements/socket/esplora-elements-liquidtestnet", "UNIX_SOCKET_PATH": "/elements/socket/esplora-elements-liquidtestnet",
"FALLBACK": [ "FALLBACK": [
"http://node201.hnl.mempool.space:3004", "http://node201.fmt.mempool.space:3004",
"http://node202.hnl.mempool.space:3004", "http://node202.fmt.mempool.space:3004",
"http://node203.hnl.mempool.space:3004", "http://node203.fmt.mempool.space:3004",
"http://node204.hnl.mempool.space:3004", "http://node204.fmt.mempool.space:3004",
"http://node201.sg1.mempool.space:3004", "http://node205.fmt.mempool.space:3004",
"http://node202.sg1.mempool.space:3004", "http://node206.fmt.mempool.space:3004",
"http://node203.sg1.mempool.space:3004",
"http://node204.sg1.mempool.space:3004",
"http://node201.va1.mempool.space:3004", "http://node201.va1.mempool.space:3004",
"http://node202.va1.mempool.space:3004", "http://node202.va1.mempool.space:3004",
"http://node203.va1.mempool.space:3004", "http://node203.va1.mempool.space:3004",

View File

@ -19,14 +19,12 @@
"ESPLORA": { "ESPLORA": {
"UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-mainnet", "UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-mainnet",
"FALLBACK": [ "FALLBACK": [
"http://node201.hnl.mempool.space:3000", "http://node201.fmt.mempool.space:3000",
"http://node202.hnl.mempool.space:3000", "http://node202.fmt.mempool.space:3000",
"http://node203.hnl.mempool.space:3000", "http://node203.fmt.mempool.space:3000",
"http://node204.hnl.mempool.space:3000", "http://node204.fmt.mempool.space:3000",
"http://node201.sg1.mempool.space:3000", "http://node205.fmt.mempool.space:3000",
"http://node202.sg1.mempool.space:3000", "http://node206.fmt.mempool.space:3000",
"http://node203.sg1.mempool.space:3000",
"http://node204.sg1.mempool.space:3000",
"http://node201.va1.mempool.space:3000", "http://node201.va1.mempool.space:3000",
"http://node202.va1.mempool.space:3000", "http://node202.va1.mempool.space:3000",
"http://node203.va1.mempool.space:3000", "http://node203.va1.mempool.space:3000",

View File

@ -30,8 +30,7 @@
"CORE_RPC": { "CORE_RPC": {
"PORT": 8332, "PORT": 8332,
"USERNAME": "__BITCOIN_RPC_USER__", "USERNAME": "__BITCOIN_RPC_USER__",
"PASSWORD": "__BITCOIN_RPC_PASS__", "PASSWORD": "__BITCOIN_RPC_PASS__"
"DEBUG_LOG_PATH": "/bitcoin/debug.log"
}, },
"SECOND_CORE_RPC": { "SECOND_CORE_RPC": {
"PORT": 8302, "PORT": 8302,
@ -41,14 +40,12 @@
"ESPLORA": { "ESPLORA": {
"UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-mainnet", "UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-mainnet",
"FALLBACK": [ "FALLBACK": [
"http://node201.hnl.mempool.space:3000", "http://node201.fmt.mempool.space:3000",
"http://node202.hnl.mempool.space:3000", "http://node202.fmt.mempool.space:3000",
"http://node203.hnl.mempool.space:3000", "http://node203.fmt.mempool.space:3000",
"http://node204.hnl.mempool.space:3000", "http://node204.fmt.mempool.space:3000",
"http://node201.sg1.mempool.space:3000", "http://node205.fmt.mempool.space:3000",
"http://node202.sg1.mempool.space:3000", "http://node206.fmt.mempool.space:3000",
"http://node203.sg1.mempool.space:3000",
"http://node204.sg1.mempool.space:3000",
"http://node201.va1.mempool.space:3000", "http://node201.va1.mempool.space:3000",
"http://node202.va1.mempool.space:3000", "http://node202.va1.mempool.space:3000",
"http://node203.va1.mempool.space:3000", "http://node203.va1.mempool.space:3000",
@ -104,14 +101,12 @@
"STATISTICS": true, "STATISTICS": true,
"STATISTICS_START_TIME": "24h", "STATISTICS_START_TIME": "24h",
"SERVERS": [ "SERVERS": [
"node201.hnl.mempool.space", "node201.fmt.mempool.space",
"node202.hnl.mempool.space", "node202.fmt.mempool.space",
"node203.hnl.mempool.space", "node203.fmt.mempool.space",
"node204.hnl.mempool.space", "node204.fmt.mempool.space",
"node201.sg1.mempool.space", "node205.fmt.mempool.space",
"node202.sg1.mempool.space", "node206.fmt.mempool.space",
"node203.sg1.mempool.space",
"node204.sg1.mempool.space",
"node201.va1.mempool.space", "node201.va1.mempool.space",
"node202.va1.mempool.space", "node202.va1.mempool.space",
"node203.va1.mempool.space", "node203.va1.mempool.space",

View File

@ -19,14 +19,12 @@
"ESPLORA": { "ESPLORA": {
"UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-signet", "UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-signet",
"FALLBACK": [ "FALLBACK": [
"http://node201.hnl.mempool.space:3003", "http://node201.fmt.mempool.space:3003",
"http://node202.hnl.mempool.space:3003", "http://node202.fmt.mempool.space:3003",
"http://node203.hnl.mempool.space:3003", "http://node203.fmt.mempool.space:3003",
"http://node204.hnl.mempool.space:3003", "http://node204.fmt.mempool.space:3003",
"http://node201.sg1.mempool.space:3003", "http://node205.fmt.mempool.space:3003",
"http://node202.sg1.mempool.space:3003", "http://node206.fmt.mempool.space:3003",
"http://node203.sg1.mempool.space:3003",
"http://node204.sg1.mempool.space:3003",
"http://node201.va1.mempool.space:3003", "http://node201.va1.mempool.space:3003",
"http://node202.va1.mempool.space:3003", "http://node202.va1.mempool.space:3003",
"http://node203.va1.mempool.space:3003", "http://node203.va1.mempool.space:3003",

View File

@ -28,14 +28,12 @@
"ESPLORA": { "ESPLORA": {
"UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-signet", "UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-signet",
"FALLBACK": [ "FALLBACK": [
"http://node201.hnl.mempool.space:3003", "http://node201.fmt.mempool.space:3003",
"http://node202.hnl.mempool.space:3003", "http://node202.fmt.mempool.space:3003",
"http://node203.hnl.mempool.space:3003", "http://node203.fmt.mempool.space:3003",
"http://node204.hnl.mempool.space:3003", "http://node204.fmt.mempool.space:3003",
"http://node201.sg1.mempool.space:3003", "http://node205.fmt.mempool.space:3003",
"http://node202.sg1.mempool.space:3003", "http://node206.fmt.mempool.space:3003",
"http://node203.sg1.mempool.space:3003",
"http://node204.sg1.mempool.space:3003",
"http://node201.va1.mempool.space:3003", "http://node201.va1.mempool.space:3003",
"http://node202.va1.mempool.space:3003", "http://node202.va1.mempool.space:3003",
"http://node203.va1.mempool.space:3003", "http://node203.va1.mempool.space:3003",

View File

@ -19,14 +19,12 @@
"ESPLORA": { "ESPLORA": {
"UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-testnet", "UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-testnet",
"FALLBACK": [ "FALLBACK": [
"http://node201.hnl.mempool.space:3002", "http://node201.fmt.mempool.space:3002",
"http://node202.hnl.mempool.space:3002", "http://node202.fmt.mempool.space:3002",
"http://node203.hnl.mempool.space:3002", "http://node203.fmt.mempool.space:3002",
"http://node204.hnl.mempool.space:3002", "http://node204.fmt.mempool.space:3002",
"http://node201.sg1.mempool.space:3002", "http://node205.fmt.mempool.space:3002",
"http://node202.sg1.mempool.space:3002", "http://node206.fmt.mempool.space:3002",
"http://node203.sg1.mempool.space:3002",
"http://node204.sg1.mempool.space:3002",
"http://node201.va1.mempool.space:3002", "http://node201.va1.mempool.space:3002",
"http://node202.va1.mempool.space:3002", "http://node202.va1.mempool.space:3002",
"http://node203.va1.mempool.space:3002", "http://node203.va1.mempool.space:3002",

View File

@ -28,14 +28,12 @@
"ESPLORA": { "ESPLORA": {
"UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-testnet", "UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-testnet",
"FALLBACK": [ "FALLBACK": [
"http://node201.hnl.mempool.space:3002", "http://node201.fmt.mempool.space:3002",
"http://node202.hnl.mempool.space:3002", "http://node202.fmt.mempool.space:3002",
"http://node203.hnl.mempool.space:3002", "http://node203.fmt.mempool.space:3002",
"http://node204.hnl.mempool.space:3002", "http://node204.fmt.mempool.space:3002",
"http://node201.sg1.mempool.space:3002", "http://node205.fmt.mempool.space:3002",
"http://node202.sg1.mempool.space:3002", "http://node206.fmt.mempool.space:3002",
"http://node203.sg1.mempool.space:3002",
"http://node204.sg1.mempool.space:3002",
"http://node201.va1.mempool.space:3002", "http://node201.va1.mempool.space:3002",
"http://node202.va1.mempool.space:3002", "http://node202.va1.mempool.space:3002",
"http://node203.va1.mempool.space:3002", "http://node203.va1.mempool.space:3002",

View File

@ -28,14 +28,12 @@
"ESPLORA": { "ESPLORA": {
"UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-testnet4", "UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-testnet4",
"FALLBACK": [ "FALLBACK": [
"http://node201.hnl.mempool.space:3005", "http://node201.fmt.mempool.space:3005",
"http://node202.hnl.mempool.space:3005", "http://node202.fmt.mempool.space:3005",
"http://node203.hnl.mempool.space:3005", "http://node203.fmt.mempool.space:3005",
"http://node204.hnl.mempool.space:3005", "http://node204.fmt.mempool.space:3005",
"http://node201.sg1.mempool.space:3005", "http://node205.fmt.mempool.space:3005",
"http://node202.sg1.mempool.space:3005", "http://node206.fmt.mempool.space:3005",
"http://node203.sg1.mempool.space:3005",
"http://node204.sg1.mempool.space:3005",
"http://node201.va1.mempool.space:3005", "http://node201.va1.mempool.space:3005",
"http://node202.va1.mempool.space:3005", "http://node202.va1.mempool.space:3005",
"http://node203.va1.mempool.space:3005", "http://node203.va1.mempool.space:3005",

View File

@ -2,7 +2,7 @@
proxy_cache_path /var/cache/nginx/services keys_zone=services:200m levels=1:2 inactive=30d max_size=200m; proxy_cache_path /var/cache/nginx/services keys_zone=services:200m levels=1:2 inactive=30d max_size=200m;
proxy_cache_path /var/cache/nginx/apihot keys_zone=apihot:200m levels=1:2 inactive=60m max_size=20m; proxy_cache_path /var/cache/nginx/apihot keys_zone=apihot:200m levels=1:2 inactive=60m max_size=20m;
proxy_cache_path /var/cache/nginx/apiwarm keys_zone=apiwarm:200m levels=1:2 inactive=24h max_size=200m; proxy_cache_path /var/cache/nginx/apiwarm keys_zone=apiwarm:200m levels=1:2 inactive=24h max_size=200m;
proxy_cache_path /var/cache/nginx/apinormal keys_zone=apinormal:500m levels=1:2 inactive=24h max_size=2000m; proxy_cache_path /var/cache/nginx/apinormal keys_zone=apinormal:200m levels=1:2 inactive=30d max_size=2000m;
proxy_cache_path /var/cache/nginx/apicold keys_zone=apicold:200m levels=1:2 inactive=60d max_size=2000m; proxy_cache_path /var/cache/nginx/apicold keys_zone=apicold:200m levels=1:2 inactive=60d max_size=2000m;
proxy_cache_path /var/cache/nginx/unfurler keys_zone=unfurler:200m levels=1:2 inactive=30d max_size=2000m; proxy_cache_path /var/cache/nginx/unfurler keys_zone=unfurler:200m levels=1:2 inactive=30d max_size=2000m;

191
rust/gbt/Cargo.lock generated
View File

@ -1,21 +1,21 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 3
[[package]] [[package]]
name = "addr2line" name = "addr2line"
version = "0.24.2" version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
dependencies = [ dependencies = [
"gimli", "gimli",
] ]
[[package]] [[package]]
name = "adler2" name = "adler"
version = "2.0.0" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
@ -28,42 +28,48 @@ dependencies = [
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.4.0" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.74" version = "0.3.73"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
dependencies = [ dependencies = [
"addr2line", "addr2line",
"cc",
"cfg-if", "cfg-if",
"libc", "libc",
"miniz_oxide", "miniz_oxide",
"object", "object",
"rustc-demangle", "rustc-demangle",
"windows-targets",
] ]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.8.0" version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]] [[package]]
name = "bytemuck" name = "bytemuck"
version = "1.21.0" version = "1.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.9.0" version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952"
[[package]]
name = "cc"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -82,9 +88,9 @@ dependencies = [
[[package]] [[package]]
name = "ctor" name = "ctor"
version = "0.2.9" version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f"
dependencies = [ dependencies = [
"quote", "quote",
"syn", "syn",
@ -113,21 +119,27 @@ dependencies = [
[[package]] [[package]]
name = "gimli" name = "gimli"
version = "0.31.1" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.15.2" version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "hermit-abi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.7.1" version = "2.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown", "hashbrown",
@ -141,15 +153,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.169" version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]] [[package]]
name = "libloading" name = "libloading"
version = "0.8.6" version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"windows-targets", "windows-targets",
@ -157,9 +169,9 @@ dependencies = [
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.25" version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]] [[package]]
name = "matchers" name = "matchers"
@ -178,18 +190,18 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.8.3" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
dependencies = [ dependencies = [
"adler2", "adler",
] ]
[[package]] [[package]]
name = "napi" name = "napi"
version = "2.16.13" version = "2.16.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "214f07a80874bb96a8433b3cdfc84980d56c7b02e1a0d7ba4ba0db5cef785e2b" checksum = "a1bd081bbaef43600fd2c5dd4c525b8ecea7dfdacf40ebc674e87851dce6559e"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"ctor", "ctor",
@ -201,15 +213,15 @@ dependencies = [
[[package]] [[package]]
name = "napi-build" name = "napi-build"
version = "2.1.4" version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db836caddef23662b94e16bf1f26c40eceb09d6aee5d5b06a7ac199320b69b19" checksum = "e1c0f5d67ee408a4685b61f5ab7e58605c8ae3f2b4189f0127d804ff13d5560a"
[[package]] [[package]]
name = "napi-derive" name = "napi-derive"
version = "2.16.13" version = "2.16.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cbe2585d8ac223f7d34f13701434b9d5f4eb9c332cccce8dee57ea18ab8ab0c" checksum = "87c3b5d4ab13e20a4bb9d3a1e2f3d4e77eee4a205d0f810abfd226b971dc6ce5"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"convert_case", "convert_case",
@ -221,9 +233,9 @@ dependencies = [
[[package]] [[package]]
name = "napi-derive-backend" name = "napi-derive-backend"
version = "1.0.75" version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1639aaa9eeb76e91c6ae66da8ce3e89e921cd3885e99ec85f4abacae72fc91bf" checksum = "96de436a6ab93265beef838f8333c8345438f059df6081fe0ad0b8648ee0c524"
dependencies = [ dependencies = [
"convert_case", "convert_case",
"once_cell", "once_cell",
@ -254,19 +266,29 @@ dependencies = [
] ]
[[package]] [[package]]
name = "object" name = "num_cpus"
version = "0.36.7" version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "object"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.20.2" version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]] [[package]]
name = "overload" name = "overload"
@ -276,15 +298,15 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.16" version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]] [[package]]
name = "priority-queue" name = "priority-queue"
version = "2.1.1" version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "714c75db297bc88a63783ffc6ab9f830698a6705aa0201416931759ef4c8183d" checksum = "70c501afe3a2e25c9bd219aa56ec1e04cdb3fcdd763055be268778c13fa82c1f"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"equivalent", "equivalent",
@ -293,32 +315,32 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.93" version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.38" version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.11.1" version = "1.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-automata 0.4.9", "regex-automata 0.4.7",
"regex-syntax 0.8.5", "regex-syntax 0.8.4",
] ]
[[package]] [[package]]
@ -332,13 +354,13 @@ dependencies = [
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.4.9" version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-syntax 0.8.5", "regex-syntax 0.8.4",
] ]
[[package]] [[package]]
@ -349,9 +371,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.8.5" version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
@ -361,9 +383,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.25" version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
[[package]] [[package]]
name = "sharded-slab" name = "sharded-slab"
@ -382,9 +404,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.96" version = "2.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -403,19 +425,20 @@ dependencies = [
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.43.0" version = "1.38.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"num_cpus",
"pin-project-lite", "pin-project-lite",
] ]
[[package]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.41" version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [ dependencies = [
"pin-project-lite", "pin-project-lite",
"tracing-attributes", "tracing-attributes",
@ -424,9 +447,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-attributes" name = "tracing-attributes"
version = "0.1.28" version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -435,9 +458,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-core" name = "tracing-core"
version = "0.1.33" version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"valuable", "valuable",
@ -456,9 +479,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-subscriber" name = "tracing-subscriber"
version = "0.3.19" version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
dependencies = [ dependencies = [
"matchers", "matchers",
"nu-ansi-term", "nu-ansi-term",
@ -474,21 +497,21 @@ dependencies = [
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.15" version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]] [[package]]
name = "unicode-segmentation" name = "unicode-segmentation"
version = "1.12.0" version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
[[package]] [[package]]
name = "valuable" name = "valuable"
version = "0.1.1" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]] [[package]]
name = "winapi" name = "winapi"

View File

@ -1 +1 @@
1.84 1.79