bcoin: start switching to class syntax.

This commit is contained in:
Christopher Jeffrey 2017-11-01 16:58:39 -07:00
parent f9eba3f5a6
commit a79c2b0b1a
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
11 changed files with 4504 additions and 4396 deletions

File diff suppressed because it is too large Load Diff

View File

@ -690,7 +690,7 @@ Mempool.prototype.has = function has(hash) {
*/ */
Mempool.prototype.exists = function exists(hash) { Mempool.prototype.exists = function exists(hash) {
if (this.locker.hasPending(hash)) if (this.locker.pending(hash))
return true; return true;
if (this.hasOrphan(hash)) if (this.hasOrphan(hash))

View File

@ -93,6 +93,14 @@ exports.MAX_BLOCK_SIGOPS = 1000000 / 50;
exports.MAX_BLOCK_SIGOPS_COST = 80000; exports.MAX_BLOCK_SIGOPS_COST = 80000;
/**
* Size of set to pick median time from.
* @const {Number}
* @default
*/
exports.MEDIAN_TIMESPAN = 11;
/** /**
* What bits to set in version * What bits to set in version
* for versionbits blocks. * for versionbits blocks.

View File

@ -9,70 +9,72 @@
const assert = require('assert'); const assert = require('assert');
/** /**
* Represents a promise-resolving event emitter. * Async Emitter
* @alias module:utils.AsyncEmitter * @alias module:utils.AsyncEmitter
* @see EventEmitter * @see EventEmitter
*/
class AsyncEmitter {
/**
* Create an async emitter.
* @constructor * @constructor
*/ */
function AsyncEmitter() { constructor() {
if (!(this instanceof AsyncEmitter))
return new AsyncEmitter();
this._events = Object.create(null); this._events = Object.create(null);
} }
/** /**
* Add a listener. * Add a listener.
* @param {String} type * @param {String} type
* @param {Function} handler * @param {Function} handler
*/ */
AsyncEmitter.prototype.addListener = function addListener(type, handler) { addListener(type, handler) {
return this._push(type, handler, false); return this._push(type, handler, false);
}; }
/** /**
* Add a listener. * Add a listener.
* @param {String} type * @param {String} type
* @param {Function} handler * @param {Function} handler
*/ */
AsyncEmitter.prototype.on = function on(type, handler) { on(type, handler) {
return this.addListener(type, handler); return this.addListener(type, handler);
}; }
/** /**
* Add a listener to execute once. * Add a listener to execute once.
* @param {String} type * @param {String} type
* @param {Function} handler * @param {Function} handler
*/ */
AsyncEmitter.prototype.once = function once(type, handler) { once(type, handler) {
return this._push(type, handler, true); return this._push(type, handler, true);
}; }
/** /**
* Prepend a listener. * Prepend a listener.
* @param {String} type * @param {String} type
* @param {Function} handler * @param {Function} handler
*/ */
AsyncEmitter.prototype.prependListener = function prependListener(type, handler) { prependListener(type, handler) {
return this._unshift(type, handler, false); return this._unshift(type, handler, false);
}; }
/** /**
* Prepend a listener to execute once. * Prepend a listener to execute once.
* @param {String} type * @param {String} type
* @param {Function} handler * @param {Function} handler
*/ */
AsyncEmitter.prototype.prependOnceListener = function prependOnceListener(type, handler) { prependOnceListener(type, handler) {
return this._unshift(type, handler, true); return this._unshift(type, handler, true);
}; }
/** /**
* Push a listener. * Push a listener.
* @private * @private
* @param {String} type * @param {String} type
@ -80,42 +82,42 @@ AsyncEmitter.prototype.prependOnceListener = function prependOnceListener(type,
* @param {Boolean} once * @param {Boolean} once
*/ */
AsyncEmitter.prototype._push = function _push(type, handler, once) { _push(type, handler, once) {
assert(typeof type === 'string', '`type` must be a string.'); assert(typeof type === 'string', '`type` must be a string.');
if (!this._events[type]) if (!this._events[type])
this._events[type] = []; this._events[type] = [];
this._events[type].push(new Listener(handler, once));
this.emit('newListener', type, handler); this.emit('newListener', type, handler);
};
/** this._events[type].push(new Listener(handler, once));
}
/**
* Unshift a listener. * Unshift a listener.
* @param {String} type * @param {String} type
* @param {Function} handler * @param {Function} handler
* @param {Boolean} once * @param {Boolean} once
*/ */
AsyncEmitter.prototype._unshift = function _unshift(type, handler, once) { _unshift(type, handler, once) {
assert(typeof type === 'string', '`type` must be a string.'); assert(typeof type === 'string', '`type` must be a string.');
if (!this._events[type]) if (!this._events[type])
this._events[type] = []; this._events[type] = [];
this._events[type].unshift(new Listener(handler, once));
this.emit('newListener', type, handler); this.emit('newListener', type, handler);
};
/** this._events[type].unshift(new Listener(handler, once));
}
/**
* Remove a listener. * Remove a listener.
* @param {String} type * @param {String} type
* @param {Function} handler * @param {Function} handler
*/ */
AsyncEmitter.prototype.removeListener = function removeListener(type, handler) { removeListener(type, handler) {
assert(typeof type === 'string', '`type` must be a string.'); assert(typeof type === 'string', '`type` must be a string.');
const listeners = this._events[type]; const listeners = this._events[type];
@ -136,31 +138,31 @@ AsyncEmitter.prototype.removeListener = function removeListener(type, handler) {
if (index === -1) if (index === -1)
return; return;
listeners.splice(index, 1); splice(listeners, index);
if (listeners.length === 0) if (listeners.length === 0)
delete this._events[type]; delete this._events[type];
this.emit('removeListener', type, handler); this.emit('removeListener', type, handler);
}; }
/** /**
* Set max listeners. * Set max listeners.
* @param {Number} max * @param {Number} max
*/ */
AsyncEmitter.prototype.setMaxListeners = function setMaxListeners(max) { setMaxListeners(max) {
assert(typeof max === 'number', '`max` must be a number.'); assert(typeof max === 'number', '`max` must be a number.');
assert(max >= 0, '`max` must be non-negative.'); assert(max >= 0, '`max` must be non-negative.');
assert(Number.isSafeInteger(max), '`max` must be an integer.'); assert(Number.isSafeInteger(max), '`max` must be an integer.');
}; }
/** /**
* Remove all listeners. * Remove all listeners.
* @param {String?} type * @param {String?} type
*/ */
AsyncEmitter.prototype.removeAllListeners = function removeAllListeners(type) { removeAllListeners(type) {
if (arguments.length === 0) { if (arguments.length === 0) {
this._events = Object.create(null); this._events = Object.create(null);
return; return;
@ -169,15 +171,15 @@ AsyncEmitter.prototype.removeAllListeners = function removeAllListeners(type) {
assert(typeof type === 'string', '`type` must be a string.'); assert(typeof type === 'string', '`type` must be a string.');
delete this._events[type]; delete this._events[type];
}; }
/** /**
* Get listeners array. * Get listeners array.
* @param {String} type * @param {String} type
* @returns {Function[]} * @returns {Function[]}
*/ */
AsyncEmitter.prototype.listeners = function listeners(type) { listeners(type) {
assert(typeof type === 'string', '`type` must be a string.'); assert(typeof type === 'string', '`type` must be a string.');
const listeners = this._events[type]; const listeners = this._events[type];
@ -191,14 +193,14 @@ AsyncEmitter.prototype.listeners = function listeners(type) {
result.push(handler); result.push(handler);
return result; return result;
}; }
/** /**
* Get listener count for an event. * Get listener count for an event.
* @param {String} type * @param {String} type
*/ */
AsyncEmitter.prototype.listenerCount = function listenerCount(type) { listenerCount(type) {
assert(typeof type === 'string', '`type` must be a string.'); assert(typeof type === 'string', '`type` must be a string.');
const listeners = this._events[type]; const listeners = this._events[type];
@ -207,16 +209,25 @@ AsyncEmitter.prototype.listenerCount = function listenerCount(type) {
return 0; return 0;
return listeners.length; return listeners.length;
}; }
/** /**
* Get event names.
* @returns {String[]}
*/
eventNames() {
return Object.keys(this._events);
}
/**
* Emit an event synchronously. * Emit an event synchronously.
* @param {String} type * @param {String} type
* @param {...Object} args * @param {...Object} args
* @returns {Promise} * @returns {Promise}
*/ */
AsyncEmitter.prototype.emit = function emit(type) { emit(type) {
try { try {
this._emit.apply(this, arguments); this._emit.apply(this, arguments);
} catch (e) { } catch (e) {
@ -225,9 +236,9 @@ AsyncEmitter.prototype.emit = function emit(type) {
this._emit('error', e); this._emit('error', e);
} }
}; }
/** /**
* Emit an event synchronously. * Emit an event synchronously.
* @private * @private
* @param {String} type * @param {String} type
@ -235,20 +246,20 @@ AsyncEmitter.prototype.emit = function emit(type) {
* @returns {Promise} * @returns {Promise}
*/ */
AsyncEmitter.prototype._emit = function _emit(type) { _emit(type) {
assert(typeof type === 'string', '`type` must be a string.'); assert(typeof type === 'string', '`type` must be a string.');
const listeners = this._events[type]; const listeners = this._events[type];
if (!listeners) { if (!listeners) {
if (type === 'error') { if (type === 'error') {
const error = arguments[1]; const msg = arguments[1];
if (error instanceof Error) if (msg instanceof Error)
throw error; throw msg;
const err = new Error(`Uncaught, unspecified "error" event. (${error})`); const err = new Error(`Uncaught, unspecified "error" event. (${msg})`);
err.context = error; err.context = msg;
throw err; throw err;
} }
return; return;
@ -263,7 +274,9 @@ AsyncEmitter.prototype._emit = function _emit(type) {
const handler = listener.handler; const handler = listener.handler;
if (listener.once) { if (listener.once) {
listeners.splice(i, 1); splice(listeners, i);
if (listeners.length === 0)
delete this._events[type];
i -= 1; i -= 1;
} }
@ -290,9 +303,9 @@ AsyncEmitter.prototype._emit = function _emit(type) {
break; break;
} }
} }
}; }
/** /**
* Emit an event. Wait for promises to resolve. * Emit an event. Wait for promises to resolve.
* @method * @method
* @param {String} type * @param {String} type
@ -300,7 +313,7 @@ AsyncEmitter.prototype._emit = function _emit(type) {
* @returns {Promise} * @returns {Promise}
*/ */
AsyncEmitter.prototype.emitAsync = async function emitAsync(type) { async emitAsync(type) {
try { try {
await this._emitAsync.apply(this, arguments); await this._emitAsync.apply(this, arguments);
} catch (e) { } catch (e) {
@ -309,9 +322,9 @@ AsyncEmitter.prototype.emitAsync = async function emitAsync(type) {
await this._emitAsync('error', e); await this._emitAsync('error', e);
} }
}; }
/** /**
* Emit an event. Wait for promises to resolve. * Emit an event. Wait for promises to resolve.
* @private * @private
* @param {String} type * @param {String} type
@ -319,20 +332,20 @@ AsyncEmitter.prototype.emitAsync = async function emitAsync(type) {
* @returns {Promise} * @returns {Promise}
*/ */
AsyncEmitter.prototype._emitAsync = async function _emitAsync(type) { async _emitAsync(type) {
assert(typeof type === 'string', '`type` must be a string.'); assert(typeof type === 'string', '`type` must be a string.');
const listeners = this._events[type]; const listeners = this._events[type];
if (!listeners) { if (!listeners) {
if (type === 'error') { if (type === 'error') {
const error = arguments[1]; const msg = arguments[1];
if (error instanceof Error) if (msg instanceof Error)
throw error; throw msg;
const err = new Error(`Uncaught, unspecified "error" event. (${error})`); const err = new Error(`Uncaught, unspecified "error" event. (${msg})`);
err.context = error; err.context = msg;
throw err; throw err;
} }
return; return;
@ -347,7 +360,9 @@ AsyncEmitter.prototype._emitAsync = async function _emitAsync(type) {
const handler = listener.handler; const handler = listener.handler;
if (listener.once) { if (listener.once) {
listeners.splice(i, 1); splice(listeners, i);
if (listeners.length === 0)
delete this._events[type];
i -= 1; i -= 1;
} }
@ -374,23 +389,48 @@ AsyncEmitter.prototype._emitAsync = async function _emitAsync(type) {
break; break;
} }
} }
}; }
}
/** /**
* Event Listener * Event Listener
* @constructor
* @ignore * @ignore
* @param {Function} handler
* @param {Boolean} once
* @property {Function} handler * @property {Function} handler
* @property {Boolean} once * @property {Boolean} once
*/ */
function Listener(handler, once) { class Listener {
/**
* Create an event listener.
* @constructor
* @param {Function} handler
* @param {Boolean} once
*/
constructor(handler, once) {
assert(typeof handler === 'function', '`handler` must be a function.'); assert(typeof handler === 'function', '`handler` must be a function.');
assert(typeof once === 'boolean', '`once` must be a function.'); assert(typeof once === 'boolean', '`once` must be a function.');
this.handler = handler; this.handler = handler;
this.once = once; this.once = once;
}
}
/*
* Helpers
*/
function splice(list, i) {
if (i === 0) {
list.shift();
return;
}
let k = i + 1;
while (k < list.length)
list[i++] = list[k++];
list.pop();
} }
/* /*

View File

@ -79,7 +79,25 @@ exports.remove = function remove(items, item, compare) {
if (i === -1) if (i === -1)
return false; return false;
items.splice(i, 1); splice(items, i);
return true; return true;
}; };
/*
* Helpers
*/
function splice(list, i) {
if (i === 0) {
list.shift();
return;
}
let k = i + 1;
while (k < list.length)
list[i++] = list[k++];
list.pop();
}

View File

@ -11,26 +11,28 @@ const assert = require('assert');
/** /**
* Binary Heap * Binary Heap
* @alias module:utils.Heap * @alias module:utils.Heap
*/
class Heap {
/**
* Create a binary heap.
* @constructor * @constructor
* @param {Function?} compare * @param {Function?} compare
*/ */
function Heap(compare) { constructor(compare) {
if (!(this instanceof Heap))
return new Heap(compare);
this.compare = comparator; this.compare = comparator;
this.items = []; this.items = [];
if (compare) if (compare)
this.set(compare); this.set(compare);
} }
/** /**
* Initialize and sort heap. * Initialize and sort heap.
*/ */
Heap.prototype.init = function init() { init() {
const n = this.items.length; const n = this.items.length;
if (n <= 1) if (n <= 1)
@ -38,47 +40,47 @@ Heap.prototype.init = function init() {
for (let i = (n / 2 | 0) - 1; i >= 0; i--) for (let i = (n / 2 | 0) - 1; i >= 0; i--)
this.down(i, n); this.down(i, n);
}; }
/** /**
* Get heap size. * Get heap size.
* @returns {Number} * @returns {Number}
*/ */
Heap.prototype.size = function size() { size() {
return this.items.length; return this.items.length;
}; }
/** /**
* Set comparator. * Set comparator.
* @param {Function} compare * @param {Function} compare
*/ */
Heap.prototype.set = function set(compare) { set(compare) {
assert(typeof compare === 'function', assert(typeof compare === 'function',
'Comparator must be a function.'); 'Comparator must be a function.');
this.compare = compare; this.compare = compare;
}; }
/** /**
* Push item onto heap. * Push item onto heap.
* @param {Object} item * @param {Object} item
* @returns {Number} * @returns {Number}
*/ */
Heap.prototype.insert = function insert(item) { insert(item) {
this.items.push(item); this.items.push(item);
this.up(this.items.length - 1); this.up(this.items.length - 1);
return this.items.length; return this.items.length;
}; }
/** /**
* Pop next item off of heap. * Pop next item off of heap.
* @param {Object} item * @param {Object} item
* @returns {Object} * @returns {Object}
*/ */
Heap.prototype.shift = function shift() { shift() {
if (this.items.length === 0) if (this.items.length === 0)
return null; return null;
@ -88,15 +90,15 @@ Heap.prototype.shift = function shift() {
this.down(0, n); this.down(0, n);
return this.items.pop(); return this.items.pop();
}; }
/** /**
* Remove item from heap. * Remove item from heap.
* @param {Number} i * @param {Number} i
* @returns {Object} * @returns {Object}
*/ */
Heap.prototype.remove = function remove(i) { remove(i) {
if (this.items.length === 0) if (this.items.length === 0)
return null; return null;
@ -112,23 +114,23 @@ Heap.prototype.remove = function remove(i) {
} }
return this.items.pop(); return this.items.pop();
}; }
/** /**
* Swap indicies. * Swap indicies.
* @private * @private
* @param {Number} a * @param {Number} a
* @param {Number} b * @param {Number} b
*/ */
Heap.prototype.swap = function swap(a, b) { swap(a, b) {
const x = this.items[a]; const x = this.items[a];
const y = this.items[b]; const y = this.items[b];
this.items[a] = y; this.items[a] = y;
this.items[b] = x; this.items[b] = x;
}; }
/** /**
* Compare indicies. * Compare indicies.
* @private * @private
* @param {Number} i * @param {Number} i
@ -136,18 +138,18 @@ Heap.prototype.swap = function swap(a, b) {
* @returns {Boolean} * @returns {Boolean}
*/ */
Heap.prototype.less = function less(i, j) { less(i, j) {
return this.compare(this.items[i], this.items[j]) < 0; return this.compare(this.items[i], this.items[j]) < 0;
}; }
/** /**
* Bubble item down. * Bubble item down.
* @private * @private
* @param {Number} i * @param {Number} i
* @param {Number} n * @param {Number} n
*/ */
Heap.prototype.down = function down(i, n) { down(i, n) {
for (;;) { for (;;) {
const l = 2 * i + 1; const l = 2 * i + 1;
@ -168,15 +170,15 @@ Heap.prototype.down = function down(i, n) {
this.swap(i, j); this.swap(i, j);
i = j; i = j;
} }
}; }
/** /**
* Bubble item up. * Bubble item up.
* @private * @private
* @param {Number} i * @param {Number} i
*/ */
Heap.prototype.up = function up(i) { up(i) {
for (;;) { for (;;) {
const j = (i - 1) / 2 | 0; const j = (i - 1) / 2 | 0;
@ -191,14 +193,14 @@ Heap.prototype.up = function up(i) {
this.swap(j, i); this.swap(j, i);
i = j; i = j;
} }
}; }
/** /**
* Convert heap to sorted array. * Convert heap to sorted array.
* @returns {Object[]} * @returns {Object[]}
*/ */
Heap.prototype.toArray = function toArray() { toArray() {
const heap = new Heap(); const heap = new Heap();
const result = []; const result = [];
@ -209,22 +211,23 @@ Heap.prototype.toArray = function toArray() {
result.push(heap.shift()); result.push(heap.shift());
return result; return result;
}; }
/** /**
* Instantiate heap from array and comparator. * Instantiate heap from array and comparator.
* @param {Function} compare * @param {Function} compare
* @param {Object[]} items * @param {Object[]} items
* @returns {Heap} * @returns {Heap}
*/ */
Heap.fromArray = function fromArray(compare, items) { static fromArray(compare, items) {
const heap = new Heap(); const heap = new Heap();
heap.set(compare); heap.set(compare);
heap.items = items; heap.items = items;
heap.init(); heap.init();
return heap; return heap;
}; }
}
/* /*
* Helpers * Helpers

View File

@ -9,28 +9,30 @@
const assert = require('assert'); const assert = require('assert');
/** /**
* A double linked list. * Double Linked List
* @alias module:utils.List * @alias module:utils.List
*/
class List {
/**
* Create a list.
* @constructor * @constructor
* @property {ListItem|null} head * @property {ListItem|null} head
* @property {ListItem|null} tail * @property {ListItem|null} tail
* @property {Number} size * @property {Number} size
*/ */
function List() { constructor() {
if (!(this instanceof List))
return new List();
this.head = null; this.head = null;
this.tail = null; this.tail = null;
this.size = 0; this.size = 0;
} }
/** /**
* Reset the cache. Clear all items. * Reset the cache. Clear all items.
*/ */
List.prototype.reset = function reset() { reset() {
let item, next; let item, next;
for (item = this.head; item; item = next) { for (item = this.head; item; item = next) {
@ -44,14 +46,14 @@ List.prototype.reset = function reset() {
this.head = null; this.head = null;
this.tail = null; this.tail = null;
this.size = 0; this.size = 0;
}; }
/** /**
* Remove the first item in the list. * Remove the first item in the list.
* @returns {ListItem} * @returns {ListItem}
*/ */
List.prototype.shift = function shift() { shift() {
const item = this.head; const item = this.head;
if (!item) if (!item)
@ -60,34 +62,34 @@ List.prototype.shift = function shift() {
this.remove(item); this.remove(item);
return item; return item;
}; }
/** /**
* Prepend an item to the linked list (sets new head). * Prepend an item to the linked list (sets new head).
* @param {ListItem} * @param {ListItem}
* @returns {Boolean} * @returns {Boolean}
*/ */
List.prototype.unshift = function unshift(item) { unshift(item) {
return this.insert(null, item); return this.insert(null, item);
}; }
/** /**
* Append an item to the linked list (sets new tail). * Append an item to the linked list (sets new tail).
* @param {ListItem} * @param {ListItem}
* @returns {Boolean} * @returns {Boolean}
*/ */
List.prototype.push = function push(item) { push(item) {
return this.insert(this.tail, item); return this.insert(this.tail, item);
}; }
/** /**
* Remove the last item in the list. * Remove the last item in the list.
* @returns {ListItem} * @returns {ListItem}
*/ */
List.prototype.pop = function pop() { pop() {
const item = this.tail; const item = this.tail;
if (!item) if (!item)
@ -96,9 +98,9 @@ List.prototype.pop = function pop() {
this.remove(item); this.remove(item);
return item; return item;
}; }
/** /**
* Insert item into the linked list. * Insert item into the linked list.
* @private * @private
* @param {ListItem|null} ref * @param {ListItem|null} ref
@ -106,7 +108,7 @@ List.prototype.pop = function pop() {
* @returns {Boolean} * @returns {Boolean}
*/ */
List.prototype.insert = function insert(ref, item) { insert(ref, item) {
if (item.prev || item.next || item === this.head) if (item.prev || item.next || item === this.head)
return false; return false;
@ -122,7 +124,7 @@ List.prototype.insert = function insert(ref, item) {
item.next = this.head; item.next = this.head;
this.head = item; this.head = item;
} }
this.size++; this.size += 1;
return true; return true;
} }
@ -133,19 +135,19 @@ List.prototype.insert = function insert(ref, item) {
if (ref === this.tail) if (ref === this.tail)
this.tail = item; this.tail = item;
this.size++; this.size += 1;
return true; return true;
}; }
/** /**
* Remove item from the linked list. * Remove item from the linked list.
* @private * @private
* @param {ListItem} * @param {ListItem}
* @returns {Boolean} * @returns {Boolean}
*/ */
List.prototype.remove = function remove(item) { remove(item) {
if (!item.prev && !item.next && item !== this.head) if (!item.prev && !item.next && item !== this.head)
return false; return false;
@ -170,18 +172,18 @@ List.prototype.remove = function remove(item) {
item.prev = null; item.prev = null;
item.next = null; item.next = null;
this.size--; this.size -= 1;
return true; return true;
}; }
/** /**
* Replace an item in-place. * Replace an item in-place.
* @param {ListItem} ref * @param {ListItem} ref
* @param {ListItem} item * @param {ListItem} item
*/ */
List.prototype.replace = function replace(ref, item) { replace(ref, item) {
if (ref.prev) if (ref.prev)
ref.prev.next = item; ref.prev.next = item;
@ -199,28 +201,29 @@ List.prototype.replace = function replace(ref, item) {
if (this.tail === ref) if (this.tail === ref)
this.tail = item; this.tail = item;
}; }
/** /**
* Slice the list to an array of items. * Slice the list to an array of items.
* Will remove the items sliced. * Will remove the items sliced.
* @param {Number?} total * @param {Number?} total
* @returns {ListItem[]} * @returns {ListItem[]}
*/ */
List.prototype.slice = function slice(total) { slice(total) {
const items = [];
let item, next;
if (total == null) if (total == null)
total = -1; total = -1;
for (item = this.head; item; item = next) { const items = [];
let next = null;
for (let item = this.head; item; item = next) {
next = item.next; next = item.next;
item.prev = null; item.prev = null;
item.next = null; item.next = null;
this.size--; this.size -= 1;
items.push(item); items.push(item);
@ -237,35 +240,42 @@ List.prototype.slice = function slice(total) {
} }
return items; return items;
}; }
/** /**
* Convert the list to an array of items. * Convert the list to an array of items.
* @returns {ListItem[]} * @returns {ListItem[]}
*/ */
List.prototype.toArray = function toArray() { toArray() {
const items = []; const items = [];
for (let item = this.head; item; item = item.next) for (let item = this.head; item; item = item.next)
items.push(item); items.push(item);
return items; return items;
}; }
}
/** /**
* Represents an linked list item. * List Item
* @alias module:utils.ListItem * @alias module:utils.ListItem
*/
class ListItem {
/**
* Create a list item.
* @constructor * @constructor
* @private * @private
* @param {String} key * @param {String} key
* @param {Object} value * @param {Object} value
*/ */
function ListItem(value) { constructor(value) {
this.next = null; this.next = null;
this.prev = null; this.prev = null;
this.value = value; this.value = value;
}
} }
/* /*

View File

@ -10,17 +10,19 @@
const assert = require('assert'); const assert = require('assert');
/** /**
* Represents a mutex lock for locking asynchronous object methods. * Mutex Lock
* @alias module:utils.Lock * @alias module:utils.Lock
*/
class Lock {
/**
* Create a lock.
* @constructor * @constructor
* @param {Boolean?} named - Whether to * @param {Boolean?} named - Whether to
* maintain a map of queued jobs by job name. * maintain a map of queued jobs by job name.
*/ */
function Lock(named) { constructor(named = false) {
if (!(this instanceof Lock))
return Lock.create(named);
this.named = named === true; this.named = named === true;
this.jobs = []; this.jobs = [];
@ -31,50 +33,45 @@ function Lock(named) {
this.current = null; this.current = null;
this.unlocker = this.unlock.bind(this); this.unlocker = this.unlock.bind(this);
} }
/** /**
* Create a closure scoped lock. * Create a closure scoped lock.
* @param {Boolean?} named * @param {Boolean?} named
* @returns {Function} Lock method. * @returns {Function} Lock method.
*/ */
Lock.create = function create(named) { static create(named) {
const lock = new Lock(named); const lock = new Lock(named);
return function _lock(arg1, arg2) { return function _lock(arg1, arg2) {
return lock.lock(arg1, arg2); return lock.lock(arg1, arg2);
}; };
}; }
/** /**
* Test whether the lock has a pending * Test whether the lock has a pending
* job or a job in progress (by name). * job or a job in progress (by name).
* @param {String} name * @param {String} name
* @returns {Boolean} * @returns {Boolean}
*/ */
Lock.prototype.has = function has(name) { has(name) {
assert(this.named, 'Must use named jobs.'); assert(this.named, 'Must use named jobs.');
if (this.current === name) if (this.current === name)
return true; return true;
const count = this.map.get(name); return this.pending(name);
}
if (count == null) /**
return false;
return count > 0;
};
/**
* Test whether the lock has * Test whether the lock has
* a pending job by name. * a pending job by name.
* @param {String} name * @param {String} name
* @returns {Boolean} * @returns {Boolean}
*/ */
Lock.prototype.hasPending = function hasPending(name) { pending(name) {
assert(this.named, 'Must use named jobs.'); assert(this.named, 'Must use named jobs.');
const count = this.map.get(name); const count = this.map.get(name);
@ -83,9 +80,9 @@ Lock.prototype.hasPending = function hasPending(name) {
return false; return false;
return count > 0; return count > 0;
}; }
/** /**
* Lock the parent object and all its methods * Lock the parent object and all its methods
* which use the lock. Begin to queue calls. * which use the lock. Begin to queue calls.
* @param {String?} name - Job name. * @param {String?} name - Job name.
@ -95,15 +92,15 @@ Lock.prototype.hasPending = function hasPending(name) {
* to resolve the queue. * to resolve the queue.
*/ */
Lock.prototype.lock = function lock(arg1, arg2) { lock(arg1, arg2) {
let name, force; let name, force;
if (this.named) { if (this.named) {
name = arg1 || null; name = arg1 || null;
force = arg2; force = arg2 || false;
} else { } else {
name = null; name = null;
force = arg1; force = arg1 || false;
} }
if (this.destroyed) if (this.destroyed)
@ -116,9 +113,7 @@ Lock.prototype.lock = function lock(arg1, arg2) {
if (this.busy) { if (this.busy) {
if (name) { if (name) {
let count = this.map.get(name); const count = this.map.get(name) || 0;
if (!count)
count = 0;
this.map.set(name, count + 1); this.map.set(name, count + 1);
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -130,14 +125,14 @@ Lock.prototype.lock = function lock(arg1, arg2) {
this.current = name; this.current = name;
return Promise.resolve(this.unlocker); return Promise.resolve(this.unlocker);
}; }
/** /**
* The actual unlock callback. * The actual unlock callback.
* @private * @private
*/ */
Lock.prototype.unlock = function unlock() { unlock() {
assert(this.destroyed || this.busy); assert(this.destroyed || this.busy);
this.busy = false; this.busy = false;
@ -163,13 +158,13 @@ Lock.prototype.unlock = function unlock() {
this.current = job.name; this.current = job.name;
job.resolve(this.unlocker); job.resolve(this.unlocker);
}; }
/** /**
* Destroy the lock. Purge all pending calls. * Destroy the lock. Purge all pending calls.
*/ */
Lock.prototype.destroy = function destroy() { destroy() {
assert(!this.destroyed, 'Lock is already destroyed.'); assert(!this.destroyed, 'Lock is already destroyed.');
this.destroyed = true; this.destroyed = true;
@ -183,21 +178,28 @@ Lock.prototype.destroy = function destroy() {
for (const job of jobs) for (const job of jobs)
job.reject(new Error('Lock was destroyed.')); job.reject(new Error('Lock was destroyed.'));
}; }
}
/** /**
* Lock Job * Lock Job
* @constructor
* @ignore * @ignore
*/
class Job {
/**
* Create a lock job.
* @constructor
* @param {Function} resolve * @param {Function} resolve
* @param {Function} reject * @param {Function} reject
* @param {String?} name * @param {String?} name
*/ */
function Job(resolve, reject, name) { constructor(resolve, reject, name) {
this.resolve = resolve; this.resolve = resolve;
this.reject = reject; this.reject = reject;
this.name = name || null; this.name = name || null;
}
} }
/* /*

View File

@ -10,17 +10,19 @@
const assert = require('assert'); const assert = require('assert');
/** /**
* An LRU cache, used for caching {@link ChainEntry}s. * LRU Cache
* @alias module:utils.LRU * @alias module:utils.LRU
*/
class LRU {
/**
* Create an LRU cache.
* @constructor * @constructor
* @param {Number} capacity * @param {Number} capacity
* @param {Function?} getSize * @param {Function?} getSize
*/ */
function LRU(capacity, getSize) { constructor(capacity, getSize) {
if (!(this instanceof LRU))
return new LRU(capacity, getSize);
this.map = new Map(); this.map = new Map();
this.size = 0; this.size = 0;
this.items = 0; this.items = 0;
@ -34,41 +36,46 @@ function LRU(capacity, getSize) {
this.capacity = capacity; this.capacity = capacity;
this.getSize = getSize; this.getSize = getSize;
} }
/** /**
* Calculate size of an item. * Calculate size of an item.
* @private * @private
* @param {LRUItem} item * @param {LRUItem} item
* @returns {Number} Size. * @returns {Number} Size.
*/ */
LRU.prototype._getSize = function _getSize(item) { _getSize(item) {
if (this.getSize) { if (this.getSize) {
const keySize = Math.floor(item.key.length * 1.375); const keySize = Math.floor(item.key.length * 1.375);
return 120 + keySize + this.getSize(item.value); return 120 + keySize + this.getSize(item.value);
} }
return 1; return 1;
}; }
/** /**
* Compact the LRU linked list. * Compact the LRU linked list.
* @private * @private
*/ */
LRU.prototype._compact = function _compact() { _compact() {
if (this.size <= this.capacity) if (this.size <= this.capacity)
return; return;
let item, next; let item = null;
let next = null;
for (item = this.head; item; item = next) { for (item = this.head; item; item = next) {
if (this.size <= this.capacity) if (this.size <= this.capacity)
break; break;
this.size -= this._getSize(item); this.size -= this._getSize(item);
this.items--; this.items -= 1;
this.map.delete(item.key); this.map.delete(item.key);
next = item.next; next = item.next;
item.prev = null; item.prev = null;
item.next = null; item.next = null;
} }
@ -81,18 +88,18 @@ LRU.prototype._compact = function _compact() {
this.head = item; this.head = item;
item.prev = null; item.prev = null;
}; }
/** /**
* Reset the cache. Clear all items. * Reset the cache. Clear all items.
*/ */
LRU.prototype.reset = function reset() { reset() {
let item, next; let item, next;
for (item = this.head; item; item = next) { for (item = this.head; item; item = next) {
this.map.delete(item.key); this.map.delete(item.key);
this.items--; this.items -= 1;
next = item.next; next = item.next;
item.prev = null; item.prev = null;
item.next = null; item.next = null;
@ -103,15 +110,15 @@ LRU.prototype.reset = function reset() {
this.size = 0; this.size = 0;
this.head = null; this.head = null;
this.tail = null; this.tail = null;
}; }
/** /**
* Add an item to the cache. * Add an item to the cache.
* @param {String|Number} key * @param {String|Number} key
* @param {Object} value * @param {Object} value
*/ */
LRU.prototype.set = function set(key, value) { set(key, value) {
if (this.capacity === 0) if (this.capacity === 0)
return; return;
@ -136,18 +143,18 @@ LRU.prototype.set = function set(key, value) {
this._appendList(item); this._appendList(item);
this.size += this._getSize(item); this.size += this._getSize(item);
this.items++; this.items += 1;
this._compact(); this._compact();
}; }
/** /**
* Retrieve an item from the cache. * Retrieve an item from the cache.
* @param {String|Number} key * @param {String|Number} key
* @returns {Object} Item. * @returns {Object} Item.
*/ */
LRU.prototype.get = function get(key) { get(key) {
if (this.capacity === 0) if (this.capacity === 0)
return null; return null;
@ -162,27 +169,27 @@ LRU.prototype.get = function get(key) {
this._appendList(item); this._appendList(item);
return item.value; return item.value;
}; }
/** /**
* Test whether the cache contains a key. * Test whether the cache contains a key.
* @param {String|Number} key * @param {String|Number} key
* @returns {Boolean} * @returns {Boolean}
*/ */
LRU.prototype.has = function has(key) { has(key) {
if (this.capacity === 0) if (this.capacity === 0)
return false; return false;
return this.map.has(String(key)); return this.map.has(String(key));
}; }
/** /**
* Remove an item from the cache. * Remove an item from the cache.
* @param {String|Number} key * @param {String|Number} key
* @returns {Boolean} Whether an item was removed. * @returns {Boolean} Whether an item was removed.
*/ */
LRU.prototype.remove = function remove(key) { remove(key) {
if (this.capacity === 0) if (this.capacity === 0)
return false; return false;
@ -194,43 +201,43 @@ LRU.prototype.remove = function remove(key) {
return false; return false;
this.size -= this._getSize(item); this.size -= this._getSize(item);
this.items--; this.items -= 1;
this.map.delete(key); this.map.delete(key);
this._removeList(item); this._removeList(item);
return true; return true;
}; }
/** /**
* Prepend an item to the linked list (sets new head). * Prepend an item to the linked list (sets new head).
* @private * @private
* @param {LRUItem} * @param {LRUItem}
*/ */
LRU.prototype._prependList = function _prependList(item) { _prependList(item) {
this._insertList(null, item); this._insertList(null, item);
}; }
/** /**
* Append an item to the linked list (sets new tail). * Append an item to the linked list (sets new tail).
* @private * @private
* @param {LRUItem} * @param {LRUItem}
*/ */
LRU.prototype._appendList = function _appendList(item) { _appendList(item) {
this._insertList(this.tail, item); this._insertList(this.tail, item);
}; }
/** /**
* Insert item into the linked list. * Insert item into the linked list.
* @private * @private
* @param {LRUItem|null} ref * @param {LRUItem|null} ref
* @param {LRUItem} item * @param {LRUItem} item
*/ */
LRU.prototype._insertList = function _insertList(ref, item) { _insertList(ref, item) {
assert(!item.next); assert(!item.next);
assert(!item.prev); assert(!item.prev);
@ -252,15 +259,15 @@ LRU.prototype._insertList = function _insertList(ref, item) {
if (ref === this.tail) if (ref === this.tail)
this.tail = item; this.tail = item;
}; }
/** /**
* Remove item from the linked list. * Remove item from the linked list.
* @private * @private
* @param {LRUItem} * @param {LRUItem}
*/ */
LRU.prototype._removeList = function _removeList(item) { _removeList(item) {
if (item.prev) if (item.prev)
item.prev.next = item.next; item.prev.next = item.next;
@ -281,14 +288,14 @@ LRU.prototype._removeList = function _removeList(item) {
item.prev = null; item.prev = null;
item.next = null; item.next = null;
}; }
/** /**
* Collect all keys in the cache, sorted by LRU. * Collect all keys in the cache, sorted by LRU.
* @returns {String[]} * @returns {String[]}
*/ */
LRU.prototype.keys = function keys() { keys() {
const items = []; const items = [];
for (let item = this.head; item; item = item.next) { for (let item = this.head; item; item = item.next) {
@ -302,172 +309,184 @@ LRU.prototype.keys = function keys() {
} }
return items; return items;
}; }
/** /**
* Collect all values in the cache, sorted by LRU. * Collect all values in the cache, sorted by LRU.
* @returns {String[]} * @returns {String[]}
*/ */
LRU.prototype.values = function values() { values() {
const items = []; const items = [];
for (let item = this.head; item; item = item.next) for (let item = this.head; item; item = item.next)
items.push(item.value); items.push(item.value);
return items; return items;
}; }
/** /**
* Convert the LRU cache to an array of items. * Convert the LRU cache to an array of items.
* @returns {Object[]} * @returns {Object[]}
*/ */
LRU.prototype.toArray = function toArray() { toArray() {
const items = []; const items = [];
for (let item = this.head; item; item = item.next) for (let item = this.head; item; item = item.next)
items.push(item); items.push(item);
return items; return items;
}; }
/** /**
* Create an atomic batch for the lru * Create an atomic batch for the lru
* (used for caching database writes). * (used for caching database writes).
* @returns {LRUBatch} * @returns {LRUBatch}
*/ */
LRU.prototype.batch = function batch() { batch() {
return new LRUBatch(this); return new LRUBatch(this);
}; }
/** /**
* Start the pending batch. * Start the pending batch.
*/ */
LRU.prototype.start = function start() { start() {
assert(!this.pending); assert(!this.pending);
this.pending = this.batch(); this.pending = this.batch();
}; }
/** /**
* Clear the pending batch. * Clear the pending batch.
*/ */
LRU.prototype.clear = function clear() { clear() {
assert(this.pending); assert(this.pending);
this.pending.clear(); this.pending.clear();
}; }
/** /**
* Drop the pending batch. * Drop the pending batch.
*/ */
LRU.prototype.drop = function drop() { drop() {
assert(this.pending); assert(this.pending);
this.pending = null; this.pending = null;
}; }
/** /**
* Commit the pending batch. * Commit the pending batch.
*/ */
LRU.prototype.commit = function commit() { commit() {
assert(this.pending); assert(this.pending);
this.pending.commit(); this.pending.commit();
this.pending = null; this.pending = null;
}; }
/** /**
* Push an item onto the pending batch. * Push an item onto the pending batch.
* @param {String} key * @param {String} key
* @param {Object} value * @param {Object} value
*/ */
LRU.prototype.push = function push(key, value) { push(key, value) {
assert(this.pending); assert(this.pending);
if (this.capacity === 0) if (this.capacity === 0)
return; return;
this.pending.set(key, value); this.pending.set(key, value);
}; }
/** /**
* Push a removal onto the pending batch. * Push a removal onto the pending batch.
* @param {String} key * @param {String} key
*/ */
LRU.prototype.unpush = function unpush(key) { unpush(key) {
assert(this.pending); assert(this.pending);
if (this.capacity === 0) if (this.capacity === 0)
return; return;
this.pending.remove(key); this.pending.remove(key);
}; }
}
/** /**
* Represents an LRU item. * LRU Item
* @alias module:utils.LRUItem * @alias module:utils.LRUItem
*/
class LRUItem {
/**
* Create an LRU item.
* @constructor * @constructor
* @private * @private
* @param {String} key * @param {String} key
* @param {Object} value * @param {Object} value
*/ */
function LRUItem(key, value) { constructor(key, value) {
this.key = key; this.key = key;
this.value = value; this.value = value;
this.next = null; this.next = null;
this.prev = null; this.prev = null;
}
} }
/** /**
* LRU Batch * LRU Batch
* @alias module:utils.LRUBatch * @alias module:utils.LRUBatch
*/
class LRUBatch {
/**
* Create an LRU batch.
* @constructor * @constructor
* @param {LRU} lru * @param {LRU} lru
*/ */
function LRUBatch(lru) { constructor(lru) {
this.lru = lru; this.lru = lru;
this.ops = []; this.ops = [];
} }
/** /**
* Push an item onto the batch. * Push an item onto the batch.
* @param {String} key * @param {String} key
* @param {Object} value * @param {Object} value
*/ */
LRUBatch.prototype.set = function set(key, value) { set(key, value) {
this.ops.push(new LRUOp(false, key, value)); this.ops.push(new LRUOp(false, key, value));
}; }
/** /**
* Push a removal onto the batch. * Push a removal onto the batch.
* @param {String} key * @param {String} key
*/ */
LRUBatch.prototype.remove = function remove(key) { remove(key) {
this.ops.push(new LRUOp(true, key, null)); this.ops.push(new LRUOp(true, key, null));
}; }
/** /**
* Clear the batch. * Clear the batch.
*/ */
LRUBatch.prototype.clear = function clear() { clear() {
this.ops.length = 0; this.ops.length = 0;
}; }
/** /**
* Commit the batch. * Commit the batch.
*/ */
LRUBatch.prototype.commit = function commit() { commit() {
for (const op of this.ops) { for (const op of this.ops) {
if (op.remove) { if (op.remove) {
this.lru.remove(op.key); this.lru.remove(op.key);
@ -477,22 +496,29 @@ LRUBatch.prototype.commit = function commit() {
} }
this.ops.length = 0; this.ops.length = 0;
}; }
}
/** /**
* LRU Op * LRU Op
* @alias module:utils.LRUOp * @alias module:utils.LRUOp
* @constructor
* @private * @private
*/
class LRUOp {
/**
* Create an LRU op.
* @constructor
* @param {Boolean} remove * @param {Boolean} remove
* @param {String} key * @param {String} key
* @param {Object} value * @param {Object} value
*/ */
function LRUOp(remove, key, value) { constructor(remove, key, value) {
this.remove = remove; this.remove = remove;
this.key = key; this.key = key;
this.value = value; this.value = value;
}
} }
/* /*

View File

@ -10,67 +10,68 @@
const assert = require('assert'); const assert = require('assert');
/** /**
* Represents a mutex lock for locking asynchronous object methods. * Mapped Lock
* Locks methods according to passed-in key.
* @alias module:utils.MappedLock * @alias module:utils.MappedLock
*/
class MappedLock {
/**
* Create a mapped lock.
* @constructor * @constructor
*/ */
function MappedLock() { constructor() {
if (!(this instanceof MappedLock))
return MappedLock.create();
this.jobs = new Map(); this.jobs = new Map();
this.busy = new Set(); this.busy = new Set();
this.destroyed = false; this.destroyed = false;
} }
/** /**
* Create a closure scoped lock. * Create a closure scoped lock.
* @returns {Function} Lock method. * @returns {Function} Lock method.
*/ */
MappedLock.create = function create() { static create() {
const lock = new MappedLock(); const lock = new MappedLock();
return function _lock(key, force) { return function _lock(key, force) {
return lock.lock(key, force); return lock.lock(key, force);
}; };
}; }
/** /**
* Test whether the lock has a pending * Test whether the lock has a pending
* job or a job in progress (by name). * job or a job in progress (by name).
* @param {String} name * @param {String} name
* @returns {Boolean} * @returns {Boolean}
*/ */
MappedLock.prototype.has = function has(name) { has(name) {
return this.busy.has(name); return this.busy.has(name);
}; }
/** /**
* Test whether the lock has * Test whether the lock has
* a pending job by name. * a pending job by name.
* @param {String} name * @param {String} name
* @returns {Boolean} * @returns {Boolean}
*/ */
MappedLock.prototype.hasPending = function hasPending(name) { pending(name) {
return this.jobs.has(name); return this.jobs.has(name);
}; }
/** /**
* Lock the parent object and all its methods * Lock the parent object and all its methods
* which use the lock with a specified key. * which use the lock with a specified key.
* Begin to queue calls. * Begin to queue calls.
* @param {String|Number} key * @param {String|Number} key
* @param {Boolean?} force - Force a call. * @param {Boolean} [force=false] - Force a call.
* @returns {Promise} - Returns {Function}, must be * @returns {Promise} - Returns {Function}, must be
* called once the method finishes executing in order * called once the method finishes executing in order
* to resolve the queue. * to resolve the queue.
*/ */
MappedLock.prototype.lock = function lock(key, force) { lock(key, force = false) {
if (this.destroyed) if (this.destroyed)
return Promise.reject(new Error('Lock is destroyed.')); return Promise.reject(new Error('Lock is destroyed.'));
@ -93,16 +94,16 @@ MappedLock.prototype.lock = function lock(key, force) {
this.busy.add(key); this.busy.add(key);
return Promise.resolve(this.unlock(key)); return Promise.resolve(this.unlock(key));
}; }
/** /**
* Create an unlock callback. * Create an unlock callback.
* @private * @private
* @param {String} key * @param {String} key
* @returns {Function} Unlocker. * @returns {Function} Unlocker.
*/ */
MappedLock.prototype.unlock = function unlock(key) { unlock(key) {
const self = this; const self = this;
return function unlocker() { return function unlocker() {
const jobs = self.jobs.get(key); const jobs = self.jobs.get(key);
@ -125,13 +126,13 @@ MappedLock.prototype.unlock = function unlock(key) {
job.resolve(unlocker); job.resolve(unlocker);
}; };
}; }
/** /**
* Destroy the lock. Purge all pending calls. * Destroy the lock. Purge all pending calls.
*/ */
MappedLock.prototype.destroy = function destroy() { destroy() {
assert(!this.destroyed, 'Lock is already destroyed.'); assert(!this.destroyed, 'Lock is already destroyed.');
const map = this.jobs; const map = this.jobs;
@ -145,19 +146,26 @@ MappedLock.prototype.destroy = function destroy() {
for (const job of jobs) for (const job of jobs)
job.reject(new Error('Lock was destroyed.')); job.reject(new Error('Lock was destroyed.'));
} }
}; }
}
/** /**
* Lock Job * Lock Job
* @constructor
* @ignore * @ignore
*/
class Job {
/**
* Create a lock job.
* @constructor
* @param {Function} resolve * @param {Function} resolve
* @param {Function} reject * @param {Function} reject
*/ */
function Job(resolve, reject) { constructor(resolve, reject) {
this.resolve = resolve; this.resolve = resolve;
this.reject = reject; this.reject = reject;
}
} }
/* /*

View File

@ -10,17 +10,18 @@ const assert = require('assert');
const AsyncEmitter = require('../utils/asyncemitter'); const AsyncEmitter = require('../utils/asyncemitter');
/** /**
* NodeClient * Node Client
* Sort of a fake local client for separation of concerns.
* @alias module:node.NodeClient * @alias module:node.NodeClient
*/
class NodeClient extends AsyncEmitter {
/**
* Create a node client.
* @constructor * @constructor
*/ */
function NodeClient(node) { constructor(node) {
if (!(this instanceof NodeClient)) super();
return new NodeClient(node);
AsyncEmitter.call(this);
this.node = node; this.node = node;
this.network = node.network; this.network = node.network;
@ -28,16 +29,13 @@ function NodeClient(node) {
this.opened = false; this.opened = false;
this.init(); this.init();
} }
Object.setPrototypeOf(NodeClient.prototype, AsyncEmitter.prototype); /**
/**
* Initialize the client. * Initialize the client.
* @returns {Promise}
*/ */
NodeClient.prototype.init = function init() { init() {
this.node.on('connect', (entry, block) => { this.node.on('connect', (entry, block) => {
if (!this.opened) if (!this.opened)
return; return;
@ -65,66 +63,66 @@ NodeClient.prototype.init = function init() {
this.emit('chain reset', tip); this.emit('chain reset', tip);
}); });
}; }
/** /**
* Open the client. * Open the client.
* @returns {Promise} * @returns {Promise}
*/ */
NodeClient.prototype.open = async function open(options) { async open(options) {
assert(!this.opened, 'NodeClient is already open.'); assert(!this.opened, 'NodeClient is already open.');
this.opened = true; this.opened = true;
setImmediate(() => this.emit('connect')); setImmediate(() => this.emit('connect'));
}; }
/** /**
* Close the client. * Close the client.
* @returns {Promise} * @returns {Promise}
*/ */
NodeClient.prototype.close = async function close() { async close() {
assert(this.opened, 'NodeClient is not open.'); assert(this.opened, 'NodeClient is not open.');
this.opened = false; this.opened = false;
setImmediate(() => this.emit('disconnect')); setImmediate(() => this.emit('disconnect'));
}; }
/** /**
* Add a listener. * Add a listener.
* @param {String} type * @param {String} type
* @param {Function} handler * @param {Function} handler
*/ */
NodeClient.prototype.bind = function bind(type, handler) { bind(type, handler) {
return this.on(type, handler); return this.on(type, handler);
}; }
/** /**
* Add a listener. * Add a listener.
* @param {String} type * @param {String} type
* @param {Function} handler * @param {Function} handler
*/ */
NodeClient.prototype.hook = function hook(type, handler) { hook(type, handler) {
return this.on(type, handler); return this.on(type, handler);
}; }
/** /**
* Get chain tip. * Get chain tip.
* @returns {Promise} * @returns {Promise}
*/ */
NodeClient.prototype.getTip = async function getTip() { async getTip() {
return this.node.chain.tip; return this.node.chain.tip;
}; }
/** /**
* Get chain entry. * Get chain entry.
* @param {Hash} hash * @param {Hash} hash
* @returns {Promise} * @returns {Promise}
*/ */
NodeClient.prototype.getEntry = async function getEntry(hash) { async getEntry(hash) {
const entry = await this.node.chain.getEntry(hash); const entry = await this.node.chain.getEntry(hash);
if (!entry) if (!entry)
@ -134,73 +132,73 @@ NodeClient.prototype.getEntry = async function getEntry(hash) {
return null; return null;
return entry; return entry;
}; }
/** /**
* Send a transaction. Do not wait for promise. * Send a transaction. Do not wait for promise.
* @param {TX} tx * @param {TX} tx
* @returns {Promise} * @returns {Promise}
*/ */
NodeClient.prototype.send = async function send(tx) { async send(tx) {
this.node.relay(tx); this.node.relay(tx);
}; }
/** /**
* Set bloom filter. * Set bloom filter.
* @param {Bloom} filter * @param {Bloom} filter
* @returns {Promise} * @returns {Promise}
*/ */
NodeClient.prototype.setFilter = async function setFilter(filter) { async setFilter(filter) {
this.filter = filter; this.filter = filter;
this.node.pool.setFilter(filter); this.node.pool.setFilter(filter);
}; }
/** /**
* Add data to filter. * Add data to filter.
* @param {Buffer} data * @param {Buffer} data
* @returns {Promise} * @returns {Promise}
*/ */
NodeClient.prototype.addFilter = async function addFilter(data) { async addFilter(data) {
this.node.pool.queueFilterLoad(); this.node.pool.queueFilterLoad();
}; }
/** /**
* Reset filter. * Reset filter.
* @returns {Promise} * @returns {Promise}
*/ */
NodeClient.prototype.resetFilter = async function resetFilter() { async resetFilter() {
this.node.pool.queueFilterLoad(); this.node.pool.queueFilterLoad();
}; }
/** /**
* Esimate smart fee. * Esimate smart fee.
* @param {Number?} blocks * @param {Number?} blocks
* @returns {Promise} * @returns {Promise}
*/ */
NodeClient.prototype.estimateFee = async function estimateFee(blocks) { async estimateFee(blocks) {
if (!this.node.fees) if (!this.node.fees)
return this.network.feeRate; return this.network.feeRate;
return this.node.fees.estimateFee(blocks); return this.node.fees.estimateFee(blocks);
}; }
/** /**
* Get hash range. * Get hash range.
* @param {Number} start * @param {Number} start
* @param {Number} end * @param {Number} end
* @returns {Promise} * @returns {Promise}
*/ */
NodeClient.prototype.getHashes = async function getHashes(start = -1, end = -1) { async getHashes(start = -1, end = -1) {
return this.node.chain.getHashes(start, end); return this.node.chain.getHashes(start, end);
}; }
/** /**
* Rescan for any missed transactions. * Rescan for any missed transactions.
* @param {Number|Hash} start - Start block. * @param {Number|Hash} start - Start block.
* @param {Bloom} filter * @param {Bloom} filter
@ -208,11 +206,12 @@ NodeClient.prototype.getHashes = async function getHashes(start = -1, end = -1)
* @returns {Promise} * @returns {Promise}
*/ */
NodeClient.prototype.rescan = async function rescan(start) { async rescan(start) {
return this.node.chain.scan(start, this.filter, (entry, txs) => { return this.node.chain.scan(start, this.filter, (entry, txs) => {
return this.emitAsync('block rescan', entry, txs); return this.emitAsync('block rescan', entry, txs);
}); });
}; }
}
/* /*
* Expose * Expose