Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a5eb24b
added config reload function
MicahMaphet Nov 10, 2025
4dc58b0
fixed build import and other compile errors
MicahMaphet Nov 10, 2025
4344e93
added reloadRefresh script
MicahMaphet Nov 11, 2025
6ccf30e
finished config refresh mechanism and create shell script to start co…
MicahMaphet Nov 25, 2025
b858f14
reloadConfig.sh features: reload many workers, reload all workers, li…
MicahMaphet Nov 25, 2025
8e4d17a
fixed no args error
MicahMaphet Nov 25, 2025
01bbf5a
show the change in the config and restart server on a new port on con…
MicahMaphet Dec 2, 2025
4f4dc51
add node connections when added to config (does not remove nodes
MicahMaphet Dec 4, 2025
903cb21
finished reloading+adding+removing peer connections on config refresh
MicahMaphet Dec 4, 2025
66894c5
show worker pid and name in output for reload script
MicahMaphet Dec 4, 2025
5bb2f09
disable and enable peers on config refresh
MicahMaphet Dec 10, 2025
44e8381
merge master into config-refresh
MicahMaphet Dec 17, 2025
2e19c59
Merge branch 'master' into config-refresh
MicahMaphet Apr 14, 2026
dc1eb4f
fix some merge errors
MicahMaphet Apr 14, 2026
f3e5486
copilot review: import paths and pid file logic
MicahMaphet May 2, 2026
58c11b6
removed refresh listener on p2p manager
MicahMaphet May 4, 2026
587ba75
Merge branch 'master' into config-refresh
MicahMaphet May 11, 2026
4f47823
Merge branch 'master' into config-refresh
MicahMaphet May 12, 2026
ed4deac
fixed master merge
MicahMaphet May 12, 2026
37e0f27
save config changes from last reload
MicahMaphet May 14, 2026
6467ea7
re did config reload functionality to just reload modules and disable…
MicahMaphet May 15, 2026
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
93 changes: 93 additions & 0 deletions conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
diff --git a/packages/bitcore-cli/package.json b/packages/bitcore-cli/package.json
index e291ea3ba..875c2d210 100644
--- a/packages/bitcore-cli/package.json
+++ b/packages/bitcore-cli/package.json
@@ -30,8 +30,7 @@
Comment on lines +1 to +5
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file appears to be an accidentally committed terminal-colored git diff output (contains ANSI escape sequences) rather than source code/config. It should be removed from the repository (and the intended changes applied to the real files instead, if needed).

Copilot uses AI. Check for mistakes.
},

