Skip to content

Commit cee3e2a

Browse files
committed
Merge branch 'thoroughScan' of github.com:kajoseph/bitcore
2 parents 4bdbcec + ebb1375 commit cee3e2a

File tree

15 files changed

+719
-668
lines changed

15 files changed

+719
-668
lines changed

packages/bitcore-node/src/models/walletAddress.ts

+29-32
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,10 @@ export class WalletAddressModel extends BaseModel<IWalletAddress> {
3737
return JSON.stringify(transform);
3838
}
3939

40-
async updateCoins(params: { wallet: IWallet; addresses: string[] }) {
41-
const { wallet, addresses } = params;
40+
async updateCoins(params: { wallet: IWallet; addresses: string[]; opts?: { reprocess?: boolean } }) {
41+
const { wallet, addresses, opts } = params;
4242
const { chain, network } = wallet;
43+
const { reprocess } = opts || {};
4344

4445
class AddressInputStream extends Readable {
4546
addressBatches: string[][];
@@ -65,19 +66,19 @@ export class WalletAddressModel extends BaseModel<IWalletAddress> {
6566
}
6667
async _transform(addressBatch, _, callback) {
6768
try {
68-
let exists = (
69-
await WalletAddressStorage.collection
70-
.find({ chain, network, wallet: wallet._id, address: { $in: addressBatch } })
71-
.project({ address: 1, processed: 1 })
72-
.toArray()
73-
)
74-
.filter(walletAddress => walletAddress.processed)
75-
.map(walletAddress => walletAddress.address);
76-
this.push(
77-
addressBatch.filter(address => {
78-
return !exists.includes(address);
79-
})
80-
);
69+
if (reprocess) {
70+
this.push(addressBatch);
71+
} else {
72+
const exists = (
73+
await WalletAddressStorage.collection
74+
.find({ chain, network, wallet: wallet._id, address: { $in: addressBatch } })
75+
.project({ address: 1, processed: 1 })
76+
.toArray()
77+
)
78+
.filter(walletAddress => walletAddress.processed)
79+
.map(walletAddress => walletAddress.address);
80+
this.push(addressBatch.filter(address => !exists.includes(address)));
81+
}
8182
callback();
8283
} catch (err) {
8384
callback(err);
@@ -95,15 +96,13 @@ export class WalletAddressModel extends BaseModel<IWalletAddress> {
9596
}
9697
try {
9798
await WalletAddressStorage.collection.bulkWrite(
98-
addressBatch.map(address => {
99-
return {
100-
insertOne: {
101-
document: { chain, network, wallet: wallet._id, address, processed: false }
102-
}
103-
};
104-
})
105-
),
106-
{ ordered: false };
99+
addressBatch.map(address => ({
100+
insertOne: {
101+
document: { chain, network, wallet: wallet._id, address, processed: false }
102+
}
103+
})),
104+
{ ordered: false }
105+
);
107106
} catch (err: any) {
108107
// Ignore duplicate keys, they may be half processed
109108
if (err.code !== 11000) {
@@ -125,14 +124,12 @@ export class WalletAddressModel extends BaseModel<IWalletAddress> {
125124
}
126125
try {
127126
await CoinStorage.collection.bulkWrite(
128-
addressBatch.map(address => {
129-
return {
130-
updateMany: {
131-
filter: { chain, network, address },
132-
update: { $addToSet: { wallets: wallet._id } }
133-
}
134-
};
135-
}),
127+
addressBatch.map(address => ({
128+
updateMany: {
129+
filter: { chain, network, address },
130+
update: { $addToSet: { wallets: wallet._id } }
131+
}
132+
})),
136133
{ ordered: false }
137134
);
138135
this.push(addressBatch);

packages/bitcore-node/src/providers/chain-state/internal/internal.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -371,8 +371,8 @@ export class InternalStateProvider implements IChainStateService {
371371
}
372372

373373
async updateWallet(params: UpdateWalletParams) {
374-
const { wallet, addresses } = params;
375-
await WalletAddressStorage.updateCoins({ wallet, addresses });
374+
const { wallet, addresses, reprocess = false } = params;
375+
await WalletAddressStorage.updateCoins({ wallet, addresses, opts: { reprocess } });
376376
}
377377

378378
async streamWalletTransactions(params: StreamWalletTransactionsParams) {

packages/bitcore-node/src/routes/api/wallet.ts

+18-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import logger from '../../logger';
44
import { ChainStateProvider } from '../../providers/chain-state';
55
import { StreamWalletAddressesParams } from '../../types/namespaces/ChainStateProvider';
66
import { Auth, AuthenticatedRequest } from '../../utils/auth';
7+
import config from '../../config';
78
const router = Router({ mergeParams: true });
89

910
function isTooLong(field, maxLength = 255) {
@@ -97,15 +98,27 @@ router.get('/:pubKey/check', Auth.authenticateMiddleware, async (req: Authentica
9798
router.post('/:pubKey', Auth.authenticateMiddleware, async (req: AuthenticatedRequest, res: Response) => {
9899
let keepAlive;
99100
try {
100-
let { chain, network } = req.params;
101-
let addressLines: { address: string }[] = req.body.filter(line => !!line.address);
101+
const { chain, network, pubKey } = req.params;
102+
const addressLines: { address: string }[] = req.body.filter(line => !!line.address);
102103

103-
let addresses = addressLines.map(({ address }) => address);
104+
const addresses = addressLines.map(({ address }) => address);
104105
for (const address of addresses) {
105106
if (isTooLong(address) || !Validation.validateAddress(chain, network, address)) {
106107
return res.status(413).send('Invalid address');
107108
}
108109
}
110+
let reprocess = false;
111+
if (req.headers['x-reprocess']) {
112+
const reprocessOk = Auth.verifyRequestSignature({
113+
message: ['reprocess', '/addAddresses' + pubKey, JSON.stringify(req.body)].join('|'),
114+
pubKey: config.services.socket.bwsKeys[0],
115+
signature: req.headers['x-reprocess']
116+
});
117+
if (!reprocessOk) {
118+
return res.status(401).send('Authentication failed');
119+
}
120+
reprocess = true;
121+
}
109122
res.status(200);
110123
keepAlive = setInterval(() => {
111124
res.write('\n');
@@ -114,7 +127,8 @@ router.post('/:pubKey', Auth.authenticateMiddleware, async (req: AuthenticatedRe
114127
chain,
115128
network,
116129
wallet: req.wallet!,
117-
addresses
130+
addresses,
131+
reprocess
118132
});
119133
clearInterval(keepAlive);
120134
return res.end();

packages/bitcore-node/src/types/namespaces/ChainStateProvider.ts

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ export type GetWalletParams = ChainNetwork & PubKey;
8484
export type UpdateWalletParams = ChainNetwork & {
8585
wallet: MongoBound<IWallet>;
8686
addresses: string[];
87+
reprocess?: boolean;
8788
};
8889

8990
export type GetWalletBalanceParams = ChainNetwork & {

packages/bitcore-wallet-client/src/lib/api.ts

+13-11
Original file line numberDiff line numberDiff line change
@@ -2328,22 +2328,24 @@ export class API extends EventEmitter {
23282328
});
23292329
}
23302330

2331-
// /**
2332-
// * Start an address scanning process.
2333-
// * When finished, the scanning process will send a notification 'ScanFinished' to all copayers.
2334-
// *
2335-
// * @param {Object} opts
2336-
// * @param {Boolean} opts.includeCopayerBranches (defaults to false)
2337-
// * @param {Callback} cb
2338-
// */
2331+
/**
2332+
* Start an address scanning process.
2333+
* When finished, the scanning process will send a notification 'ScanFinished' to all copayers.
2334+
*
2335+
* @param {Object} opts
2336+
* @param {Boolean} opts.includeCopayerBranches (defaults to false)
2337+
* @param {Number} opts.startIdx (optional) address derivation path start index (support agents only)
2338+
* @param {Callback} cb
2339+
*/
23392340
startScan(opts, cb) {
23402341
$.checkState(
23412342
this.credentials && this.credentials.isComplete(),
23422343
'Failed state: this.credentials at <startScan()>'
23432344
);
23442345

2345-
var args = {
2346-
includeCopayerBranches: opts.includeCopayerBranches
2346+
const args = {
2347+
includeCopayerBranches: opts.includeCopayerBranches,
2348+
startIdx: opts.startIdx
23472349
};
23482350

23492351
this.request.post('/v1/addresses/scan', args, err => {
@@ -2460,7 +2462,7 @@ export class API extends EventEmitter {
24602462

24612463
opts = opts || {};
24622464
var args = [];
2463-
if (_.isNumber(opts.minTs)) {
2465+
if (opts.minTs != null && !isNaN(opts.minTs)) {
24642466
args.push('minTs=' + opts.minTs);
24652467
}
24662468
var qs = '';

packages/bitcore-wallet-service/src/lib/blockchainexplorer.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ const PROVIDERS = {
4848
}
4949
};
5050

51-
export function BlockChainExplorer(opts) {
51+
export function BlockChainExplorer(opts): V8 {
5252
$.checkArgument(opts, 'Failed state: opts undefined at <BlockChainExplorer()>');
5353

5454
const provider = opts.provider || 'v8';

packages/bitcore-wallet-service/src/lib/blockchainexplorers/v8.ts

+18-15
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ const Constants = Common.Constants,
2828
Defaults = Common.Defaults,
2929
Utils = Common.Utils;
3030

31+
const { sortDesc } = Utils;
32+
3133
function v8network(bwsNetwork, chain = 'btc') {
3234
if (Utils.getGenericName(bwsNetwork) == 'livenet') return 'mainnet';
3335
if (Utils.getGenericName(bwsNetwork) == 'testnet' && config.blockchainExplorerOpts?.[chain.toLowerCase()]?.[Utils.getNetworkName(chain.toLowerCase(), 'testnet')]?.regtestEnabled) {
@@ -94,22 +96,23 @@ export class V8 {
9496
});
9597
}
9698

97-
addAddresses(wallet, addresses, cb) {
99+
addAddresses(wallet, addresses, cb, opts?) {
98100
const client = this._getAuthClient(wallet);
101+
const payload = addresses.map(a => ({ address: a }));
102+
if (opts?.reprocess) {
103+
// For peformance, ensure reprocess requests only come from BWS
104+
const c = this._getAuthClient({ beAuthPrivateKey2: config.blockchainExplorerOpts.socketApiKey });
105+
opts.reprocess = c.sign({ method: 'reprocess', url: 'http://thisdontmatter.com/addAddresses' + wallet.beAuthPublicKey2, payload });
106+
}
99107

100-
const payload = _.map(addresses, a => {
101-
return {
102-
address: a
103-
};
104-
});
105-
106-
const k = 'addAddresses' + addresses.length;
108+
const k = 'addAddresses' + !!opts.reprocess + addresses.length;
107109
const perfKey = getPerformanceKey(k);
108110
console.time(perfKey);
109111
client
110112
.importAddresses({
111113
payload,
112-
pubKey: wallet.beAuthPublicKey2
114+
pubKey: wallet.beAuthPublicKey2,
115+
reprocess: opts?.reprocess
113116
})
114117
.then(ret => {
115118
console.timeEnd(perfKey);
@@ -278,7 +281,7 @@ export class V8 {
278281
client
279282
.getTx({ txid })
280283
.then(tx => {
281-
if (!tx || _.isEmpty(tx)) {
284+
if (!tx || JSON.stringify(tx) === '{}') {
282285
return cb();
283286
}
284287
return cb(null, tx);
@@ -327,7 +330,7 @@ export class V8 {
327330
multisigContractAddress: wallet.multisigContractAddress
328331
};
329332

330-
if (_.isNumber(startBlock)) opts.startBlock = startBlock;
333+
if (startBlock != null && !isNaN(startBlock)) opts.startBlock = startBlock;
331334

332335
const txStream = client.listTransactions(opts);
333336
txStream.on('data', raw => {
@@ -341,8 +344,8 @@ export class V8 {
341344

342345
const txs = [],
343346
unconf = [];
344-
_.each(acum.split(/\r?\n/), rawTx => {
345-
if (!rawTx) return;
347+
for (const rawTx of acum.split(/\r?\n/)) {
348+
if (!rawTx) continue;
346349

347350
let tx;
348351
try {
@@ -356,10 +359,10 @@ export class V8 {
356359

357360
if (tx.height >= 0) txs.push(tx);
358361
else if (tx.height >= -2) unconf.push(tx);
359-
});
362+
}
360363
console.timeEnd(perfKey);
361364
// blockTime on unconf is 'seenTime';
362-
return cb(null, _.flatten(_.orderBy(unconf, 'blockTime', 'desc').concat(txs.reverse())));
365+
return cb(null, _.flatten(sortDesc(unconf, 'blockTime').concat(txs.reverse())));
363366
});
364367

365368
txStream.on('error', e => {

packages/bitcore-wallet-service/src/lib/blockchainexplorers/v8/client.ts

+3
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ export class Client {
160160
logger.debug('addAddresses: %o %o', url, payload);
161161
const signature = this.sign({ method: 'POST', url, payload });
162162
const h = { 'x-signature': signature };
163+
if (params.reprocess) {
164+
h['x-reprocess'] = params.reprocess;
165+
}
163166
return request.post(url, {
164167
headers: h,
165168
body: payload,

packages/bitcore-wallet-service/src/lib/chain/btc/index.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export class BtcChain implements IChain {
3838
return 0;
3939
}
4040

41-
getWalletBalance(server, wallet, opts, cb) {
41+
getWalletBalance(server: WalletService, wallet, opts, cb) {
4242
server.getUtxosForCurrentWallet(
4343
{
4444
coin: opts.coin,
@@ -74,7 +74,7 @@ export class BtcChain implements IChain {
7474
}
7575

7676
// opts.payProUrl => only to use different safety margin or not
77-
getWalletSendMaxInfo(server, wallet, opts, cb) {
77+
getWalletSendMaxInfo(server: WalletService, wallet, opts, cb) {
7878
server.getUtxosForCurrentWallet({}, (err, utxos) => {
7979
if (err) return cb(err);
8080

@@ -167,7 +167,7 @@ export class BtcChain implements IChain {
167167
return null;
168168
}
169169

170-
getChangeAddress(server, wallet, opts) {
170+
getChangeAddress(server: WalletService, wallet, opts) {
171171
return new Promise((resolve, reject) => {
172172
const getChangeAddress = (wallet, cb) => {
173173
if (wallet.singleAddress) {
@@ -339,7 +339,7 @@ export class BtcChain implements IChain {
339339
return parseInt(fee.toFixed(0));
340340
}
341341

342-
getFee(server, wallet, opts) {
342+
getFee(server: WalletService, wallet, opts) {
343343
return new Promise(resolve => {
344344
server._getFeePerKb(wallet, opts, (err, feePerKb) => {
345345
return resolve({ feePerKb });
@@ -514,7 +514,7 @@ export class BtcChain implements IChain {
514514
return bitcoreError;
515515
}
516516

517-
checkTxUTXOs(server, txp, opts, cb) {
517+
checkTxUTXOs(server: WalletService, txp, opts, cb) {
518518
logger.debug('Rechecking UTXOs availability for publishTx');
519519

520520
if (txp.replaceTxByFee) {
@@ -561,7 +561,7 @@ export class BtcChain implements IChain {
561561
return balance;
562562
}
563563

564-
selectTxInputs(server, txp, wallet, opts, cb) {
564+
selectTxInputs(server: WalletService, txp, wallet, opts, cb) {
565565
const MAX_TX_SIZE_IN_KB = Defaults.MAX_TX_SIZE_IN_KB_BTC;
566566

567567
// todo: check inputs are ours and have enough value

0 commit comments

Comments
 (0)