mapping.
This commit is contained in:
parent
cbd7f06aba
commit
79d2471a33
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user