refactor: use maps and sets wherever possible.

This commit is contained in:
Christopher Jeffrey 2017-07-25 05:15:47 -07:00
parent 590c4350e9
commit 7eefb773be
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
31 changed files with 200 additions and 203 deletions

View File

@ -22,10 +22,10 @@ const x509 = exports;
/** /**
* Map of trusted root certs. * Map of trusted root certs.
* @type {Object} * @type {Set}
*/ */
x509.trusted = {}; x509.trusted = new Set();
/** /**
* Whether to allow untrusted root * Whether to allow untrusted root
@ -127,7 +127,7 @@ x509.getCAName = function getCAName(cert) {
x509.isTrusted = function isTrusted(cert) { x509.isTrusted = function isTrusted(cert) {
let fingerprint = digest.sha256(cert.raw); let fingerprint = digest.sha256(cert.raw);
let hash = fingerprint.toString('hex'); let hash = fingerprint.toString('hex');
return x509.trusted[hash] === true; return x509.trusted.has(hash);
}; };
/** /**
@ -154,7 +154,7 @@ x509.setTrust = function setTrust(certs) {
hash = digest.sha256(cert.raw); hash = digest.sha256(cert.raw);
hash = hash.toString('hex'); hash = hash.toString('hex');
x509.trusted[hash] = true; x509.trusted.add(hash);
} }
}; };
@ -174,7 +174,7 @@ x509.setFingerprints = function setFingerprints(hashes) {
assert(hash.length === 32, 'Fingerprint must be a sha256 hash.'); assert(hash.length === 32, 'Fingerprint must be a sha256 hash.');
hash = hash.toString('hex'); hash = hash.toString('hex');
x509.trusted[hash] = true; x509.trusted.add(hash);
} }
}; };

View File

@ -1144,7 +1144,7 @@ ChainDB.prototype.getCoinsByAddress = async function getCoinsByAddress(addrs) {
*/ */
ChainDB.prototype.getHashesByAddress = async function getHashesByAddress(addrs) { ChainDB.prototype.getHashesByAddress = async function getHashesByAddress(addrs) {
let hashes = {}; let hashes = Object.create(null);
if (!this.options.indexTX || !this.options.indexAddress) if (!this.options.indexTX || !this.options.indexAddress)
return []; return [];

View File

@ -566,15 +566,14 @@ LowlevelUp.prototype.values = async function _values(options) {
*/ */
LowlevelUp.prototype.dump = async function dump() { LowlevelUp.prototype.dump = async function dump() {
let records = {}; let records = Object.create(null);
let items = await this.range({ let items = await this.range({
gte: LOW, gte: LOW,
lte: HIGH lte: HIGH
}); });
for (let i = 0; i < items.length; i++) { for (let item of items) {
let item = items[i];
let key = item.key.toString('hex'); let key = item.key.toString('hex');
let value = item.value.toString('hex'); let value = item.value.toString('hex');
records[key] = value; records[key] = value;

View File

@ -1509,7 +1509,7 @@ function WebSocket(socket, ctx) {
this.context = ctx; this.context = ctx;
this.socket = socket; this.socket = socket;
this.remoteAddress = socket.conn.remoteAddress; this.remoteAddress = socket.conn.remoteAddress;
this.hooks = {}; this.hooks = Object.create(null);
this.channels = new Map(); this.channels = new Map();
this.auth = false; this.auth = false;
this.filter = null; this.filter = null;

View File

@ -228,7 +228,7 @@ RequestOptions.prototype.getHeaders = function getHeaders() {
if (this.headers) if (this.headers)
return this.headers; return this.headers;
headers = {}; headers = Object.create(null);
headers['User-Agent'] = this.agent; headers['User-Agent'] = this.agent;

View File

@ -855,7 +855,7 @@ RPC.prototype.getTXOutProof = async function getTXOutProof(args, help) {
let valid = new Validator([args]); let valid = new Validator([args]);
let txids = valid.array(0); let txids = valid.array(0);
let hash = valid.hash(1); let hash = valid.hash(1);
let uniq = {}; let uniq = new Set();
let block, last; let block, last;
if (help || (args.length !== 1 && args.length !== 2)) { if (help || (args.length !== 1 && args.length !== 2)) {
@ -880,10 +880,10 @@ RPC.prototype.getTXOutProof = async function getTXOutProof(args, help) {
if (!txid) if (!txid)
throw new RPCError(errs.TYPE_ERROR, 'Invalid TXID.'); throw new RPCError(errs.TYPE_ERROR, 'Invalid TXID.');
if (uniq[txid]) if (uniq.has(txid))
throw new RPCError(errs.INVALID_PARAMETER, 'Duplicate txid.'); throw new RPCError(errs.INVALID_PARAMETER, 'Duplicate txid.');
uniq[txid] = true; uniq.add(txid);
txids[i] = txid; txids[i] = txid;
last = txid; last = txid;
} }
@ -1269,7 +1269,7 @@ RPC.prototype._createTemplate = async function _createTemplate(maxVersion, coinb
let scale = attempt.witness ? 1 : consensus.WITNESS_SCALE_FACTOR; let scale = attempt.witness ? 1 : consensus.WITNESS_SCALE_FACTOR;
let mutable = ['time', 'transactions', 'prevblock']; let mutable = ['time', 'transactions', 'prevblock'];
let txs = []; let txs = [];
let index = {}; let index = new Map();
let vbavailable = {}; let vbavailable = {};
let vbrules = []; let vbrules = [];
let json; let json;
@ -1293,7 +1293,7 @@ RPC.prototype._createTemplate = async function _createTemplate(maxVersion, coinb
// Build an index of every transaction. // Build an index of every transaction.
for (let i = 0; i < attempt.items.length; i++) { for (let i = 0; i < attempt.items.length; i++) {
let entry = attempt.items[i]; let entry = attempt.items[i];
index[entry.hash] = i + 1; index.set(entry.hash, i + 1);
} }
// Calculate dependencies for each transaction. // Calculate dependencies for each transaction.
@ -1304,7 +1304,7 @@ RPC.prototype._createTemplate = async function _createTemplate(maxVersion, coinb
for (let j = 0; j < tx.inputs.length; j++) { for (let j = 0; j < tx.inputs.length; j++) {
let input = tx.inputs[j]; let input = tx.inputs[j];
let dep = index[input.prevout.hash]; let dep = index.get(input.prevout.hash);
if (dep == null) if (dep == null)
continue; continue;
@ -1634,7 +1634,8 @@ RPC.prototype.createRawTransaction = async function createRawTransaction(args, h
let inputs = valid.array(0); let inputs = valid.array(0);
let sendTo = valid.obj(1); let sendTo = valid.obj(1);
let locktime = valid.u32(2); let locktime = valid.u32(2);
let tx, addrs; let uniq = new Set();
let tx;
if (help || args.length < 2 || args.length > 3) { if (help || args.length < 2 || args.length > 3) {
throw new RPCError(errs.MISC_ERROR, throw new RPCError(errs.MISC_ERROR,
@ -1675,7 +1676,6 @@ RPC.prototype.createRawTransaction = async function createRawTransaction(args, h
} }
valid = new Validator([sendTo]); valid = new Validator([sendTo]);
addrs = {};
for (let key of Object.keys(sendTo)) { for (let key of Object.keys(sendTo)) {
let addr, b58, value, output; let addr, b58, value, output;
@ -1698,10 +1698,10 @@ RPC.prototype.createRawTransaction = async function createRawTransaction(args, h
addr = parseAddress(key, this.network); addr = parseAddress(key, this.network);
b58 = addr.toString(this.network); b58 = addr.toString(this.network);
if (addrs[b58]) if (uniq.has(b58))
throw new RPCError(errs.INVALID_PARAMETER, 'Duplicate address'); throw new RPCError(errs.INVALID_PARAMETER, 'Duplicate address');
addrs[b58] = true; uniq.add(b58);
value = valid.btc(key); value = valid.btc(key);
@ -1814,8 +1814,8 @@ RPC.prototype.signRawTransaction = async function signRawTransaction(args, help)
let secrets = valid.array(2); let secrets = valid.array(2);
let sighash = valid.str(3); let sighash = valid.str(3);
let type = Script.hashType.ALL; let type = Script.hashType.ALL;
let map = new Map();
let keys = []; let keys = [];
let map = {};
let tx; let tx;
if (help || args.length < 1 || args.length > 4) { if (help || args.length < 1 || args.length > 4) {
@ -1841,7 +1841,7 @@ RPC.prototype.signRawTransaction = async function signRawTransaction(args, help)
for (let i = 0; i < secrets.length; i++) { for (let i = 0; i < secrets.length; i++) {
let secret = valid.str(i, ''); let secret = valid.str(i, '');
let key = parseSecret(secret, this.network); let key = parseSecret(secret, this.network);
map[key.getPublicKey('hex')] = key; map.set(key.getPublicKey('hex'), key);
keys.push(key); keys.push(key);
} }
} }
@ -1886,7 +1886,7 @@ RPC.prototype.signRawTransaction = async function signRawTransaction(args, help)
if (!op.data) if (!op.data)
continue; continue;
key = map[op.data.toString('hex')]; key = map.get(op.data.toString('hex'));
if (key) { if (key) {
key.script = redeem; key.script = redeem;

View File

@ -25,7 +25,7 @@ function RPCBase() {
EventEmitter.call(this); EventEmitter.call(this);
this.logger = Logger.global; this.logger = Logger.global;
this.calls = {}; this.calls = Object.create(null);
this.mounts = []; this.mounts = [];
this.locker = new Lock(); this.locker = new Lock();
} }

View File

@ -1144,7 +1144,7 @@ Mempool.prototype.removeSpenders = function removeSpenders(entry) {
*/ */
Mempool.prototype.countAncestors = function countAncestors(entry) { Mempool.prototype.countAncestors = function countAncestors(entry) {
return this._countAncestors(entry, 0, {}, entry, nop); return this._countAncestors(entry, new Set(), entry, nop);
}; };
/** /**
@ -1157,21 +1157,20 @@ Mempool.prototype.countAncestors = function countAncestors(entry) {
*/ */
Mempool.prototype.updateAncestors = function updateAncestors(entry, map) { Mempool.prototype.updateAncestors = function updateAncestors(entry, map) {
return this._countAncestors(entry, 0, {}, entry, map); return this._countAncestors(entry, new Set(), entry, map);
}; };
/** /**
* Traverse ancestors and count. * Traverse ancestors and count.
* @private * @private
* @param {MempoolEntry} entry * @param {MempoolEntry} entry
* @param {Number} count
* @param {Object} set * @param {Object} set
* @param {MempoolEntry} child * @param {MempoolEntry} child
* @param {Function} map * @param {Function} map
* @returns {Number} * @returns {Number}
*/ */
Mempool.prototype._countAncestors = function countAncestors(entry, count, set, child, map) { Mempool.prototype._countAncestors = function countAncestors(entry, set, child, map) {
let tx = entry.tx; let tx = entry.tx;
for (let input of tx.inputs) { for (let input of tx.inputs) {
@ -1181,24 +1180,23 @@ Mempool.prototype._countAncestors = function countAncestors(entry, count, set, c
if (!parent) if (!parent)
continue; continue;
if (set[hash]) if (set.has(hash))
continue; continue;
set[hash] = true; set.add(hash);
count += 1;
map(parent, child); map(parent, child);
if (count > this.options.maxAncestors) if (set.size > this.options.maxAncestors)
break; break;
count = this._countAncestors(parent, count, set, child, map); this._countAncestors(parent, set, child, map);
if (count > this.options.maxAncestors) if (set.size > this.options.maxAncestors)
break; break;
} }
return count; return set.size;
}; };
/** /**
@ -1209,7 +1207,7 @@ Mempool.prototype._countAncestors = function countAncestors(entry, count, set, c
*/ */
Mempool.prototype.countDescendants = function countDescendants(entry) { Mempool.prototype.countDescendants = function countDescendants(entry) {
return this._countDescendants(entry, 0, {}); return this._countDescendants(entry, new Set());
}; };
/** /**
@ -1217,12 +1215,11 @@ Mempool.prototype.countDescendants = function countDescendants(entry) {
* descendants a transaction may have. * descendants a transaction may have.
* @private * @private
* @param {MempoolEntry} entry * @param {MempoolEntry} entry
* @param {Number} count
* @param {Object} set * @param {Object} set
* @returns {Number} * @returns {Number}
*/ */
Mempool.prototype._countDescendants = function countDescendants(entry, count, set) { Mempool.prototype._countDescendants = function countDescendants(entry, set) {
let tx = entry.tx; let tx = entry.tx;
let hash = tx.hash('hex'); let hash = tx.hash('hex');
@ -1235,16 +1232,15 @@ Mempool.prototype._countDescendants = function countDescendants(entry, count, se
next = child.hash('hex'); next = child.hash('hex');
if (set[next]) if (set.has(next))
continue; continue;
set[next] = true; set.add(next);
count += 1;
count = this._countDescendants(child, count, set); this._countDescendants(child, set);
} }
return count; return set.size;
}; };
/** /**
@ -1254,7 +1250,7 @@ Mempool.prototype._countDescendants = function countDescendants(entry, count, se
*/ */
Mempool.prototype.getAncestors = function getAncestors(entry) { Mempool.prototype.getAncestors = function getAncestors(entry) {
return this._getAncestors(entry, [], {}); return this._getAncestors(entry, [], new Set());
}; };
/** /**
@ -1276,10 +1272,10 @@ Mempool.prototype._getAncestors = function getAncestors(entry, entries, set) {
if (!parent) if (!parent)
continue; continue;
if (set[hash]) if (set.has(hash))
continue; continue;
set[hash] = true; set.add(hash);
entries.push(parent); entries.push(parent);
this._getAncestors(parent, entries, set); this._getAncestors(parent, entries, set);
@ -1295,7 +1291,7 @@ Mempool.prototype._getAncestors = function getAncestors(entry, entries, set) {
*/ */
Mempool.prototype.getDescendants = function getDescendants(entry) { Mempool.prototype.getDescendants = function getDescendants(entry) {
return this._getDescendants(entry, [], {}); return this._getDescendants(entry, [], new Set());
}; };
/** /**
@ -1319,10 +1315,10 @@ Mempool.prototype._getDescendants = function getDescendants(entry, entries, set)
next = child.hash('hex'); next = child.hash('hex');
if (set[next]) if (set.has(next))
continue; continue;
set[next] = true; set.add(next);
entries.push(child); entries.push(child);
this._getDescendants(child, entries, set); this._getDescendants(child, entries, set);

View File

@ -256,7 +256,7 @@ Miner.prototype.getAddress = function getAddress() {
Miner.prototype.assemble = function assemble(attempt) { Miner.prototype.assemble = function assemble(attempt) {
let priority = this.options.priorityWeight > 0; let priority = this.options.priorityWeight > 0;
let queue = new Heap(cmpRate); let queue = new Heap(cmpRate);
let depMap = {}; let depMap = new Map();
if (priority) if (priority)
queue.set(cmpPriority); queue.set(cmpPriority);
@ -284,10 +284,10 @@ Miner.prototype.assemble = function assemble(attempt) {
item.depCount += 1; item.depCount += 1;
if (!depMap[hash]) if (!depMap.has(hash))
depMap[hash] = []; depMap.set(hash, []);
depMap[hash].push(item); depMap.get(hash).push(item);
} }
if (item.depCount > 0) if (item.depCount > 0)
@ -339,7 +339,7 @@ Miner.prototype.assemble = function assemble(attempt) {
attempt.fees += item.fee; attempt.fees += item.fee;
attempt.items.push(item); attempt.items.push(item);
deps = depMap[hash]; deps = depMap.get(hash);
if (!deps) if (!deps)
continue; continue;

View File

@ -1140,7 +1140,7 @@ HostList.prototype.toJSON = function toJSON() {
*/ */
HostList.prototype.fromJSON = function fromJSON(json) { HostList.prototype.fromJSON = function fromJSON(json) {
let sources = {}; let sources = new Map();
let map = new Map(); let map = new Map();
let totalFresh = 0; let totalFresh = 0;
let totalUsed = 0; let totalUsed = 0;
@ -1156,12 +1156,12 @@ HostList.prototype.fromJSON = function fromJSON(json) {
for (let addr of json.addrs) { for (let addr of json.addrs) {
let entry = HostEntry.fromJSON(addr, this.network); let entry = HostEntry.fromJSON(addr, this.network);
let src = sources[entry.src.hostname]; let src = sources.get(entry.src.hostname);
// Save some memory. // Save some memory.
if (!src) { if (!src) {
src = entry.src; src = entry.src;
sources[src.hostname] = src; sources.set(src.hostname, src);
} }
entry.src = src; entry.src = src;

View File

@ -77,7 +77,7 @@ exports.types = {
* @default * @default
*/ */
exports.typesByVal = util.revMap(exports.types); exports.typesByVal = util.reverse(exports.types);
/** /**
* Base Packet * Base Packet
@ -1474,7 +1474,7 @@ RejectPacket.codes = {
* @const {RevMap} * @const {RevMap}
*/ */
RejectPacket.codesByVal = util.revMap(RejectPacket.codes); RejectPacket.codesByVal = util.reverse(RejectPacket.codes);
RejectPacket.prototype.cmd = 'reject'; RejectPacket.prototype.cmd = 'reject';
RejectPacket.prototype.type = exports.types.REJECT; RejectPacket.prototype.type = exports.types.REJECT;

View File

@ -55,7 +55,7 @@ SOCKS.states = {
RESOLVE_DONE: 7 RESOLVE_DONE: 7
}; };
SOCKS.statesByVal = util.revMap(SOCKS.states); SOCKS.statesByVal = util.reverse(SOCKS.states);
SOCKS.errors = [ SOCKS.errors = [
'', '',

View File

@ -262,7 +262,7 @@ UPNP.prototype.resolve = async function resolve(location, targets) {
UPNP.parseHeader = function parseHeader(str) { UPNP.parseHeader = function parseHeader(str) {
let lines = str.split(/\r?\n/); let lines = str.split(/\r?\n/);
let headers = {}; let headers = Object.create(null);
for (let line of lines) { for (let line of lines) {
let index, left, right; let index, left, right;
@ -635,7 +635,7 @@ function parseServices(el) {
} }
function parseService(el) { function parseService(el) {
let service = {}; let service = Object.create(null);
for (let child of el.children) { for (let child of el.children) {
if (child.children.length > 0) if (child.children.length > 0)

View File

@ -33,7 +33,7 @@ function Logger(options) {
this.closing = false; this.closing = false;
this.filename = null; this.filename = null;
this.stream = null; this.stream = null;
this.contexts = {}; this.contexts = Object.create(null);
this.locker = new Lock(); this.locker = new Lock();
if (options) if (options)

View File

@ -42,7 +42,7 @@ function Node(options) {
this.network = Network.get(this.config.network); this.network = Network.get(this.config.network);
this.startTime = -1; this.startTime = -1;
this.bound = []; this.bound = [];
this.plugins = {}; this.plugins = Object.create(null);
this.stack = []; this.stack = [];
this.logger = null; this.logger = null;

View File

@ -57,7 +57,7 @@ Address.types = {
* @const {RevMap} * @const {RevMap}
*/ */
Address.typesByVal = util.revMap(Address.types); Address.typesByVal = util.reverse(Address.types);
/** /**
* Inject properties from options object. * Inject properties from options object.

View File

@ -514,7 +514,7 @@ Block.prototype.getClaimed = function getClaimed() {
*/ */
Block.prototype.getPrevout = function getPrevout() { Block.prototype.getPrevout = function getPrevout() {
let prevout = {}; let prevout = Object.create(null);
for (let i = 1; i < this.txs.length; i++) { for (let i = 1; i < this.txs.length; i++) {
let tx = this.txs[i]; let tx = this.txs[i];

View File

@ -51,7 +51,7 @@ InvItem.types = {
* @const {RevMap} * @const {RevMap}
*/ */
InvItem.typesByVal = util.revMap(InvItem.types); InvItem.typesByVal = util.reverse(InvItem.types);
/** /**
* Witness bit for inv types. * Witness bit for inv types.

View File

@ -524,18 +524,18 @@ MerkleBlock.fromBlock = function fromBlock(block, filter) {
*/ */
MerkleBlock.fromHashes = function fromHashes(block, hashes) { MerkleBlock.fromHashes = function fromHashes(block, hashes) {
let filter = {}; let filter = new Set();
let matches = []; let matches = [];
for (let hash of hashes) { for (let hash of hashes) {
if (Buffer.isBuffer(hash)) if (Buffer.isBuffer(hash))
hash = hash.toString('hex'); hash = hash.toString('hex');
filter[hash] = true; filter.add(hash);
} }
for (let tx of block.txs) { for (let tx of block.txs) {
let hash = tx.hash('hex'); let hash = tx.hash('hex');
matches.push(filter[hash] ? 1 : 0); matches.push(filter.has(hash) ? 1 : 0);
} }
return MerkleBlock.fromMatches(block, matches); return MerkleBlock.fromMatches(block, matches);

View File

@ -1013,7 +1013,7 @@ TX.prototype.getOutputValue = function getOutputValue() {
*/ */
TX.prototype._getInputAddresses = function getInputAddresses(view) { TX.prototype._getInputAddresses = function getInputAddresses(view) {
let table = {}; let table = Object.create(null);
let addrs = []; let addrs = [];
if (this.isCoinbase()) if (this.isCoinbase())
@ -1045,7 +1045,7 @@ TX.prototype._getInputAddresses = function getInputAddresses(view) {
*/ */
TX.prototype._getOutputAddresses = function getOutputAddresses() { TX.prototype._getOutputAddresses = function getOutputAddresses() {
let table = {}; let table = Object.create(null);
let addrs = []; let addrs = [];
for (let output of this.outputs) { for (let output of this.outputs) {
@ -1423,7 +1423,7 @@ TX.prototype.isSane = function isSane() {
*/ */
TX.prototype.checkSanity = function checkSanity() { TX.prototype.checkSanity = function checkSanity() {
let prevout = {}; let prevout = new Set();
let total = 0; let total = 0;
if (this.inputs.length === 0) if (this.inputs.length === 0)
@ -1450,9 +1450,9 @@ TX.prototype.checkSanity = function checkSanity() {
for (let input of this.inputs) { for (let input of this.inputs) {
let key = input.prevout.toKey(); let key = input.prevout.toKey();
if (prevout[key]) if (prevout.has(key))
return [false, 'bad-txns-inputs-duplicate', 100]; return [false, 'bad-txns-inputs-duplicate', 100];
prevout[key] = true; prevout.add(key);
} }
if (this.isCoinbase()) { if (this.isCoinbase()) {
@ -1944,7 +1944,7 @@ TX.prototype.getRate = function getRate(view, size) {
*/ */
TX.prototype.getPrevout = function getPrevout() { TX.prototype.getPrevout = function getPrevout() {
let prevout = {}; let prevout = Object.create(null);
if (this.isCoinbase()) if (this.isCoinbase())
return []; return [];

View File

@ -162,7 +162,7 @@ exports.opcodes = {
* @const {RevMap} * @const {RevMap}
*/ */
exports.opcodesByVal = util.revMap(exports.opcodes); exports.opcodesByVal = util.reverse(exports.opcodes);
/** /**
* Script and locktime flags. See {@link VerifyFlags}. * Script and locktime flags. See {@link VerifyFlags}.
@ -267,7 +267,7 @@ exports.hashType = {
* @const {RevMap} * @const {RevMap}
*/ */
exports.hashTypeByVal = util.revMap(exports.hashType); exports.hashTypeByVal = util.reverse(exports.hashType);
/** /**
* Output script types. * Output script types.
@ -292,7 +292,7 @@ exports.types = {
* @const {RevMap} * @const {RevMap}
*/ */
exports.typesByVal = util.revMap(exports.types); exports.typesByVal = util.reverse(exports.types);
/** /**
* False stack return value. * False stack return value.

View File

@ -27,7 +27,7 @@ function Lock(named) {
this.busy = false; this.busy = false;
this.destroyed = false; this.destroyed = false;
this.map = Object.create(null); this.map = new Map();
this.current = null; this.current = null;
this.unlocker = this.unlock.bind(this); this.unlocker = this.unlock.bind(this);
@ -54,12 +54,19 @@ Lock.create = function create(named) {
*/ */
Lock.prototype.has = function has(name) { Lock.prototype.has = function has(name) {
let count;
assert(this.named, 'Must use named jobs.'); assert(this.named, 'Must use named jobs.');
if (this.current === name) if (this.current === name)
return true; return true;
return this.map[name] > 0; count = this.map.get(name);
if (count == null)
return false;
return count > 0;
}; };
/** /**
@ -70,8 +77,16 @@ Lock.prototype.has = function has(name) {
*/ */
Lock.prototype.hasPending = function hasPending(name) { Lock.prototype.hasPending = function hasPending(name) {
let count;
assert(this.named, 'Must use named jobs.'); assert(this.named, 'Must use named jobs.');
return this.map[name] > 0;
count = this.map.get(name);
if (count == null)
return false;
return count > 0;
}; };
/** /**
@ -105,9 +120,10 @@ Lock.prototype.lock = function lock(arg1, arg2) {
if (this.busy) { if (this.busy) {
if (name) { if (name) {
if (!this.map[name]) let count = this.map.get(name);
this.map[name] = 0; if (!count)
this.map[name]++; count = 0;
this.map.set(name, count + 1);
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.jobs.push(new Job(resolve, reject, name)); this.jobs.push(new Job(resolve, reject, name));
@ -141,9 +157,12 @@ Lock.prototype.unlock = function unlock() {
job = this.jobs.shift(); job = this.jobs.shift();
if (job.name) { if (job.name) {
assert(this.map[job.name] > 0); let count = this.map.get(job.name);
if (--this.map[job.name] === 0) assert(count > 0);
delete this.map[job.name]; if (--count === 0)
this.map.delete(job.name);
else
this.map.set(job.name, count);
} }
this.busy = true; this.busy = true;
@ -167,7 +186,7 @@ Lock.prototype.destroy = function destroy() {
this.busy = false; this.busy = false;
this.jobs.length = 0; this.jobs.length = 0;
this.map = Object.create(null); this.map.clear();
this.current = null; this.current = null;
for (let job of jobs) for (let job of jobs)

View File

@ -642,50 +642,20 @@ util.hex32 = function hex32(num) {
}; };
/** /**
* Convert an array to a map. * Reverse an object's keys and values.
* @param {String[]} items * @param {Object} obj
* @returns {Object} Map. * @returns {Object} Reversed object.
*/ */
util.toMap = function toMap(items) { util.reverse = function reverse(obj) {
let map = {};
for (let value of items)
map[value] = true;
return map;
};
/**
* Reverse a map.
* @param {Object} map
* @returns {Object} Reversed map.
*/
util.revMap = function revMap(map) {
let reversed = {}; let reversed = {};
for (let key of Object.keys(map)) for (let key of Object.keys(obj))
reversed[map[key]] = key; reversed[obj[key]] = key;
return reversed; return reversed;
}; };
/**
* Get object values.
* @param {Object} map
* @returns {Array} Values.
*/
util.values = function values(map) {
let items = [];
for (let key of Object.keys(map))
items.push(map[key]);
return items;
};
/** /**
* Perform a binary search on a sorted array. * Perform a binary search on a sorted array.
* @param {Array} items * @param {Array} items

View File

@ -81,36 +81,38 @@ common.sortCoins = function sortCoins(coins) {
*/ */
common.sortDeps = function sortDeps(txs) { common.sortDeps = function sortDeps(txs) {
let depMap = {}; let map = new Map();
let count = {}; let depMap = new Map();
let depCount = new Map();
let result = []; let result = [];
let top = []; let top = [];
let map = {};
for (let tx of txs) { for (let tx of txs) {
let hash = tx.hash('hex'); let hash = tx.hash('hex');
map[hash] = tx; map.set(hash, tx);
} }
for (let tx of txs) { for (let [hash, tx] of map) {
let hash = tx.hash('hex'); let hash = tx.hash('hex');
let hasDeps = false; let hasDeps = false;
count[hash] = 0; depCount.set(hash, 0);
for (let input of tx.inputs) { for (let input of tx.inputs) {
let prev = input.prevout.hash; let prev = input.prevout.hash;
let count;
if (!map[prev]) if (!map.has(prev))
continue; continue;
count[hash] += 1; count = depCount.get(hash);
depCount.set(hash, count + 1);
hasDeps = true; hasDeps = true;
if (!depMap[prev]) if (!depMap.has(prev))
depMap[prev] = []; depMap.set(prev, []);
depMap[prev].push(tx); depMap.get(prev).push(tx);
} }
if (hasDeps) if (hasDeps)
@ -121,7 +123,7 @@ common.sortDeps = function sortDeps(txs) {
for (let tx of top) { for (let tx of top) {
let hash = tx.hash('hex'); let hash = tx.hash('hex');
let deps = depMap[hash]; let deps = depMap.get(hash);
result.push(tx); result.push(tx);
@ -130,9 +132,12 @@ common.sortDeps = function sortDeps(txs) {
for (let tx of deps) { for (let tx of deps) {
let hash = tx.hash('hex'); let hash = tx.hash('hex');
let count = depCount.get(hash);
if (--count[hash] === 0) if (--count === 0)
top.push(tx); top.push(tx);
depCount.set(hash, count);
} }
} }

View File

@ -238,7 +238,7 @@ function BlockMapRecord(height) {
this.height = height != null ? height : -1; this.height = height != null ? height : -1;
this.txs = []; this.txs = [];
this.index = {}; this.index = new Map();
} }
/** /**
@ -256,7 +256,7 @@ BlockMapRecord.prototype.fromRaw = function fromRaw(data) {
let hash = br.readHash('hex'); let hash = br.readHash('hex');
let tx = TXMapRecord.fromReader(hash, br); let tx = TXMapRecord.fromReader(hash, br);
this.txs.push(tx); this.txs.push(tx);
this.index[tx.hash] = tx; this.index.set(tx.hash, tx);
} }
return this; return this;
@ -319,13 +319,13 @@ BlockMapRecord.prototype.toRaw = function toRaw() {
*/ */
BlockMapRecord.prototype.add = function add(hash, wid) { BlockMapRecord.prototype.add = function add(hash, wid) {
let tx = this.index[hash]; let tx = this.index.get(hash);
if (!tx) { if (!tx) {
tx = new TXMapRecord(hash); tx = new TXMapRecord(hash);
tx.wids.push(wid); tx.wids.push(wid);
this.txs.push(tx); this.txs.push(tx);
this.index[tx.hash] = tx; this.index.set(tx.hash, tx);
return true; return true;
} }
@ -340,7 +340,7 @@ BlockMapRecord.prototype.add = function add(hash, wid) {
*/ */
BlockMapRecord.prototype.remove = function remove(hash, wid) { BlockMapRecord.prototype.remove = function remove(hash, wid) {
let tx = this.index[hash]; let tx = this.index.get(hash);
if (!tx) if (!tx)
return false; return false;
@ -351,7 +351,7 @@ BlockMapRecord.prototype.remove = function remove(hash, wid) {
if (tx.wids.length === 0) { if (tx.wids.length === 0) {
let result = util.binaryRemove(this.txs, tx, cmpid); let result = util.binaryRemove(this.txs, tx, cmpid);
assert(result); assert(result);
delete this.index[tx.hash]; this.index.delete(tx.hash);
} }
return true; return true;

View File

@ -458,8 +458,8 @@ RPC.prototype.getReceivedByAccount = async function getReceivedByAccount(args, h
let name = valid.str(0); let name = valid.str(0);
let minconf = valid.u32(0, 0); let minconf = valid.u32(0, 0);
let height = this.wdb.state.height; let height = this.wdb.state.height;
let filter = new Set();
let total = 0; let total = 0;
let filter = {};
let lastConf = -1; let lastConf = -1;
let paths, txs; let paths, txs;
@ -474,7 +474,7 @@ RPC.prototype.getReceivedByAccount = async function getReceivedByAccount(args, h
paths = await wallet.getPaths(name); paths = await wallet.getPaths(name);
for (let path of paths) for (let path of paths)
filter[path.hash] = true; filter.add(path.hash);
txs = await wallet.getHistory(name); txs = await wallet.getHistory(name);
@ -489,7 +489,7 @@ RPC.prototype.getReceivedByAccount = async function getReceivedByAccount(args, h
for (let output of wtx.tx.outputs) { for (let output of wtx.tx.outputs) {
let hash = output.getHash('hex'); let hash = output.getHash('hex');
if (hash && filter[hash]) if (hash && filter.has(hash))
total += output.value; total += output.value;
} }
} }
@ -903,21 +903,21 @@ RPC.prototype._listReceived = async function _listReceived(minconf, empty, watch
let wallet = this.wallet; let wallet = this.wallet;
let paths = await wallet.getPaths(); let paths = await wallet.getPaths();
let height = this.wdb.state.height; let height = this.wdb.state.height;
let map = new Map();
let out = []; let out = [];
let result = []; let result = [];
let map = {};
let txs; let txs;
for (let path of paths) { for (let path of paths) {
let addr = path.toAddress(); let addr = path.toAddress();
map[path.hash] = { map.set(path.hash, {
involvesWatchonly: wallet.watchOnly, involvesWatchonly: wallet.watchOnly,
address: addr.toString(this.network), address: addr.toString(this.network),
account: path.name, account: path.name,
amount: 0, amount: 0,
confirmations: -1, confirmations: -1,
label: '', label: '',
}; });
} }
txs = await wallet.getHistory(); txs = await wallet.getHistory();
@ -936,7 +936,7 @@ RPC.prototype._listReceived = async function _listReceived(minconf, empty, watch
continue; continue;
hash = addr.getHash('hex'); hash = addr.getHash('hex');
entry = map[hash]; entry = map.get(hash);
if (entry) { if (entry) {
if (entry.confirmations === -1 || conf < entry.confirmations) if (entry.confirmations === -1 || conf < entry.confirmations)
@ -947,18 +947,16 @@ RPC.prototype._listReceived = async function _listReceived(minconf, empty, watch
} }
} }
for (let key of Object.keys(map)) { for (let entry of map.values())
let entry = map[key];
out.push(entry); out.push(entry);
}
if (account) { if (account) {
let map = {}; let map = new Map();
for (let entry of out) { for (let entry of out) {
let item = map[entry.account]; let item = map.get(entry.account);
if (!item) { if (!item) {
map[entry.account] = entry; map.set(entry.account, entry);
entry.address = undefined; entry.address = undefined;
continue; continue;
} }
@ -967,10 +965,8 @@ RPC.prototype._listReceived = async function _listReceived(minconf, empty, watch
out = []; out = [];
for (let key of Object.keys(map)) { for (let entry of map.values())
let entry = map[key];
out.push(entry); out.push(entry);
}
} }
for (let entry of out) { for (let entry of out) {
@ -1158,8 +1154,8 @@ RPC.prototype.listUnspent = async function listUnspent(args, help) {
let maxDepth = valid.u32(1, 9999999); let maxDepth = valid.u32(1, 9999999);
let addrs = valid.array(2); let addrs = valid.array(2);
let height = this.wdb.state.height; let height = this.wdb.state.height;
let map = new Set();
let out = []; let out = [];
let map = {};
let coins; let coins;
if (help || args.length > 3) { if (help || args.length > 3) {
@ -1173,10 +1169,10 @@ RPC.prototype.listUnspent = async function listUnspent(args, help) {
let addr = valid.str(i, ''); let addr = valid.str(i, '');
let hash = parseHash(addr, this.network); let hash = parseHash(addr, this.network);
if (map[hash]) if (map.has(hash))
throw new RPCError(errs.INVALID_PARAMETER, 'Duplicate address.'); throw new RPCError(errs.INVALID_PARAMETER, 'Duplicate address.');
map[hash] = true; map.add(hash);
} }
} }
@ -1199,7 +1195,7 @@ RPC.prototype.listUnspent = async function listUnspent(args, help) {
hash = coin.getHash('hex'); hash = coin.getHash('hex');
if (addrs) { if (addrs) {
if (!hash || !map[hash]) if (!hash || !map.has(hash))
continue; continue;
} }
@ -1319,8 +1315,8 @@ RPC.prototype.sendMany = async function sendMany(args, help) {
let sendTo = valid.obj(1); let sendTo = valid.obj(1);
let minconf = valid.u32(2, 1); let minconf = valid.u32(2, 1);
let subtractFee = valid.bool(4, false); let subtractFee = valid.bool(4, false);
let uniq = new Set();
let outputs = []; let outputs = [];
let uniq = {};
let options, tx; let options, tx;
if (help || args.length < 2 || args.length > 5) { if (help || args.length < 2 || args.length > 5) {
@ -1346,10 +1342,10 @@ RPC.prototype.sendMany = async function sendMany(args, help) {
if (value == null) if (value == null)
throw new RPCError(errs.INVALID_PARAMETER, 'Invalid parameter.'); throw new RPCError(errs.INVALID_PARAMETER, 'Invalid parameter.');
if (uniq[hash]) if (uniq.has(hash))
throw new RPCError(errs.INVALID_PARAMETER, 'Invalid parameter.'); throw new RPCError(errs.INVALID_PARAMETER, 'Invalid parameter.');
uniq[hash] = true; uniq.add(hash);
output = new Output(); output = new Output();
output.value = value; output.value = value;

View File

@ -3070,7 +3070,7 @@ function BlockRecord(hash, height, ts) {
this.height = height != null ? height : -1; this.height = height != null ? height : -1;
this.ts = ts || 0; this.ts = ts || 0;
this.hashes = []; this.hashes = [];
this.index = {}; this.index = new Set();
} }
/** /**
@ -3080,10 +3080,10 @@ function BlockRecord(hash, height, ts) {
*/ */
BlockRecord.prototype.add = function add(hash) { BlockRecord.prototype.add = function add(hash) {
if (this.index[hash]) if (this.index.has(hash))
return false; return false;
this.index[hash] = true; this.index.add(hash);
this.hashes.push(hash); this.hashes.push(hash);
return true; return true;
@ -3098,10 +3098,10 @@ BlockRecord.prototype.add = function add(hash) {
BlockRecord.prototype.remove = function remove(hash) { BlockRecord.prototype.remove = function remove(hash) {
let index; let index;
if (!this.index[hash]) if (!this.index.has(hash))
return false; return false;
delete this.index[hash]; this.index.delete(hash);
// Fast case // Fast case
if (this.hashes[this.hashes.length - 1] === hash) { if (this.hashes[this.hashes.length - 1] === hash) {
@ -3136,7 +3136,7 @@ BlockRecord.prototype.fromRaw = function fromRaw(data) {
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
let hash = br.readHash('hex'); let hash = br.readHash('hex');
this.index[hash] = true; this.index.add(hash);
this.hashes.push(hash); this.hashes.push(hash);
} }

View File

@ -1956,8 +1956,8 @@ Wallet.prototype._setLookahead = async function setLookahead(acct, lookahead) {
*/ */
Wallet.prototype.syncOutputDepth = async function syncOutputDepth(details) { Wallet.prototype.syncOutputDepth = async function syncOutputDepth(details) {
let accounts = new Map();
let derived = []; let derived = [];
let accounts = {};
if (!details) if (!details)
return derived; return derived;
@ -1971,15 +1971,13 @@ Wallet.prototype.syncOutputDepth = async function syncOutputDepth(details) {
if (path.index === -1) if (path.index === -1)
continue; continue;
if (!accounts[path.account]) if (!accounts.has(path.account))
accounts[path.account] = []; accounts.set(path.account, []);
accounts[path.account].push(path); accounts.get(path.account).push(path);
} }
accounts = util.values(accounts); for (let paths of accounts.values()) {
for (let paths of accounts) {
let acct = paths[0].account; let acct = paths[0].account;
let receive = -1; let receive = -1;
let change = -1; let change = -1;

View File

@ -68,7 +68,7 @@ async function updateTXDB() {
batch.del(key); batch.del(key);
} }
txs = util.values(txs); txs = getValues(txs);
await batch.write(); await batch.write();
await db.close(); await db.close();
@ -129,6 +129,15 @@ function fromExtended(data, saveCoins) {
return tx; return tx;
} }
function getValues(map) {
let items = [];
for (let key of Object.keys(map))
items.push(map[key]);
return items;
}
(async () => { (async () => {
await db.open(); await db.open();
batch = db.batch(); batch = db.batch();

View File

@ -19,7 +19,7 @@ tests.ca = {
}; };
x509.allowUntrusted = true; x509.allowUntrusted = true;
x509.trusted = {}; x509.trusted.clear();
describe('BIP70', function() { describe('BIP70', function() {
function testRequest(data) { function testRequest(data) {

View File

@ -29,10 +29,10 @@ function MemWallet(options) {
this.changeDepth = 1; this.changeDepth = 1;
this.receive = null; this.receive = null;
this.change = null; this.change = null;
this.map = {}; this.map = new Set();
this.coins = {}; this.coins = new Map();
this.spent = {}; this.spent = new Map();
this.paths = {}; this.paths = new Map();
this.balance = 0; this.balance = 0;
this.txs = 0; this.txs = 0;
this.filter = Bloom.fromRate(1000000, 0.001, -1); this.filter = Bloom.fromRate(1000000, 0.001, -1);
@ -105,7 +105,7 @@ MemWallet.prototype.createReceive = function createReceive() {
let key = this.deriveReceive(index); let key = this.deriveReceive(index);
let hash = key.getHash('hex'); let hash = key.getHash('hex');
this.filter.add(hash, 'hex'); this.filter.add(hash, 'hex');
this.paths[hash] = new Path(hash, 0, index); this.paths.set(hash, new Path(hash, 0, index));
this.receive = key; this.receive = key;
return key; return key;
}; };
@ -115,7 +115,7 @@ MemWallet.prototype.createChange = function createChange() {
let key = this.deriveChange(index); let key = this.deriveChange(index);
let hash = key.getHash('hex'); let hash = key.getHash('hex');
this.filter.add(hash, 'hex'); this.filter.add(hash, 'hex');
this.paths[hash] = new Path(hash, 1, index); this.paths.set(hash, new Path(hash, 1, index));
this.change = key; this.change = key;
return key; return key;
}; };
@ -145,22 +145,22 @@ MemWallet.prototype.deriveKey = function deriveKey(branch, index) {
}; };
MemWallet.prototype.getKey = function getKey(hash) { MemWallet.prototype.getKey = function getKey(hash) {
let path = this.paths[hash]; let path = this.paths.get(hash);
if (!path) if (!path)
return; return;
return this.derivePath(path); return this.derivePath(path);
}; };
MemWallet.prototype.getPath = function getPath(hash) { MemWallet.prototype.getPath = function getPath(hash) {
return this.paths[hash]; return this.paths.get(hash);
}; };
MemWallet.prototype.getCoin = function getCoin(key) { MemWallet.prototype.getCoin = function getCoin(key) {
return this.coins[key]; return this.coins.get(key);
}; };
MemWallet.prototype.getUndo = function getUndo(key) { MemWallet.prototype.getUndo = function getUndo(key) {
return this.spent[key]; return this.spent.get(key);
}; };
MemWallet.prototype.addCoin = function addCoin(coin) { MemWallet.prototype.addCoin = function addCoin(coin) {
@ -169,22 +169,22 @@ MemWallet.prototype.addCoin = function addCoin(coin) {
this.filter.add(op.toRaw()); this.filter.add(op.toRaw());
delete this.spent[key]; this.spent.delete(key);
this.coins[key] = coin; this.coins.set(key, coin);
this.balance += coin.value; this.balance += coin.value;
}; };
MemWallet.prototype.removeCoin = function removeCoin(key) { MemWallet.prototype.removeCoin = function removeCoin(key) {
let coin = this.coins[key]; let coin = this.coins.get(key);
if (!coin) if (!coin)
return; return;
this.spent[key] = coin; this.spent.set(key, coin);
this.balance -= coin.value; this.balance -= coin.value;
delete this.coins[key]; this.coins.delete(key);
}; };
MemWallet.prototype.getAddress = function getAddress() { MemWallet.prototype.getAddress = function getAddress() {
@ -200,7 +200,12 @@ MemWallet.prototype.getChange = function getChange() {
}; };
MemWallet.prototype.getCoins = function getCoins() { MemWallet.prototype.getCoins = function getCoins() {
return util.values(this.coins); let coins = [];
for (let coin of this.coins.values())
coins.push(coin);
return coins;
}; };
MemWallet.prototype.syncKey = function syncKey(path) { MemWallet.prototype.syncKey = function syncKey(path) {
@ -245,7 +250,7 @@ MemWallet.prototype.addTX = function addTX(tx, height) {
if (height == null) if (height == null)
height = -1; height = -1;
if (this.map[hash]) if (this.map.has(hash))
return true; return true;
for (i = 0; i < tx.inputs.length; i++) { for (i = 0; i < tx.inputs.length; i++) {
@ -282,7 +287,7 @@ MemWallet.prototype.addTX = function addTX(tx, height) {
if (result) { if (result) {
this.txs++; this.txs++;
this.map[hash] = true; this.map.add(hash);
} }
return result; return result;
@ -293,7 +298,7 @@ MemWallet.prototype.removeTX = function removeTX(tx, height) {
let result = false; let result = false;
let i, op, coin, input; let i, op, coin, input;
if (!this.map[hash]) if (!this.map.has(hash))
return false; return false;
for (i = 0; i < tx.outputs.length; i++) { for (i = 0; i < tx.outputs.length; i++) {
@ -324,7 +329,7 @@ MemWallet.prototype.removeTX = function removeTX(tx, height) {
if (result) if (result)
this.txs--; this.txs--;
delete this.map[hash]; this.map.delete(hash);
return result; return result;
}; };