walletdb: cleanup.

This commit is contained in:
Christopher Jeffrey 2016-11-01 23:40:10 -07:00
parent 3a89e627b8
commit 60575c0ea0
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
7 changed files with 109 additions and 292 deletions

View File

@ -323,12 +323,6 @@ CLI.prototype.resendWallet = co(function* resendWallet() {
this.log('Resending...');
});
CLI.prototype.zap = co(function* zap() {
var age = +this.argv[0] || 72 * 3600;
yield this.client.zap(age);
this.log('Zapped.');
});
CLI.prototype.backup = co(function* backup() {
var path = this.argv[0];
@ -529,8 +523,6 @@ CLI.prototype.handleNode = co(function* handleNode() {
return yield this.rescan();
case 'resend':
return yield this.resend();
case 'zap':
return yield this.zap();
case 'backup':
return yield this.backup();
case 'rpc':
@ -547,7 +539,6 @@ CLI.prototype.handleNode = co(function* handleNode() {
this.log(' $ block [hash/height]: View block.');
this.log(' $ rescan [height/hash]: Rescan for transactions.');
this.log(' $ resend: Resend pending 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;

View File

@ -362,17 +362,6 @@ HTTPClient.prototype.resend = function resend() {
return this._post('/resend', {});
};
/**
* Zap stale transactions.
* @param {Number} age
* @returns {Promise}
*/
HTTPClient.prototype.zap = function zap(age) {
var options = { age: age };
return this._post('/zap', options);
};
/**
* Backup the walletdb.
* @param {String} path

View File

@ -740,18 +740,6 @@ HTTPServer.prototype._init = function _init() {
send(200, { success: true });
}));
// 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;

View File

@ -45,11 +45,8 @@ layout.walletdb = {
return [+key.slice(1, 11), key.slice(11)];
},
R: 'R',
c: function c(height) {
return 'c' + pad32(height);
},
cc: function cc(key) {
return +key.slice(1);
h: function c(height) {
return 'h' + pad32(height);
},
b: function b(height) {
return 'b' + pad32(height);
@ -57,12 +54,6 @@ layout.walletdb = {
bb: function bb(key) {
return +key.slice(1);
},
e: function e(hash) {
return 'e' + hash;
},
ee: function ee(key) {
return key.slice(1);
},
o: function o(hash) {
return 'o' + hash + pad32(index);
},

View File

@ -362,19 +362,6 @@ TXMapRecord.prototype.remove = function remove(wid) {
return utils.binaryRemove(this.wids, wid, cmp);
};
TXMapRecord.prototype.toRaw = function toRaw() {
return serializeWallets(this.wids);
};
TXMapRecord.prototype.fromRaw = function fromRaw(data) {
this.wids = parseWallets(data);
return this;
};
TXMapRecord.fromRaw = function fromRaw(hash, data) {
return new TXMapRecord(hash).fromRaw(data);
};
/**
* Outpoint Map
* @constructor

View File

@ -19,7 +19,6 @@ var Coin = require('../primitives/coin');
var Outpoint = require('../primitives/outpoint');
var records = require('./records');
var BlockMapRecord = records.BlockMapRecord;
var TXMapRecord = records.TXMapRecord;
var OutpointMapRecord = records.OutpointMapRecord;
var DUMMY = new Buffer([0]);
@ -887,49 +886,6 @@ TXDB.prototype.isSpent = function isSpent(hash, index) {
return this.has(layout.s(hash, index));
};
/**
* Append to the global tx record.
* @param {TX} tx
* @returns {Promise}
*/
TXDB.prototype.addTXMap = co(function* addTXMap(tx) {
var hash = tx.hash('hex');
var map = yield this.walletdb.getTXMap(hash);
if (!map)
map = new TXMapRecord(hash);
if (!map.add(this.wallet.wid))
return;
this.walletdb.writeTXMap(this.wallet, hash, map);
});
/**
* Remove from the global tx record.
* @param {TX} tx
* @returns {Promise}
*/
TXDB.prototype.removeTXMap = co(function* removeTXMap(tx) {
var hash = tx.hash('hex');
var map = yield this.walletdb.getTXMap(hash);
if (!map)
return;
if (!map.remove(this.wallet.wid))
return;
if (map.wids.length === 0) {
this.walletdb.unwriteTXMap(this.wallet, hash);
return;
}
this.walletdb.writeTXMap(this.wallet, hash, map);
});
/**
* Append to the global unspent record.
* @param {Hash} hash
@ -1311,8 +1267,6 @@ TXDB.prototype.insert = co(function* insert(tx, block) {
this.put(layout.H(account, tx.height, hash), DUMMY);
}
yield this.addTXMap(tx);
if (tx.height !== -1)
yield this.addBlockMap(tx, tx.height);
@ -1483,8 +1437,6 @@ TXDB.prototype._confirm = co(function* confirm(tx, block) {
this.put(layout.H(account, tx.height, hash), DUMMY);
}
yield this.addTXMap(tx);
if (tx.height !== -1)
yield this.addBlockMap(tx, tx.height);
@ -1615,8 +1567,6 @@ TXDB.prototype.erase = co(function* erase(tx) {
this.del(layout.H(account, tx.height, hash));
}
yield this.removeTXMap(tx);
if (tx.height !== -1)
yield this.removeBlockMap(tx, tx.height);

View File

@ -29,7 +29,6 @@ var ChainState = records.ChainState;
var BlockMapRecord = records.BlockMapRecord;
var BlockMeta = records.BlockMeta;
var PathMapRecord = records.PathMapRecord;
var TXMapRecord = records.TXMapRecord;
var OutpointMapRecord = records.OutpointMapRecord;
var TXDB = require('./txdb');
var U32 = utils.U32;
@ -43,10 +42,10 @@ var U32 = utils.U32;
* a[wid][index] -> account
* i[wid][name] -> account index
* t[wid]* -> txdb
* R -> tip height
* c[height] -> chain header
* R -> chain sync state
* h[height] -> recent block hash
* b[height] -> block->wid map
* e[hash] -> tx->wid map
* o[hash][index] -> outpoint->wid map
*/
var layout = {
@ -109,15 +108,12 @@ var layout = {
return [key.readUInt32BE(1, true), key.toString('ascii', 5)];
},
R: new Buffer([0x52]),
c: function c(height) {
h: function h(height) {
var key = new Buffer(5);
key[0] = 0x63;
key[0] = 0x68;
key.writeUInt32BE(height, 1, true);
return key;
},
cc: function cc(key) {
return key.readUInt32BE(1, true);
},
b: function b(height) {
var key = new Buffer(5);
key[0] = 0x62;
@ -127,18 +123,9 @@ var layout = {
bb: function bb(key) {
return key.readUInt32BE(1, true);
},
e: function e(hash) {
var key = new Buffer(33);
key[0] = 0x65;
key.write(hash, 1, 'hex');
return key;
},
ee: function ee(key) {
return key.toString('hex', 1);
},
o: function o(hash, index) {
var key = new Buffer(37);
key[0] = 0x01;
key[0] = 0x6f;
key.write(hash, 1, 'hex');
key.writeUInt32BE(index, 33, true);
return key;
@ -266,17 +253,30 @@ WalletDB.prototype._close = co(function* close() {
});
/**
* Connect and sync with the chain server (without a lock).
* Watch addresses and outpoints.
* @private
* @returns {Promise}
*/
WalletDB.prototype.watch = co(function* watch() {
var data = yield this.getFilterData();
var hashes = yield this.getHashes();
var outpoints = yield this.getOutpoints();
var chunks = [];
var i, hash, outpoint;
this.logger.info('Adding %d hashes to WalletDB filter.', data.length);
for (i = 0; i < hashes.length; i++) {
hash = hashes[i];
chunks.push(hash);
}
this.addFilter(data);
for (i = 0; i < outpoints.length; i++) {
outpoint = outpoints[i];
chunks.push(outpoint.toRaw());
}
this.logger.info('Adding %d chunks to WalletDB filter.', chunks.length);
this.addFilter(chunks);
});
/**
@ -460,6 +460,7 @@ WalletDB.prototype.wipe = co(function* wipe() {
this.logger.warning('Wiping WalletDB TXDB...');
this.logger.warning('I hope you know what you\'re doing.');
// All TXDB records
keys = yield this.db.keys({
gte: TXDB.layout.prefix(0x00000000, dummy),
lte: TXDB.layout.prefix(0xffffffff, dummy)
@ -470,6 +471,62 @@ WalletDB.prototype.wipe = co(function* wipe() {
batch.del(key);
}
// All recent block hashes
keys = yield this.db.keys({
gte: layout.h(0),
lte: layout.h(0xffffffff)
});
for (i = 0; i < keys.length; i++) {
key = keys[i];
batch.del(key);
}
// The state record
batch.del(layout.R);
// All block maps
keys = yield this.db.keys({
gte: layout.b(0),
lte: layout.b(0xffffffff)
});
for (i = 0; i < keys.length; i++) {
key = keys[i];
batch.del(key);
}
// All outpoint maps
keys = yield this.db.keys({
gte: layout.o(constants.NULL_HASH, 0),
lte: layout.o(constants.HIGH_HASH, 0xffffffff)
});
for (i = 0; i < keys.length; i++) {
key = keys[i];
batch.del(key);
}
// All TX maps (e -- old)
gte = new Buffer(33);
gte.fill(0);
gte[0] = 0x65;
lte = new Buffer(33);
lte.fill(255);
lte[0] = 0x65;
keys = yield this.db.keys({
gte: gte,
lte: lte
});
for (i = 0; i < keys.length; i++) {
key = keys[i];
batch.del(key);
}
// All block maps (b -- 32 byte old)
gte = new Buffer(33);
gte.fill(0);
gte[0] = 0x62;
@ -488,9 +545,18 @@ WalletDB.prototype.wipe = co(function* wipe() {
batch.del(key);
}
// All block records (c -- old)
gte = new Buffer(33);
gte.fill(0);
gte[0] = 0x63;
lte = new Buffer(33);
lte.fill(255);
lte[0] = 0x63;
keys = yield this.db.keys({
gte: layout.b(0),
lte: layout.b(0xffffffff)
gte: gte,
lte: lte
});
for (i = 0; i < keys.length; i++) {
@ -498,28 +564,6 @@ WalletDB.prototype.wipe = co(function* wipe() {
batch.del(key);
}
keys = yield this.db.keys({
gte: layout.c(0),
lte: layout.c(0xffffffff)
});
for (i = 0; i < keys.length; i++) {
key = keys[i];
batch.del(key);
}
keys = yield this.db.keys({
gte: layout.e(constants.NULL_HASH),
lte: layout.e(constants.HIGH_HASH)
});
for (i = 0; i < keys.length; i++) {
key = keys[i];
batch.del(key);
}
batch.del(layout.R);
yield batch.write();
});
@ -1201,30 +1245,6 @@ WalletDB.prototype.getOutpoints = function getOutpoints() {
});
};
/**
* Get hashes required for rescan filter.
* @returns {Promise}
*/
WalletDB.prototype.getFilterData = co(function* getFilterData() {
var chunks = [];
var hashes = yield this.getHashes();
var unspent = yield this.getOutpoints();
var i, hash, outpoint;
for (i = 0; i < hashes.length; i++) {
hash = hashes[i];
chunks.push(hash);
}
for (i = 0; i < unspent.length; i++) {
outpoint = unspent[i];
chunks.push(outpoint.toRaw());
}
return chunks;
});
/**
* Get all address hashes.
* @param {WalletID} wid
@ -1358,7 +1378,7 @@ WalletDB.prototype.getPendingKeys = co(function* getPendingKeys() {
var keys = [];
var iter, item;
iter = yield this.db.iterator({
iter = this.db.iterator({
gte: layout.prefix(0x00000000, dummy),
lte: layout.prefix(0xffffffff, dummy)
});
@ -1407,34 +1427,6 @@ WalletDB.prototype.getPendingTX = co(function* getPendingTX() {
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}
@ -1602,8 +1594,8 @@ WalletDB.prototype.resetState = co(function* resetState(tip) {
var iter, item;
iter = this.db.iterator({
gte: layout.c(0),
lte: layout.c(0xffffffff),
gte: layout.h(0),
lte: layout.h(0xffffffff),
values: false
});
@ -1625,7 +1617,7 @@ WalletDB.prototype.resetState = co(function* resetState(tip) {
state.startHash = tip.hash;
state.height = tip.height;
batch.put(layout.c(tip.height), tip.toHash());
batch.put(layout.h(tip.height), tip.toHash());
batch.put(layout.R, state.toRaw());
yield batch.write();
@ -1654,7 +1646,7 @@ WalletDB.prototype.syncState = co(function* syncState(tip) {
blocks = this.keepBlocks;
for (i = 0; i < blocks; i++) {
batch.del(layout.c(height));
batch.del(layout.h(height));
height--;
}
} else if (tip.height > state.height) {
@ -1664,13 +1656,13 @@ WalletDB.prototype.syncState = co(function* syncState(tip) {
height = tip.height - this.keepBlocks;
if (height >= 0)
batch.del(layout.c(height));
batch.del(layout.h(height));
}
state.height = tip.height;
// Save tip and state.
batch.put(layout.c(tip.height), tip.toHash());
batch.put(layout.h(tip.height), tip.toHash());
batch.put(layout.R, state.toRaw());
yield batch.write();
@ -1702,32 +1694,6 @@ WalletDB.prototype.unwriteBlockMap = function unwriteBlockMap(wallet, height) {
batch.del(layout.b(height));
};
/**
* Add a transaction to global tx map.
* @param {Wallet} wallet
* @param {Hash} hash
* @param {TXMapRecord} map
* @returns {Promise}
*/
WalletDB.prototype.writeTXMap = function writeTXMap(wallet, hash, map) {
var batch = this.batch(wallet);
batch.put(layout.e(hash), map.toRaw());
this.addFilter(hash);
};
/**
* Remove a transaction from global tx map.
* @param {Wallet} wallet
* @param {Hash} hash
* @returns {Promise}
*/
WalletDB.prototype.unwriteTXMap = function unwriteTXMap(wallet, hash) {
var batch = this.batch(wallet);
batch.del(layout.e(hash));
};
/**
* Add an outpoint to global unspent map.
* @param {Wallet} wallet
@ -1739,8 +1705,10 @@ WalletDB.prototype.unwriteTXMap = function unwriteTXMap(wallet, hash) {
WalletDB.prototype.writeOutpointMap = function writeOutpointMap(wallet, hash, i, map) {
var batch = this.batch(wallet);
batch.put(layout.o(hash, i), map.toRaw());
this.addFilter(new Outpoint(hash, i).toRaw());
batch.put(layout.o(hash, i), map.toRaw());
};
/**
@ -1778,7 +1746,7 @@ WalletDB.prototype.getBlockMap = co(function* getBlockMap(height) {
*/
WalletDB.prototype.getBlock = co(function* getBlock(height) {
var data = yield this.db.get(layout.c(height));
var data = yield this.db.get(layout.h(height));
var block;
if (!data)
@ -1806,21 +1774,6 @@ WalletDB.prototype.getTip = co(function* getTip() {
return tip;
});
/**
* Get a TX->Wallet map.
* @param {Hash} hash
* @returns {Promise}
*/
WalletDB.prototype.getTXMap = co(function* getTXMap(hash) {
var data = yield this.db.get(layout.e(hash));
if (!data)
return;
return TXMapRecord.fromRaw(hash, data);
});
/**
* Get a Unspent->Wallet map.
* @param {Hash} hash
@ -1889,12 +1842,13 @@ WalletDB.prototype.rollback = co(function* rollback(height) {
WalletDB.prototype.revert = co(function* revert(height) {
var total = 0;
var i, iter, item, block, tx;
var i, iter, item, height, block, tx;
iter = this.db.iterator({
gte: layout.b(height + 1),
lte: layout.b(0xffffffff),
reverse: true
reverse: true,
values: true
});
for (;;) {
@ -1904,7 +1858,8 @@ WalletDB.prototype.revert = co(function* revert(height) {
break;
try {
block = BlockMapRecord.fromRaw(item.value);
height = layout.bb(item.key);
block = BlockMapRecord.fromRaw(height, item.value);
total += block.txs.length;
for (i = block.txs.length - 1; i >= 0; i--) {
@ -2143,40 +2098,6 @@ WalletDB.prototype._unconfirm = co(function* unconfirm(tx) {
}
});
/**
* 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 wids = yield this.getPendingWallets();
var i, wid, wallet;
for (i = 0; i < wids.length; i++) {
wid = wids[i];
wallet = yield this.get(wid);
assert(wallet);
yield wallet.zap(age);
}
});
/*
* Helpers
*/