"scripts": {
- "test": "npm run compile && mocha 'build/test/**/*.js'",
- "coverage": "npm run compile && nyc mocha 'build/test/**/*.js'",
+ "test": "npm run compile && nyc mocha 'build/test/**/*.js' --timeout 5000",
"build": "tsc",
"postbuild": "node createBin -v",
"clean": "rm -rf ./build",
diff --git a/packages/bitcore-client/package.json b/packages/bitcore-client/package.json
index ffe3e25eb..12e2e6ff4 100644
--- a/packages/bitcore-client/package.json
+++ b/packages/bitcore-client/package.json
@@ -23,8 +23,7 @@
"watch": "tsc --watch",
"precompile": "cd ../bitcore-node && npm run clean && npm run build:prod",
"compile": "npm run clean && npm run build",
- "test": "npm run compile && mocha -r tsx --exit 'test/**/*.test.ts'",
- "coverage": "npm run compile && nyc mocha -r tsx --exit 'test/**/*.test.ts'",
+ "test": "npm run compile && nyc mocha --exit 'ts_build/test/**/*.test.js'",
"precommit": "npm run lint",
"lint": "eslint .",
"fix:errors": "eslint --fix --quiet .",
diff --git a/packages/bitcore-client/test/unit/wallet.test.ts b/packages/bitcore-client/test/unit/wallet.test.ts
index a9947ce4e..a75d02ed4 100644
--- a/packages/bitcore-client/test/unit/wallet.test.ts
+++ b/packages/bitcore-client/test/unit/wallet.test.ts
@@ -1,10 +1,10 @@
import * as chai from 'chai';
import * as CWC from '@bitpay-labs/crypto-wallet-core';
import { AddressTypes, Wallet } from '../../src/wallet';
-import { Api as bcnApi } from '../../../bitcore-node/build/src/services/api';
-import { Storage as bcnStorage } from '../../../bitcore-node/build/src/services/storage';
+import { Api as bcnApi } from '../../../bitcore-node/src/services/api';
+import { Storage as bcnStorage } from '../../../bitcore-node/src/services/storage';
import crypto from 'crypto';
-import { Modules } from '../../../bitcore-node/build/src/modules';
+import { Modules } from '../../../bitcore-node/src/modules';
import request from 'request-promise-native';
import requestStream from 'request';
import { Server } from 'http';
@@ -136,7 +136,7 @@ describe('Wallet', function() {
expect(err.message).to.equal('Must provide changeIdx for UTXO chains');
}
});
- 
+
it('should throw an error if neither rawTx nor txid is provided', async () => {
try {
await wallet.bumpTxFee({ changeIdx: 0 });
@@ -171,12 +171,12 @@ describe('Wallet', function() {
sandbox.stub(wallet, 'getTransactionByTxid').resolves({ '_id': '65982807d85e75f781a0d56f', 'txid': '8b78e4d2ac2211472454f940445210b6487aaa0f889e18066eb3f623352607f5', 'network': 'regtest', 'chain': 'BTC', 'blockHeight': -1, 'blockHash': '', 'blockTime': '2024-01-05T16:02:15.678Z', 'blockTimeNormalized': '2024-01-05T16:02:15.678Z', 'coinbase': false, 'locktime': -1, 'inputCount': 5, 'outputCount': 1, 'size': 780, 'fee': 2409, 'value': 950891, 'confirmations': 0, 'coins': { 'inputs': [{ '_id': '659825bed85e75f781a01812', 'chain': 'BTC', 'network': 'regtest', 'coinbase': false, 'mintIndex': 1, 'spentTxid': '8b78e4d2ac2211472454f940445210b6487aaa0f889e18066eb3f623352607f5', 'mintTxid': '330716a75c23512202e45ffee478bdce7a33f298edf7eef30a42dbde06746c48', 'mintHeight': 154, 'spentHeight': -1, 'address': 'n2vpyzbBPBEni9FgkeQSnXvAQAfnRmKxFZ', 'script': '76a914eade85745090388e64a9341a82d8f94371430d1a88ac', 'value': 244000, 'confirmations': -1, 'sequenceNumber': 4294967293 }, { '_id': '65982587d85e75f781a0046f', 'chain': 'BTC', 'network': 'regtest', 'coinbase': false, 'mintIndex': 1, 'spentTxid': '8b78e4d2ac2211472454f940445210b6487aaa0f889e18066eb3f623352607f5', 'mintTxid': '7b83f82a22f94fc3e615743a5e6fb2345ed79aad8a2b564af2ace49da1e27ebb', 'mintHeight': 152, 'spentHeight': -1, 'address': 'muEU9KaNEw5doymy59ScrgEE3Eq4CQ45U9', 'script': '76a91496739b4ef4e793c05a78624da38d96f2c4059c6b88ac', 'value': 239400, 'confirmations': -1, 'sequenceNumber': 4294967293 }, { '_id': '65982511d85e75f7819fdd40', 'chain': 'BTC', 'network': 'regtest', 'coinbase': false, 'mintIndex': 0, 'spentTxid': '8b78e4d2ac2211472454f940445210b6487aaa0f889e18066eb3f623352607f5', 'mintTxid': 'fb4d8039024c80a655fea29e01faf202f30e936af5738e31c5841a84215ca4d6', 'mintHeight': 149, 'spentHeight': -1, 'address': 'muEU9KaNEw5doymy59ScrgEE3Eq4CQ45U9', 'script': '76a91496739b4ef4e793c05a78624da38d96f2c4059c6b88ac', 'value': 239400, 'confirmations': -1, 'sequenceNumber': 4294967293 }, { '_id': '659824d7d85e75f7819fc75d', 'chain': 'BTC', 'network': 'regtest', 'coinbase': false, 'mintIndex': 0, 'spentTxid': '8b78e4d2ac2211472454f940445210b6487aaa0f889e18066eb3f623352607f5', 'mintTxid': '8221ed6891f6ba82ab72bb8298a661e21b47b04408861b0c3268c4a04a0435b3', 'mintHeight': 145, 'spentHeight': -1, 'address': 'miEzS8fSvtDjwkEjY14FEuWumFKg8nTPV9', 'script': '76a9141de381fc20d34d20e11a5543f536a4b74f495a9888ac', 'value': 228000, 'confirmations': -1, 'sequenceNumber': 4294967293 }, { '_id': '65982389d85e75f7819f57ff', 'chain': 'BTC', 'network': 'regtest', 'coinbase': false, 'mintIndex': 0, 'spentTxid': '8b78e4d2ac2211472454f940445210b6487aaa0f889e18066eb3f623352607f5', 'mintTxid': '95f713c2d7e09ab57ec3016bb767b26e6ee849cf487e86d8ed6126ae1b893e0f', 'mintHeight': 143, 'spentHeight': -1, 'address': 'msnM9VB5usfBahZNo57ZUq9uzwRxQXksUz', 'script': '76a914868ad3308906626182d1c6cd703cc7ce78b3a28d88ac', 'value': 2500, 'confirmations': -1, 'sequenceNumber': 4294967293 }], 'outputs': [{ '_id': '65982807d85e75f781a0d55d', 'chain': 'BTC', 'network': 'regtest', 'coinbase': false, 'mintIndex': 0, 'spentTxid': '', 'mintTxid': '8b78e4d2ac2211472454f940445210b6487aaa0f889e18066eb3f623352607f5', 'mintHeight': -1, 'spentHeight': -2, 'address': 'mwwrGzk9q8xugY97C8BiNbcgqXNyjH4kp8', 'script': '76a914b4376347e4cffb1e9a475b2661bbe74de3c1f86a88ac', 'value': 950891, 'confirmations': -1 }] } });
sandbox.stub(wallet.client, 'importAddresses').resolves();
sandbox.spy(CWC.BitcoreLib.Transaction.prototype, 'feePerByte');
- 
+
await wallet.generateAddressPair(1310066242, true);
await wallet.generateAddressPair(1087984800, true);
await wallet.generateAddressPair(1310064953, true);
await wallet.generateAddressPair(1310062823, true);
- 
+
const { tx: newTx } = await wallet.bumpTxFee({
txid: '8b78e4d2ac2211472454f940445210b6487aaa0f889e18066eb3f623352607f5',
changeIdx: 0,
@@ -204,7 +204,7 @@ describe('Wallet', function() {
await wallet.unlock('abc123');
});

- 
+
it('should throw an error if neither rawTx nor txid is provided', async () => {
try {
await wallet.bumpTxFee({ changeIdx: 0 });
@@ -230,7 +230,7 @@ describe('Wallet', function() {
it('should bump the fee of a transaction with feeRate', async function() {
sandbox.stub(wallet, 'getTransactionByTxid').resolves({ 'txid': '0x0cf410cfe7fb268ad06ae115edfa8a30a8dea3979336a647b09b5a789c4b53d5', 'network': 'regtest', 'chain': 'ETH', 'blockHeight': 43245, 'blockHash': '0x9edb8d10883a360f7ff0c26860b6a159f5b7a74226949a4365691a879fafcdfc', 'blockTime': '2024-01-08T16:31:46.000Z', 'blockTimeNormalized': '2024-01-08T16:31:46.000Z', 'fee': 42000000000000, 'value': 1000000000000000000, 'gasLimit': 200000, 'gasPrice': 2000000000, 'nonce': 0, 'to': '0x7ee308b49e36Ab516cd0186B3a47CFD31d2499A1', 'from': '0x5FbdD2712d05D1a73e0b3Eba5efE8c3d42a336C3', 'effects': [], 'data': '0x', 'internal': [], 'calls': [], 'confirmations': 33 });
sandbox.stub(wallet.client, 'importAddresses').resolves();
- 
+
const { tx: newTx, params } = await wallet.bumpTxFee({
txid: '0x0cf410cfe7fb268ad06ae115edfa8a30a8dea3979336a647b09b5a789c4b53d5',
feeRate: 300
@@ -549,4 +549,3 @@ describe('Wallet', function() {
});
});
});
-
2 changes: 1 addition & 1 deletion packages/bitcore-node/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ RUN npm run compile

# Start the server
WORKDIR /bitcore/packages/bitcore-node
CMD ["node", "./build/src/server.js"]
CMD ["node", "./build/src/server.js"]
83 changes: 83 additions & 0 deletions packages/bitcore-node/scripts/reloadConfig.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/bin/sh

dir=$(pwd)
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script uses dir=$(pwd), so it only works when run from the directory containing pids/. Resolve the base directory relative to the script path instead (e.g., using dirname "$0") so it works from any cwd.

Suggested change
dir=$(pwd)
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
dir=$(CDPATH= cd -- "$script_dir/.." && pwd)

Copilot uses AI. Check for mistakes.

if [ $# = 0 ]; then
pid_paths=$dir/pids/*

for path in $pid_paths; do
pid=$(cat "$path")
Comment thread
MicahMaphet marked this conversation as resolved.
printf "$(basename "$path" .pid)::$pid "
pids="$pids $pid"
done
echo ''

kill -USR1 $pids &&
echo "Refreshed all workers"
exit 0
fi

if [ $1 = --help ]; then
cat << EOF
Usage: $(basename "$0") [OPTIONS] [WORKER...]

Reload configuration for bitcore workers

Options:
--help Show this help message and exit
list List all running workers

Arguments:
WORKER Name(s) of worker(s) to reload configs (e.g., all api p2p)
If no worker is specified, reload all running workers configs.

Examples:
$(basename "$0") Reload config for all workers
$(basename "$0") api p2p Reload config for 'api' and 'p2p' workers
$(basename "$0") list List all running workers
EOF
exit 0
fi

if [ $1 = list ]; then
pid_paths=$(ls $dir/pids/*.pid 2>/dev/null)
for path in $pid_paths; do
worker=$(basename "$path" .pid)
pid=$(cat "$path")
printf "%-3s %s\n" "$worker" "$pid"
done
exit 0
fi

for worker in $@; do
if [ ! -f "$dir/pids/$worker.pid" ]; then
echo "$worker is not running\n$worker.pid not found in $dir/pids"
case $worker in
all|api|p2p) ;;
*)
echo "$worker is not a standard worker\nstandard workers: all, api, p2p"
;;
esac
exit 1
fi
done

pid_paths=$(
for worker in $@; do
printf "$dir/pids/$worker.pid "
done
)

pids=$(
for path in $pid_paths; do
cat $path
printf ' '
done
)

kill -USR1 $pids &&

cat << EOF
Sent reload signal(s) SIGUSR1 to '$@'
pids: $pids
EOF
14 changes: 7 additions & 7 deletions packages/bitcore-node/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,28 @@ function findConfig(): ConfigType | undefined {
if (bitcoreConfigPath[0] === '~') {
bitcoreConfigPath = bitcoreConfigPath.replace('~', homedir());
}

if (!fs.existsSync(bitcoreConfigPath)) {
throw new Error(`No bitcore config exists at ${bitcoreConfigPath}`);
}

const bitcoreConfigStat = fs.statSync(bitcoreConfigPath);

if (bitcoreConfigStat.isDirectory()) {
if (!fs.existsSync(path.join(bitcoreConfigPath, 'bitcore.config.json'))) {
throw new Error(`No bitcore config exists in directory ${bitcoreConfigPath}`);
}
bitcoreConfigPath = path.join(bitcoreConfigPath, 'bitcore.config.json');
}
logger.info('Using config at: ' + bitcoreConfigPath);

let rawBitcoreConfig;
try {
rawBitcoreConfig = fs.readFileSync(bitcoreConfigPath).toString();
} catch (error) {
throw new Error(`Error in loading bitcore config\nFound file at ${bitcoreConfigPath}\n${error}`);
}

let bitcoreConfig;
try {
bitcoreConfig = JSON.parse(rawBitcoreConfig).bitcoreNode;
Expand Down Expand Up @@ -63,7 +63,7 @@ function setTrustedPeers(config: ConfigType): ConfigType {
}
return config;
}
const Config = function(): ConfigType {
const loadConfig = function(): ConfigType {
let config: ConfigType = {
maxPoolSize: 50,
port: 3000,
Expand Down Expand Up @@ -130,4 +130,4 @@ const Config = function(): ConfigType {
return config;
};

export default Config();
export default loadConfig;
23 changes: 10 additions & 13 deletions packages/bitcore-node/src/modules/moralis/api/csp.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import os from 'os';
import { LRUCache } from 'lru-cache';
import request from 'request';
import config from '../../../config';
import logger from '../../../logger';
import { MongoBound } from '../../../models/base';
import { CacheStorage } from '../../../models/cache';
Expand All @@ -19,6 +18,7 @@ import {
transformMoralisTransaction
} from '../../../providers/chain-state/external/adapters/moralis-utils';
import { ExternalApiStream } from '../../../providers/chain-state/external/streams/apiStream';
import { Config } from '../../../services/config';
import { IBlock } from '../../../types/Block';
import { ChainId, ChainNetwork } from '../../../types/ChainNetwork';
import { IAddressSubscription } from '../../../types/ExternalProvider';
Expand All @@ -27,8 +27,6 @@ import { isDateValid } from '../../../utils';
import { normalizeChainNetwork } from '../../../utils';
import { ReadableWithEventPipe } from '../../../utils/streamWithEventPipe';



export interface MoralisAddressSubscription {
id?: string;
message?: string;
Expand All @@ -38,15 +36,14 @@ export interface MoralisAddressSubscription {
export class MoralisStateProvider extends BaseEVMStateProvider {
baseUrl = 'https://deep-index.moralis.io/api/v2.2';
baseStreamUrl = 'https://api.moralis-streams.com/streams/evm';
apiKey = config.externalProviders?.moralis?.apiKey;
baseWebhookurl = config.externalProviders?.moralis?.webhookBaseUrl;
apiKey = Config.get().externalProviders?.moralis?.apiKey;
baseWebhookurl = Config.get().externalProviders?.moralis?.webhookBaseUrl;
headers = {
'Content-Type': 'application/json',
'X-API-Key': this.apiKey,
};
blockAtTimeCache: { [key: string]: LRUCache<string, IBlock> } = {};


constructor(chain: string) {
super(chain);
}
Expand Down Expand Up @@ -114,7 +111,7 @@ export class MoralisStateProvider extends BaseEVMStateProvider {
const blockRange = await this.getBlocksRange({ ...params, chainId });
const tipHeight = Number(await web3.eth.getBlockNumber());
let isReading = false;

const stream = new ReadableWithEventPipe({
objectMode: true,
async read() {
Expand Down Expand Up @@ -205,7 +202,7 @@ export class MoralisStateProvider extends BaseEVMStateProvider {
}
});
transactionStream = txStream.eventPipe(transactionStream);

// Do not await these promises. They are not critical to the stream.
WalletAddressStorage.updateLastQueryTime({ chain: this.chain, network, address })
.catch(e => logger.warn(`Failed to update ${this.chain}:${network} address lastQueryTime: %o`, e)),
Expand All @@ -230,7 +227,7 @@ export class MoralisStateProvider extends BaseEVMStateProvider {
convertedBlock.nextBlockHash = nextBlock?.hash!;
blocks.push(convertedBlock);
}

const tipHeight = Number(await web3.eth.getBlockNumber());
return { tipHeight, blocks };
}
Expand Down Expand Up @@ -371,10 +368,10 @@ export class MoralisStateProvider extends BaseEVMStateProvider {

/**
* Request wrapper for moralis Streams (subscriptions)
* @param method
* @param url
* @param body
* @returns
* @param method
* @param url
* @param body
* @returns
*/
_subsRequest(method: string, url: string, body?: any) {
return new Promise((resolve, reject) => {
Expand Down
4 changes: 2 additions & 2 deletions packages/bitcore-node/src/modules/ripple/api/csp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import util from 'util';
import { CryptoRpc } from '@bitpay-labs/crypto-rpc';
import { ObjectId } from 'mongodb';
import request from 'request';
import Config from '../../../config';
import logger from '../../../logger';
import { CacheStorage } from '../../../models/cache';
import { ICoin } from '../../../models/coin';
import { WalletAddressStorage } from '../../../models/walletAddress';
import { InternalStateProvider } from '../../../providers/chain-state/internal/internal';
import { Config } from '../../../services/config';
import { Storage } from '../../../services/storage';
import { IBlock } from '../../../types/Block';
import { ChainNetwork } from '../../../types/ChainNetwork';
Expand Down Expand Up @@ -39,7 +39,7 @@ export class RippleStateProvider extends InternalStateProvider implements IChain

constructor(public chain: string = 'XRP') {
super(chain, RippleDbWalletTransactions);
this.config = Config.chains[this.chain];
this.config = Config.get().chains[this.chain];
}

async getClient(network: string) {
Expand Down
Loading