utils: remove some control flow. add base58.

This commit is contained in:
Christopher Jeffrey 2016-10-02 02:58:08 -07:00
parent 1a8657d131
commit 76a32feb5d
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
5 changed files with 198 additions and 483 deletions

View File

@ -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);
};
/*

View File

@ -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]));

View File

@ -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');

132
lib/utils/base58.js Normal file
View File

@ -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;

View File

@ -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