From 7eefb773be2482b0b1b3a3f2420c332d63e42994 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Tue, 25 Jul 2017 05:15:47 -0700 Subject: [PATCH] refactor: use maps and sets wherever possible. --- lib/bip70/x509.js | 10 ++++---- lib/blockchain/chaindb.js | 2 +- lib/db/lowlevelup.js | 5 ++-- lib/http/base.js | 2 +- lib/http/request.js | 2 +- lib/http/rpc.js | 26 ++++++++++---------- lib/http/rpcbase.js | 2 +- lib/mempool/mempool.js | 46 ++++++++++++++++------------------- lib/mining/miner.js | 10 ++++---- lib/net/hostlist.js | 6 ++--- lib/net/packets.js | 4 +-- lib/net/socks.js | 2 +- lib/net/upnp.js | 4 +-- lib/node/logger.js | 2 +- lib/node/node.js | 2 +- lib/primitives/address.js | 2 +- lib/primitives/block.js | 2 +- lib/primitives/invitem.js | 2 +- lib/primitives/merkleblock.js | 6 ++--- lib/primitives/tx.js | 12 ++++----- lib/script/common.js | 6 ++--- lib/utils/lock.js | 39 +++++++++++++++++++++-------- lib/utils/util.js | 42 +++++--------------------------- lib/wallet/common.js | 31 +++++++++++++---------- lib/wallet/records.js | 12 ++++----- lib/wallet/rpc.js | 42 +++++++++++++++----------------- lib/wallet/txdb.js | 12 ++++----- lib/wallet/wallet.js | 12 ++++----- migrate/walletdb3to4.js | 11 ++++++++- test/bip70-test.js | 2 +- test/util/memwallet.js | 45 +++++++++++++++++++--------------- 31 files changed, 200 insertions(+), 203 deletions(-) diff --git a/lib/bip70/x509.js b/lib/bip70/x509.js index 4620caec..f7e0f398 100644 --- a/lib/bip70/x509.js +++ b/lib/bip70/x509.js @@ -22,10 +22,10 @@ const x509 = exports; /** * Map of trusted root certs. - * @type {Object} + * @type {Set} */ -x509.trusted = {}; +x509.trusted = new Set(); /** * Whether to allow untrusted root @@ -127,7 +127,7 @@ x509.getCAName = function getCAName(cert) { x509.isTrusted = function isTrusted(cert) { let fingerprint = digest.sha256(cert.raw); 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 = 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.'); hash = hash.toString('hex'); - x509.trusted[hash] = true; + x509.trusted.add(hash); } }; diff --git a/lib/blockchain/chaindb.js b/lib/blockchain/chaindb.js index dbbc2577..1f144829 100644 --- a/lib/blockchain/chaindb.js +++ b/lib/blockchain/chaindb.js @@ -1144,7 +1144,7 @@ ChainDB.prototype.getCoinsByAddress = async function getCoinsByAddress(addrs) { */ ChainDB.prototype.getHashesByAddress = async function getHashesByAddress(addrs) { - let hashes = {}; + let hashes = Object.create(null); if (!this.options.indexTX || !this.options.indexAddress) return []; diff --git a/lib/db/lowlevelup.js b/lib/db/lowlevelup.js index d1685f0c..ce6d84ca 100644 --- a/lib/db/lowlevelup.js +++ b/lib/db/lowlevelup.js @@ -566,15 +566,14 @@ LowlevelUp.prototype.values = async function _values(options) { */ LowlevelUp.prototype.dump = async function dump() { - let records = {}; + let records = Object.create(null); let items = await this.range({ gte: LOW, lte: HIGH }); - for (let i = 0; i < items.length; i++) { - let item = items[i]; + for (let item of items) { let key = item.key.toString('hex'); let value = item.value.toString('hex'); records[key] = value; diff --git a/lib/http/base.js b/lib/http/base.js index 01ef851d..e89df804 100644 --- a/lib/http/base.js +++ b/lib/http/base.js @@ -1509,7 +1509,7 @@ function WebSocket(socket, ctx) { this.context = ctx; this.socket = socket; this.remoteAddress = socket.conn.remoteAddress; - this.hooks = {}; + this.hooks = Object.create(null); this.channels = new Map(); this.auth = false; this.filter = null; diff --git a/lib/http/request.js b/lib/http/request.js index 8c7d9d47..4a877522 100644 --- a/lib/http/request.js +++ b/lib/http/request.js @@ -228,7 +228,7 @@ RequestOptions.prototype.getHeaders = function getHeaders() { if (this.headers) return this.headers; - headers = {}; + headers = Object.create(null); headers['User-Agent'] = this.agent; diff --git a/lib/http/rpc.js b/lib/http/rpc.js index 2bd5a7ef..436fa316 100644 --- a/lib/http/rpc.js +++ b/lib/http/rpc.js @@ -855,7 +855,7 @@ RPC.prototype.getTXOutProof = async function getTXOutProof(args, help) { let valid = new Validator([args]); let txids = valid.array(0); let hash = valid.hash(1); - let uniq = {}; + let uniq = new Set(); let block, last; if (help || (args.length !== 1 && args.length !== 2)) { @@ -880,10 +880,10 @@ RPC.prototype.getTXOutProof = async function getTXOutProof(args, help) { if (!txid) throw new RPCError(errs.TYPE_ERROR, 'Invalid TXID.'); - if (uniq[txid]) + if (uniq.has(txid)) throw new RPCError(errs.INVALID_PARAMETER, 'Duplicate txid.'); - uniq[txid] = true; + uniq.add(txid); txids[i] = 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 mutable = ['time', 'transactions', 'prevblock']; let txs = []; - let index = {}; + let index = new Map(); let vbavailable = {}; let vbrules = []; let json; @@ -1293,7 +1293,7 @@ RPC.prototype._createTemplate = async function _createTemplate(maxVersion, coinb // Build an index of every transaction. for (let i = 0; i < attempt.items.length; i++) { let entry = attempt.items[i]; - index[entry.hash] = i + 1; + index.set(entry.hash, i + 1); } // 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++) { let input = tx.inputs[j]; - let dep = index[input.prevout.hash]; + let dep = index.get(input.prevout.hash); if (dep == null) continue; @@ -1634,7 +1634,8 @@ RPC.prototype.createRawTransaction = async function createRawTransaction(args, h let inputs = valid.array(0); let sendTo = valid.obj(1); let locktime = valid.u32(2); - let tx, addrs; + let uniq = new Set(); + let tx; if (help || args.length < 2 || args.length > 3) { throw new RPCError(errs.MISC_ERROR, @@ -1675,7 +1676,6 @@ RPC.prototype.createRawTransaction = async function createRawTransaction(args, h } valid = new Validator([sendTo]); - addrs = {}; for (let key of Object.keys(sendTo)) { let addr, b58, value, output; @@ -1698,10 +1698,10 @@ RPC.prototype.createRawTransaction = async function createRawTransaction(args, h addr = parseAddress(key, this.network); b58 = addr.toString(this.network); - if (addrs[b58]) + if (uniq.has(b58)) throw new RPCError(errs.INVALID_PARAMETER, 'Duplicate address'); - addrs[b58] = true; + uniq.add(b58); value = valid.btc(key); @@ -1814,8 +1814,8 @@ RPC.prototype.signRawTransaction = async function signRawTransaction(args, help) let secrets = valid.array(2); let sighash = valid.str(3); let type = Script.hashType.ALL; + let map = new Map(); let keys = []; - let map = {}; let tx; 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++) { let secret = valid.str(i, ''); let key = parseSecret(secret, this.network); - map[key.getPublicKey('hex')] = key; + map.set(key.getPublicKey('hex'), key); keys.push(key); } } @@ -1886,7 +1886,7 @@ RPC.prototype.signRawTransaction = async function signRawTransaction(args, help) if (!op.data) continue; - key = map[op.data.toString('hex')]; + key = map.get(op.data.toString('hex')); if (key) { key.script = redeem; diff --git a/lib/http/rpcbase.js b/lib/http/rpcbase.js index ead171b9..23213a8a 100644 --- a/lib/http/rpcbase.js +++ b/lib/http/rpcbase.js @@ -25,7 +25,7 @@ function RPCBase() { EventEmitter.call(this); this.logger = Logger.global; - this.calls = {}; + this.calls = Object.create(null); this.mounts = []; this.locker = new Lock(); } diff --git a/lib/mempool/mempool.js b/lib/mempool/mempool.js index 84e2a54b..bc85d777 100644 --- a/lib/mempool/mempool.js +++ b/lib/mempool/mempool.js @@ -1144,7 +1144,7 @@ Mempool.prototype.removeSpenders = function removeSpenders(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) { - return this._countAncestors(entry, 0, {}, entry, map); + return this._countAncestors(entry, new Set(), entry, map); }; /** * Traverse ancestors and count. * @private * @param {MempoolEntry} entry - * @param {Number} count * @param {Object} set * @param {MempoolEntry} child * @param {Function} map * @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; for (let input of tx.inputs) { @@ -1181,24 +1180,23 @@ Mempool.prototype._countAncestors = function countAncestors(entry, count, set, c if (!parent) continue; - if (set[hash]) + if (set.has(hash)) continue; - set[hash] = true; - count += 1; + set.add(hash); map(parent, child); - if (count > this.options.maxAncestors) + if (set.size > this.options.maxAncestors) 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; } - return count; + return set.size; }; /** @@ -1209,7 +1207,7 @@ Mempool.prototype._countAncestors = function countAncestors(entry, count, set, c */ 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. * @private * @param {MempoolEntry} entry - * @param {Number} count * @param {Object} set * @returns {Number} */ -Mempool.prototype._countDescendants = function countDescendants(entry, count, set) { +Mempool.prototype._countDescendants = function countDescendants(entry, set) { let tx = entry.tx; let hash = tx.hash('hex'); @@ -1235,16 +1232,15 @@ Mempool.prototype._countDescendants = function countDescendants(entry, count, se next = child.hash('hex'); - if (set[next]) + if (set.has(next)) continue; - set[next] = true; - count += 1; + set.add(next); - 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) { - return this._getAncestors(entry, [], {}); + return this._getAncestors(entry, [], new Set()); }; /** @@ -1276,10 +1272,10 @@ Mempool.prototype._getAncestors = function getAncestors(entry, entries, set) { if (!parent) continue; - if (set[hash]) + if (set.has(hash)) continue; - set[hash] = true; + set.add(hash); entries.push(parent); this._getAncestors(parent, entries, set); @@ -1295,7 +1291,7 @@ Mempool.prototype._getAncestors = function getAncestors(entry, entries, set) { */ 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'); - if (set[next]) + if (set.has(next)) continue; - set[next] = true; + set.add(next); entries.push(child); this._getDescendants(child, entries, set); diff --git a/lib/mining/miner.js b/lib/mining/miner.js index fc40bd3c..a5202ec6 100644 --- a/lib/mining/miner.js +++ b/lib/mining/miner.js @@ -256,7 +256,7 @@ Miner.prototype.getAddress = function getAddress() { Miner.prototype.assemble = function assemble(attempt) { let priority = this.options.priorityWeight > 0; let queue = new Heap(cmpRate); - let depMap = {}; + let depMap = new Map(); if (priority) queue.set(cmpPriority); @@ -284,10 +284,10 @@ Miner.prototype.assemble = function assemble(attempt) { item.depCount += 1; - if (!depMap[hash]) - depMap[hash] = []; + if (!depMap.has(hash)) + depMap.set(hash, []); - depMap[hash].push(item); + depMap.get(hash).push(item); } if (item.depCount > 0) @@ -339,7 +339,7 @@ Miner.prototype.assemble = function assemble(attempt) { attempt.fees += item.fee; attempt.items.push(item); - deps = depMap[hash]; + deps = depMap.get(hash); if (!deps) continue; diff --git a/lib/net/hostlist.js b/lib/net/hostlist.js index 075c23a5..64090d42 100644 --- a/lib/net/hostlist.js +++ b/lib/net/hostlist.js @@ -1140,7 +1140,7 @@ HostList.prototype.toJSON = function toJSON() { */ HostList.prototype.fromJSON = function fromJSON(json) { - let sources = {}; + let sources = new Map(); let map = new Map(); let totalFresh = 0; let totalUsed = 0; @@ -1156,12 +1156,12 @@ HostList.prototype.fromJSON = function fromJSON(json) { for (let addr of json.addrs) { let entry = HostEntry.fromJSON(addr, this.network); - let src = sources[entry.src.hostname]; + let src = sources.get(entry.src.hostname); // Save some memory. if (!src) { src = entry.src; - sources[src.hostname] = src; + sources.set(src.hostname, src); } entry.src = src; diff --git a/lib/net/packets.js b/lib/net/packets.js index 2b492244..29017e29 100644 --- a/lib/net/packets.js +++ b/lib/net/packets.js @@ -77,7 +77,7 @@ exports.types = { * @default */ -exports.typesByVal = util.revMap(exports.types); +exports.typesByVal = util.reverse(exports.types); /** * Base Packet @@ -1474,7 +1474,7 @@ RejectPacket.codes = { * @const {RevMap} */ -RejectPacket.codesByVal = util.revMap(RejectPacket.codes); +RejectPacket.codesByVal = util.reverse(RejectPacket.codes); RejectPacket.prototype.cmd = 'reject'; RejectPacket.prototype.type = exports.types.REJECT; diff --git a/lib/net/socks.js b/lib/net/socks.js index 86852dbe..e368fe06 100644 --- a/lib/net/socks.js +++ b/lib/net/socks.js @@ -55,7 +55,7 @@ SOCKS.states = { RESOLVE_DONE: 7 }; -SOCKS.statesByVal = util.revMap(SOCKS.states); +SOCKS.statesByVal = util.reverse(SOCKS.states); SOCKS.errors = [ '', diff --git a/lib/net/upnp.js b/lib/net/upnp.js index f435385d..c38a6bf7 100644 --- a/lib/net/upnp.js +++ b/lib/net/upnp.js @@ -262,7 +262,7 @@ UPNP.prototype.resolve = async function resolve(location, targets) { UPNP.parseHeader = function parseHeader(str) { let lines = str.split(/\r?\n/); - let headers = {}; + let headers = Object.create(null); for (let line of lines) { let index, left, right; @@ -635,7 +635,7 @@ function parseServices(el) { } function parseService(el) { - let service = {}; + let service = Object.create(null); for (let child of el.children) { if (child.children.length > 0) diff --git a/lib/node/logger.js b/lib/node/logger.js index 2cf5dab0..569dc33a 100644 --- a/lib/node/logger.js +++ b/lib/node/logger.js @@ -33,7 +33,7 @@ function Logger(options) { this.closing = false; this.filename = null; this.stream = null; - this.contexts = {}; + this.contexts = Object.create(null); this.locker = new Lock(); if (options) diff --git a/lib/node/node.js b/lib/node/node.js index 6221653e..aa6181dc 100644 --- a/lib/node/node.js +++ b/lib/node/node.js @@ -42,7 +42,7 @@ function Node(options) { this.network = Network.get(this.config.network); this.startTime = -1; this.bound = []; - this.plugins = {}; + this.plugins = Object.create(null); this.stack = []; this.logger = null; diff --git a/lib/primitives/address.js b/lib/primitives/address.js index b24b39cd..0bedf746 100644 --- a/lib/primitives/address.js +++ b/lib/primitives/address.js @@ -57,7 +57,7 @@ Address.types = { * @const {RevMap} */ -Address.typesByVal = util.revMap(Address.types); +Address.typesByVal = util.reverse(Address.types); /** * Inject properties from options object. diff --git a/lib/primitives/block.js b/lib/primitives/block.js index d2b5725e..517b963e 100644 --- a/lib/primitives/block.js +++ b/lib/primitives/block.js @@ -514,7 +514,7 @@ Block.prototype.getClaimed = function getClaimed() { */ Block.prototype.getPrevout = function getPrevout() { - let prevout = {}; + let prevout = Object.create(null); for (let i = 1; i < this.txs.length; i++) { let tx = this.txs[i]; diff --git a/lib/primitives/invitem.js b/lib/primitives/invitem.js index 397ccb7e..74d9a066 100644 --- a/lib/primitives/invitem.js +++ b/lib/primitives/invitem.js @@ -51,7 +51,7 @@ InvItem.types = { * @const {RevMap} */ -InvItem.typesByVal = util.revMap(InvItem.types); +InvItem.typesByVal = util.reverse(InvItem.types); /** * Witness bit for inv types. diff --git a/lib/primitives/merkleblock.js b/lib/primitives/merkleblock.js index ec8dc51e..2d3998cb 100644 --- a/lib/primitives/merkleblock.js +++ b/lib/primitives/merkleblock.js @@ -524,18 +524,18 @@ MerkleBlock.fromBlock = function fromBlock(block, filter) { */ MerkleBlock.fromHashes = function fromHashes(block, hashes) { - let filter = {}; + let filter = new Set(); let matches = []; for (let hash of hashes) { if (Buffer.isBuffer(hash)) hash = hash.toString('hex'); - filter[hash] = true; + filter.add(hash); } for (let tx of block.txs) { let hash = tx.hash('hex'); - matches.push(filter[hash] ? 1 : 0); + matches.push(filter.has(hash) ? 1 : 0); } return MerkleBlock.fromMatches(block, matches); diff --git a/lib/primitives/tx.js b/lib/primitives/tx.js index fa861af6..51670eb5 100644 --- a/lib/primitives/tx.js +++ b/lib/primitives/tx.js @@ -1013,7 +1013,7 @@ TX.prototype.getOutputValue = function getOutputValue() { */ TX.prototype._getInputAddresses = function getInputAddresses(view) { - let table = {}; + let table = Object.create(null); let addrs = []; if (this.isCoinbase()) @@ -1045,7 +1045,7 @@ TX.prototype._getInputAddresses = function getInputAddresses(view) { */ TX.prototype._getOutputAddresses = function getOutputAddresses() { - let table = {}; + let table = Object.create(null); let addrs = []; for (let output of this.outputs) { @@ -1423,7 +1423,7 @@ TX.prototype.isSane = function isSane() { */ TX.prototype.checkSanity = function checkSanity() { - let prevout = {}; + let prevout = new Set(); let total = 0; if (this.inputs.length === 0) @@ -1450,9 +1450,9 @@ TX.prototype.checkSanity = function checkSanity() { for (let input of this.inputs) { let key = input.prevout.toKey(); - if (prevout[key]) + if (prevout.has(key)) return [false, 'bad-txns-inputs-duplicate', 100]; - prevout[key] = true; + prevout.add(key); } if (this.isCoinbase()) { @@ -1944,7 +1944,7 @@ TX.prototype.getRate = function getRate(view, size) { */ TX.prototype.getPrevout = function getPrevout() { - let prevout = {}; + let prevout = Object.create(null); if (this.isCoinbase()) return []; diff --git a/lib/script/common.js b/lib/script/common.js index e728e619..db804c82 100644 --- a/lib/script/common.js +++ b/lib/script/common.js @@ -162,7 +162,7 @@ exports.opcodes = { * @const {RevMap} */ -exports.opcodesByVal = util.revMap(exports.opcodes); +exports.opcodesByVal = util.reverse(exports.opcodes); /** * Script and locktime flags. See {@link VerifyFlags}. @@ -267,7 +267,7 @@ exports.hashType = { * @const {RevMap} */ -exports.hashTypeByVal = util.revMap(exports.hashType); +exports.hashTypeByVal = util.reverse(exports.hashType); /** * Output script types. @@ -292,7 +292,7 @@ exports.types = { * @const {RevMap} */ -exports.typesByVal = util.revMap(exports.types); +exports.typesByVal = util.reverse(exports.types); /** * False stack return value. diff --git a/lib/utils/lock.js b/lib/utils/lock.js index 4ecd72f0..56c1f49e 100644 --- a/lib/utils/lock.js +++ b/lib/utils/lock.js @@ -27,7 +27,7 @@ function Lock(named) { this.busy = false; this.destroyed = false; - this.map = Object.create(null); + this.map = new Map(); this.current = null; this.unlocker = this.unlock.bind(this); @@ -54,12 +54,19 @@ Lock.create = function create(named) { */ Lock.prototype.has = function has(name) { + let count; + assert(this.named, 'Must use named jobs.'); if (this.current === name) 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) { + let count; + 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 (name) { - if (!this.map[name]) - this.map[name] = 0; - this.map[name]++; + let count = this.map.get(name); + if (!count) + count = 0; + this.map.set(name, count + 1); } return new Promise((resolve, reject) => { this.jobs.push(new Job(resolve, reject, name)); @@ -141,9 +157,12 @@ Lock.prototype.unlock = function unlock() { job = this.jobs.shift(); if (job.name) { - assert(this.map[job.name] > 0); - if (--this.map[job.name] === 0) - delete this.map[job.name]; + let count = this.map.get(job.name); + assert(count > 0); + if (--count === 0) + this.map.delete(job.name); + else + this.map.set(job.name, count); } this.busy = true; @@ -167,7 +186,7 @@ Lock.prototype.destroy = function destroy() { this.busy = false; this.jobs.length = 0; - this.map = Object.create(null); + this.map.clear(); this.current = null; for (let job of jobs) diff --git a/lib/utils/util.js b/lib/utils/util.js index 7795f878..d3d99b0a 100644 --- a/lib/utils/util.js +++ b/lib/utils/util.js @@ -642,50 +642,20 @@ util.hex32 = function hex32(num) { }; /** - * Convert an array to a map. - * @param {String[]} items - * @returns {Object} Map. + * Reverse an object's keys and values. + * @param {Object} obj + * @returns {Object} Reversed object. */ -util.toMap = function toMap(items) { - 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) { +util.reverse = function reverse(obj) { let reversed = {}; - for (let key of Object.keys(map)) - reversed[map[key]] = key; + for (let key of Object.keys(obj)) + reversed[obj[key]] = key; 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. * @param {Array} items diff --git a/lib/wallet/common.js b/lib/wallet/common.js index 71ee62db..f821b937 100644 --- a/lib/wallet/common.js +++ b/lib/wallet/common.js @@ -81,36 +81,38 @@ common.sortCoins = function sortCoins(coins) { */ common.sortDeps = function sortDeps(txs) { - let depMap = {}; - let count = {}; + let map = new Map(); + let depMap = new Map(); + let depCount = new Map(); let result = []; let top = []; - let map = {}; for (let tx of txs) { 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 hasDeps = false; - count[hash] = 0; + depCount.set(hash, 0); for (let input of tx.inputs) { let prev = input.prevout.hash; + let count; - if (!map[prev]) + if (!map.has(prev)) continue; - count[hash] += 1; + count = depCount.get(hash); + depCount.set(hash, count + 1); hasDeps = true; - if (!depMap[prev]) - depMap[prev] = []; + if (!depMap.has(prev)) + depMap.set(prev, []); - depMap[prev].push(tx); + depMap.get(prev).push(tx); } if (hasDeps) @@ -121,7 +123,7 @@ common.sortDeps = function sortDeps(txs) { for (let tx of top) { let hash = tx.hash('hex'); - let deps = depMap[hash]; + let deps = depMap.get(hash); result.push(tx); @@ -130,9 +132,12 @@ common.sortDeps = function sortDeps(txs) { for (let tx of deps) { let hash = tx.hash('hex'); + let count = depCount.get(hash); - if (--count[hash] === 0) + if (--count === 0) top.push(tx); + + depCount.set(hash, count); } } diff --git a/lib/wallet/records.js b/lib/wallet/records.js index a7270765..460ae1c7 100644 --- a/lib/wallet/records.js +++ b/lib/wallet/records.js @@ -238,7 +238,7 @@ function BlockMapRecord(height) { this.height = height != null ? height : -1; this.txs = []; - this.index = {}; + this.index = new Map(); } /** @@ -256,7 +256,7 @@ BlockMapRecord.prototype.fromRaw = function fromRaw(data) { let hash = br.readHash('hex'); let tx = TXMapRecord.fromReader(hash, br); this.txs.push(tx); - this.index[tx.hash] = tx; + this.index.set(tx.hash, tx); } return this; @@ -319,13 +319,13 @@ BlockMapRecord.prototype.toRaw = function toRaw() { */ BlockMapRecord.prototype.add = function add(hash, wid) { - let tx = this.index[hash]; + let tx = this.index.get(hash); if (!tx) { tx = new TXMapRecord(hash); tx.wids.push(wid); this.txs.push(tx); - this.index[tx.hash] = tx; + this.index.set(tx.hash, tx); return true; } @@ -340,7 +340,7 @@ BlockMapRecord.prototype.add = function add(hash, wid) { */ BlockMapRecord.prototype.remove = function remove(hash, wid) { - let tx = this.index[hash]; + let tx = this.index.get(hash); if (!tx) return false; @@ -351,7 +351,7 @@ BlockMapRecord.prototype.remove = function remove(hash, wid) { if (tx.wids.length === 0) { let result = util.binaryRemove(this.txs, tx, cmpid); assert(result); - delete this.index[tx.hash]; + this.index.delete(tx.hash); } return true; diff --git a/lib/wallet/rpc.js b/lib/wallet/rpc.js index f1a518b3..a9d094cd 100644 --- a/lib/wallet/rpc.js +++ b/lib/wallet/rpc.js @@ -458,8 +458,8 @@ RPC.prototype.getReceivedByAccount = async function getReceivedByAccount(args, h let name = valid.str(0); let minconf = valid.u32(0, 0); let height = this.wdb.state.height; + let filter = new Set(); let total = 0; - let filter = {}; let lastConf = -1; let paths, txs; @@ -474,7 +474,7 @@ RPC.prototype.getReceivedByAccount = async function getReceivedByAccount(args, h paths = await wallet.getPaths(name); for (let path of paths) - filter[path.hash] = true; + filter.add(path.hash); txs = await wallet.getHistory(name); @@ -489,7 +489,7 @@ RPC.prototype.getReceivedByAccount = async function getReceivedByAccount(args, h for (let output of wtx.tx.outputs) { let hash = output.getHash('hex'); - if (hash && filter[hash]) + if (hash && filter.has(hash)) total += output.value; } } @@ -903,21 +903,21 @@ RPC.prototype._listReceived = async function _listReceived(minconf, empty, watch let wallet = this.wallet; let paths = await wallet.getPaths(); let height = this.wdb.state.height; + let map = new Map(); let out = []; let result = []; - let map = {}; let txs; for (let path of paths) { let addr = path.toAddress(); - map[path.hash] = { + map.set(path.hash, { involvesWatchonly: wallet.watchOnly, address: addr.toString(this.network), account: path.name, amount: 0, confirmations: -1, label: '', - }; + }); } txs = await wallet.getHistory(); @@ -936,7 +936,7 @@ RPC.prototype._listReceived = async function _listReceived(minconf, empty, watch continue; hash = addr.getHash('hex'); - entry = map[hash]; + entry = map.get(hash); if (entry) { 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)) { - let entry = map[key]; + for (let entry of map.values()) out.push(entry); - } if (account) { - let map = {}; + let map = new Map(); for (let entry of out) { - let item = map[entry.account]; + let item = map.get(entry.account); if (!item) { - map[entry.account] = entry; + map.set(entry.account, entry); entry.address = undefined; continue; } @@ -967,10 +965,8 @@ RPC.prototype._listReceived = async function _listReceived(minconf, empty, watch out = []; - for (let key of Object.keys(map)) { - let entry = map[key]; + for (let entry of map.values()) out.push(entry); - } } for (let entry of out) { @@ -1158,8 +1154,8 @@ RPC.prototype.listUnspent = async function listUnspent(args, help) { let maxDepth = valid.u32(1, 9999999); let addrs = valid.array(2); let height = this.wdb.state.height; + let map = new Set(); let out = []; - let map = {}; let coins; if (help || args.length > 3) { @@ -1173,10 +1169,10 @@ RPC.prototype.listUnspent = async function listUnspent(args, help) { let addr = valid.str(i, ''); let hash = parseHash(addr, this.network); - if (map[hash]) + if (map.has(hash)) 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'); if (addrs) { - if (!hash || !map[hash]) + if (!hash || !map.has(hash)) continue; } @@ -1319,8 +1315,8 @@ RPC.prototype.sendMany = async function sendMany(args, help) { let sendTo = valid.obj(1); let minconf = valid.u32(2, 1); let subtractFee = valid.bool(4, false); + let uniq = new Set(); let outputs = []; - let uniq = {}; let options, tx; if (help || args.length < 2 || args.length > 5) { @@ -1346,10 +1342,10 @@ RPC.prototype.sendMany = async function sendMany(args, help) { if (value == null) throw new RPCError(errs.INVALID_PARAMETER, 'Invalid parameter.'); - if (uniq[hash]) + if (uniq.has(hash)) throw new RPCError(errs.INVALID_PARAMETER, 'Invalid parameter.'); - uniq[hash] = true; + uniq.add(hash); output = new Output(); output.value = value; diff --git a/lib/wallet/txdb.js b/lib/wallet/txdb.js index 8b15fbde..aef5f0bc 100644 --- a/lib/wallet/txdb.js +++ b/lib/wallet/txdb.js @@ -3070,7 +3070,7 @@ function BlockRecord(hash, height, ts) { this.height = height != null ? height : -1; this.ts = ts || 0; this.hashes = []; - this.index = {}; + this.index = new Set(); } /** @@ -3080,10 +3080,10 @@ function BlockRecord(hash, height, ts) { */ BlockRecord.prototype.add = function add(hash) { - if (this.index[hash]) + if (this.index.has(hash)) return false; - this.index[hash] = true; + this.index.add(hash); this.hashes.push(hash); return true; @@ -3098,10 +3098,10 @@ BlockRecord.prototype.add = function add(hash) { BlockRecord.prototype.remove = function remove(hash) { let index; - if (!this.index[hash]) + if (!this.index.has(hash)) return false; - delete this.index[hash]; + this.index.delete(hash); // Fast case 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++) { let hash = br.readHash('hex'); - this.index[hash] = true; + this.index.add(hash); this.hashes.push(hash); } diff --git a/lib/wallet/wallet.js b/lib/wallet/wallet.js index 6282d2d7..d29ca615 100644 --- a/lib/wallet/wallet.js +++ b/lib/wallet/wallet.js @@ -1956,8 +1956,8 @@ Wallet.prototype._setLookahead = async function setLookahead(acct, lookahead) { */ Wallet.prototype.syncOutputDepth = async function syncOutputDepth(details) { + let accounts = new Map(); let derived = []; - let accounts = {}; if (!details) return derived; @@ -1971,15 +1971,13 @@ Wallet.prototype.syncOutputDepth = async function syncOutputDepth(details) { if (path.index === -1) continue; - if (!accounts[path.account]) - accounts[path.account] = []; + if (!accounts.has(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) { + for (let paths of accounts.values()) { let acct = paths[0].account; let receive = -1; let change = -1; diff --git a/migrate/walletdb3to4.js b/migrate/walletdb3to4.js index 005db2c0..664241ac 100644 --- a/migrate/walletdb3to4.js +++ b/migrate/walletdb3to4.js @@ -68,7 +68,7 @@ async function updateTXDB() { batch.del(key); } - txs = util.values(txs); + txs = getValues(txs); await batch.write(); await db.close(); @@ -129,6 +129,15 @@ function fromExtended(data, saveCoins) { return tx; } +function getValues(map) { + let items = []; + + for (let key of Object.keys(map)) + items.push(map[key]); + + return items; +} + (async () => { await db.open(); batch = db.batch(); diff --git a/test/bip70-test.js b/test/bip70-test.js index f5fa1166..40a947a9 100644 --- a/test/bip70-test.js +++ b/test/bip70-test.js @@ -19,7 +19,7 @@ tests.ca = { }; x509.allowUntrusted = true; -x509.trusted = {}; +x509.trusted.clear(); describe('BIP70', function() { function testRequest(data) { diff --git a/test/util/memwallet.js b/test/util/memwallet.js index 939f4663..2388f9dc 100644 --- a/test/util/memwallet.js +++ b/test/util/memwallet.js @@ -29,10 +29,10 @@ function MemWallet(options) { this.changeDepth = 1; this.receive = null; this.change = null; - this.map = {}; - this.coins = {}; - this.spent = {}; - this.paths = {}; + this.map = new Set(); + this.coins = new Map(); + this.spent = new Map(); + this.paths = new Map(); this.balance = 0; this.txs = 0; this.filter = Bloom.fromRate(1000000, 0.001, -1); @@ -105,7 +105,7 @@ MemWallet.prototype.createReceive = function createReceive() { let key = this.deriveReceive(index); let hash = key.getHash('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; return key; }; @@ -115,7 +115,7 @@ MemWallet.prototype.createChange = function createChange() { let key = this.deriveChange(index); let hash = key.getHash('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; return key; }; @@ -145,22 +145,22 @@ MemWallet.prototype.deriveKey = function deriveKey(branch, index) { }; MemWallet.prototype.getKey = function getKey(hash) { - let path = this.paths[hash]; + let path = this.paths.get(hash); if (!path) return; return this.derivePath(path); }; MemWallet.prototype.getPath = function getPath(hash) { - return this.paths[hash]; + return this.paths.get(hash); }; MemWallet.prototype.getCoin = function getCoin(key) { - return this.coins[key]; + return this.coins.get(key); }; MemWallet.prototype.getUndo = function getUndo(key) { - return this.spent[key]; + return this.spent.get(key); }; MemWallet.prototype.addCoin = function addCoin(coin) { @@ -169,22 +169,22 @@ MemWallet.prototype.addCoin = function addCoin(coin) { 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; }; MemWallet.prototype.removeCoin = function removeCoin(key) { - let coin = this.coins[key]; + let coin = this.coins.get(key); if (!coin) return; - this.spent[key] = coin; + this.spent.set(key, coin); this.balance -= coin.value; - delete this.coins[key]; + this.coins.delete(key); }; MemWallet.prototype.getAddress = function getAddress() { @@ -200,7 +200,12 @@ MemWallet.prototype.getChange = function getChange() { }; 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) { @@ -245,7 +250,7 @@ MemWallet.prototype.addTX = function addTX(tx, height) { if (height == null) height = -1; - if (this.map[hash]) + if (this.map.has(hash)) return true; for (i = 0; i < tx.inputs.length; i++) { @@ -282,7 +287,7 @@ MemWallet.prototype.addTX = function addTX(tx, height) { if (result) { this.txs++; - this.map[hash] = true; + this.map.add(hash); } return result; @@ -293,7 +298,7 @@ MemWallet.prototype.removeTX = function removeTX(tx, height) { let result = false; let i, op, coin, input; - if (!this.map[hash]) + if (!this.map.has(hash)) return false; for (i = 0; i < tx.outputs.length; i++) { @@ -324,7 +329,7 @@ MemWallet.prototype.removeTX = function removeTX(tx, height) { if (result) this.txs--; - delete this.map[hash]; + this.map.delete(hash); return result; };