This commit is contained in:
Christopher Jeffrey 2016-05-29 19:15:22 -07:00
parent cbd7f06aba
commit 79d2471a33
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
4 changed files with 174 additions and 45 deletions

View File

@ -38,6 +38,7 @@ function KeyRing(options) {
this.m = options.m || 1;
this.n = options.n || 1;
this.witness = options.witness || false;
this.name = options.name;
this.account = options.account;
this.change = options.change;
this.index = options.index;
@ -527,6 +528,7 @@ KeyRing.prototype.toJSON = function toJSON() {
m: this.m,
n: this.n,
witness: this.witness,
name: this.name,
account: this.account,
change: this.change,
index: this.index,
@ -552,6 +554,7 @@ KeyRing.fromJSON = function fromJSON(json) {
m: json.m,
n: json.n,
witness: json.witness,
name: json.name,
account: json.account,
change: json.change,
index: json.index,
@ -574,6 +577,7 @@ KeyRing.prototype.toRaw = function toRaw(writer) {
p.writeU8(this.m);
p.writeU8(this.n);
p.writeU8(this.witness ? 1 : 0);
p.writeVarString(this.name, 'utf8');
p.writeU32(this.account);
p.writeU32(this.change);
p.writeU32(this.index);
@ -601,6 +605,7 @@ KeyRing.fromRaw = function fromRaw(data) {
var m = p.readU8();
var n = p.readU8();
var witness = p.readU8() === 1;
var name = p.readVarString('utf8');
var account = p.readU32();
var change = p.readU32();
var index = p.readU32();
@ -617,6 +622,7 @@ KeyRing.fromRaw = function fromRaw(data) {
m: m,
n: n,
witness: witness,
name: name,
account: account,
change: change,
index: index,

View File

@ -126,6 +126,25 @@ TXDB.prototype._testFilter = function _testFilter(addresses) {
* @param {Function} callback - Returns [Error, {@link AddressMap}].
*/
function uniq(obj) {
var uniq = {};
var out = [];
var i, key, value;
for (i = 0; i < obj.length; i++) {
value = obj[i];
key = value.id + '/' + value.account;
if (uniq[key])
continue;
uniq[key] = true;
out.push(value);
}
return out;
}
TXDB.prototype.getMap = function getMap(tx, callback) {
var input, output, addresses, table, map;
@ -160,9 +179,9 @@ TXDB.prototype.getMap = function getMap(tx, callback) {
map.output = map.output.concat(map.table[address]);
});
map.input = utils.uniq(map.input);
map.output = utils.uniq(map.output);
map.all = utils.uniq(map.input.concat(map.output));
map.input = uniq(map.input);
map.output = uniq(map.output);
map.all = uniq(map.input.concat(map.output));
return callback(null, map);
}
@ -179,6 +198,8 @@ TXDB.prototype.getMap = function getMap(tx, callback) {
TXDB.prototype.mapAddresses = function mapAddresses(address, callback) {
var self = this;
var table = { count: 0 };
var values = [];
var i, keys;
if (Array.isArray(address)) {
return utils.forEachSerial(address, function(address, next) {
@ -204,8 +225,18 @@ TXDB.prototype.mapAddresses = function mapAddresses(address, callback) {
if (err)
return callback(err);
table[address] = paths ? Object.keys(paths) : [];
table.count += table[address].length;
if (!paths) {
table[address] = [];
return callback(null, table);
}
keys = Object.keys(paths);
for (i = 0; i < keys.length; i++)
values.push(paths[keys[i]]);
table[address] = values;
table.count += values.length;
return callback(null, table);
});
@ -357,7 +388,8 @@ TXDB.prototype._add = function add(tx, map, callback, force) {
batch.put('m/' + pad32(tx.ts) + '/' + hash, DUMMY);
}
map.all.forEach(function(id) {
map.all.forEach(function(path) {
var id = path.id + '/' + path.account;
batch.put('T/' + id + '/' + hash, DUMMY);
if (tx.ts === 0) {
batch.put('P/' + id + '/' + hash, DUMMY);
@ -400,7 +432,8 @@ TXDB.prototype._add = function add(tx, map, callback, force) {
updated = true;
if (address) {
map.table[address].forEach(function(id) {
map.table[address].forEach(function(path) {
var id = path.id + '/' + path.account;
batch.del('C/' + id + '/' + key);
});
}
@ -537,7 +570,8 @@ TXDB.prototype._add = function add(tx, map, callback, force) {
if (!orphans) {
if (address) {
map.table[address].forEach(function(id) {
map.table[address].forEach(function(path) {
var id = path.id + '/' + path.account;
batch.put('C/' + id + '/' + key, DUMMY);
});
}
@ -712,7 +746,8 @@ TXDB.prototype._confirm = function _confirm(tx, map, callback, force) {
batch.del('m/' + pad32(existing.ps) + '/' + hash);
batch.put('m/' + pad32(tx.ts) + '/' + hash, DUMMY);
map.all.forEach(function(id) {
map.all.forEach(function(path) {
var id = path.id + '/' + path.account;
batch.del('P/' + id + '/' + hash);
batch.put('H/' + id + '/' + pad32(tx.height) + '/' + hash, DUMMY);
batch.del('M/' + id + '/' + pad32(existing.ps) + '/' + hash);
@ -859,7 +894,8 @@ TXDB.prototype._remove = function remove(tx, map, callback, force) {
batch.del('m/' + pad32(tx.ts) + '/' + hash);
}
map.all.forEach(function(id) {
map.all.forEach(function(path) {
var id = path.id + '/' + path.account;
batch.del('T/' + id + '/' + hash);
if (tx.ts === 0) {
batch.del('P/' + id + '/' + hash);
@ -888,7 +924,8 @@ TXDB.prototype._remove = function remove(tx, map, callback, force) {
return;
if (address) {
map.table[address].forEach(function(id) {
map.table[address].forEach(function(path) {
var id = path.id + '/' + path.account;
batch.put('C/' + id + '/' + key, DUMMY);
});
}
@ -909,7 +946,8 @@ TXDB.prototype._remove = function remove(tx, map, callback, force) {
return;
if (address) {
map.table[address].forEach(function(id) {
map.table[address].forEach(function(path) {
var id = path.id + '/' + path.account;
batch.del('C/' + id + '/' + key);
});
}
@ -1007,7 +1045,8 @@ TXDB.prototype._unconfirm = function unconfirm(tx, map, callback, force) {
batch.del('m/' + pad32(ts) + '/' + hash);
batch.put('m/' + pad32(tx.ps) + '/' + hash, DUMMY);
map.all.forEach(function(id) {
map.all.forEach(function(path) {
var id = path.id + '/' + path.account;
batch.put('P/' + id + '/' + hash, DUMMY);
batch.del('H/' + id + '/' + pad32(height) + '/' + hash);
batch.del('M/' + id + '/' + pad32(ts) + '/' + hash);
@ -1081,12 +1120,12 @@ TXDB.prototype.getHistoryHashes = function getHistoryHashes(address, callback) {
}
this.db.iterate({
gte: address ? 'T/' + address : 't',
lte: address ? 'T/' + address + '~' : 't~',
gte: address ? 'T/' + address + '/' : 't',
lte: address ? 'T/' + address + '/~' : 't~',
transform: function(key) {
key = key.split('/');
if (address)
return key[2];
return key[3];
return key[1];
}
}, callback);
@ -1131,12 +1170,12 @@ TXDB.prototype.getUnconfirmedHashes = function getUnconfirmedHashes(address, cal
}
this.db.iterate({
gte: address ? 'P/' + address : 'p',
lte: address ? 'P/' + address + '~' : 'p~',
gte: address ? 'P/' + address + '/' : 'p',
lte: address ? 'P/' + address + '/~' : 'p~',
transform: function(key) {
key = key.split('/');
if (address)
return key[2];
return key[3];
return key[1];
}
}, callback);
@ -1178,12 +1217,12 @@ TXDB.prototype.getCoinHashes = function getCoinHashes(address, callback) {
}
this.db.iterate({
gte: address ? 'C/' + address : 'c',
lte: address ? 'C/' + address + '~' : 'c~',
gte: address ? 'C/' + address + '/' : 'c',
lte: address ? 'C/' + address + '/~' : 'c~',
transform: function(key) {
key = key.split('/');
if (address)
return [key[2], +key[3]];
return [key[3], +key[4]];
return [key[1], +key[2]];
}
}, callback);
@ -1221,7 +1260,7 @@ TXDB.prototype.getHeightRangeHashes = function getHeightRangeHashes(address, opt
transform: function(key) {
key = key.split('/');
if (address)
return key[3];
return key[4];
return key[2];
}
}, callback);
@ -1268,7 +1307,7 @@ TXDB.prototype.getRangeHashes = function getRangeHashes(address, options, callba
transform: function(key) {
key = key.split('/');
if (address)
return key[3];
return key[4];
return key[2];
}
}, callback);

View File

@ -544,6 +544,7 @@ Wallet.prototype.deriveAddress = function deriveAddress(change, index) {
change: change,
index: index,
type: this.type,
name: 'default',
witness: this.witness,
m: this.m,
n: this.n,

View File

@ -121,22 +121,22 @@ WalletDB.prototype._init = function _init() {
this.tx.on('tx', function(tx, map) {
self.emit('tx', tx, map);
map.all.forEach(function(id) {
self.fire(id, 'tx', tx);
map.all.forEach(function(path) {
self.fire(path.id, 'tx', tx);
});
});
this.tx.on('confirmed', function(tx, map) {
self.emit('confirmed', tx, map);
map.all.forEach(function(id) {
self.fire(id, 'confirmed', tx);
map.all.forEach(function(path) {
self.fire(path.id, 'confirmed', tx);
});
});
this.tx.on('unconfirmed', function(tx, map) {
self.emit('unconfirmed', tx, map);
map.all.forEach(function(id) {
self.fire(id, 'unconfirmed', tx);
map.all.forEach(function(path) {
self.fire(path.id, 'unconfirmed', tx);
});
});
@ -144,24 +144,24 @@ WalletDB.prototype._init = function _init() {
var balances = {};
self.emit('updated', tx, map);
map.all.forEach(function(id) {
self.fire(id, 'updated', tx);
map.all.forEach(function(path) {
self.fire(path.id, 'updated', tx);
});
utils.forEachSerial(map.output, function(id, next) {
utils.forEachSerial(map.output, function(path, next) {
if (self.listeners('balance').length === 0
&& !self.hasListener(id, 'balance')) {
&& !self.hasListener(path.id, 'balance')) {
return next();
}
self.getBalance(id, function(err, balance) {
self.getBalance(path.id, function(err, balance) {
if (err)
return next(err);
balances[id] = balance;
balances[path.id] = balance;
self.emit('balance', balance, id);
self.fire(id, 'balance', balance);
self.emit('balance', balance, path.id);
self.fire(path.id, 'balance', balance);
next();
});
@ -189,8 +189,8 @@ WalletDB.prototype._init = function _init() {
WalletDB.prototype.sync = function sync(tx, map, callback) {
var self = this;
utils.forEachSerial(map.output, function(id, next) {
self.syncOutputDepth(id, tx, next);
utils.forEachSerial(map.output, function(path, next) {
self.syncOutputDepth(path.id, tx, next);
}, callback);
};
@ -296,7 +296,7 @@ WalletDB.prototype.hasListener = function hasListener(id, event) {
};
/**
* Get a wallet from the database, instantiate, decrypt, and setup watcher.
* Get a wallet from the database, setup watcher.
* @param {WalletID} id
* @param {Function} callback - Returns [Error, {@link Wallet}].
*/
@ -314,12 +314,9 @@ WalletDB.prototype.get = function get(id, callback) {
}
this.db.get('w/' + id, function(err, data) {
if (err && err.type === 'NotFoundError')
if (err && err.type !== 'NotFoundError')
return callback();
if (err)
return callback(err);
if (!data)
return callback();
@ -350,6 +347,71 @@ WalletDB.prototype.save = function save(wallet, callback) {
this.db.put('w/' + wallet.id, wallet.toRaw(), callback);
};
/**
* Get an account from the database.
* @param {WalletID} id
* @param {Function} callback - Returns [Error, {@link Wallet}].
*/
WalletDB.prototype.getAccountIndex = function getAccountIndex(wid, name, callback) {
return this.db.get('a/' + wid + '/' + name, function(err, index) {
if (err && err.type !== 'NotFoundError')
return callback();
if (!index)
return callback(null, -1);
return callback(null, index.readUInt32LE(0, true));
});
};
WalletDB.prototype.getAccount = function getAccount(wid, id, callback) {
var self = this;
var aid = wid + '/' + id;
var account;
if (!id)
return callback();
if (typeof id === 'string') {
return this.getAccountIndex(wid, id, function(err, index) {
if (err)
return callback(err);
if (index === -1)
return callback();
return self.getAccount(wid, index, callback);
});
}
this.db.get('a/' + aid, function(err, data) {
if (err && err.type !== 'NotFoundError')
return callback();
if (err)
return callback(err);
if (!data)
return callback();
try {
data = bcoin.account.parseRaw(data);
data.db = self;
account = bcoin.account.fromRaw(data);
} catch (e) {
return callback(e);
}
account.open(function(err) {
if (err)
return callback(err);
return callback(null, account);
});
});
};
/**
* Remove wallet from the database. Destroy wallet if passed in.
* @param {WalletID} id
@ -365,6 +427,24 @@ WalletDB.prototype.remove = function remove(id, callback) {
});
};
/**
* Save a wallet to the database.
* @param {Wallet} wallet
* @param {Function} callback
*/
WalletDB.prototype.saveAccount = function saveAccount(account, callback) {
var index = new Buffer(4);
this.db.put('a/' + account.wid + '/' + account.index, account.toRaw(), function(err) {
if (err)
return callback(err);
index.writeUInt32LE(account.index, 0, true);
self.db.put('a/' + account.wid + '/' + account.name, index, callback);
});
};
/**
* Create a new wallet, save to database, setup watcher.
* @param {Object} options - See {@link Wallet}.
@ -814,6 +894,8 @@ function parsePaths(data) {
while (p.left()) {
id = p.readVarString('utf8');
out[id] = {
id: id,
name: p.readVarString('utf8'),
account: p.readU32(),
change: p.readU32(),
index: p.readU32()
@ -832,6 +914,7 @@ function serializePaths(out) {
id = keys[i];
path = out[id];
p.writeVarString(id, 'utf8');
p.writeVarString(path.name, 'utf8');
p.writeU32(path.account);
p.writeU32(path.change);
p.writeU32(path.index);