Skip to content

[BCN/BWS] A few helper scripts for BCN and BWS #3908

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 21, 2025
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
64 changes: 64 additions & 0 deletions packages/bitcore-node/scripts/findReplacedTx.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env node

const { Storage } = require('../build/src/services/storage');
const { TransactionStorage } = require('../build/src/models/transaction');

function usage(errMsg) {
console.log('USAGE: ./findReplacedTx.js <options>');
console.log('OPTIONS:');
console.log(' --chain <value> REQUIRED - e.g. BTC, BCH, DOGE, LTC...');
console.log(' --network <value> REQUIRED - e.g. mainnet, testnet3, regtest...');
console.log(' --txid <value> REQUIRED Transaction Id that replaced');
console.log(' --window [value] Minutes to look back (default: 10)')
if (errMsg) {
console.log('\nERROR: ' + errMsg);
}
process.exit();
}

const args = process.argv.slice(2);

if (args.includes('--help') || args.includes('-h')) {
usage();
}


const chainIdx = args.indexOf('--chain');
const networkIdx = args.indexOf('--network');
const txidIdx = args.indexOf('--txid');
const chain = args[chainIdx + 1]?.toUpperCase();
const network = args[networkIdx + 1]?.toLowerCase();
const txid = args[txidIdx + 1];

if (chainIdx === -1 || networkIdx === -1 || txidIdx === -1 || !chain || !network || !txid) {
usage('Missing required options.');
}

const windowIdx = args.indexOf('--window');
const windowMins = (windowIdx > -1 && parseInt(args[windowIdx + 1])) || 10;

console.log('Connecting to database...');

Storage.start()
.then(async () => {

const confirmedTx = await TransactionStorage.collection.findOne({ chain, network, txid });
if (!confirmedTx) {
console.log('Tx not found in db:', txid);
return;
}
const $lt = new Date(confirmedTx.blockTimeNormalized);
const $gt = new Date($lt.getTime() - (1000 * 60 * windowMins));
const related = TransactionStorage.collection.find({ chain, network, blockTimeNormalized: { $lt, $gt }, blockHeight: -3 });
for await (const tx of related) {
if (tx.replacedByTxid === txid) {
console.log(tx);
break;
}
}

})
.catch(console.error)
.finally(() => {
Storage.stop();
});
105 changes: 105 additions & 0 deletions packages/bitcore-wallet-service/src/scripts/purgeNotifications.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env node

const config = require('../../ts_build/config').default;
const { Storage } = require('../../ts_build');
const rl = require('readline').createInterface({ input: process.stdin, output: process.stdout });


let stop = false;
process.on('SIGINT', () => {
stop = true;
});

function usage(errMsg) {
console.log('USAGE: ./purgeNotifications.js <options>');
console.log();
console.log('OPTIONS:');
console.log(' --walletId <value> WalletId to purge notifications for. Often this is in the format `<chain>:<network>`');
console.log(' --batchSize [value] How many docs to delete at once. Default: 1000');
console.log(' --doit Save the migration to the db');
if (errMsg) {
console.log();
console.log('\nERROR: ' + errMsg);
}
process.exit();
}

const args = process.argv.slice(2);

if (args.includes('--help') || args.includes('-h')) {
usage();
}

const walletIdIdx = args.indexOf('--walletId');
const batchSizeIdx = args.indexOf('--batchSize');
const walletId = args[walletIdIdx + 1];
const batchSize = batchSizeIdx > -1 ? parseInt(args[batchSizeIdx + 1]) : 1000;
const doit = args.includes('--doit');

if (walletIdIdx === -1 || !walletId) {
usage('Missing required --walletId');
}

if (batchSizeIdx > -1 && isNaN(batchSize)) {
usage('Invalid batch size');
}

if (!doit) {
console.log('Dry run (pass --doit to actually do it)');
} else {
console.log('LET\'S DO IT FOR REAL');
}

const storage = new Storage();
storage.connect(config.storageOpts, async (err) => {
if (err) {
console.log(err);
return;
}

function done(err) {
if (err) { console.log(err) }
rl.close();
storage.disconnect(() => { console.log('done'); });
}

try {
// Get all notifications
const notiCnt = await storage.db.collection(Storage.collections.NOTIFICATIONS).count({ walletId });

console.log(`Found ${Intl.NumberFormat().format(notiCnt)} total notifications for ${walletId} to delete`);
const ans = await new Promise(r => rl.question(`Would you like to continue ${doit ? 'FOR REAL' : 'a dry run'}? (y/N): `, r));
if (ans?.toLowerCase() !== 'y') {
return done('Good bye.');
}

let count = 0;
let notifications = [];
const getNextPage = async () => storage.db.collection(Storage.collections.NOTIFICATIONS).find({ walletId }).skip(doit ? 0 : count).limit(batchSize).toArray();
while ((notifications = await getNextPage()).length > 0 && !stop) {
if (count % (batchSize * 10) === 0) {
process.stdout.write(`Purged ${(count / notiCnt * 100).toFixed(4)}% notifications (${count})\r`); // shows how fast things are working
await new Promise(resolve => setTimeout(resolve, 250)); // cooldown
}

const query = { _id: { $in: notifications.map(n => n._id) } };

if (doit) {
const res = await storage.db.collection(Storage.collections.NOTIFICATIONS).deleteMany(query);
count += res.deletedCount;
} else {
// Update Wallets collection
const notificationCount = await storage.db.collection(Storage.collections.NOTIFICATIONS).countDocuments(query);
count += notificationCount;
}
}
process.stdout.write('\n');

console.log(`\u2713 Purged ${Intl.NumberFormat().format(count)} notifications`);
stop && console.log('Stopped prematurely by user');

return done();
} catch (err) {
return done(err);
}
});
Loading