walletdb: fixes.

This commit is contained in:
Christopher Jeffrey 2016-08-15 05:53:02 -07:00
parent 17b176141e
commit cfad740b09
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
4 changed files with 73 additions and 66 deletions

View File

@ -956,7 +956,7 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
if (this.depth >= 0xff) if (this.depth >= 0xff)
throw new Error('Depth too high.'); throw new Error('Depth too high.');
id = this.xprivkey + '/' + index; id = this.getID(index);
child = HD.cache.get(id); child = HD.cache.get(id);
if (child) if (child)
@ -1002,6 +1002,19 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
return child; return child;
}; };
/**
* Unique HD key ID.
* @private
* @param {Number} index
* @returns {String}
*/
HDPrivateKey.prototype.getID = function getID(index) {
return this.network.keyPrefix.xprivkey58
+ this.publicKey.toString('hex')
+ '/' + index;
};
/** /**
* Derive a BIP44 account key. * Derive a BIP44 account key.
* @param {Number} accountIndex * @param {Number} accountIndex
@ -1603,7 +1616,7 @@ HDPublicKey.prototype.derive = function derive(index, hardened) {
if (this.depth >= 0xff) if (this.depth >= 0xff)
throw new Error('Depth too high.'); throw new Error('Depth too high.');
id = this.xpubkey + '/' + index; id = this.getID(index);
child = HD.cache.get(id); child = HD.cache.get(id);
if (child) if (child)
@ -1640,6 +1653,19 @@ HDPublicKey.prototype.derive = function derive(index, hardened) {
return child; return child;
}; };
/**
* Unique HD key ID.
* @private
* @param {Number} index
* @returns {String}
*/
HDPublicKey.prototype.getID = function getID(index) {
return this.network.keyPrefix.xpubkey58
+ this.publicKey.toString('hex')
+ '/' + index;
};
/** /**
* Derive a BIP44 account key (does not derive, only ensures account key). * Derive a BIP44 account key (does not derive, only ensures account key).
* @method * @method

View File

@ -1493,7 +1493,7 @@ Wallet.prototype.addTX = function addTX(tx, callback) {
*/ */
Wallet.prototype.getHistory = function getHistory(account, callback) { Wallet.prototype.getHistory = function getHistory(account, callback) {
this._getKey(account, callback, function(account, callback) { this._getIndex(account, callback, function(account, callback) {
this.tx.getHistory(account, callback); this.tx.getHistory(account, callback);
}); });
}; };
@ -1505,7 +1505,7 @@ Wallet.prototype.getHistory = function getHistory(account, callback) {
*/ */
Wallet.prototype.getCoins = function getCoins(account, callback) { Wallet.prototype.getCoins = function getCoins(account, callback) {
this._getKey(account, callback, function(account, callback) { this._getIndex(account, callback, function(account, callback) {
this.tx.getCoins(account, callback); this.tx.getCoins(account, callback);
}); });
}; };
@ -1517,7 +1517,7 @@ Wallet.prototype.getCoins = function getCoins(account, callback) {
*/ */
Wallet.prototype.getUnconfirmed = function getUnconfirmed(account, callback) { Wallet.prototype.getUnconfirmed = function getUnconfirmed(account, callback) {
this._getKey(account, callback, function(account, callback) { this._getIndex(account, callback, function(account, callback) {
this.tx.getUnconfirmed(account, callback); this.tx.getUnconfirmed(account, callback);
}); });
}; };
@ -1529,7 +1529,7 @@ Wallet.prototype.getUnconfirmed = function getUnconfirmed(account, callback) {
*/ */
Wallet.prototype.getBalance = function getBalance(account, callback) { Wallet.prototype.getBalance = function getBalance(account, callback) {
this._getKey(account, callback, function(account, callback) { this._getIndex(account, callback, function(account, callback) {
this.tx.getBalance(account, callback); this.tx.getBalance(account, callback);
}); });
}; };
@ -1543,7 +1543,7 @@ Wallet.prototype.getBalance = function getBalance(account, callback) {
*/ */
Wallet.prototype.getLastTime = function getLastTime(account, callback) { Wallet.prototype.getLastTime = function getLastTime(account, callback) {
this._getKey(account, callback, function(account, callback) { this._getIndex(account, callback, function(account, callback) {
this.tx.getLastTime(account, callback); this.tx.getLastTime(account, callback);
}); });
}; };
@ -1561,7 +1561,7 @@ Wallet.prototype.getLast = function getLast(account, limit, callback) {
limit = account; limit = account;
account = null; account = null;
} }
this._getKey(account, callback, function(account, callback) { this._getIndex(account, callback, function(account, callback) {
this.tx.getLast(account, limit, callback); this.tx.getLast(account, limit, callback);
}); });
}; };
@ -1581,7 +1581,7 @@ Wallet.prototype.getTimeRange = function getTimeRange(account, options, callback
options = account; options = account;
account = null; account = null;
} }
this._getKey(account, callback, function(account, callback) { this._getIndex(account, callback, function(account, callback) {
this.tx.getTimeRange(account, options, callback); this.tx.getTimeRange(account, options, callback);
}); });
}; };
@ -1599,7 +1599,7 @@ Wallet.prototype.zap = function zap(account, age, callback) {
age = account; age = account;
account = null; account = null;
} }
this._getKey(account, callback, function(account, callback) { this._getIndex(account, callback, function(account, callback) {
this.tx.zap(account, age, callback); this.tx.zap(account, age, callback);
}); });
}; };
@ -1610,15 +1610,8 @@ Wallet.prototype.zap = function zap(account, age, callback) {
* @param {Function} callback - Returns [Error]. * @param {Function} callback - Returns [Error].
*/ */
Wallet.prototype.abandon = function abandon(account, hash, callback) { Wallet.prototype.abandon = function abandon(hash, callback) {
if (typeof hash === 'function') { this.tx.abandon(hash, callback);
callback = hash;
hash = account;
account = null;
}
this._getKey(account, callback, function(account, callback) {
this.tx.abandon(account, hash, callback);
});
}; };
/** /**
@ -1629,7 +1622,7 @@ Wallet.prototype.abandon = function abandon(account, hash, callback) {
* @param {Function} callback * @param {Function} callback
*/ */
Wallet.prototype._getKey = function _getKey(account, errback, callback) { Wallet.prototype._getIndex = function _getIndex(account, errback, callback) {
var self = this; var self = this;
if (typeof account === 'function') { if (typeof account === 'function') {
@ -2715,9 +2708,6 @@ Account.prototype.toRaw = function toRaw(writer) {
var i; var i;
p.writeU32(this.network.magic); p.writeU32(this.network.magic);
// NOTE: Passed in by caller.
// p.writeU32(this.wid);
// p.writeVarString(this.id, 'utf8');
p.writeVarString(this.name, 'utf8'); p.writeVarString(this.name, 'utf8');
p.writeU8(this.initialized ? 1 : 0); p.writeU8(this.initialized ? 1 : 0);
p.writeU8(this.type === 'pubkeyhash' ? 0 : 1); p.writeU8(this.type === 'pubkeyhash' ? 0 : 1);
@ -2751,9 +2741,6 @@ Account.prototype.fromRaw = function fromRaw(data) {
var i, count; var i, count;
this.network = bcoin.network.fromMagic(p.readU32()); this.network = bcoin.network.fromMagic(p.readU32());
// NOTE: Passed in by caller.
// this.wid = p.readU32();
// this.id = p.readVarString('utf8');
this.name = p.readVarString('utf8'); this.name = p.readVarString('utf8');
this.initialized = p.readU8() === 1; this.initialized = p.readU8() === 1;
this.type = p.readU8() === 0 ? 'pubkeyhash' : 'multisig'; this.type = p.readU8() === 0 ? 'pubkeyhash' : 'multisig';
@ -3039,8 +3026,9 @@ MasterKey.prototype.encrypt = function encrypt(passphrase, callback) {
if (!passphrase) if (!passphrase)
return callback(); return callback();
iv = bcoin.ec.random(16);
data = this.key.toExtended(); data = this.key.toExtended();
iv = bcoin.ec.random(16);
this.stop(); this.stop();
utils.encrypt(data, passphrase, iv, function(err, data) { utils.encrypt(data, passphrase, iv, function(err, data) {

View File

@ -9,15 +9,15 @@
/* /*
* Database Layout: * Database Layout:
* (inherits all from txdb) * p/[address] -> path data
* p/[address] -> wid & path data
* w/[wid] -> wallet * w/[wid] -> wallet
* l/[label] -> wallet wid * l/[id] -> wid
* a/[wid]/[index] -> account * a/[wid]/[index] -> account
* i/[wid]/[name] -> account index * i/[wid]/[name] -> account index
* t/[wid]/* -> txdb
* R -> tip * R -> tip
* b/[hash] -> wallet block * b/[hash] -> wallet block
* t/[hash] -> tx->wallet-wid map * t/[hash] -> tx->wid map
*/ */
var bcoin = require('./env'); var bcoin = require('./env');
@ -186,7 +186,7 @@ WalletDB.prototype.getDepth = function getDepth(callback) {
// This may seem like a strange way to do // This may seem like a strange way to do
// this, but updating a global state when // this, but updating a global state when
// creating a new wallet is actually pretty // creating a new wallet is actually pretty
// damn tricky. They would be major atomicity // damn tricky. There would be major atomicity
// issues if updating a global state inside // issues if updating a global state inside
// a "scoped" state. So, we avoid all the // a "scoped" state. So, we avoid all the
// nonsense of adding a global lock to // nonsense of adding a global lock to
@ -290,8 +290,8 @@ WalletDB.prototype.loadFilter = function loadFilter(callback) {
return callback(); return callback();
this.db.iterate({ this.db.iterate({
gte: 'W', gte: 'p/' + constants.NULL_HASH,
lte: 'W~', lte: 'p/' + constants.HIGH_HASH,
transform: function(key) { transform: function(key) {
key = key.split('/')[1]; key = key.split('/')[1];
self.filter.add(key, 'hex'); self.filter.add(key, 'hex');
@ -563,12 +563,12 @@ WalletDB.prototype.create = function create(options, callback) {
/** /**
* Test for the existence of a wallet. * Test for the existence of a wallet.
* @param {WalletID?} wid * @param {WalletID} id
* @param {Function} callback * @param {Function} callback
*/ */
WalletDB.prototype.has = function has(wid, callback) { WalletDB.prototype.has = function has(id, callback) {
this.getWalletID(wid, function(err, wid) { this.getWalletID(id, function(err, wid) {
if (err) if (err)
return callback(err); return callback(err);
return callback(null, wid != null); return callback(null, wid != null);
@ -577,7 +577,6 @@ WalletDB.prototype.has = function has(wid, callback) {
/** /**
* Attempt to create wallet, return wallet if already exists. * Attempt to create wallet, return wallet if already exists.
* @param {WalletID?} wid
* @param {Object} options - See {@link Wallet}. * @param {Object} options - See {@link Wallet}.
* @param {Function} callback * @param {Function} callback
*/ */
@ -663,9 +662,6 @@ WalletDB.prototype.getAccounts = function getAccounts(wid, callback) {
var map = []; var map = [];
var i, accounts; var i, accounts;
if (!utils.isNumber(wid))
return callback(new Error('Wallet IDs must be alphanumeric.'));
this.db.iterate({ this.db.iterate({
gte: 'i/' + pad32(wid) + '/', gte: 'i/' + pad32(wid) + '/',
lte: 'i/' + pad32(wid) + '/~', lte: 'i/' + pad32(wid) + '/~',
@ -944,8 +940,8 @@ WalletDB.prototype.getAddresses = function getAddresses(wid, callback) {
} }
this.db.iterate({ this.db.iterate({
gte: 'W', gte: 'p/' + constants.NULL_HASH,
lte: 'W~', lte: 'p/' + constants.HIGH_HASH,
values: true, values: true,
parse: function(value, key) { parse: function(value, key) {
var paths = parsePaths(value); var paths = parsePaths(value);
@ -965,8 +961,8 @@ WalletDB.prototype.getAddresses = function getAddresses(wid, callback) {
WalletDB.prototype.getWallets = function getWallets(callback) { WalletDB.prototype.getWallets = function getWallets(callback) {
this.db.iterate({ this.db.iterate({
gte: 'w', gte: 'l/',
lte: 'w~', lte: 'l/~',
transform: function(key) { transform: function(key) {
return key.split('/')[1]; return key.split('/')[1];
} }
@ -1194,15 +1190,7 @@ WalletDB.prototype.writeBlock = function writeBlock(block, matches, callback) {
} }
} }
batch.write(function(err) { batch.write(callback);
if (err)
return callback(err);
self.tip = block.hash;
self.height = block.height;
return callback();
});
}; };
/** /**
@ -1219,15 +1207,7 @@ WalletDB.prototype.unwriteBlock = function unwriteBlock(block, callback) {
batch.put('R', prev.toTip()); batch.put('R', prev.toTip());
batch.del('b/' + block.hash); batch.del('b/' + block.hash);
batch.write(function(err) { batch.write(callback);
if (err)
return callback(err);
self.tip = prev.hash;
self.height = prev.height;
return callback();
});
}; };
/** /**
@ -1277,6 +1257,11 @@ WalletDB.prototype.addBlock = function addBlock(entry, txs, callback, force) {
block = WalletBlock.fromEntry(entry); block = WalletBlock.fromEntry(entry);
matches = []; matches = [];
// Update these early so transactions
// get correct confirmation calculations.
this.tip = block.hash;
this.height = block.height;
// NOTE: Atomicity doesn't matter here. If we crash // NOTE: Atomicity doesn't matter here. If we crash
// during this loop, the automatic rescan will get // during this loop, the automatic rescan will get
// the database back into the correct state. // the database back into the correct state.
@ -1359,7 +1344,15 @@ WalletDB.prototype.removeBlock = function removeBlock(entry, callback, force) {
wallet.tx.unconfirm(hash, next); wallet.tx.unconfirm(hash, next);
}); });
}, callback); }, function(err) {
if (err)
return callback(err);
self.tip = block.hash;
self.height = block.height;
return callback();
});
}); });
}); });
}); });

View File

@ -222,8 +222,8 @@ describe('Chain', function() {
var txs = []; var txs = [];
walletdb.getAddresses(function(err, hashes) { walletdb.getAddresses(function(err, hashes) {
assert.ifError(err); assert.ifError(err);
chain.db.scan(null, hashes, function(tx, block, next) { chain.db.scan(null, hashes, function(block, tx, next) {
txs.push(tx); txs = txs.concat(tx);
next(); next();
}, function(err) { }, function(err) {
assert.ifError(err); assert.ifError(err);