diff --git a/browser/index.js b/browser/index.js index 21e964d7..66863e58 100644 --- a/browser/index.js +++ b/browser/index.js @@ -222,6 +222,10 @@ function formatWallet(wallet) { }); } +bcoin.set({ + useWorkers: true +}); + node = new bcoin.fullnode({ hash: true, query: true, diff --git a/lib/bcoin.js b/lib/bcoin.js index d64184c7..ad0bfbeb 100644 --- a/lib/bcoin.js +++ b/lib/bcoin.js @@ -23,12 +23,13 @@ var util = require('./utils/util'); var global = util.global; /* - * Expose bcoin globally in the - * browser. Necessary for workers. + * Expose bcoin globally in the browser. */ -if (util.isBrowser) +if (typeof window !== 'undefined' + || typeof self !== 'undefined') { global.bcoin = env; +} /* * Expose diff --git a/lib/node/config.js b/lib/node/config.js index 796f050e..fdc01caf 100644 --- a/lib/node/config.js +++ b/lib/node/config.js @@ -711,9 +711,13 @@ Config.prototype.parseArg = function parseArg(argv) { if (!argv || typeof argv !== 'object') argv = process.argv; + assert(Array.isArray(argv)); + for (i = 2; i < argv.length; i++) { arg = argv[i]; + assert(typeof arg === 'string'); + if (arg.indexOf('--') === 0) { // e.g. --opt arg = arg.split('='); @@ -794,6 +798,8 @@ Config.prototype.parseEnv = function parseEnv(env) { if (!env || typeof env !== 'object') env = process.env; + assert(env && typeof env === 'object'); + keys = Object.keys(env); for (i = 0; i < keys.length; i++) { @@ -802,6 +808,8 @@ Config.prototype.parseEnv = function parseEnv(env) { if (key.indexOf(prefix) !== 0) continue; + assert(typeof env[key] === 'string'); + value = env[key].trim(); key = key.substring(prefix.length); @@ -829,10 +837,13 @@ Config.prototype.parseEnv = function parseEnv(env) { Config.prototype.parseQuery = function parseQuery(query) { if (typeof query !== 'string') { - if (!util.isBrowser || !global.location) + if (!global.location) return {}; - query = global.location.search || ''; + query = global.location.search; + + if (typeof query !== 'string') + return {}; } return this.parseForm(query, this.query); @@ -846,10 +857,13 @@ Config.prototype.parseQuery = function parseQuery(query) { Config.prototype.parseHash = function parseHash(hash) { if (typeof hash !== 'string') { - if (!util.isBrowser || !global.location) + if (!global.location) return {}; - hash = global.location.hash || ''; + hash = global.location.hash; + + if (typeof hash !== 'string') + return {}; } return this.parseForm(hash, this.hash); diff --git a/lib/node/logger.js b/lib/node/logger.js index 7a011aa7..ffc89659 100644 --- a/lib/node/logger.js +++ b/lib/node/logger.js @@ -550,7 +550,7 @@ Logger.prototype.writeConsole = function writeConsole(level, module, args) { if (!this.console) return; - if (util.isBrowser) { + if (!process.stdout) { msg += '[' + name + '] '; if (module) @@ -639,7 +639,7 @@ Logger.prototype.logError = function logError(level, module, err) { if (this.closed) return; - if (util.isBrowser && this.console) { + if (fs.unsupported && this.console) { if (level <= Logger.levels.WARNING) console.error(err); } diff --git a/lib/utils/encoding.js b/lib/utils/encoding.js index f0d6c64c..4eef2162 100644 --- a/lib/utils/encoding.js +++ b/lib/utils/encoding.js @@ -14,20 +14,6 @@ var BN = require('bn.js'); var encoding = exports; -/** - * UINT32_MAX - * @const {BN} - */ - -encoding.U32_MAX = new BN(0xffffffff); - -/** - * UINT64_MAX - * @const {BN} - */ - -encoding.U64_MAX = new BN('ffffffffffffffff', 'hex'); - /** * Max safe integer (53 bits). * @const {Number} @@ -36,15 +22,6 @@ encoding.U64_MAX = new BN('ffffffffffffffff', 'hex'); encoding.MAX_SAFE_INTEGER = 0x1fffffffffffff; -/** - * Max 52 bit integer (safe for additions). - * `(MAX_SAFE_INTEGER - 1) / 2` - * @const {Number} - * @default - */ - -encoding.MAX_SAFE_ADDITION = 0xfffffffffffff; - /** * An empty buffer. * @const {Buffer} @@ -536,13 +513,14 @@ encoding.read64BEBN = function read64BEBN(data, off) { */ encoding._write64BN = function _write64BN(dst, num, off, be) { + var bits = num.bitLength(); var i; - if (num.bitLength() <= 53) + if (bits <= 53) return encoding._write64(dst, num.toNumber(), off, be); - if (num.bitLength() > 64) - num = num.uand(encoding.U64_MAX); + if (bits > 64) + num = num.maskn(64); if (num.isNeg()) num = num.neg().inotn(64).iaddn(1); diff --git a/lib/utils/util.js b/lib/utils/util.js index 52029453..e98ff10b 100644 --- a/lib/utils/util.js +++ b/lib/utils/util.js @@ -10,7 +10,6 @@ var assert = require('assert'); var nodeUtil = require('util'); var os = require('os'); -var Number, Math, Date; /** * @exports utils/util @@ -41,23 +40,6 @@ util.global = (function() { assert(false, 'No global defined.'); })(); -/* - * Globals - */ - -Number = util.global.Number; -Math = util.global.Math; -Date = util.global.Date; - -/** - * Whether we're in a browser or not. - * @const {Boolean} - */ - -util.isBrowser = - (typeof process !== 'undefined' && process.browser) - || typeof window !== 'undefined'; - /** * The home directory. * @const {String} @@ -123,7 +105,7 @@ util.isBase58 = function isBase58(obj) { util.hrtime = function hrtime(time) { var now, ms, sec, elapsed; - if (util.isBrowser) { + if (!process.hrtime) { now = util.ms(); if (time) { time = time[0] * 1000 + time[1] / 1e6; @@ -218,15 +200,6 @@ if (Object.assign) util.MAX_SAFE_INTEGER = 0x1fffffffffffff; -/** - * Max 52 bit integer (safe for additions). - * `(MAX_SAFE_INTEGER - 1) / 2` - * @const {Number} - * @default - */ - -util.MAX_SAFE_ADDITION = 0xfffffffffffff; - /** * Test whether a number is below MAX_SAFE_INTEGER. * @param {Number} value @@ -234,9 +207,7 @@ util.MAX_SAFE_ADDITION = 0xfffffffffffff; */ util.isSafeInteger = function isSafeInteger(value) { - if (Number.isSafeInteger) - return Number.isSafeInteger(value); - return Math.abs(value) <= util.MAX_SAFE_INTEGER; + return value >= -0x1fffffffffffff && value <= 0x1fffffffffffff; }; /** @@ -269,7 +240,7 @@ util.isInt = function isInt(value) { */ util.isInt8 = function isInt8(value) { - return util.isInt(value) && Math.abs(value) <= 0x7f; + return util.isInt(value) && value >= -0x80 && value <= 0x7f; }; /** @@ -289,7 +260,7 @@ util.isUInt8 = function isUInt8(value) { */ util.isInt32 = function isInt32(value) { - return util.isInt(value) && Math.abs(value) <= 0x7fffffff; + return util.isInt(value) && value >= -0x80000000 && value <= 0x7fffffff; }; /** @@ -409,7 +380,7 @@ util.log = function log() { for (i = 0; i < args.length; i++) args[i] = arguments[i]; - if (util.isBrowser) { + if (!process.stdout) { msg = typeof args[0] !== 'object' ? util.format(args, false) : args[0]; @@ -434,7 +405,7 @@ util.error = function error() { for (i = 0; i < args.length; i++) args[i] = arguments[i]; - if (util.isBrowser) { + if (!process.stderr) { msg = typeof args[0] !== 'object' ? util.format(args, false) : args[0]; @@ -563,17 +534,6 @@ util.strcmp = function strcmp(a, b) { return 0; }; -/** - * Buffer comparator (memcmp + length comparison). - * @param {Buffer} a - * @param {Buffer} b - * @returns {Number} -1, 1, or 0. - */ - -util.cmp = function cmp(a, b) { - return a.compare(b); -}; - /** * Convert bytes to mb. * @param {Number} size diff --git a/lib/utils/validator.js b/lib/utils/validator.js index 2fb1bb34..a5a2922f 100644 --- a/lib/utils/validator.js +++ b/lib/utils/validator.js @@ -1,3 +1,9 @@ +/*! + * validator.js - validator for bcoin + * Copyright (c) 2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + 'use strict'; var assert = require('assert'); @@ -246,7 +252,7 @@ Validator.prototype.i32 = function i32(key, fallback) { if (value === null) return fallback; - if (value % 1 !== 0 || Math.abs(value) > 0x7fffffff) + if (value % 1 !== 0 || value < -0x80000000 || value > 0x7fffffff) throw new ValidationError(fmt(key) + ' must be an int32.'); return value; @@ -357,8 +363,10 @@ Validator.prototype.hash = function hash(key, fallback) { if (typeof value !== 'string') { if (!Buffer.isBuffer(value)) throw new ValidationError(fmt(key) + ' must be a hash.'); + if (value.length !== 32) throw new ValidationError(fmt(key) + ' must be a hash.'); + return value.toString('hex'); } diff --git a/lib/workers/master.js b/lib/workers/master.js index 3c9e7277..4792ea88 100644 --- a/lib/workers/master.js +++ b/lib/workers/master.js @@ -16,6 +16,8 @@ var Parser = require('./parser-client'); var Framer = require('./framer'); var packets = require('./packets'); var global = util.global; +var HAS_WORKERS = typeof global.postMessage === 'function'; +var HAS_CP = !!(process.stdin && process.stdout && process.stderr); var server; /** @@ -61,12 +63,14 @@ Master.prototype._init = function _init() { self.emit('packet', packet); }); - if (util.isBrowser) { + if (HAS_WORKERS) { // Web workers this._initWebWorkers(); - } else { + } else if (HAS_CP) { // Child process + pipes this._initChildProcess(); + } else { + throw new Error('Workers not available.'); } }; @@ -135,7 +139,7 @@ Master.prototype.set = function set(network) { */ Master.prototype.write = function write(data) { - if (util.isBrowser) { + if (HAS_WORKERS) { if (global.postMessage.length === 2) { data.__proto__ = Uint8Array.prototype; global.postMessage({ buf: data }, [data]); @@ -179,7 +183,7 @@ Master.prototype.sendEvent = function sendEvent() { */ Master.prototype.destroy = function destroy() { - if (util.isBrowser) + if (HAS_WORKERS) return global.close(); return process.exit(0); }; @@ -268,7 +272,7 @@ Master.prototype.handlePacket = function handlePacket(packet) { server = new Master(); -if (util.isBrowser) +if (HAS_WORKERS) global.master = server; module.exports = server; diff --git a/lib/workers/workerpool.js b/lib/workers/workerpool.js index 89fafc62..e0ec2915 100644 --- a/lib/workers/workerpool.js +++ b/lib/workers/workerpool.js @@ -13,12 +13,14 @@ var os = require('os'); var cp = require('child_process'); var util = require('../utils/util'); var co = require('../utils/co'); -var global = util.global; var Network = require('../protocol/network'); var jobs = require('./jobs'); var Parser = require('./parser'); var Framer = require('./framer'); var packets = require('./packets'); +var global = util.global; +var HAS_WORKERS = typeof global.Worker === 'function'; +var HAS_CP = typeof cp.spawn === 'function'; /** * A worker pool. @@ -57,12 +59,7 @@ util.inherits(WorkerPool, EventEmitter); * @const {Boolean} */ -WorkerPool.support = true; - -if (util.isBrowser) { - WorkerPool.support = typeof global.Worker === 'function' - || typeof global.postMessage === 'function'; -} +WorkerPool.support = HAS_WORKERS || HAS_CP; /** * Number of CPUs/cores available. @@ -104,7 +101,7 @@ WorkerPool.bound = false; */ WorkerPool.bindExit = function bindExit() { - if (util.isBrowser) + if (!HAS_CP) return; if (WorkerPool.bound) @@ -483,12 +480,14 @@ Worker.prototype._init = function _init() { self.emit('packet', packet); }); - if (util.isBrowser) { + if (HAS_WORKERS) { // Web workers this._initWebWorkers(); - } else { + } else if (HAS_CP) { // Child process + pipes this._initChildProcess(); + } else { + throw new Error('Workers not available.'); } this._bind(); @@ -651,7 +650,7 @@ Worker.prototype.handlePacket = function handlePacket(packet) { */ Worker.prototype.write = function write(data) { - if (util.isBrowser) { + if (HAS_WORKERS) { if (this.child.postMessage.length === 2) { data.__proto__ = Uint8Array.prototype; this.child.postMessage({ buf: data }, [data]); @@ -695,7 +694,7 @@ Worker.prototype.sendEvent = function sendEvent() { */ Worker.prototype.destroy = function destroy() { - if (util.isBrowser) { + if (HAS_WORKERS) { this.child.terminate(); this.emit('exit', -1, 'SIGTERM'); return; @@ -884,7 +883,6 @@ function getCores() { */ exports.pool = new WorkerPool(); -exports.pool.enabled = true; exports.set = function set(options) { this.pool.set({ @@ -895,7 +893,7 @@ exports.set = function set(options) { }; exports.set({ - useWorkers: +process.env.BCOIN_USE_WORKERS !== 0, + useWorkers: HAS_CP && +process.env.BCOIN_USE_WORKERS !== 0, maxWorkers: +process.env.BCOIN_MAX_WORKERS, workerTimeout: +process.env.BCOIN_WORKER_TIMEOUT }); diff --git a/test/tx-test.js b/test/tx-test.js index 099d457b..cc99403a 100644 --- a/test/tx-test.js +++ b/test/tx-test.js @@ -29,6 +29,9 @@ var tx4 = parseTX('data/tx4.hex'); var wtx = parseTX('data/wtx.hex'); var coolest = parseTX('data/coolest-tx-ever-sent.hex'); +var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER; +var MAX_SAFE_ADDITION = 0xfffffffffffff; + function clearCache(tx, noCache) { if (!noCache) { assert.equal(tx.hash('hex'), tx.clone().hash('hex')); @@ -554,7 +557,7 @@ describe('TX', function() { var tx = new TX({ version: 1, flag: 1, - inputs: [createInput(util.MAX_SAFE_INTEGER, view)], + inputs: [createInput(MAX_SAFE_INTEGER, view)], outputs: [{ script: [], value: consensus.MAX_MONEY @@ -573,7 +576,7 @@ describe('TX', function() { inputs: [createInput(consensus.MAX_MONEY, view)], outputs: [{ script: [], - value: util.MAX_SAFE_INTEGER + value: MAX_SAFE_INTEGER }], locktime: 0 }); @@ -586,7 +589,7 @@ describe('TX', function() { var tx = new TX({ version: 1, flag: 1, - inputs: [createInput(util.MAX_SAFE_INTEGER, view)], + inputs: [createInput(MAX_SAFE_INTEGER, view)], outputs: [{ script: [], value: 0 @@ -597,7 +600,7 @@ describe('TX', function() { assert.ok(!tx.checkInputs(view, 0)); }); - [util.MAX_SAFE_ADDITION, util.MAX_SAFE_INTEGER].forEach(function(MAX) { + [MAX_SAFE_ADDITION, MAX_SAFE_INTEGER].forEach(function(MAX) { it('should fail on >53 bit values from multiple', function() { var view = new CoinView(); var tx = new TX({