You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

2500 lines
52 KiB

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: bcoin/utils.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: bcoin/utils.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/*!
* utils.js - utils for bcoin
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/indutny/bcoin
*/
/* global gc */
/**
* @exports utils
*/
var utils = exports;
var assert = require('assert');
var bn = require('bn.js');
var util = require('util');
var crypto, supersha, hash, aes;
/**
* Whether we're in a browser or not.
* @const {Boolean}
*/
utils.isBrowser =
(typeof process !== 'undefined' &amp;&amp; process.browser)
|| typeof window !== 'undefined';
if (!utils.isBrowser) {
crypto = require('cry' + 'pto');
try {
supersha = require('super' + 'sha');
} catch (e) {
;
}
} else {
hash = require('hash.js');
aes = require('./aes');
}
/**
* The home directory.
* @const {String}
*/
try {
utils.HOME = require('o' + 's').homedir();
} catch (e) {
utils.HOME = process.env.HOME
|| process.env.USERPROFILE
|| process.env.HOMEPATH
|| '/';
}
/**
* Global NOP function.
* @type function
* @static
* @method
*/
utils.nop = function() {};
/**
* Garbage collector for `--expose-gc`.
* @type function
* @static
* @method
*/
utils.gc = !utils.isBrowser &amp;&amp; typeof gc === 'function' ? gc : utils.nop;
/**
* Clone a buffer.
* @param {Buffer} data
* @returns {Buffer}
*/
utils.copy = function copy(data) {
var clone = new Buffer(data.length);
data.copy(clone, 0, 0, data.length);
return clone;
};
/*
* Base58
*/
var base58 = ''
+ '123456789'
+ 'ABCDEFGHJKLMNPQRSTUVWXYZ'
+ 'abcdefghijkmnopqrstuvwxyz';
var unbase58 = {};
for (var i = 0; i &lt; base58.length; i++)
unbase58[base58[i]] = i;
/**
* Encode a base58 string.
* @see https://github.com/bitcoin/bitcoin/blob/master/src/base58.cpp
* @param {Buffer} data
* @returns {Base58String}
*/
utils.toBase58 = function toBase58(data) {
var zeroes = 0;
var length = 0;
var str = '';
var i, b58, carry, j, k;
for (i = 0; i &lt; data.length; i++) {
if (data[i] !== 0)
break;
zeroes++;
}
b58 = new Buffer(((data.length * 138 / 100) | 0) + 1);
b58.fill(0);
for (; i &lt; data.length; i++) {
carry = data[i];
j = 0;
for (k = b58.length - 1; k >= 0; k--, j++) {
if (carry === 0 &amp;&amp; j >= length)
break;
carry += 256 * b58[k];
b58[k] = carry % 58;
carry = carry / 58 | 0;
}
assert(carry === 0);
length = j;
}
i = b58.length - length;
while (i &lt; b58.length &amp;&amp; b58[i] === 0)
i++;
for (j = 0; j &lt; zeroes; j++)
str += '1';
for (; i &lt; b58.length; i++)
str += base58[b58[i]];
return str;
};
/**
* Decode a base58 string.
* @see https://github.com/bitcoin/bitcoin/blob/master/src/base58.cpp
* @param {Base58String} str
* @returns {Buffer}
* @throws on non-base58 character.
*/
utils.fromBase58 = function fromBase58(str) {
var zeroes = 0;
var i = 0;
var b256, ch, carry, j, out;
for (i = 0; i &lt; str.length; i++) {
if (str[i] !== '1')
break;
zeroes++;
}
b256 = new Buffer(((str.length * 733) / 1000 | 0) + 1);
b256.fill(0);
for (; i &lt; str.length; i++) {
ch = unbase58[str[i]];
if (ch == null)
throw new Error('Non-base58 character.');
carry = ch;
for (j = b256.length - 1; j >= 0; j--) {
carry += 58 * b256[j];
b256[j] = carry % 256;
carry = carry / 256 | 0;
}
assert(carry === 0);
}
i = 0;
while (i &lt; b256.length &amp;&amp; b256[i] === 0)
i++;
out = new Buffer(zeroes + (b256.length - i));
for (j = 0; j &lt; zeroes; j++)
out[j] = 0;
while (i &lt; b256.length)
out[j++] = b256[i++];
return out;
};
/**
* Test whether a string is base58 (note that you
* may get a false positive on a hex string).
* @param {String?} obj
* @returns {Boolean}
*/
utils.isBase58 = function isBase58(obj) {
return typeof obj === 'string' &amp;&amp; /^[1-9a-zA-Z]+$/.test(obj);
};
/**
* Hash with chosen algorithm.
* @param {String} alg
* @param {Buffer|String} data
* @param {String?} enc - Any buffer-supported encoding.
* @returns {Buffer}
*/
utils.hash = function _hash(alg, data, enc) {
if (!crypto)
return new Buffer(hash[alg]().update(data, enc).digest());
return crypto.createHash(alg).update(data, enc).digest();
};
/**
* Hash with ripemd160.
* @param {Buffer|String} data
* @param {String?} enc - Any buffer-supported encoding.
* @returns {Buffer}
*/
utils.ripemd160 = function ripemd160(data, enc) {
return utils.hash('ripemd160', data, enc);
};
/**
* Hash with sha1.
* @param {Buffer|String} data
* @param {String?} enc - Any buffer-supported encoding.
* @returns {Buffer}
*/
utils.sha1 = function sha1(data, enc) {
return utils.hash('sha1', data, enc);
};
/**
* Hash with sha256.
* @param {Buffer|String} data
* @param {String?} enc - Any buffer-supported encoding.
* @returns {Buffer}
*/
utils.sha256 = function sha256(data, enc) {
if (supersha) {
if (!Buffer.isBuffer(data))
data = new Buffer(data, enc);
return supersha.sha256(data);
}
return utils.hash('sha256', data, enc);
};
/**
* Hash with sha256 and ripemd160 (OP_HASH160).
* @param {Buffer|String} data
* @param {String?} enc - Any buffer-supported encoding.
* @returns {Buffer}
*/
utils.ripesha = function ripesha(data, enc) {
return utils.ripemd160(utils.sha256(data, enc));
};
/**
* Hash with sha256 twice (OP_HASH256).
* @param {Buffer|String} data
* @param {String?} enc - Any buffer-supported encoding.
* @returns {Buffer}
*/
utils.dsha256 = function dsha256(data, enc) {
if (supersha) {
if (!Buffer.isBuffer(data))
data = new Buffer(data, enc);
return supersha.dsha256(data);
}
return utils.sha256(utils.sha256(data, enc));
};
/**
* Create a sha256 checksum (common in bitcoin).
* @param {Buffer|String} data
* @param {String?} enc - Any buffer-supported encoding.
* @returns {Buffer}
*/
utils.checksum = function checksum(data, enc) {
return utils.dsha256(data, enc).slice(0, 4);
};
/**
* Create an HMAC.
* @param {String} alg
* @param {Buffer} data
* @param {Buffer} salt
* @returns {Buffer} HMAC
*/
utils.hmac = function hmac(alg, data, salt) {
var hmac;
if (!crypto) {
hmac = hash.hmac(hash[alg], salt);
return new Buffer(hmac.update(data).digest());
}
hmac = crypto.createHmac(alg, salt);
return hmac.update(data).digest();
};
/**
* Perform key stretching using PBKDF2.
* @param {Buffer} key
* @param {Buffer} salt
* @param {Number} iterations
* @param {Number} dkLen - Output size.
* @param {String?} alg
*/
/*!
* PBKDF2
* Credit to: https://github.com/stayradiated/pbkdf2-sha512
* Copyright (c) 2010-2011 Intalio Pte, All Rights Reserved
* Copyright (c) 2014, JP Richardson
*/
utils.pbkdf2 = function pbkdf2(key, salt, iterations, dkLen, alg) {
var hLen, DK, U, T, block, l, r;
var i, j, k, destPos, len;
if (typeof key === 'string')
key = new Buffer(key, 'utf8');
if (typeof salt === 'string')
salt = new Buffer(salt, 'utf8');
if (!alg)
alg = 'sha512';
if (crypto &amp;&amp; crypto.pbkdf2Sync)
return crypto.pbkdf2Sync(key, salt, iterations, dkLen, alg);
if (alg === 'sha512')
hLen = 64;
else if (alg === 'sha256')
hLen = 32;
else if (alg === 'sha1' || alg === 'ripemd160')
hLen = 20;
else if (alg === 'md5')
hLen = 16;
assert(dkLen &lt;= 0xffffffff * hLen, 'Requested key length too long');
DK = new Buffer(dkLen);
T = new Buffer(hLen);
block = new Buffer(salt.length + 4);
l = Math.ceil(dkLen / hLen);
r = dkLen - (l - 1) * hLen;
salt.copy(block, 0, 0, salt.length);
for (i = 1; i &lt;= l; i++) {
block[salt.length + 0] = (i >>> 24) &amp; 0xff;
block[salt.length + 1] = (i >>> 16) &amp; 0xff;
block[salt.length + 2] = (i >>> 8) &amp; 0xff;
block[salt.length + 3] = (i >>> 0) &amp; 0xff;
U = utils.hmac(alg, block, key);
U.copy(T, 0, 0, hLen);
for (j = 1; j &lt; iterations; j++) {
U = utils.hmac(alg, U, key);
for (k = 0; k &lt; hLen; k++)
T[k] ^= U[k];
}
destPos = (i - 1) * hLen;
len = i === l ? r : hLen;
T.copy(DK, destPos, 0, len);
}
return DK;
};
/**
* Encrypt with aes-256-cbc.
* @param {Buffer|String} data
* @param {Buffer|String} passphrase
* @returns {Buffer}
*/
utils.encrypt = function encrypt(data, passphrase) {
var key, cipher, out;
assert(passphrase, 'No passphrase.');
if (typeof data === 'string')
data = new Buffer(data, 'utf8');
if (typeof passphrase === 'string')
passphrase = new Buffer(passphrase, 'utf8');
key = utils.pbkdf2key(passphrase, 2048, 32, 16);
if (!crypto) {
out = aes.cbc.encrypt(data, key.key, key.iv);
key.key.fill(0);
key.iv.fill(0);
return out;
}
cipher = crypto.createCipheriv('aes-256-cbc', key.key, key.iv);
out = Buffer.concat([
cipher.update(data),
cipher.final()
]);
key.key.fill(0);
key.iv.fill(0);
return out;
};
/**
* Decrypt from aes-256-cbc.
* @param {Buffer|String} data
* @param {Buffer|String} passphrase
* @returns {Buffer}
*/
utils.decrypt = function decrypt(data, passphrase) {
var key, decipher, out;
assert(passphrase, 'No passphrase.');
if (typeof data === 'string')
data = new Buffer(data, 'hex');
if (typeof passphrase === 'string')
passphrase = new Buffer(passphrase, 'utf8');
key = utils.pbkdf2key(passphrase, 2048, 32, 16);
if (!crypto) {
out = aes.cbc.decrypt(data, key.key, key.iv);
key.key.fill(0);
key.iv.fill(0);
return out;
}
decipher = crypto.createDecipheriv('aes-256-cbc', key.key, key.iv);
out = Buffer.concat([
decipher.update(data),
decipher.final()
]);
key.key.fill(0);
key.iv.fill(0);
return out;
};
/**
* Generate a key and IV using pbkdf2.
* @param {Buffer|String} passphrase
* @param {(Buffer|String)?} salt
* @param {Number} iterations
* @param {Number} dkLen
* @param {Number} ivLen
* @param {String?} alg
* @returns {Buffer}
*/
utils.pbkdf2key = function pbkdf2key(passphrase, iterations, dkLen, ivLen, alg) {
var key = utils.pbkdf2(passphrase, '', iterations, dkLen + ivLen, alg);
return {
key: key.slice(0, dkLen),
iv: key.slice(dkLen, dkLen + ivLen)
};
};
/**
* Test whether a string is hex. Note that this
* _could_ yield a false positive on base58
* strings.
* @param {String?} obj
* @returns {Boolean}
*/
utils.isHex = function isHex(obj) {
return typeof obj === 'string'
&amp;&amp; /^[0-9a-f]+$/i.test(obj)
&amp;&amp; obj.length % 2 === 0;
};
/**
* Test whether two buffers are equal.
* @param {Buffer?} a
* @param {Buffer?} b
* @returns {Boolean}
*/
utils.equal = function equal(a, b) {
var i;
if (!Buffer.isBuffer(a))
return false;
if (!Buffer.isBuffer(b))
return false;
if (a.compare)
return a.compare(b) === 0;
if (a.length !== b.length)
return false;
for (i = 0; i &lt; a.length; i++) {
if (a[i] !== b[i])
return false;
}
return true;
};
/**
* Call `setImmediate`, `process.nextTick`,
* or `setInterval` depending.
* @name nextTick
* @function
* @param {Function} callback
*/
if (utils.isBrowser)
require('../../browser/setimmediate');
if (typeof setImmediate === 'function') {
utils.nextTick = setImmediate;
} else if (!utils.isBrowser) {
utils.nextTick = process.nextTick;
} else {
utils.nextTick = function nextTick(fn) {
setTimeout(fn, 1);
};
}
/**
* Wrap a function in a `nextTick`.
* @param {Function} callback
* @returns {Function} Asyncified function.
*/
utils.asyncify = function asyncify(callback) {
if (callback &amp;&amp; callback._asyncified)
return callback;
function asyncifyFn(err, result1, result2) {
if (!callback)
return;
utils.nextTick(function() {
callback(err, result1, result2);
});
}
asyncifyFn._asyncified = true;
if (callback)
asyncifyFn._once = callback._once;
return asyncifyFn;
};
/**
* Ensure a callback exists, return a NOP if not.
* @param {Function} callback
* @returns {Function}
*/
utils.ensure = function ensure(callback) {
if (!callback)
return utils.nop;
return callback;
};
/**
* Reverse a hex-string (used because of
* bitcoind's affinity for uint256le).
* @param {String} s - Hex string.
* @returns {String} Reversed hex string.
*/
utils.revHex = function revHex(s) {
var r = '';
var i = 0;
for (; i &lt; s.length; i += 2)
r = s.slice(i, i + 2) + r;
return r;
};
/**
* Shallow merge between multiple objects.
* @param {Object} target
* @param {...Object} args
* @returns {Object} target
*/
utils.merge = function merge(target) {
var args = Array.prototype.slice.call(arguments, 1);
args.forEach(function(obj) {
Object.keys(obj).forEach(function(key) {
target[key] = obj[key];
});
});
return target;
};
/**
* Assertion.
* @param {Boolean} value - Expression.
* @param {String?} message - Optional error message.
*/
utils.assert = function _assert(value, message) {
if (!value) {
throw new assert.AssertionError({
message: message,
actual: value,
expected: true,
operator: '==',
stackStartFunction: _assert
});
}
};
utils.merge(utils.assert, assert);
utils.assert.fatal = function fatal(value, message) {
var err;
if (!value) {
if (!message)
message = 'Assertion failed (fatal exception)';
err = new assert.AssertionError({
message: message,
actual: value,
expected: true,
operator: '==',
stackStartFunction: fatal
});
if (process.exit) {
console.error(err.stack + '');
process.exit(1);
} else {
throw err;
}
}
};
/**
* Safely convert satoshis to a BTC string.
* This function explicitly avoids any
* floating point arithmetic.
* @param {Amount} value - Satoshis.
* @returns {String} BTC string.
*/
utils.btc = function btc(value) {
var negative = false;
var hi, lo, result;
if (utils.isFloat(value))
return value;
assert(utils.isInt(value), 'Non-satoshi value for conversion.');
if (value &lt; 0) {
value = -value;
negative = true;
}
assert(value &lt;= utils.MAX_SAFE_INTEGER, 'Number exceeds 2^53-1.');
value = value.toString(10);
assert(value.length &lt;= 16, 'Number exceeds 2^53-1.');
while (value.length &lt; 9)
value = '0' + value;
hi = value.slice(0, -8);
lo = value.slice(-8);
lo = lo.replace(/0+$/, '');
if (lo.length === 0)
lo += '0';
result = hi + '.' + lo;
if (negative)
result = '-' + result;
return result;
};
/**
* Safely convert a BTC string to satoshis.
* This function explicitly avoids any
* floating point arithmetic. It also does
* extra validation to ensure the resulting
* Number will be 53 bits or less.
* @param {String} value - BTC
* @returns {Amount} Satoshis.
* @throws on parse error
*/
utils.satoshi = function satoshi(value) {
var negative = false;
var parts, hi, lo, result;
if (utils.isInt(value))
return value;
assert(utils.isFloat(value), 'Non-BTC value for conversion.');
if (value[0] === '-') {
negative = true;
value = value.substring(1);
}
parts = value.split('.');
assert(parts.length &lt;= 2, 'Bad decimal point.');
hi = parts[0] || '0';
lo = parts[1] || '0';
hi = hi.replace(/^0+/, '');
lo = lo.replace(/0+$/, '');
assert(hi.length &lt;= 8, 'Number exceeds 2^53-1.');
assert(lo.length &lt;= 8, 'Too many decimal places.');
if (hi.length === 0)
hi = '0';
while (lo.length &lt; 8)
lo += '0';
hi = parseInt(hi, 10);
lo = parseInt(lo, 10);
assert(hi &lt; 90071992 || (hi === 90071992 &amp;&amp; lo &lt;= 54740991),
'Number exceeds 2^53-1.');
result = hi * 100000000 + lo;
if (negative)
result = -result;
return result;
};
/**
* Test whether a number is both a Number and finite.
* @param {Number?} value
* @returns {Boolean}
*/
utils.isNumber = function isNumber(value) {
return typeof value === 'number' &amp;&amp; isFinite(value);
};
/**
* Test whether a string qualifies as a float.
* @param {String?} value
* @returns {Boolean}
*/
utils.isFloat = function isFloat(value) {
return typeof value === 'string'
&amp;&amp; /^-?(\d+)?(?:\.\d*)?$/.test(value)
&amp;&amp; value.length !== 0
&amp;&amp; value !== '-';
};
/**
* Test whether an object is a finite number and int.
* @param {Number?} value
* @returns {Boolean}
*/
utils.isInt = function isInt(value) {
return utils.isNumber(value) &amp;&amp; value % 1 === 0;
};
/**
* Test and validate a satoshi value (Number).
* @param {Number?} value
* @returns {Boolean}
*/
utils.isSatoshi = function isSatoshi(value) {
try {
utils.satoshi(value);
return true;
} catch (e) {
return false;
}
};
/**
* Test and validate a BTC string.
* @param {String?} value
* @returns {Boolean}
*/
utils.isBTC = function isBTC(value) {
try {
utils.btc(value);
return true;
} catch (e) {
return false;
}
};
/**
* util.inspect() with 20 levels of depth.
* @param {Object|String} obj
* @param {Boolean?} color
* @return {String}
*/
utils.inspectify = function inspectify(obj, color) {
return typeof obj !== 'string'
? util.inspect(obj, null, 20, color !== false)
: obj;
};
/**
* Format a string.
* @param {Array} args
* @param {Boolean?} color
* @return {String}
*/
utils.format = function format(args, color) {
color = color
? (process.stdout ? process.stdout.isTTY : false)
: false;
return typeof args[0] === 'object'
? utils.inspectify(args[0], color)
: util.format.apply(util, args);
};
/**
* Write a message to stdout (console in browser).
* @param {Object|String} obj
* @param {...String} args
*/
utils.print = function print() {
var args = Array.prototype.slice.call(arguments);
var msg;
if (utils.isBrowser) {
msg = typeof args[0] !== 'object'
? utils.format(args, false)
: args[0];
console.log(msg);
return;
}
msg = utils.format(args, true);
process.stdout.write(msg + '\n');
};
/**
* Write a message to stderr (console in browser).
* @param {Object|String} obj
* @param {...String} args
*/
utils.error = function error() {
var args = Array.prototype.slice.call(arguments);
var msg;
if (utils.isBrowser) {
msg = typeof args[0] !== 'object'
? utils.format(args, false)
: args[0];
console.log(msg);
return;
}
msg = utils.format(args, true);
process.stderr.write(msg + '\n');
};
/**
* Sort public keys lexicographically.
* @param {Buffer[]} keys
* @returns {Buffer[]} Sorted keys.
*/
utils.sortKeys = function sortKeys(keys) {
return keys.slice().sort(function(a, b) {
return utils.cmp(a, b);
});
};
/**
* Sort HD public keys lexicographically.
* @param {HDPublicKey[]} keys
* @returns {HDPublicKey[]} Sorted keys.
*/
utils.sortHDKeys = function sortHDKeys(keys) {
return keys.slice().sort(function(a, b) {
return utils.cmp(a.publicKey, b.publicKey);
});
};
/**
* Sort transactions by timestamp.
* @param {TX[]} txs
* @returns {TX[]} Sorted transactions.
*/
utils.sortTX = function sortTX(txs) {
return txs.slice().sort(function(a, b) {
a = a.ts || a.ps;
b = b.ts || b.ps;
return a - b;
});
};
/**
* Unique-ify an array of strings.
* @param {String[]} obj
* @returns {String[]}
*/
utils.uniq = function uniq(obj) {
var table = {};
var out = [];
var i = 0;
for (; i &lt; obj.length; i++) {
if (!table[obj[i]]) {
out.push(obj[i]);
table[obj[i]] = true;
}
}
return out;
};
/**
* Convert a compact number to a big number.
* Used for `block.bits` -> `target` conversion.
* @param {Number} compact
* @returns {BN}
*/
utils.fromCompact = function fromCompact(compact) {
var exponent = compact >>> 24;
var negative = (compact >>> 23) &amp; 1;
var mantissa = compact &amp; 0x7fffff;
var num;
if (compact === 0)
return new bn(0);
// Logic ported from btcd since
// the bitcoind code is a nightmare.
if (exponent &lt;= 3) {
mantissa >>>= 8 * (3 - exponent);
num = new bn(mantissa);
} else {
num = new bn(mantissa);
num.iushln(8 * (exponent - 3));
}
if (negative)
num.ineg();
return num;
};
/**
* Convert a big number to a compact number.
* Used for `target` -> `block.bits` conversion.
* @param {BN} num
* @returns {Number}
*/
utils.toCompact = function toCompact(num) {
var mantissa, exponent, compact;
if (num.cmpn(0) === 0)
return 0;
exponent = num.byteLength();
// Logic ported from btcd since
// the bitcoind code is a nightmare.
if (exponent &lt;= 3) {
mantissa = num.toNumber();
mantissa &lt;&lt;= 8 * (3 - exponent);
} else {
mantissa = num.ushrn(8 * (exponent - 3)).toNumber();
}
if (mantissa &amp; 0x800000) {
mantissa >>= 8;
exponent++;
}
compact = (exponent &lt;&lt; 24) | mantissa;
if (num.isNeg())
compact |= 0x800000;
compact >>>= 0;
return compact;
};
/**
* Test hash against a target.
* @param {Buffer|Hash} hash
* @param {BN|Number} target - Compact number or big number.
* @returns {Boolean} True if hash is less than target.
*/
utils.testTarget = function testTarget(hash, target) {
if (typeof hash === 'string')
hash = new Buffer(hash, 'hex');
if (typeof target === 'number')
target = utils.fromCompact(target);
return new bn(hash, 'le').cmp(target) &lt; 0;
};
/**
* Get current time in unix time (seconds).
* @returns {Number}
*/
utils.now = function now() {
return Math.floor(+new Date() / 1000);
};
/**
* Get current time in unix time (milliseconds).
* @returns {Number}
*/
utils.ms = function ms() {
return +new Date();
};
/**
* Create a Date ISO string from time in unix time (seconds).
* @param {Number?} ts - Seconds in unix time.
* @returns {String}
*/
utils.date = function date(ts) {
if (ts == null)
ts = utils.now();
return new Date(ts * 1000).toISOString().slice(0, -5) + 'Z';
};
/**
* Get unix seconds from a Date string.
* @param {String} date - Date ISO String.
* @returns {Number}
*/
utils.time = function time(date) {
if (date == null)
return utils.now();
return new Date(date) / 1000 | 0;
};
/**
* UINT32_MAX
* @const {BN}
*/
utils.U32 = new bn(0xffffffff);
/**
* UINT64_MAX
* @const {BN}
*/
utils.U64 = new bn('ffffffffffffffff', 'hex');
/**
* Create an 8 byte nonce.
* @returns {BN}
*/
utils.nonce = function _nonce() {
var nonce = new Buffer(8);
nonce.writeUInt32LE((Math.random() * 0x100000000) >>> 0, 0, true);
nonce.writeUInt32LE((Math.random() * 0x100000000) >>> 0, 4, true);
return new bn(nonce);
};
/**
* Read uint64le.
* @param {Buffer} data
* @param {Number} off
* @returns {BN}
*/
utils.readU64 = function readU64(data, off) {
var num;
off = off >>> 0;
num = data.slice(off, off + 8);
return new bn(num, 'le');
};
/**
* Read uint64be.
* @param {Buffer} data
* @param {Number} off
* @returns {BN}
*/
utils.readU64BE = function readU64BE(data, off) {
var num;
off = off >>> 0;
num = data.slice(off, off + 8);
return new bn(num, 'be');
};
/**
* Read int64le.
* @param {Buffer} data
* @param {Number} off
* @returns {BN}
*/
utils.read64 = function read64(data, off) {
var num;
off = off >>> 0;
num = data.slice(off, off + 8);
if (num[num.length - 1] &amp; 0x80)
return new bn(num, 'le').notn(64).addn(1).neg();
return new bn(num, 'le');
};
/**
* Read int64be.
* @param {Buffer} data
* @param {Number} off
* @returns {BN}
*/
utils.read64BE = function read64BE(data, off) {
var num;
off = off >>> 0;
num = data.slice(off, off + 8);
if (num[0] &amp; 0x80)
return new bn(num, 'be').notn(64).addn(1).neg();
return new bn(num, 'be');
};
/**
* Write uint64le.
* @param {BN|Number} value
*/
utils.writeU64 = function writeU64(dst, num, off) {
return utils.write64(dst, num, off);
};
/**
* Write uint64be.
* @param {BN|Number} value
*/
utils.writeU64BE = function writeU64BE(dst, num, off) {
return utils.write64BE(dst, num, off);
};
/**
* Write a javascript number as a uint64le (faster than big numbers).
* @param {Number} value
* @throws on num > MAX_SAFE_INTEGER
*/
utils.writeU64N = function writeU64N(dst, num, off) {
return utils.write64N(dst, num, off);
};
/**
* Write a javascript number as a uint64be (faster than big numbers).
* @param {Number} value
* @throws on num > MAX_SAFE_INTEGER
*/
utils.writeU64NBE = function writeU64NBE(dst, num, off) {
return utils.write64NBE(dst, num, off);
};
/**
* Max safe integer (53 bits).
* @const {Number}
* @default
*/
utils.MAX_SAFE_INTEGER = 0x1fffffffffffff;
/**
* Max 52 bit integer (safe for additions).
* `(MAX_SAFE_INTEGER - 1) / 2`
* @const {Number}
* @default
*/
utils.MAX_SAFE_ADDITION = 0xfffffffffffff;
/**
* Write a javascript number as an int64le (faster than big numbers).
* @param {Number} value
* @throws on num > MAX_SAFE_INTEGER
*/
utils.write64N = function write64N(dst, num, off, be) {
var negative, hi, lo;
assert(typeof num === 'number');
off = off >>> 0;
negative = num &lt; 0;
if (negative) {
num = -num;
num -= 1;
}
assert(num &lt;= utils.MAX_SAFE_INTEGER, 'Number exceeds 2^53-1');
lo = num % 0x100000000;
hi = (num - lo) / 0x100000000;
if (negative) {
hi = ~hi >>> 0;
lo = ~lo >>> 0;
}
if (be) {
dst[off + 0] = (hi >>> 24) &amp; 0xff;
dst[off + 1] = (hi >>> 16) &amp; 0xff;
dst[off + 2] = (hi >>> 8) &amp; 0xff;
dst[off + 3] = (hi >>> 0) &amp; 0xff;
dst[off + 4] = (lo >>> 24) &amp; 0xff;
dst[off + 5] = (lo >>> 16) &amp; 0xff;
dst[off + 6] = (lo >>> 8) &amp; 0xff;
dst[off + 7] = (lo >>> 0) &amp; 0xff;
} else {
dst[off + 0] = (lo >>> 0) &amp; 0xff;
dst[off + 1] = (lo >>> 8) &amp; 0xff;
dst[off + 2] = (lo >>> 16) &amp; 0xff;
dst[off + 3] = (lo >>> 24) &amp; 0xff;
dst[off + 4] = (hi >>> 0) &amp; 0xff;
dst[off + 5] = (hi >>> 8) &amp; 0xff;
dst[off + 6] = (hi >>> 16) &amp; 0xff;
dst[off + 7] = (hi >>> 24) &amp; 0xff;
}
return off + 8;
};
/**
* Write a javascript number as an int64be (faster than big numbers).
* @param {Number} value
* @throws on num > MAX_SAFE_INTEGER
*/
utils.write64NBE = function write64NBE(dst, num, off) {
return utils.write64N(dst, num, off, true);
};
/**
* Read uint64le as a js number.
* @param {Buffer} data
* @param {Number} off
* @param {Boolean} force53 - Read only 53 bits, but maintain the sign.
* @returns {Number}
* @throws on num > MAX_SAFE_INTEGER
*/
utils.readU64N = function readU64N(data, off, force53, be) {
var hi, lo;
off = off >>> 0;
if (be) {
hi = data.readUInt32BE(off, true);
lo = data.readUInt32BE(off + 4, true);
} else {
hi = data.readUInt32LE(off + 4, true);
lo = data.readUInt32LE(off, true);
}
if (force53)
hi &amp;= 0x1fffff;
assert((hi &amp; 0xffe00000) === 0, 'Number exceeds 2^53-1');
return (hi * 0x100000000) + lo;
};
/**
* Read uint64be as a js number.
* @param {Buffer} data
* @param {Number} off
* @param {Boolean} force53 - Read only 53 bits, but maintain the sign.
* @returns {Number}
* @throws on num > MAX_SAFE_INTEGER
*/
utils.readU64NBE = function readU64NBE(data, off, force53) {
return utils.readU64N(data, off, force53, true);
};
/**
* Read int64le as a js number.
* @param {Buffer} data
* @param {Number} off
* @param {Boolean} force53 - Read only 53 bits, but maintain the sign.
* @returns {Number}
* @throws on num > MAX_SAFE_INTEGER
*/
utils.read64N = function read64N(data, off, force53, be) {
var hi, lo;
off = off >>> 0;
if (be) {
hi = data.readUInt32BE(off, true);
lo = data.readUInt32BE(off + 4, true);
} else {
hi = data.readUInt32LE(off + 4, true);
lo = data.readUInt32LE(off, true);
}
if (hi &amp; 0x80000000) {
hi = ~hi >>> 0;
lo = ~lo >>> 0;
if (force53)
hi &amp;= 0x1fffff;
assert((hi &amp; 0xffe00000) === 0, 'Number exceeds 2^53-1');
return -(hi * 0x100000000 + lo + 1);
}
if (force53)
hi &amp;= 0x1fffff;
assert((hi &amp; 0xffe00000) === 0, 'Number exceeds 2^53-1');
return hi * 0x100000000 + lo;
};
/**
* Read int64be as a js number.
* @param {Buffer} data
* @param {Number} off
* @param {Boolean} force53 - Read only 53 bits, but maintain the sign.
* @returns {Number}
* @throws on num > MAX_SAFE_INTEGER
*/
utils.read64NBE = function read64NBE(data, off, force53) {
return utils.read64N(data, off, force53, true);
};
/**
* Write int64le.
* @param {Buffer} dst
* @param {BN|Number} num
* @param {Number} off
* @returns {Number} Number of bytes written.
*/
utils.write64 = function write64(dst, num, off) {
var i;
if (typeof num === 'number')
return utils.write64N(dst, num, off);
off = off >>> 0;
if (num.isNeg())
num = num.neg().inotn(64).iaddn(1);
if (num.bitLength() > 64)
num = num.uand(utils.U64);
num = num.toArray('le', 8);
for (i = 0; i &lt; num.length; i++)
dst[off++] = num[i];
return off;
};
/**
* Write int64be.
* @param {Buffer} dst
* @param {BN|Number} num
* @param {Number} off
* @returns {Number} Number of bytes written.
*/
utils.write64BE = function write64BE(dst, num, off) {
var i;
if (typeof num === 'number')
return utils.write64NBE(dst, num, off);
off = off >>> 0;
if (num.isNeg())
num = num.neg().inotn(64).iaddn(1);
if (num.bitLength() > 64)
num = num.uand(utils.U64);
num = num.toArray('be', 8);
for (i = 0; i &lt; num.length; i++)
dst[off++] = num[i];
return off;
};
/**
* Read a varint.
* @param {Buffer} data
* @param {Number} off
* @param {Boolean?} big - Whether to read as a big number.
* @returns {Object}
*/
utils.readVarint = function readVarint(data, off, big) {
var value, size;
off = off >>> 0;
assert(off &lt; data.length);
if (data[off] &lt; 0xfd) {
size = 1;
value = data[off];
if (big)
value = new bn(value);
} else if (data[off] === 0xfd) {
size = 3;
assert(off + size &lt;= data.length);
value = data[off + 1] | (data[off + 2] &lt;&lt; 8);
assert(value >= 0xfd);
if (big)
value = new bn(value);
} else if (data[off] === 0xfe) {
size = 5;
assert(off + size &lt;= data.length);
value = data.readUInt32LE(off + 1, true);
assert(value > 0xffff);
if (big)
value = new bn(value);
} else if (data[off] === 0xff) {
size = 9;
assert(off + size &lt;= data.length);
if (big) {
value = utils.readU64(data, off + 1);
assert(value.bitLength() > 32);
} else {
value = utils.readU64N(data, off + 1);
assert(value > 0xffffffff);
}
} else {
assert(false, 'Malformed varint.');
}
return { size: size, value: value };
};
/**
* Write a varint.
* @param {Buffer} dst
* @param {BN|Number} num
* @param {Number} off
* @returns {Number} Number of bytes written.
*/
utils.writeVarint = function writeVarint(dst, num, off) {
off = off >>> 0;
if (bn.isBN(num)) {
if (num.bitLength() > 32) {
dst[off] = 0xff;
utils.writeU64(dst, num, off + 1);
return off + 9;
}
num = num.toNumber();
}
num = +num;
if (num &lt; 0xfd) {
dst[off] = num &amp; 0xff;
return off + 1;
}
if (num &lt;= 0xffff) {
dst[off] = 0xfd;
dst[off + 1] = num &amp; 0xff;
dst[off + 2] = (num >>> 8) &amp; 0xff;
return off + 3;
}
if (num &lt;= 0xffffffff) {
dst[off] = 0xfe;
dst[off + 1] = num &amp; 0xff;
dst[off + 2] = (num >>> 8) &amp; 0xff;
dst[off + 3] = (num >>> 16) &amp; 0xff;
dst[off + 4] = (num >>> 24) &amp; 0xff;
return off + 5;
}
dst[off] = 0xff;
utils.writeU64N(dst, num, off + 1);
return off + 9;
};
/**
* Calculate size of varint.
* @param {BN|Number} num
* @returns {Number} size
*/
utils.sizeVarint = function sizeVarint(num) {
if (bn.isBN(num)) {
if (num.bitLength() > 32)
return 9;
num = num.toNumber();
}
if (num &lt; 0xfd)
return 1;
if (num &lt;= 0xffff)
return 3;
if (num &lt;= 0xffffffff)
return 5;
return 9;
};
/**
* Read a varint (type 2).
* @param {Buffer} data
* @param {Number} off
* @param {Boolean?} big - Whether to read as a big number.
* @returns {Object}
*/
utils.readVarint2 = function readVarint2(data, off, big) {
var num = 0;
var size = 0;
var bnum, ch;
off = off >>> 0;
for (;;) {
assert(off &lt; data.length);
ch = data[off++];
size++;
if (num >= 0x3fffffffffff) {
assert(big, 'Number exceeds 2^53-1.');
bnum = new bn(num);
num = 0;
}
if (bnum) {
bnum.iushln(7).iaddn(ch &amp; 0x7f);
if ((ch &amp; 0x80) === 0)
break;
bnum.iaddn(1);
continue;
}
num = (num * 0x80) + (ch &amp; 0x7f);
if ((ch &amp; 0x80) === 0)
break;
num++;
}
if (bnum)
return { size: size, value: bnum };
if (big)
num = new bn(num);
return { size: size, value: num };
};
/**
* Write a varint (type 2).
* @param {Buffer} dst
* @param {BN|Number} num
* @param {Number} off
* @returns {Number} Number of bytes written.
*/
utils.writeVarint2 = function writeVarint2(dst, num, off) {
var tmp = [];
var len = 0;
if (bn.isBN(num)) {
if (num.bitLength() > 53) {
for (;;) {
tmp[len] = (num.words[0] &amp; 0x7f) | (len ? 0x80 : 0x00);
if (num.cmpn(0x7f) &lt;= 0)
break;
num.iushrn(7).isubn(1);
len++;
}
assert(off + len &lt;= dst.length);
do {
dst[off++] = tmp[len];
} while (len--);
return off;
}
num = num.toNumber();
}
off = off >>> 0;
num = +num;
for (;;) {
tmp[len] = (num &amp; 0x7f) | (len ? 0x80 : 0x00);
if (num &lt;= 0x7f)
break;
num = ((num - (num % 0x80)) / 0x80) - 1;
len++;
}
assert(off + len &lt;= dst.length);
do {
dst[off++] = tmp[len];
} while (len--);
return off;
};
/**
* Calculate size of varint (type 2).
* @param {BN|Number} num
* @returns {Number} size
*/
utils.sizeVarint2 = function sizeVarint2(num) {
var size = 0;
if (bn.isBN(num)) {
if (num.bitLength() > 53) {
num = num.clone();
for (;;) {
size++;
if (num.cmpn(0x7f) &lt;= 0)
break;
num.iushrn(7).isubn(1);
}
return size;
}
num = num.toNumber();
}
num = +num;
for (;;) {
size++;
if (num &lt;= 0x7f)
break;
num = ((num - (num % 0x80)) / 0x80) - 1;
}
return size;
};
/**
* Buffer comparator (memcmp + length comparison).
* @param {Buffer} a
* @param {Buffer} b
* @returns {Number} -1, 1, or 0.
*/
utils.cmp = function cmp(a, b) {
var len, i;
if (a.compare)
return a.compare(b);
len = Math.min(a.length, b.length);
for (i = 0; i &lt; len; i++) {
if (a[i] &lt; b[i])
return -1;
if (a[i] > b[i])
return 1;
}
if (a.length &lt; b.length)
return -1;
if (a.length > b.length)
return 1;
return 0;
};
/**
* Memcmp for comparing a needle to a haystack.
* @param {Buffer} target - Haystack.
* @param {Buffer} data - Needle.
* @param {Number} start - Index in haystack to begin the comparison.
* @returns {Number} -1, 1, or 0.
*/
utils.icmp = function icmp(target, data, start) {
var i, a, b;
if (target.length - start &lt; data.length)
return -1;
for (i = 0; i &lt; data.length; i++) {
a = target[i + start];
b = data[i];
if (a &lt; b)
return -1;
if (a > b)
return 1;
}
return 0;
};
/**
* memcmp in constant time (can only return true or false).
* This protects us against timing attacks when
* comparing an input against a secret string.
* @see https://cryptocoding.net/index.php/Coding_rules
* @see `$ man 3 memcmp` (NetBSD's consttime_memequal)
* @param {Buffer} a
* @param {Buffer} b
* @returns {Boolean}
*/
utils.ccmp = function ccmp(a, b) {
var res = 0;
var i;
if (!Buffer.isBuffer(a))
return false;
if (!Buffer.isBuffer(b))
return false;
for (i = 0; i &lt; a.length; i++)
res |= a[i] ^ b[i];
return res === 0;
};
/**
* Asnchronously iterate over a range in parallel.
* @param {Number} from
* @param {Number} to
* @param {Function} iter
* @param {Function} callback
*/
utils.forRange = function forRange(from, to, iter, callback) {
var pending = to - from;
var i, error;
callback = utils.asyncify(callback);
if (pending &lt;= 0)
return callback();
function next(err) {
assert(pending > 0);
if (err)
error = err;
if (!--pending)
callback(error);
}
for (i = from; i &lt; to; i++)
iter(i, next, i);
};
/**
* Asynchronously iterate over an array in parallel.
* @param {Array} obj
* @param {Function} iter
* @param {Function} callback
*/
utils.forEach = function forEach(obj, iter, callback) {
var pending = obj.length;
var error;
callback = utils.asyncify(callback);
if (!pending)
return callback();
function next(err) {
assert(pending > 0);
if (err)
error = err;
if (!--pending)
callback(error);
}
obj.forEach(function(item, i) {
iter(item, next, i);
});
};
/**
* Asnchronously iterate over a range in serial.
* @param {Number} from
* @param {Number} to
* @param {Function} iter
* @param {Function} callback
*/
utils.forRangeSerial = function forRangeSerial(from, to, iter, callback) {
var called = false;
callback = utils.ensure(callback);
(function next(err) {
assert(!called);
if (err) {
called = true;
return callback(err);
}
if (from >= to) {
called = true;
return callback();
}
from++;
utils.nextTick(function() {
iter(from - 1, next, from - 1);
});
})();
};
/**
* Asynchronously iterate over an array in serial.
* @param {Array} obj
* @param {Function} iter
* @param {Function} callback
*/
utils.forEachSerial = function forEachSerial(obj, iter, callback) {
var i = 0;
var called = false;
callback = utils.ensure(callback);
(function next(err) {
var item;
assert(!called);
if (err) {
called = true;
return callback(err);
}
if (i >= obj.length) {
called = true;
return callback();
}
item = obj[i];
i++;
utils.nextTick(function() {
iter(item, next, i - 1);
});
})();
};
/**
* Asynchronously apply a truth test to every
* member of an array in parallel.
* @param {Array} obj
* @param {Function} iter
* @param {Function} callback
*/
utils.every = function every(obj, iter, callback) {
var pending = obj.length;
var result = true;
var error;
callback = utils.asyncify(callback);
if (!pending)
return callback(null, result);
function next(err, res) {
assert(pending > 0);
if (err)
error = err;
if (!res)
result = false;
if (!--pending) {
if (error)
return callback(error);
callback(null, result);
}
}
obj.forEach(function(item, i) {
iter(item, next, i);
});
};
/**
* Asynchronously apply a truth test to every
* member of an array in serial.
* @param {Array} obj
* @param {Function} iter
* @param {Function} callback
*/
utils.everySerial = function everySerial(obj, iter, callback) {
var i = 0;
var called = false;
callback = utils.ensure(callback);
(function next(err, res) {
var item;
assert(!called);
if (err) {
called = true;
return callback(err);
}
if (!res) {
called = true;
return callback(null, false);
}
if (i >= obj.length) {
called = true;
return callback(null, true);
}
item = obj[i];
i++;
utils.nextTick(function() {
iter(item, next, i - 1);
});
})(null, true);
};
/**
* Convert bytes to mb.
* @param {Number} size
* @returns {Number} mb
*/
utils.mb = function mb(size) {
return size / 1024 / 1024 | 0;
};
/**
* Inheritance.
* @param {Function} obj - Constructor to inherit.
* @param {Function} from - Parent constructor.
*/
utils.inherits = function inherits(obj, from) {
var f;
obj.super_ = from;
if (Object.setPrototypeOf) {
Object.setPrototypeOf(obj.prototype, from.prototype);
Object.defineProperty(obj.prototype, 'constructor', {
value: obj,
enumerable: false
});
return;
}
if (Object.create) {
obj.prototype = Object.create(from.prototype, {
constructor: {
value: obj,
enumerable: false
}
});
return;
}
f = function() {};
f.prototype = from.prototype;
obj.prototype = new f;
obj.prototype.constructor = obj;
};
/**
* Wrap a callback to ensure it is only called once.
* @param {Function} callback
* @returns {Function} Wrapped callback.
*/
utils.once = function once(callback) {
var called;
if (callback &amp;&amp; callback._once)
return callback;
function onceFn(err, result1, result2) {
if (called)
return;
called = true;
if (callback)
callback(err, result1, result2);
}
onceFn._once = true;
if (callback)
onceFn._asyncified = callback._asyncified;
return onceFn;
};
/**
* Build a merkle tree from leaves.
* @param {Buffer[]} leaves
* @returns {Buffer[]} Tree (in rare cases this may return null).
*/
utils.buildMerkleTree = function buildMerkleTree(leaves) {
var tree = leaves.slice();
var i, j, size, i2, hash;
j = 0;
size = leaves.length;
for (; size > 1; size = ((size + 1) / 2) | 0) {
for (i = 0; i &lt; size; i += 2) {
i2 = Math.min(i + 1, size - 1);
if (i2 === i + 1 &amp;&amp; i2 + 1 === size
&amp;&amp; utils.equal(tree[j + i], tree[j + i2])) {
return;
}
hash = Buffer.concat([tree[j + i], tree[j + i2]]);
hash = utils.dsha256(hash);
tree.push(hash);
}
j += size;
}
if (!tree.length)
return;
return tree;
};
/**
* Calculate merkle root from leaves.
* @param {Buffer[]} leaves
* @returns {Buffer?} Merkle root.
*/
utils.getMerkleRoot = function getMerkleRoot(leaves) {
var tree = utils.buildMerkleTree(leaves);
if (!tree)
return;
return tree[tree.length - 1];
};
/**
* Collect a merkle branch at vector index.
* @param {Number} index
* @param {Buffer[]} leaves
* @returns {Buffer[]} branch
*/
utils.getMerkleBranch = function getMerkleBranch(index, leaves) {
var tree = utils.buildMerkleTree(leaves);
var size = leaves.length;
var branch = [];
var j = 0;
var i;
for (; size > 1; size = (size + 1) / 2 | 0) {
i = Math.min(index ^ 1, size - 1);
branch.push(tree[j + i]);
index >>>= 1;
j += size;
}
return branch;
};
/**
* Check a merkle branch at vector index.
* @param {Buffer} hash
* @param {Buffer[]} branch
* @param {Number} index
* @returns {Buffer} Hash.
*/
utils.checkMerkleBranch = function checkMerkleBranch(hash, branch, index) {
var otherside, i;
if (index === -1)
return false;
if (typeof hash === 'string')
hash = new Buffer(hash, 'hex');
for (i = 0; i &lt; branch.length; i++) {
otherside = branch[i];
if (index &amp; 1)
hash = utils.dsha256(Buffer.concat([otherside, hash]));
else
hash = utils.dsha256(Buffer.concat([hash, otherside]));
index >>>= 1;
}
return hash;
};
/**
* Find index of a buffer in an array of buffers.
* @param {Buffer[]} obj
* @param {Buffer} data - Target buffer to find.
* @returns {Number} Index (-1 if not found).
*/
utils.indexOf = function indexOf(obj, data) {
var i;
assert(Array.isArray(obj));
assert(Buffer.isBuffer(data));
for (i = 0; i &lt; obj.length; i++) {
if (!Buffer.isBuffer(obj[i]))
continue;
if (utils.equal(obj[i], data))
return i;
}
return -1;
};
/**
* Convert a number to a padded uint32
* string (10 digits in decimal).
* @param {Number} num
* @returns {String} Padded number.
*/
utils.pad32 = function pad32(num) {
assert(num >= 0);
num = num + '';
while (num.length &lt; 10)
num = '0' + num;
assert(num.length === 10);
return num;
};
/**
* Wrap a callback with an `unlock` callback.
* @see Locker
* @param {Function} callback
* @param {Function} unlock
* @returns {Function} Wrapped callback.
*/
utils.wrap = function wrap(callback, unlock) {
return function(err, res1, res2) {
unlock();
if (callback)
callback(err, res1, res2);
};
};
/**
* Execute a stack of functions in parallel.
* @param {Function[]} stack
* @param {Function} callback
*/
utils.parallel = function parallel(stack, callback) {
var pending = stack.length;
var error;
var i;
callback = utils.once(callback);
if (!pending)
return utils.nextTick(callback);
function next(err) {
assert(pending > 0);
if (err)
error = err;
if (!--pending)
callback(error);
}
for (i = 0; i &lt; stack.length; i++) {
try {
// if (stack[i].length >= 2) {
// stack[i](error, next);
// error = null;
// continue;
// }
if (error)
continue;
stack[i](next);
} catch (e) {
pending--;
error = e;
}
}
};
/**
* Execute a stack of functions in serial.
* @param {Function[]} stack
* @param {Function} callback
*/
utils.serial = function serial(stack, callback) {
var i = 0;
(function next(err) {
var cb = stack[i++];
if (!cb)
return callback(err);
// if (cb.length >= 2) {
// try {
// return cb(err, next);
// } catch (e) {
// return next(e);
// }
// }
if (err)
return utils.nextTick(next.bind(null, err));
try {
return cb(next);
} catch (e) {
return next(e);
}
})();
};
/**
* Convert an array to a map.
* @param {String[]} obj
* @returns {Object} Map.
*/
utils.toMap = function toMap(obj) {
var map = {};
var i, value;
for (i = 0; i &lt; obj.length; i++) {
value = obj[i];
map[value] = true;
}
return map;
};
/**
* Reverse a map.
* @param {Object} map
* @param {Object} Reversed map.
*/
utils.revMap = function revMap(map) {
var reversed = {};
var keys = Object.keys(map);
var i, key;
for (i = 0; i &lt; keys.length; i++) {
key = keys[i];
reversed[map[key]] = key;
}
return reversed;
};
/**
* Perform a binary search on a sorted array.
* @param {Array} items
* @param {Object} key
* @param {Function} compare
* @param {Boolean?} insert
* @returns {Number} Index.
*/
utils.binarySearch = function binarySearch(items, key, compare, insert) {
var start = 0;
var end = items.length - 1;
var pos, cmp;
while (start &lt;= end) {
pos = (start + end) >>> 1;
cmp = compare(items[pos], key);
if (cmp === 0)
return pos;
if (cmp &lt; 0)
start = pos + 1;
else
end = pos - 1;
}
if (!insert)
return -1;
return start - 1;
};
/**
* Perform a binary insert on a sorted array.
* @param {Array} items
* @param {Object} item
* @param {Function?} compare
* @returns {Number} Length.
*/
utils.binaryInsert = function binaryInsert(items, item, compare) {
var i = utils.binarySearch(items, item, compare, true);
items.splice(i + 1, 0, item);
return items.length;
};
/**
* Perform a binary removal on a sorted array.
* @param {Array} items
* @param {Object} item
* @param {Function?} compare
* @returns {Number} Length.
*/
utils.binaryRemove = function binaryRemove(items, item, compare) {
var i = utils.binarySearch(items, item, compare, false);
if (i === -1)
return false;
items.splice(i, 1);
return true;
};
/**
* Reference to the global object.
* @const {Object}
*/
utils.global = (function() {
/* global self */
if (this)
return this;
if (typeof window !== 'undefined')
return window;
if (typeof self !== 'undefined')
return self;
if (typeof global !== 'undefined')
return global;
})();
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-bcoin.html">bcoin</a></li><li><a href="module-constants.html">constants</a></li><li><a href="module-ec.html">ec</a></li><li><a href="module-ldb.html">ldb</a></li><li><a href="module-network.html">network</a></li><li><a href="module-profiler.html">profiler</a></li><li><a href="module-request.html">request</a></li><li><a href="module-uri.html">uri</a></li><li><a href="module-utils.html">utils</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractBlock.html">AbstractBlock</a></li><li><a href="Account.html">Account</a></li><li><a href="Address.html">Address</a></li><li><a href="AES.html">AES</a></li><li><a href="Block.html">Block</a></li><li><a href="Bloom.html">Bloom</a></li><li><a href="BroadcastItem.html">BroadcastItem</a></li><li><a href="BST.html">BST</a></li><li><a href="BufferReader.html">BufferReader</a></li><li><a href="BufferWriter.html">BufferWriter</a></li><li><a href="Chain.html">Chain</a></li><li><a href="ChainDB.html">ChainDB</a></li><li><a href="ChainEntry.html">ChainEntry</a></li><li><a href="Coin.html">Coin</a></li><li><a href="Coins.html">Coins</a></li><li><a href="CoinView.html">CoinView</a></li><li><a href="CompactBlock.html">CompactBlock</a></li><li><a href="Environment.html">Environment</a></li><li><a href="Framer.html">Framer</a></li><li><a href="Fullnode.html">Fullnode</a></li><li><a href="HD.html">HD</a></li><li><a href="HDPrivateKey.html">HDPrivateKey</a></li><li><a href="HDPublicKey.html">HDPublicKey</a></li><li><a href="Headers.html">Headers</a></li><li><a href="HTTPBase.html">HTTPBase</a></li><li><a href="HTTPClient.html">HTTPClient</a></li><li><a href="HTTPServer.html">HTTPServer</a></li><li><a href="HTTPWallet.html">HTTPWallet</a></li><li><a href="Input.html">Input</a></li><li><a href="KeyPair.html">KeyPair</a></li><li><a href="KeyRing.html">KeyRing</a></li><li><a href="LoadRequest.html">LoadRequest</a></li><li><a href="Locker.html">Locker</a></li><li><a href="LowlevelUp.html">LowlevelUp</a></li><li><a href="LRU.html">LRU</a></li><li><a href="Master.html">Master</a></li><li><a href="Mempool.html">Mempool</a></li><li><a href="MempoolEntry.html">MempoolEntry</a></li><li><a href="MerkleBlock.html">MerkleBlock</a></li><li><a href="Miner.html">Miner</a></li><li><a href="MinerBlock.html">MinerBlock</a></li><li><a href="Mnemonic.html">Mnemonic</a></li><li><a href="MTX.html">MTX</a></li><li><a href="Network.html">Network</a></li><li><a href="NetworkAddress.html">NetworkAddress</a></li><li><a href="Node.html">Node</a></li><li><a href="NullCache.html">NullCache</a></li><li><a href="Output.html">Output</a></li><li><a href="Parser.html">Parser</a></li><li><a href="Peer.html">Peer</a></li><li><a href="Pool.html">Pool</a></li><li><a href="Profile.html">Profile</a></li><li><a href="RollingFilter.html">RollingFilter</a></li><li><a href="Script.html">Script</a></li><li><a href="ScriptError.html">ScriptError</a></li><li><a href="Snapshot.html">Snapshot</a></li><li><a href="SPVNode.html">SPVNode</a></li><li><a href="Stack.html">Stack</a></li><li><a href="TimeData.html">TimeData</a></li><li><a href="TX.html">TX</a></li><li><a href="TXDB.html">TXDB</a></li><li><a href="VerifyError.html">VerifyError</a></li><li><a href="Wallet.html">Wallet</a></li><li><a href="WalletDB.html">WalletDB</a></li><li><a href="Witness.html">Witness</a></li><li><a href="Worker.html">Worker</a></li><li><a href="Workers.html">Workers</a></li></ul><h3>Global</h3><ul><li><a href="global.html#hostname">hostname</a></li><li><a href="global.html#isMapped">isMapped</a></li><li><a href="global.html#mkdirp">mkdirp</a></li><li><a href="global.html#normalize">normalize</a></li><li><a href="global.html#parseHost">parseHost</a></li><li><a href="global.html#scrypt">scrypt</a></li><li><a href="global.html#toBuffer">toBuffer</a></li><li><a href="global.html#toString">toString</a></li><li><a href="global.html#version">version</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.0</a> on Sun Jun 05 2016 20:46:56 GMT-0700 (PDT)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>