Skip to content
Merged
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
18 changes: 8 additions & 10 deletions packages/bitcore-client/test/unit/wallet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Encryption } from '../../src/encryption';
import { Api as bcnApi } from '../../../bitcore-node/build/src/services/api';
import { Storage as bcnStorage } from '../../../bitcore-node/build/src/services/storage';
import crypto from 'crypto';
import { Modules } from '../../../bitcore-node/build/src/modules';
import { loadModules } from '../../../bitcore-node/build/src/modules';
import request from 'request-promise-native';
import requestStream from 'request';
import { Server } from 'http';
Expand All @@ -18,7 +18,6 @@ import supertest from 'supertest';
import { utils } from '../../src/utils';
import ethMigrationTestWalletFixture from './data/ethMigrationTestWallet.fixture';


const should = chai.should();
const expect = chai.expect;

Expand Down Expand Up @@ -56,7 +55,7 @@ describe('Wallet', function() {
dbPort: process.env.DB_PORT || '27017',
dbName: process.env.DB_NAME || 'bitcore-client-tests'
});
Modules.loadConfigured();
loadModules();
const httpServer: Server = await bcnApi.start();
api = supertest(httpServer);
});
Expand Down Expand Up @@ -161,7 +160,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 });
Expand Down Expand Up @@ -196,12 +195,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,
Expand Down Expand Up @@ -230,7 +229,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 });
Expand All @@ -256,7 +255,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
Expand Down Expand Up @@ -793,7 +792,7 @@ describe('Wallet', function() {
let tempHomeDir: string;
let backupDir: string;


beforeEach(async function () {
wallet = new Wallet(ethMigrationTestWalletFixture.wallet as any);
tempHomeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'bitcore-client-migration-'));
Expand Down Expand Up @@ -1173,4 +1172,3 @@ describe('Wallet', function() {
});
});
});

24 changes: 13 additions & 11 deletions packages/bitcore-node/src/modules/bitcoin-cash/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { BaseModule } from '..';
import { ChainStateProvider } from '../../providers/chain-state';
import { BCHStateProvider } from '../../providers/chain-state/bch/bch';
import { IUtxoNetworkConfig } from '../../types/Config';
import { Libs } from '../../providers/libs';
import { P2P } from '../../services/p2p';
import { Verification } from '../../services/verification';
import { RegisterModule } from '../../types/Module';
import { VerificationPeer } from '../bitcoin/VerificationPeer';
import { BitcoinP2PWorker } from '../bitcoin/p2p';

export default class BCHModule extends BaseModule {
constructor(services: BaseModule['bitcoreServices'], chain: string, network: string, _config: IUtxoNetworkConfig) {
super(services);
services.Libs.register(chain, '@bitpay-labs/bitcore-lib-cash', '@bitpay-labs/bitcore-p2p-cash');
services.P2P.register(chain, network, BitcoinP2PWorker);
services.CSP.registerService(chain, network, new BCHStateProvider());
services.Verification.register(chain, network, VerificationPeer);
}
}
const registerModule: RegisterModule = ({ chain, network }) => {
Libs.register(chain, '@bitpay-labs/bitcore-lib-cash', '@bitpay-labs/bitcore-p2p-cash');
P2P.register(chain, network, BitcoinP2PWorker);
ChainStateProvider.registerService(chain, network, new BCHStateProvider());
Verification.register(chain, network, VerificationPeer);
};

export default registerModule;
24 changes: 13 additions & 11 deletions packages/bitcore-node/src/modules/bitcoin/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { BaseModule } from '..';
import { ChainStateProvider } from '../../providers/chain-state';
import { BTCStateProvider } from '../../providers/chain-state/btc/btc';
import { IUtxoNetworkConfig } from '../../types/Config';
import { Libs } from '../../providers/libs';
import { P2P } from '../../services/p2p';
import { Verification } from '../../services/verification';
import { RegisterModule } from '../../types/Module';
import { VerificationPeer } from './VerificationPeer';
import { BitcoinP2PWorker } from './p2p';

export default class BitcoinModule extends BaseModule {
constructor(services: BaseModule['bitcoreServices'], chain: string, network: string, _config: IUtxoNetworkConfig) {
super(services);
services.Libs.register(chain, '@bitpay-labs/bitcore-lib', '@bitpay-labs/bitcore-p2p');
services.P2P.register(chain, network, BitcoinP2PWorker);
services.CSP.registerService(chain, network, new BTCStateProvider());
services.Verification.register(chain, network, VerificationPeer);
}
}
const registerModule: RegisterModule = ({ chain, network }) => {
Libs.register(chain, '@bitpay-labs/bitcore-lib', '@bitpay-labs/bitcore-p2p');
P2P.register(chain, network, BitcoinP2PWorker);
ChainStateProvider.registerService(chain, network, new BTCStateProvider());
Verification.register(chain, network, VerificationPeer);
};

