From 76a32feb5db06df8e6e50078847b22e0cb786fea Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sun, 2 Oct 2016 02:58:08 -0700 Subject: [PATCH] utils: remove some control flow. add base58. --- lib/db/rbt.js | 86 +++++--- lib/script/script.js | 4 +- lib/script/witness.js | 2 +- lib/utils/base58.js | 132 ++++++++++++ lib/utils/utils.js | 457 +----------------------------------------- 5 files changed, 198 insertions(+), 483 deletions(-) create mode 100644 lib/utils/base58.js diff --git a/lib/db/rbt.js b/lib/db/rbt.js index a1c5ae95..646417ca 100644 --- a/lib/db/rbt.js +++ b/lib/db/rbt.js @@ -15,9 +15,9 @@ var SENTINEL; /** * An iterative red black tree. - * Used for the mempool. Many of its - * options, parameters, and methods - * mimic the leveldown interface. + * Many of its options, parameters, + * and methods mimic the leveldown + * interface. * @exports RBT * @constructor * @param {String?} location - Phony location. @@ -586,7 +586,7 @@ RBT.prototype.open = function open(options, callback) { this.options = options; - return utils.nextTick(callback); + utils.nextTick(callback); }; /** @@ -595,7 +595,7 @@ RBT.prototype.open = function open(options, callback) { */ RBT.prototype.close = function close(callback) { - return utils.nextTick(callback); + utils.nextTick(callback); }; /** @@ -622,13 +622,18 @@ RBT.prototype.get = function get(key, options, callback) { err = new Error('RBT_NOTFOUND: Key not found.'); err.notFound = true; err.type = 'NotFoundError'; - return utils.asyncify(callback)(err); + utils.nextTick(function() { + callback(err); + }); + return; } if (options.asBuffer === false) value = value.toString('utf8'); - return utils.asyncify(callback)(null, value); + utils.nextTick(function() { + callback(null, value); + }); }; /** @@ -647,7 +652,7 @@ RBT.prototype.put = function put(key, value, options, callback) { this.insert(key, value); - return utils.nextTick(callback); + utils.nextTick(callback); }; /** @@ -665,7 +670,7 @@ RBT.prototype.del = function del(key, options, callback) { this.remove(key); - return utils.nextTick(callback); + utils.nextTick(callback); }; /** @@ -736,7 +741,9 @@ RBT.prototype.approximateSize = function approximateSize(start, end, callback) { size += item.value.length; } - return utils.asyncify(callback)(null, size); + utils.nextTick(function() { + callback(null, size); + }); }; /** @@ -746,7 +753,7 @@ RBT.prototype.approximateSize = function approximateSize(start, end, callback) { */ RBT.destroy = function destroy(location, callback) { - return utils.nextTick(callback); + utils.nextTick(callback); }; /** @@ -756,7 +763,7 @@ RBT.destroy = function destroy(location, callback) { */ RBT.repair = function repair(location, callback) { - return utils.nextTick(callback); + utils.nextTick(callback); }; /** @@ -940,17 +947,28 @@ Batch.prototype.del = function del(key) { Batch.prototype.write = function write(callback) { var i, op; - if (!this.tree) - return callback(new Error('Already written.')); + if (!this.tree) { + utils.nextTick(function() { + callback(new Error('Already written.')); + }); + return; + } for (i = 0; i < this.ops.length; i++) { op = this.ops[i]; - if (op.type === 'put') - this.tree.insert(op.key, op.value); - else if (op.type === 'del') - this.tree.remove(op.key); - else - assert(false); + switch (op.type) { + case 'put': + this.tree.insert(op.key, op.value); + break; + case 'del': + this.tree.remove(op.key); + break; + default: + utils.nextTick(function() { + callback(new Error('Bad operation: ' + op.type)); + }); + return; + } } this.ops.length = 0; @@ -1029,8 +1047,12 @@ function Iterator(tree, options) { Iterator.prototype.next = function(callback) { var item, key, value; - if (this.ended) - return utils.asyncify(callback)(new Error('Cannot call next after end.')); + if (this.ended) { + utils.nextTick(function() { + callback(new Error('Cannot call next after end.')); + }); + return; + } if (this.options.reverse) item = this.snapshot[this.index--]; @@ -1040,13 +1062,15 @@ Iterator.prototype.next = function(callback) { if (this.options.limit != null) { if (this.total++ >= this.options.limit) { this._end(); - return utils.nextTick(callback); + utils.nextTick(callback); + return; } } if (!item) { this._end(); - return utils.nextTick(callback); + utils.nextTick(callback); + return; } key = item.key; @@ -1064,7 +1088,9 @@ Iterator.prototype.next = function(callback) { if (this.options.valueAsBuffer === false) value = value.toString('utf8'); - utils.asyncify(callback)(null, key, value); + utils.nextTick(function() { + callback(null, key, value); + }); }; /** @@ -1105,13 +1131,17 @@ Iterator.prototype._end = function end() { */ Iterator.prototype.end = function end(callback) { - if (this.ended) - return utils.asyncify(callback)(new Error('Already ended.')); + if (this.ended) { + utils.nextTick(function() { + callback(new Error('Already ended.')); + }); + return; + } this.ended = true; this._end(); - return utils.nextTick(callback); + utils.nextTick(callback); }; /* diff --git a/lib/script/script.js b/lib/script/script.js index 96817f6a..1a5cf3f2 100644 --- a/lib/script/script.js +++ b/lib/script/script.js @@ -18,7 +18,7 @@ var BufferWriter = require('../utils/writer'); var BufferReader = require('../utils/reader'); var opcodes = constants.opcodes; var STACK_TRUE = new Buffer([1]); -var STACK_FALSE = new Buffer([]); +var STACK_FALSE = new Buffer(0); var STACK_NEGATE = new Buffer([0x81]); var ScriptError = require('../utils/errors').ScriptError; var scriptTypes = constants.scriptTypes; @@ -1224,7 +1224,7 @@ Script.num = function num(value, flags, size) { * numbers to a little-endian buffer while taking into * account negative zero, minimaldata, etc. * @example - * assert.deepEqual(Script.array(0), new Buffer([])); + * assert.deepEqual(Script.array(0), new Buffer(0)); * assert.deepEqual(Script.array(0xffee), new Buffer([0xee, 0xff, 0x00])); * assert.deepEqual(Script.array(new bn(0xffee)), new Buffer([0xee, 0xff, 0x00])); * assert.deepEqual(Script.array(new bn(0x1e).ineg()), new Buffer([0x9e])); diff --git a/lib/script/witness.js b/lib/script/witness.js index 8b38c70f..8b096ef8 100644 --- a/lib/script/witness.js +++ b/lib/script/witness.js @@ -14,7 +14,7 @@ var constants = require('../protocol/constants'); var utils = require('../utils/utils'); var assert = require('assert'); var opcodes = constants.opcodes; -var STACK_FALSE = new Buffer([]); +var STACK_FALSE = new Buffer(0); var STACK_NEGATE = new Buffer([0x81]); var scriptTypes = constants.scriptTypes; var Script = require('./script'); diff --git a/lib/utils/base58.js b/lib/utils/base58.js new file mode 100644 index 00000000..ccfbad2b --- /dev/null +++ b/lib/utils/base58.js @@ -0,0 +1,132 @@ +/*! + * base58.js - base58 for bcoin + * Copyright (c) 2014-2015, Fedor Indutny (MIT License) + * Copyright (c) 2014-2016, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +var native = require('./native'); +var assert = require('assert'); + +/* + * Base58 + */ + +var base58 = '' + + '123456789' + + 'ABCDEFGHJKLMNPQRSTUVWXYZ' + + 'abcdefghijkmnopqrstuvwxyz'; + +var unbase58 = {}; + +for (var i = 0; i < 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} + */ + +exports.toBase58 = function toBase58(data) { + var zeroes = 0; + var length = 0; + var str = ''; + var i, b58, carry, j, k; + + for (i = 0; i < data.length; i++) { + if (data[i] !== 0) + break; + zeroes++; + } + + b58 = new Buffer(((data.length * 138 / 100) | 0) + 1); + b58.fill(0); + + for (; i < data.length; i++) { + carry = data[i]; + j = 0; + for (k = b58.length - 1; k >= 0; k--, j++) { + if (carry === 0 && 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 < b58.length && b58[i] === 0) + i++; + + for (j = 0; j < zeroes; j++) + str += '1'; + + for (; i < b58.length; i++) + str += base58[b58[i]]; + + return str; +}; + +if (native) + exports.toBase58 = native.toBase58; + +/** + * 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. + */ + +exports.fromBase58 = function fromBase58(str) { + var zeroes = 0; + var i = 0; + var b256, ch, carry, j, out; + + for (i = 0; i < str.length; i++) { + if (str[i] !== '1') + break; + zeroes++; + } + + b256 = new Buffer(((str.length * 733) / 1000 | 0) + 1); + b256.fill(0); + + for (; i < 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 < b256.length && b256[i] === 0) + i++; + + out = new Buffer(zeroes + (b256.length - i)); + + for (j = 0; j < zeroes; j++) + out[j] = 0; + + while (i < b256.length) + out[j++] = b256[i++]; + + return out; +}; + +if (native) + exports.fromBase58 = native.fromBase58; diff --git a/lib/utils/utils.js b/lib/utils/utils.js index a8ddf286..148b2480 100644 --- a/lib/utils/utils.js +++ b/lib/utils/utils.js @@ -16,7 +16,7 @@ var utils = exports; var assert = require('assert'); -var native = require('./native'); +var base58 = require('./base58'); var bn = require('bn.js'); var util = require('util'); var Number, Math, Date; @@ -103,126 +103,26 @@ utils.copy = function copy(data) { return clone; }; -/* - * Base58 - */ - -var base58 = '' - + '123456789' - + 'ABCDEFGHJKLMNPQRSTUVWXYZ' - + 'abcdefghijkmnopqrstuvwxyz'; - -var unbase58 = {}; - -for (var i = 0; i < base58.length; i++) - unbase58[base58[i]] = i; - /** * Encode a base58 string. * @see https://github.com/bitcoin/bitcoin/blob/master/src/base58.cpp + * @function * @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 < data.length; i++) { - if (data[i] !== 0) - break; - zeroes++; - } - - b58 = new Buffer(((data.length * 138 / 100) | 0) + 1); - b58.fill(0); - - for (; i < data.length; i++) { - carry = data[i]; - j = 0; - for (k = b58.length - 1; k >= 0; k--, j++) { - if (carry === 0 && 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 < b58.length && b58[i] === 0) - i++; - - for (j = 0; j < zeroes; j++) - str += '1'; - - for (; i < b58.length; i++) - str += base58[b58[i]]; - - return str; -}; - -if (native) - utils.toBase58 = native.toBase58; +utils.toBase58 = base58.toBase58; /** * Decode a base58 string. * @see https://github.com/bitcoin/bitcoin/blob/master/src/base58.cpp + * @function * @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 < str.length; i++) { - if (str[i] !== '1') - break; - zeroes++; - } - - b256 = new Buffer(((str.length * 733) / 1000 | 0) + 1); - b256.fill(0); - - for (; i < 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 < b256.length && b256[i] === 0) - i++; - - out = new Buffer(zeroes + (b256.length - i)); - - for (j = 0; j < zeroes; j++) - out[j] = 0; - - while (i < b256.length) - out[j++] = b256[i++]; - - return out; -}; - -if (native) - utils.fromBase58 = native.fromBase58; +utils.fromBase58 = base58.fromBase58; /** * Test whether a string is base58 (note that you @@ -326,43 +226,6 @@ if (typeof setImmediate === 'function') { }; } -/** - * Wrap a function in a `nextTick`. - * @returns {Promise} - * @returns {Function} Asyncified function. - */ - -utils.asyncify = function asyncify(callback) { - if (callback && 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. - * @returns {Promise} - * @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). @@ -1625,199 +1488,6 @@ utils.icmp = function icmp(target, data, start) { return 0; }; -/** - * Asnchronously iterate over a range in parallel. - * @param {Number} from - * @param {Number} to - * @param {Function} iter - * @returns {Promise} - */ - -utils.forRange = function forRange(from, to, iter, callback) { - var pending = to - from; - var i, error; - - callback = utils.asyncify(callback); - - if (pending <= 0) - return callback(); - - function next(err) { - assert(pending > 0); - if (err) - error = err; - if (!--pending) - callback(error); - } - - for (i = from; i < to; i++) - iter(i, next, i); -}; - -/** - * Asynchronously iterate over an array in parallel. - * @param {Array} obj - * @param {Function} iter - * @returns {Promise} - */ - -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 - * @returns {Promise} - */ - -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 - * @returns {Promise} - */ - -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 - * @returns {Promise} - */ - -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 - * @returns {Promise} - */ - -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 @@ -1864,33 +1534,6 @@ utils.inherits = function inherits(obj, from) { obj.prototype.constructor = obj; }; -/** - * Wrap a callback to ensure it is only called once. - * @returns {Promise} - * @returns {Function} Wrapped callback. - */ - -utils.once = function once(callback) { - var called; - - if (callback && 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; -}; - /** * Find index of a buffer in an array of buffers. * @param {Buffer[]} obj @@ -1982,96 +1625,6 @@ utils.hex32 = function hex32(num) { } }; -/** - * Wrap a callback with an `unlock` callback. - * @see Locker - * @returns {Promise} - * @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 - * @returns {Promise} - */ - -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 < 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 - * @returns {Promise} - */ - -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