wallet: refactor and add global zap.
This commit is contained in:
parent
acae838059
commit
5bb21070c4
9
bin/cli
9
bin/cli
@ -303,6 +303,12 @@ CLI.prototype.rescan = co(function* rescan() {
|
||||
this.log('Rescanning...');
|
||||
});
|
||||
|
||||
CLI.prototype.zapAll = co(function* zapAll() {
|
||||
var age = +this.argv[0] || 72 * 3600;
|
||||
yield this.client.zapAll(age);
|
||||
this.log('Zapped.');
|
||||
});
|
||||
|
||||
CLI.prototype.backup = co(function* backup() {
|
||||
var path = this.argv[0];
|
||||
|
||||
@ -493,6 +499,8 @@ CLI.prototype.handleNode = co(function* handleNode() {
|
||||
return yield this.getBlock();
|
||||
case 'rescan':
|
||||
return yield this.rescan();
|
||||
case 'zap':
|
||||
return yield this.zapAll();
|
||||
case 'backup':
|
||||
return yield this.backup();
|
||||
case 'rpc':
|
||||
@ -507,6 +515,7 @@ CLI.prototype.handleNode = co(function* handleNode() {
|
||||
this.log(' $ coin [hash+index/address]: View coins.');
|
||||
this.log(' $ block [hash/height]: View block.');
|
||||
this.log(' $ rescan [height/hash]: Rescan for transactions.');
|
||||
this.log(' $ zap [age?]: Zap stale transactions from walletdb.');
|
||||
this.log(' $ backup [path]: Backup the wallet db.');
|
||||
this.log(' $ rpc [command] [args]: Execute RPC command.');
|
||||
return;
|
||||
|
||||
@ -358,6 +358,17 @@ HTTPClient.prototype.rescan = function rescan(hash) {
|
||||
return this._post('/rescan', options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Zap stale transactions.
|
||||
* @param {Number} age
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
HTTPClient.prototype.zapAll = function zapAll(age) {
|
||||
var options = { age: age };
|
||||
return this._post('/zap', options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Backup the walletdb.
|
||||
* @param {String} path
|
||||
|
||||
@ -698,6 +698,18 @@ HTTPServer.prototype._init = function _init() {
|
||||
yield this.node.scan(height);
|
||||
}));
|
||||
|
||||
// Zap
|
||||
this.post('/zap', con(function* (req, res, send, next) {
|
||||
var options = req.options;
|
||||
var age = options.age;
|
||||
|
||||
enforce(age != null, 'Age is required.');
|
||||
|
||||
yield this.walletdb.zap(age);
|
||||
|
||||
send(200, { success: true });
|
||||
}));
|
||||
|
||||
// Backup WalletDB
|
||||
this.post('/backup', con(function* (req, res, send, next) {
|
||||
var options = req.options;
|
||||
|
||||
@ -245,6 +245,9 @@ Fullnode.prototype._open = co(function* open() {
|
||||
// Ensure primary wallet.
|
||||
yield this.openWallet();
|
||||
|
||||
// Zap stale txs.
|
||||
yield this.walletdb.zap(72 * 3600);
|
||||
|
||||
// Rescan for any missed transactions.
|
||||
yield this.rescan();
|
||||
|
||||
|
||||
@ -168,6 +168,9 @@ SPVNode.prototype._open = co(function* open(callback) {
|
||||
// Load bloom filter.
|
||||
yield this.openFilter();
|
||||
|
||||
// Zap stale txs.
|
||||
yield this.walletdb.zap(72 * 3600);
|
||||
|
||||
// Rescan for any missed transactions.
|
||||
yield this.rescan();
|
||||
|
||||
|
||||
@ -1918,6 +1918,7 @@ TXDB.prototype.getAccountBalance = co(function* getBalance(account) {
|
||||
*/
|
||||
|
||||
TXDB.prototype.zap = co(function* zap(account, age) {
|
||||
var hashes = [];
|
||||
var i, txs, tx, hash;
|
||||
|
||||
if (!utils.isUInt32(age))
|
||||
@ -1937,6 +1938,9 @@ TXDB.prototype.zap = co(function* zap(account, age) {
|
||||
|
||||
this.wallet.start();
|
||||
|
||||
this.logger.debug('Zapping TX: %s (%s)',
|
||||
hash, this.wallet.id);
|
||||
|
||||
try {
|
||||
yield this._remove(hash);
|
||||
} catch (e) {
|
||||
@ -1944,8 +1948,12 @@ TXDB.prototype.zap = co(function* zap(account, age) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
hashes.push(hash);
|
||||
|
||||
yield this.wallet.commit();
|
||||
}
|
||||
|
||||
return hashes;
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@ -25,6 +25,7 @@ var ldb = require('../db/ldb');
|
||||
var Bloom = require('../utils/bloom');
|
||||
var Logger = require('../node/logger');
|
||||
var TX = require('../primitives/tx');
|
||||
var TXDB = require('./txdb');
|
||||
|
||||
/*
|
||||
* Database Layout:
|
||||
@ -743,7 +744,7 @@ WalletDB.prototype.saveAccount = function saveAccount(account) {
|
||||
var wallet = account.wallet;
|
||||
var index = account.accountIndex;
|
||||
var name = account.name;
|
||||
var batch = this.batch(account.wallet);
|
||||
var batch = this.batch(wallet);
|
||||
var buf = new Buffer(4);
|
||||
|
||||
buf.writeUInt32LE(index, 0, true);
|
||||
@ -1043,12 +1044,10 @@ WalletDB.prototype._rescan = co(function* rescan(chaindb, height) {
|
||||
*/
|
||||
|
||||
WalletDB.prototype.getPendingKeys = co(function* getPendingKeys() {
|
||||
var layout = require('./txdb').layout;
|
||||
var layout = TXDB.layout;
|
||||
var dummy = new Buffer(0);
|
||||
var uniq = {};
|
||||
var keys = [];
|
||||
var result = [];
|
||||
var i, iter, item, key, wid, hash;
|
||||
var iter, item;
|
||||
|
||||
iter = yield this.db.iterator({
|
||||
gte: layout.prefix(0x00000000, dummy),
|
||||
@ -1065,6 +1064,22 @@ WalletDB.prototype.getPendingKeys = co(function* getPendingKeys() {
|
||||
keys.push(item.key);
|
||||
}
|
||||
|
||||
return keys;
|
||||
});
|
||||
|
||||
/**
|
||||
* Get keys of all pending transactions
|
||||
* in the wallet db (for resending).
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
WalletDB.prototype.getPendingTX = co(function* getPendingTX() {
|
||||
var layout = TXDB.layout;
|
||||
var keys = yield this.getPendingKeys();
|
||||
var uniq = {};
|
||||
var result = [];
|
||||
var i, key, wid, hash;
|
||||
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
key = keys[i];
|
||||
|
||||
@ -1083,13 +1098,41 @@ WalletDB.prototype.getPendingKeys = co(function* getPendingKeys() {
|
||||
return result;
|
||||
});
|
||||
|
||||
/**
|
||||
* Get all wallet IDs with pending txs in them.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
WalletDB.prototype.getPendingWallets = co(function* getPendingWallets() {
|
||||
var layout = TXDB.layout;
|
||||
var keys = yield this.getPendingKeys();
|
||||
var uniq = {};
|
||||
var result = [];
|
||||
var i, key, wid;
|
||||
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
key = keys[i];
|
||||
|
||||
wid = layout.pre(key);
|
||||
|
||||
if (uniq[wid])
|
||||
continue;
|
||||
|
||||
uniq[wid] = true;
|
||||
|
||||
result.push(wid);
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
/**
|
||||
* Resend all pending transactions.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
WalletDB.prototype.resend = co(function* resend() {
|
||||
var keys = yield this.getPendingKeys();
|
||||
var keys = yield this.getPendingTX();
|
||||
var i, key, data, tx;
|
||||
|
||||
if (keys.length > 0)
|
||||
@ -1114,7 +1157,7 @@ WalletDB.prototype.resend = co(function* resend() {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
WalletDB.prototype.getWidsByHashes = co(function* getWidsByHashes(hashes) {
|
||||
WalletDB.prototype.getWalletsByHashes = co(function* getWalletsByHashes(hashes) {
|
||||
var result = [];
|
||||
var i, j, hash, wids;
|
||||
|
||||
@ -1126,10 +1169,16 @@ WalletDB.prototype.getWidsByHashes = co(function* getWidsByHashes(hashes) {
|
||||
|
||||
wids = yield this.getWalletsByHash(hash);
|
||||
|
||||
if (!wids)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < wids.length; j++)
|
||||
utils.binaryInsert(result, wids[j], cmp, true);
|
||||
}
|
||||
|
||||
if (result.length === 0)
|
||||
return;
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
@ -1398,13 +1447,10 @@ WalletDB.prototype._addTX = co(function* addTX(tx) {
|
||||
|
||||
assert(!tx.mutable, 'Cannot add mutable TX to wallet.');
|
||||
|
||||
// Atomicity doesn't matter here. If we crash,
|
||||
// the automatic rescan will get the database
|
||||
// back in the correct state.
|
||||
hashes = tx.getHashes('hex');
|
||||
wallets = yield this.getWidsByHashes(hashes);
|
||||
wallets = yield this.getWalletsByHashes(hashes);
|
||||
|
||||
if (wallets.length === 0)
|
||||
if (!wallets)
|
||||
return;
|
||||
|
||||
this.logger.info(
|
||||
@ -1415,8 +1461,7 @@ WalletDB.prototype._addTX = co(function* addTX(tx) {
|
||||
wid = wallets[i];
|
||||
wallet = yield this.get(wid);
|
||||
|
||||
if (!wallet)
|
||||
continue;
|
||||
assert(wallet);
|
||||
|
||||
this.logger.debug('Adding tx to wallet: %s', wallet.id);
|
||||
|
||||
@ -1459,14 +1504,45 @@ WalletDB.prototype._unconfirmTX = co(function* unconfirmTX(hash) {
|
||||
for (i = 0; i < wallets.length; i++) {
|
||||
wid = wallets[i];
|
||||
wallet = yield this.get(wid);
|
||||
|
||||
if (!wallet)
|
||||
continue;
|
||||
|
||||
assert(wallet);
|
||||
yield wallet.unconfirm(hash);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Zap stale transactions.
|
||||
* @param {Number} age
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
WalletDB.prototype.zap = co(function* zap(age) {
|
||||
var unlock = yield this.txLock.lock();
|
||||
try {
|
||||
return yield this._zap(age);
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Zap stale transactions without a lock.
|
||||
* @private
|
||||
* @param {Number} age
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
WalletDB.prototype._zap = co(function* zap(age) {
|
||||
var wallets = yield this.getPendingWallets();
|
||||
var i, wid, wallet;
|
||||
|
||||
for (i = 0; i < wallets.length; i++) {
|
||||
wid = wallets[i];
|
||||
wallet = yield this.get(wid);
|
||||
assert(wallet);
|
||||
yield wallet.zap(age);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Wallet Block
|
||||
* @constructor
|
||||
|
||||
Loading…
Reference in New Issue
Block a user