export default registerModule;
24 changes: 13 additions & 11 deletions packages/bitcore-node/src/modules/dogecoin/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { BaseModule } from '..';
import { ChainStateProvider } from '../../providers/chain-state';
import { DOGEStateProvider } from '../../providers/chain-state/doge/doge';
import { IUtxoNetworkConfig } from '../../types/Config';
import { Libs } from '../../providers/libs';
import { P2P } from '../../services/p2p';
import { Verification } from '../../services/verification';
import { RegisterModule } from '../../types/Module';
import { VerificationPeer } from '../bitcoin/VerificationPeer';
import { DogecoinP2PWorker } from './p2p';

export default class DOGEModule extends BaseModule {
constructor(services: BaseModule['bitcoreServices'], chain: string, network: string, _config: IUtxoNetworkConfig) {
super(services);
services.Libs.register(chain, '@bitpay-labs/bitcore-lib-doge', '@bitpay-labs/bitcore-p2p-doge');
services.P2P.register(chain, network, DogecoinP2PWorker);
services.CSP.registerService(chain, network, new DOGEStateProvider());
services.Verification.register(chain, network, VerificationPeer);
}
}
const registerModule: RegisterModule = ({ chain, network }) => {
Libs.register(chain, '@bitpay-labs/bitcore-lib-doge', '@bitpay-labs/bitcore-p2p-doge');
P2P.register(chain, network, DogecoinP2PWorker);
ChainStateProvider.registerService(chain, network, new DOGEStateProvider());
Verification.register(chain, network, VerificationPeer);
};

export default registerModule;
26 changes: 14 additions & 12 deletions packages/bitcore-node/src/modules/ethereum/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { BaseModule } from '..';
import { EVMVerificationPeer } from '../,,/../../providers/chain-state/evm/p2p/EVMVerificationPeer';
import { IEVMNetworkConfig } from '../../types/Config';
import { ChainStateProvider } from '../../providers/chain-state';
import { EVMVerificationPeer } from '../../providers/chain-state/evm/p2p/EVMVerificationPeer';
import { Api } from '../../services/api';
import { P2P } from '../../services/p2p';
import { Verification } from '../../services/verification';
import { RegisterModule } from '../../types/Module';
import { ETHStateProvider } from './api/csp';
import { EthRoutes } from './api/eth-routes';
import { EthP2pWorker } from './p2p/p2p';

export default class ETHModule extends BaseModule {
constructor(services: BaseModule['bitcoreServices'], chain: string, network: string, _config: IEVMNetworkConfig) {
super(services);
services.P2P.register(chain, network, EthP2pWorker);
services.CSP.registerService(chain, network, new ETHStateProvider());
services.Api.app.use(EthRoutes);
services.Verification.register(chain, network, EVMVerificationPeer);
}
}
const registerModule: RegisterModule = ({ chain, network }) => {
P2P.register(chain, network, EthP2pWorker);
ChainStateProvider.registerService(chain, network, new ETHStateProvider());
Api.app.use(EthRoutes);
Verification.register(chain, network, EVMVerificationPeer);
};

export default registerModule;
92 changes: 24 additions & 68 deletions packages/bitcore-node/src/modules/index.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,10 @@
import logger from '../logger';
import { ChainStateProvider } from '../providers/chain-state';
import { Libs } from '../providers/libs';
import { Api } from '../services/api';
import { Config } from '../services/config';
import { Event } from '../services/event';
import { P2P } from '../services/p2p';
import { Storage } from '../services/storage';
import { Verification } from '../services/verification';
import { ChainNetwork } from '../types/ChainNetwork';
import { Class } from '../types/Class';

export interface IService {
start(): Promise<void>;
stop(): Promise<void>;
}

export class BaseModule implements IService {
internalServices = new Array<IService>();
constructor(
protected bitcoreServices: {
P2P: typeof P2P;
Storage: typeof Storage;
Event: typeof Event;
Api: typeof Api;
Config: typeof Config;
CSP: typeof ChainStateProvider;
Libs: typeof Libs;
Verification: typeof Verification;
} = { P2P, Storage, Event, Api, Config, CSP: ChainStateProvider, Libs, Verification }
) {}

async start() {
for (const service of this.internalServices) {
await service.start();
}
}

async stop() {
for (const service of this.internalServices.reverse()) {
await service.stop();
}
}
}

