Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
- name: Install ${{ steps.gettoolchain.outputs.toolchain }} Rust toolchain
# Latest version available on this commit is 1.71.1
# Commit date is Aug 3, 2023
uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a
uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921
with:
toolchain: ${{ steps.gettoolchain.outputs.toolchain }}

Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/on-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@ jobs:
tag-latest:
needs: build
if: ${{ needs.build.result == 'success' }}
if: ${{ needs.build.result == 'success' && !contains(github.ref_name, '-') }}
runs-on: ubuntu-latest
timeout-minutes: 30
name: Tag images as latest
name: Tag release build as latest
strategy:
matrix:
service:
Expand All @@ -145,8 +145,8 @@ jobs:
- name: Login to Docker Hub
run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin

- name: Tag multi-arch image as latest for ${{ matrix.service }}
- name: Tag as latest for ${{ matrix.service }}
run: |
docker buildx imagetools create \
--tag ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:latest \
${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:$TAG
${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:$TAG
14 changes: 14 additions & 0 deletions backend/src/api/acceleration/acceleration.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class AccelerationRoutes {
public initRoutes(app: Application): void {
app
.get(config.MEMPOOL.API_URL_PREFIX + 'services/accelerator/accelerations', this.$getAcceleratorAccelerations.bind(this))
.get(config.MEMPOOL.API_URL_PREFIX + 'services/accelerator/accelerations/:txid', this.$getAcceleratorAcceleration.bind(this))
.get(config.MEMPOOL.API_URL_PREFIX + 'services/accelerator/accelerations/history', this.$getAcceleratorAccelerationsHistory.bind(this))
.get(config.MEMPOOL.API_URL_PREFIX + 'services/accelerator/accelerations/history/aggregated', this.$getAcceleratorAccelerationsHistoryAggregated.bind(this))
.get(config.MEMPOOL.API_URL_PREFIX + 'services/accelerator/accelerations/stats', this.$getAcceleratorAccelerationsStats.bind(this))
Expand All @@ -23,6 +24,19 @@ class AccelerationRoutes {
res.status(200).send(Object.values(accelerations));
}

private async $getAcceleratorAcceleration(req: Request, res: Response): Promise<void> {
if (req.params.txid) {
const acceleration = await AccelerationRepository.$getAccelerationInfoForTxid(req.params.txid);
if (acceleration) {
res.status(200).send(acceleration);
} else {
res.status(404).send('Acceleration not found');
}
} else {
res.status(400).send('txid is required');
}
}

private async $getAcceleratorAccelerationsHistory(req: Request, res: Response): Promise<void> {
const history = await AccelerationRepository.$getAccelerationInfo(null, req.query.blockHeight ? parseInt(req.query.blockHeight as string, 10) : null);
res.status(200).send(history.map(accel => ({
Expand Down
10 changes: 6 additions & 4 deletions backend/src/api/blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1272,11 +1272,13 @@ class Blocks {
/**
* Get one block by its hash
*/
public async $getBlock(hash: string): Promise<BlockExtended | IEsploraApi.Block> {
public async $getBlock(hash: string, skipMemoryCache: boolean = false): Promise<BlockExtended | IEsploraApi.Block> {
// Check the memory cache
const blockByHash = this.getBlocks().find((b) => b.id === hash);
if (blockByHash) {
return blockByHash;
if (!skipMemoryCache) {
const blockByHash = this.getBlocks().find((b) => b.id === hash);
if (blockByHash) {
return blockByHash;
}
}

// Not Bitcoin network, return the block as it from the bitcoin backend
Expand Down
35 changes: 28 additions & 7 deletions backend/src/api/chain-tips.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import config from '../config';
import logger from '../logger';
import { BlockExtended } from '../mempool.interfaces';
import BlocksSummariesRepository from '../repositories/BlocksSummariesRepository';
import { bitcoinCoreApi } from './bitcoin/bitcoin-api-factory';
import bitcoinApi, { bitcoinCoreApi } from './bitcoin/bitcoin-api-factory';
import bitcoinClient from './bitcoin/bitcoin-client';
import { IEsploraApi } from './bitcoin/esplora-api.interface';
import blocks from './blocks';
Expand Down Expand Up @@ -42,6 +43,13 @@ class ChainTips {
try {
this.chainTips = await bitcoinClient.getChainTips();

const activeTipHeight = this.chainTips.find(tip => tip.status === 'active')?.height || (await bitcoinApi.$getBlockHeightTip());
let minIndexHeight = 0;
const indexedBlockAmount = Math.min(config.MEMPOOL.INDEXING_BLOCKS_AMOUNT, activeTipHeight);
if (indexedBlockAmount > 0) {
minIndexHeight = Math.max(0, activeTipHeight - indexedBlockAmount + 1);
}

const start = Date.now();
const breakAt = start + 10000;
let newOrphans = 0;
Expand All @@ -64,11 +72,24 @@ class ChainTips {
prevhash: block.previousblockhash,
};
this.blockCache[hash] = orphan;
if (this.indexingQueue.length < this.maxIndexingQueueSize) {
this.indexingQueue.push({ block, tip: orphan });
} else {
// re-fetch blocks lazily if the queue is big to keep memory usage sane
this.indexingQueue.push({ blockhash: hash, tip: orphan });
// don't index stale blocks below the INDEXING_BLOCKS_AMOUNT cutoff
if (block.height >= minIndexHeight) {
if (this.indexingQueue.length < this.maxIndexingQueueSize) {
this.indexingQueue.push({ block, tip: orphan });
} else {
// re-fetch blocks lazily if the queue is big to keep memory usage sane
this.indexingQueue.push({ blockhash: hash, tip: orphan });
}
}
// make sure the cached canonical block at this height is correct & up to date
if (block.height >= (activeTipHeight - (config.MEMPOOL.INITIAL_BLOCKS_AMOUNT * 4))) {
const cachedBlocks = blocks.getBlocks();
for (const cachedBlock of cachedBlocks) {
if (cachedBlock.height === block.height) {
// ensure this stale block is included in the orphans list
cachedBlock.extras.orphans = Array.from(new Set([...(cachedBlock.extras.orphans || []), orphan]));
}
}
}
}
}
Expand Down Expand Up @@ -141,7 +162,7 @@ class ChainTips {
// don't DDOS core by indexing too fast
await Common.sleep$(5000);
} else if (needToCache) {
staleBlock = await blocks.$getBlock(block.id) as BlockExtended;
staleBlock = await blocks.$getBlock(block.id, true) as BlockExtended;
}

if (staleBlock && needToCache) {
Expand Down
6 changes: 3 additions & 3 deletions backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,9 @@ class Server {
res.setHeader('Access-Control-Expose-Headers', 'X-Total-Count,X-Mempool-Auth');
next();
})
.use(express.urlencoded({ extended: true }))
.use(express.text({ type: ['text/plain', 'application/base64'] }))
.use(express.json())
.use(express.urlencoded({ extended: true, limit: '10mb' }))
.use(express.text({ type: ['text/plain', 'application/base64'], limit: '10mb' }))
.use(express.json({ limit: '10mb' }))
;

if (config.DATABASE.ENABLED && config.FIAT_PRICE.ENABLED) {
Expand Down
26 changes: 26 additions & 0 deletions backend/src/repositories/AccelerationRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,32 @@ class AccelerationRepository {
}
}

public async $getAccelerationInfoForTxid(txid: string): Promise<PublicAcceleration | null> {
const [rows] = await DB.query(`
SELECT *, UNIX_TIMESTAMP(requested) as requested_timestamp, UNIX_TIMESTAMP(added) as block_timestamp FROM accelerations
JOIN pools on pools.unique_id = accelerations.pool
WHERE txid = ?
`, [txid]) as RowDataPacket[][];
if (rows?.length) {
const row = rows[0];
return {
txid: row.txid,
height: row.height,
added: row.requested_timestamp || row.block_timestamp,
pool: {
id: row.id,
slug: row.slug,
name: row.name,
},
effective_vsize: row.effective_vsize,
effective_fee: row.effective_fee,
boost_rate: row.boost_rate,
boost_cost: row.boost_cost,
};
}
return null;
}

public async $getAccelerationInfo(poolSlug: string | null = null, height: number | null = null, interval: string | null = null): Promise<PublicAcceleration[]> {
if (!interval || !['24h', '3d', '1w', '1m'].includes(interval)) {
interval = '1m';
Expand Down
11 changes: 10 additions & 1 deletion backend/src/repositories/BlocksRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,16 @@ class BlocksRepository {
// iterate back to genesis, resetting canonical status where necessary
let hash = tip;
const tipHeight = blocksByHash[hash].height || (await bitcoinApi.$getBlock(hash))?.height;
for (let height = tipHeight; height > 0; height--) {

// stop at the last canonical block we're supposed to have indexed already
let lastIndexedBlockHeight = minHeight;
const indexedBlockAmount = Math.min(config.MEMPOOL.INDEXING_BLOCKS_AMOUNT, tipHeight);
if (indexedBlockAmount > 0) {
lastIndexedBlockHeight = Math.max(0, tipHeight - indexedBlockAmount + 1);
}


for (let height = tipHeight; height > lastIndexedBlockHeight; height--) {
const block = blocksByHash[hash];
if (!block) {
// block hasn't been indexed
Expand Down
3 changes: 3 additions & 0 deletions contributors/AaronDewes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of October 31, 2025.

Signed: AaronDewes
Loading