Skip to content
Draft
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: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ node_modules/
.DS_Store
*.swp
.zed
coverage
.nyc_output

# VIM ignore
[._]*.s[a-w][a-z]
Expand Down
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", ".*.tsserver.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)

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

for path in $pid_paths; do
pid=$(cat "$path")
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;
35 changes: 35 additions & 0 deletions packages/bitcore-node/src/modules/bitcoin/p2p.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { StateStorage } from '../../models/state';
import { TransactionStorage } from '../../models/transaction';
import { ChainStateProvider } from '../../providers/chain-state';
import { Libs } from '../../providers/libs';
import { Config } from '../../services/config';
import { BaseP2PWorker } from '../../services/p2p';
import { SpentHeightIndicators } from '../../types/Coin';
import { IUtxoNetworkConfig } from '../../types/Config';
Expand Down Expand Up @@ -57,6 +58,10 @@ export class BitcoinP2PWorker extends BaseP2PWorker<IBtcBlock> {
network: this.network,
messages: this.messages
});

process.on('SIGUSR1', async () => {
await this.reload();
});
}

cacheInv(type: number, hash: string): void {
Expand Down Expand Up @@ -194,6 +199,36 @@ export class BitcoinP2PWorker extends BaseP2PWorker<IBtcBlock> {
}
}

async reload() {
this.chainConfig = Config.chainConfig({ chain: this.chain, network: this.network }) as IUtxoNetworkConfig;
const configPeerUris: string[] = [];

for (const peer of Object.values(this.chainConfig.trustedPeers) as any[]) {
const uri = peer.host + ':' + peer.port;
configPeerUris.push(uri);
const hashes = Object.values(this.pool._addrs).map((a: any) => a.hash);
const addr = this.pool._addAddr({ ip: { v4: peer.host }, port: peer.port });
if (!hashes.includes(addr.hash)) {
logger.info(`Adding peer ${uri}`);
}
}

for (const addr of Object.values(this.pool._addrs) as any[]) {
const uri = addr.ip.v4 + ':' + addr.port;
if (!configPeerUris.includes(uri)) {
this.pool._addrs = (this.pool._addrs as any[]).filter(({ hash }) => hash !== addr.hash);
if (this.pool._connectedPeers[addr.hash]) {
logger.info(`Removing peer ${uri}`);
} else {
logger.info(`Removing unconnected peer ${uri}`);
continue;
}
this.pool._connectedPeers[addr.hash].disconnect();
delete this.pool._connectedPeers[addr.hash];
}
};
}

public async getHeaders(candidateHashes: string[]): Promise<BitcoinHeaderObj[]> {
let received = false;
return new Promise<BitcoinHeaderObj[]>(async resolve => {
Expand Down
34 changes: 22 additions & 12 deletions packages/bitcore-node/src/modules/moralis/api/csp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import os from 'os';
import { Web3 } from '@bitpay-labs/crypto-wallet-core';
import { LRUCache } from 'lru-cache';
import request from 'request';
import config from '../../../config';
import { Config } from '../../../../src/services/config';
import logger from '../../../logger';
import { MongoBound } from '../../../models/base';
import { CacheStorage } from '../../../models/cache';
Expand All @@ -21,8 +21,6 @@ import { isDateValid } from '../../../utils';
import { normalizeChainNetwork } from '../../../utils';
import { ReadableWithEventPipe } from '../../../utils/streamWithEventPipe';



export interface MoralisAddressSubscription {
id?: string;
message?: string;
Expand All @@ -32,8 +30,8 @@ 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,
Expand All @@ -43,8 +41,20 @@ export class MoralisStateProvider extends BaseEVMStateProvider {

constructor(chain: string) {
super(chain);
this.loadConfig();
}

loadConfig() {
const config = Config.get();
this.apiKey = config.externalProviders?.moralis?.apiKey;
this.baseWebhookurl = config.externalProviders?.moralis?.webhookBaseUrl;
this.headers = {
'Content-Type': 'application/json',
'X-API-Key': this.apiKey,
};
}


// @override
async getBlockBeforeTime(params: GetBlockBeforeTimeParams): Promise<IBlock|null> {
const { chain, network, time } = params;
Expand Down Expand Up @@ -108,7 +118,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 @@ -199,7 +209,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 @@ -224,7 +234,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 @@ -480,10 +490,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
14 changes: 7 additions & 7 deletions packages/bitcore-node/src/providers/chain-state/evm/api/csp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export class BaseEVMStateProvider extends InternalStateProvider implements IChai
return;
}
BaseEVMStateProvider.rpcInitialized[chain] = true;

const configs = Config.get().chains[chain] as IChainConfig<IEVMNetworkConfig>;
for (const [network, config] of Object.entries(configs)) {
const chainNetwork = normalizeChainNetwork(chain, network);
Expand Down Expand Up @@ -207,7 +207,7 @@ export class BaseEVMStateProvider extends InternalStateProvider implements IChai
async getAaveUserAccountData(params: { network: string; address: string; version: AaveVersion }): Promise<AaveAccountData> {
const { network, address, version } = params;
const poolAddress = getAavePoolAddress(this.chain, network, version);

if (!poolAddress) {
throw new Error(
`Unsupported Aave pool for chain "${this.chain}", network "${network}", version "${version}".`
Expand Down Expand Up @@ -482,7 +482,7 @@ export class BaseEVMStateProvider extends InternalStateProvider implements IChai
const tx = await this._getTransaction(params);
let { found } = tx;
const { tipHeight } = tx;

if (found) {
let confirmations = 0;
if (found.blockHeight && found.blockHeight >= 0) {
Expand Down Expand Up @@ -712,7 +712,7 @@ export class BaseEVMStateProvider extends InternalStateProvider implements IChai
const result = await ExternalApiStream.onStream(transactionStream, req!, res!, { jsonl: true });
if (!result?.success) {
logger.error('Error mid-stream (streamWalletTransactions): %o', result.error?.log || result.error);
}
}
return resolve();
} catch (err) {
return reject(err);
Expand Down Expand Up @@ -770,7 +770,7 @@ export class BaseEVMStateProvider extends InternalStateProvider implements IChai
let windowSize = 100n;
const { web3 } = await this.getWeb3(network);
const tip = await web3.eth.getBlockNumber();

if (isNaN(args.startBlock!) || isNaN(args.endBlock!)) {
throw new Error('startBlock and endBlock must be numbers');
}
Expand All @@ -788,7 +788,7 @@ export class BaseEVMStateProvider extends InternalStateProvider implements IChai

endBlock = Utils.BI.min<bigint>([endBlock ?? tip, tip]) as bigint;
startBlock = Utils.BI.max<bigint>([startBlock != null ? startBlock : endBlock - 10000n, 0n]) as bigint;

if (startBlock! > endBlock) {
throw new Error('startBlock cannot be greater than endBlock');
} else if (endBlock - startBlock > 10000n) {
Expand Down Expand Up @@ -1011,7 +1011,7 @@ export class BaseEVMStateProvider extends InternalStateProvider implements IChai
}
blockId = undefined;
}

if (date) {
startDate = new Date(date);
endDate = new Date(date);
Expand Down
Loading