class ModuleManager extends BaseModule {
internalServices = new Array<IService>();

export function loadModules(params: Partial<ChainNetwork> = {}) {
// Chain names -> module paths map
DEFAULT_MODULE_PATHS = {
const DEFAULT_MODULE_PATHS = {
BTC: './bitcoin',
ETH: './ethereum',
MATIC: './matic',
Expand All @@ -57,30 +14,29 @@ class ModuleManager extends BaseModule {
XRP: './ripple',
SOL: './solana'
};

loadConfigured(params: Partial<ChainNetwork> = {}) {
const chains = params.chain ? [params.chain] : Config.chains();

// Auto register known modules from config.chains
for (const chain of chains) {
let modulePath = this.DEFAULT_MODULE_PATHS[chain];

// Register for each
const networks = params.network ? [params.network] : Config.networksFor(chain);
for (const network of networks) {
const config = Config.chainConfig({ chain, network });
modulePath = config.module || modulePath; // custom module path
if (!modulePath) {
logger.warn(`Module not found for ${chain}:${network}. Did you forget to specify 'module' in the config?`);
continue;
}
logger.info(`Registering module for ${chain}:${network}: ${modulePath}`);
// eslint-disable-next-line @typescript-eslint/no-require-imports
const ModuleClass: Class<BaseModule> = require(modulePath).default || require(modulePath);
this.internalServices.push(new ModuleClass(this.bitcoreServices, chain, network, config));
const chains = params.chain ? [params.chain] : Config.chains();

// Auto register known modules from config.chains
for (const chain of chains) {
const defaultModulePath = DEFAULT_MODULE_PATHS[chain];

// Register for each
const networks = params.network ? [params.network] : Config.networksFor(chain);
for (const network of networks) {
const config = Config.chainConfig({ chain, network });
const modulePath = config.module || defaultModulePath; // custom module path
if (!modulePath) {
logger.warn(`Module not found for ${chain}:${network}. Did you forget to specify 'module' in the config?`);
continue;
}
logger.info(`Registering module for ${chain}:${network}: ${modulePath}`);
// eslint-disable-next-line @typescript-eslint/no-require-imports
const loadedModule = require(modulePath);
const register = loadedModule.default ?? loadedModule;
if (typeof register !== 'function') {
throw new TypeError(`Invalid module for ${chain}:${network} at ${modulePath}: expected a default export or module.exports to be a register function`);
}
register({ chain, network });
}
}
}

export const Modules = new ModuleManager();
24 changes: 13 additions & 11 deletions packages/bitcore-node/src/modules/litecoin/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { BaseModule } from '..';
import { ChainStateProvider } from '../../providers/chain-state';
import { LTCStateProvider } from '../../providers/chain-state/ltc/ltc';
import { IUtxoNetworkConfig } from '../../types/Config';
import { Libs } from '../../providers/libs';
import { P2P } from '../../services/p2p';
import { Verification } from '../../services/verification';
import { RegisterModule } from '../../types/Module';
import { VerificationPeer } from '../bitcoin/VerificationPeer';
import { LitecoinP2PWorker } from './p2p';

export default class LTCModule extends BaseModule {
constructor(services: BaseModule['bitcoreServices'], chain: string, network: string, _config: IUtxoNetworkConfig) {
super(services);
services.Libs.register(chain, '@bitpay-labs/bitcore-lib-ltc', '@bitpay-labs/bitcore-p2p');
services.P2P.register(chain, network, LitecoinP2PWorker);
services.CSP.registerService(chain, network, new LTCStateProvider());
services.Verification.register(chain, network, VerificationPeer);
}
}
const registerModule: RegisterModule = ({ chain, network }) => {
Libs.register(chain, '@bitpay-labs/bitcore-lib-ltc', '@bitpay-labs/bitcore-p2p');
P2P.register(chain, network, LitecoinP2PWorker);
ChainStateProvider.registerService(chain, network, new LTCStateProvider());
Verification.register(chain, network, VerificationPeer);
};

export default registerModule;
24 changes: 13 additions & 11 deletions packages/bitcore-node/src/modules/matic/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { BaseModule } from '..';
import { ChainStateProvider } from '../../providers/chain-state';
import { EVMVerificationPeer } from '../../providers/chain-state/evm/p2p/EVMVerificationPeer';
import { EVMP2pWorker } from '../../providers/chain-state/evm/p2p/p2p';
import { IEVMNetworkConfig } from '../../types/Config';
import { Api } from '../../services/api';
import { P2P } from '../../services/p2p';
import { Verification } from '../../services/verification';
import { RegisterModule } from '../../types/Module';
import { MATICStateProvider } from './api/csp';
import { MaticRoutes } from './api/matic-routes';

export default class MATICModule extends BaseModule {
constructor(services: BaseModule['bitcoreServices'], chain: string, network: string, _config: IEVMNetworkConfig) {
super(services);
services.P2P.register(chain, network, EVMP2pWorker);
services.CSP.registerService(chain, network, new MATICStateProvider());
services.Api.app.use(MaticRoutes);
services.Verification.register(chain, network, EVMVerificationPeer);
}
}
const registerModule: RegisterModule = ({ chain, network }) => {
P2P.register(chain, network, EVMP2pWorker);
ChainStateProvider.registerService(chain, network, new MATICStateProvider());
Api.app.use(MaticRoutes);
Verification.register(chain, network, EVMVerificationPeer);
};

export default registerModule;
Loading
Loading