Merge PR #692 from 'nodech/net-updates'
This commit is contained in:
commit
6213460846
11 changed files with 3413 additions and 154 deletions
|
|
@ -23,6 +23,42 @@ const NetAddress = require('./netaddress');
|
|||
const common = require('./common');
|
||||
const seeds = require('./seeds');
|
||||
|
||||
/**
|
||||
* Stochastic address manager based on bitcoin addrman.
|
||||
*
|
||||
* Design goals:
|
||||
* * Keep the address tables in-memory, and asynchronously dump the entire
|
||||
* table to hosts.json.
|
||||
* * Make sure no (localized) attacker can fill the entire table with his
|
||||
* nodes/addresses.
|
||||
*
|
||||
* To that end:
|
||||
* * Addresses are organized into buckets that can each store up
|
||||
* to 64 entries (maxEntries).
|
||||
* * Addresses to which our node has not successfully connected go into
|
||||
* 1024 "fresh" buckets (maxFreshBuckets).
|
||||
* * Based on the address range of the source of information
|
||||
* 64 buckets are selected at random.
|
||||
* * The actual bucket is chosen from one of these, based on the range in
|
||||
* which the address itself is located.
|
||||
* * The position in the bucket is chosen based on the full address.
|
||||
* * One single address can occur in up to 8 different buckets to increase
|
||||
* selection chances for addresses that are seen frequently. The chance
|
||||
* for increasing this multiplicity decreases exponentially.
|
||||
* * When adding a new address to an occupied position of a bucket, it
|
||||
* will not replace the existing entry unless that address is also stored
|
||||
* in another bucket or it doesn't meet one of several quality criteria
|
||||
* (see isStale for exact criteria).
|
||||
* * Addresses of nodes that are known to be accessible go into 256 "tried"
|
||||
* buckets.
|
||||
* * Each address range selects at random 8 of these buckets.
|
||||
* * The actual bucket is chosen from one of these, based on the full
|
||||
* address.
|
||||
* * Bucket selection is based on cryptographic hashing,
|
||||
* using a randomly-generated 256-bit key, which should not be observable
|
||||
* by adversaries (key).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Host List
|
||||
* @alias module:net.HostList
|
||||
|
|
@ -42,6 +78,7 @@ class HostList {
|
|||
this.address = this.options.address;
|
||||
this.brontide = this.options.brontide;
|
||||
this.resolve = this.options.resolve;
|
||||
this.random = this.options.random;
|
||||
|
||||
this.key = rng.randomBytes(32);
|
||||
this.hash = new Hash256();
|
||||
|
|
@ -381,7 +418,7 @@ class HostList {
|
|||
buckets = this.fresh;
|
||||
|
||||
if (this.totalUsed > 0) {
|
||||
if (this.totalFresh === 0 || random(2) === 0)
|
||||
if (this.totalFresh === 0 || this.random(2) === 0)
|
||||
buckets = this.used;
|
||||
}
|
||||
|
||||
|
|
@ -393,13 +430,13 @@ class HostList {
|
|||
let factor = 1;
|
||||
|
||||
for (;;) {
|
||||
const i = random(buckets.length);
|
||||
const i = this.random(buckets.length);
|
||||
const bucket = buckets[i];
|
||||
|
||||
if (bucket.size === 0)
|
||||
continue;
|
||||
|
||||
let index = random(bucket.size);
|
||||
let index = this.random(bucket.size);
|
||||
let entry;
|
||||
|
||||
if (buckets === this.used) {
|
||||
|
|
@ -414,7 +451,7 @@ class HostList {
|
|||
}
|
||||
}
|
||||
|
||||
const num = random(1 << 30);
|
||||
const num = this.random(1 << 30);
|
||||
|
||||
if (num < factor * entry.chance(now) * (1 << 30))
|
||||
return entry;
|
||||
|
|
@ -427,17 +464,20 @@ class HostList {
|
|||
* Get fresh bucket for host.
|
||||
* @private
|
||||
* @param {HostEntry} entry
|
||||
* @param {NetAddress?} src
|
||||
* @returns {Map}
|
||||
*/
|
||||
|
||||
freshBucket(entry) {
|
||||
freshBucket(entry, src) {
|
||||
const addr = entry.addr;
|
||||
const src = entry.src;
|
||||
|
||||
if (!src)
|
||||
src = entry.src;
|
||||
|
||||
this.hash.init();
|
||||
this.hash.update(this.key);
|
||||
this.hash.update(groupKey(addr.raw));
|
||||
this.hash.update(groupKey(src.raw));
|
||||
this.hash.update(addr.getGroup());
|
||||
this.hash.update(src.getGroup());
|
||||
|
||||
const hash1 = this.hash.final();
|
||||
const hash32 = bio.readU32(hash1, 0) % 64;
|
||||
|
|
@ -446,7 +486,7 @@ class HostList {
|
|||
|
||||
this.hash.init();
|
||||
this.hash.update(this.key);
|
||||
this.hash.update(groupKey(src.raw));
|
||||
this.hash.update(src.getGroup());
|
||||
this.hash.update(this.hashbuf);
|
||||
|
||||
const hash2 = this.hash.final();
|
||||
|
|
@ -481,7 +521,7 @@ class HostList {
|
|||
|
||||
this.hash.init();
|
||||
this.hash.update(this.key);
|
||||
this.hash.update(groupKey(addr.raw));
|
||||
this.hash.update(addr.getGroup());
|
||||
this.hash.update(this.hashbuf);
|
||||
|
||||
const hash2 = this.hash.final();
|
||||
|
|
@ -552,7 +592,7 @@ class HostList {
|
|||
for (let i = 0; i < entry.refCount; i++)
|
||||
factor *= 2;
|
||||
|
||||
if (random(factor) !== 0)
|
||||
if (this.random(factor) !== 0)
|
||||
return false;
|
||||
} else {
|
||||
if (!src)
|
||||
|
|
@ -563,7 +603,7 @@ class HostList {
|
|||
this.totalFresh += 1;
|
||||
}
|
||||
|
||||
const bucket = this.freshBucket(entry);
|
||||
const bucket = this.freshBucket(entry, src);
|
||||
|
||||
if (bucket.has(entry.key()))
|
||||
return false;
|
||||
|
|
@ -828,7 +868,7 @@ class HostList {
|
|||
items.push(entry);
|
||||
|
||||
for (let i = 0; i < items.length && out.length < 2500; i++) {
|
||||
const j = random(items.length - i);
|
||||
const j = this.random(items.length - i);
|
||||
|
||||
[items[i], items[i + j]] = [items[i + j], items[i]];
|
||||
|
||||
|
|
@ -1409,6 +1449,14 @@ HostList.scores = {
|
|||
/**
|
||||
* Host Entry
|
||||
* @alias module:net.HostEntry
|
||||
* @property {NetAddress} addr - host address.
|
||||
* @property {NetAddress} src - the first address we discovered this entry
|
||||
* from.
|
||||
* @property {Boolean} used - is it in the used set.
|
||||
* @property {Number} refCount - Reference count in new buckets.
|
||||
* @property {Number} attempts - connection attempts since last successful one.
|
||||
* @property {Number} lastSuccess - last success timestamp.
|
||||
* @property {Number} lastAttempt - last attempt timestamp.
|
||||
*/
|
||||
|
||||
class HostEntry {
|
||||
|
|
@ -1630,6 +1678,7 @@ class HostListOptions {
|
|||
this.onion = false;
|
||||
this.brontideOnly = false;
|
||||
this.banTime = common.BAN_TIME;
|
||||
this.random = random;
|
||||
|
||||
this.address = new NetAddress();
|
||||
this.address.services = this.services;
|
||||
|
|
@ -1762,6 +1811,11 @@ class HostListOptions {
|
|||
this.flushInterval = options.flushInterval;
|
||||
}
|
||||
|
||||
if (options.random != null) {
|
||||
assert(typeof options.random === 'function');
|
||||
this.random = options.random;;
|
||||
}
|
||||
|
||||
this.address.time = this.network.now();
|
||||
this.address.services = this.services;
|
||||
|
||||
|
|
@ -1781,65 +1835,11 @@ function random(max) {
|
|||
return Math.floor(Math.random() * max);
|
||||
}
|
||||
|
||||
function groupKey(raw) {
|
||||
// See: https://github.com/bitcoin/bitcoin/blob/e258ce7/src/netaddress.cpp#L413
|
||||
// Todo: Use IP->ASN mapping, see:
|
||||
// https://github.com/bitcoin/bitcoin/blob/adea5e1/src/addrman.h#L274
|
||||
let type = 6; // NET_IPV6
|
||||
let start = 0;
|
||||
let bits = 16;
|
||||
let i = 0;
|
||||
|
||||
if (IP.isLocal(raw)) {
|
||||
type = 255; // NET_LOCAL
|
||||
bits = 0;
|
||||
} else if (!IP.isRoutable(raw)) {
|
||||
type = 0; // NET_UNROUTABLE
|
||||
bits = 0;
|
||||
} else if (IP.isIPv4(raw) || IP.isRFC6145(raw) || IP.isRFC6052(raw)) {
|
||||
type = 4; // NET_IPV4
|
||||
start = 12;
|
||||
} else if (IP.isRFC3964(raw)) {
|
||||
type = 4; // NET_IPV4
|
||||
start = 2;
|
||||
} else if (IP.isRFC4380(raw)) {
|
||||
const buf = Buffer.alloc(3);
|
||||
buf[0] = 4; // NET_IPV4
|
||||
buf[1] = raw[12] ^ 0xff;
|
||||
buf[2] = raw[13] ^ 0xff;
|
||||
return buf;
|
||||
} else if (IP.isOnion(raw)) {
|
||||
type = 8; // NET_ONION
|
||||
start = 6;
|
||||
bits = 4;
|
||||
} else if (raw[0] === 0x20
|
||||
&& raw[1] === 0x01
|
||||
&& raw[2] === 0x04
|
||||
&& raw[3] === 0x70) {
|
||||
bits = 36;
|
||||
} else {
|
||||
bits = 32;
|
||||
}
|
||||
|
||||
const out = Buffer.alloc(1 + ((bits + 7) >>> 3));
|
||||
|
||||
out[i++] = type;
|
||||
|
||||
while (bits >= 8) {
|
||||
out[i++] = raw[start++];
|
||||
bits -= 8;
|
||||
}
|
||||
|
||||
if (bits > 0)
|
||||
out[i++] = raw[start] | ((1 << (8 - bits)) - 1);
|
||||
|
||||
assert(i === out.length);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose
|
||||
*/
|
||||
|
||||
module.exports = HostList;
|
||||
exports = HostList;
|
||||
exports.HostEntry = HostEntry;
|
||||
|
||||
module.exports = exports;
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ class NetAddress extends bio.Struct {
|
|||
this.services = 0;
|
||||
this.time = 0;
|
||||
this.hostname = '0.0.0.0:0';
|
||||
this.raw = IP.ZERO_IP;
|
||||
this.raw = IP.ZERO_IPV4;
|
||||
this.key = ZERO_KEY;
|
||||
|
||||
if (options)
|
||||
|
|
@ -63,26 +63,32 @@ class NetAddress extends bio.Struct {
|
|||
*/
|
||||
|
||||
fromOptions(options) {
|
||||
assert(typeof options.host === 'string');
|
||||
assert(typeof options.port === 'number');
|
||||
assert(typeof options.host === 'string',
|
||||
'NetAddress requires host string.');
|
||||
assert(typeof options.port === 'number',
|
||||
'NetAddress requires port number.');
|
||||
assert(options.port >= 0 && options.port <= 0xffff,
|
||||
'port number is incorrect.');
|
||||
|
||||
this.raw = IP.toBuffer(options.host);
|
||||
this.host = IP.toString(this.raw);
|
||||
this.port = options.port;
|
||||
|
||||
if (options.services) {
|
||||
assert(typeof options.services === 'number');
|
||||
assert(typeof options.services === 'number',
|
||||
'services must be a number.');
|
||||
this.services = options.services;
|
||||
}
|
||||
|
||||
if (options.time) {
|
||||
assert(typeof options.time === 'number');
|
||||
assert(typeof options.time === 'number',
|
||||
'time must be a number.');
|
||||
this.time = options.time;
|
||||
}
|
||||
|
||||
if (options.key) {
|
||||
assert(Buffer.isBuffer(options.key));
|
||||
assert(options.key.length === 33);
|
||||
assert(Buffer.isBuffer(options.key), 'key must be a buffer.');
|
||||
assert(options.key.length === 33, 'key length must be 33.');
|
||||
this.key = options.key;
|
||||
}
|
||||
|
||||
|
|
@ -119,6 +125,42 @@ class NetAddress extends bio.Struct {
|
|||
return IP.isIPv6(this.raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether the address is RFC3964.
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
isRFC3964() {
|
||||
return IP.isRFC3964(this.raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether the address is RFC4380.
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
isRFC4380() {
|
||||
return IP.isRFC4380(this.raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether the address is RFC6052.
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
isRFC6052() {
|
||||
return IP.isRFC6052(this.raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether the address is RFC6145.
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
isRFC6145() {
|
||||
return IP.isRFC6145(this.raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether the host is null.
|
||||
* @returns {Boolean}
|
||||
|
|
@ -206,12 +248,21 @@ class NetAddress extends bio.Struct {
|
|||
return IP.getReachability(this.raw, dest.raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the canonical identifier of our network group
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
getGroup() {
|
||||
return groupKey(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set null host.
|
||||
*/
|
||||
|
||||
setNull() {
|
||||
this.raw = IP.ZERO_IP;
|
||||
this.raw = IP.ZERO_IPV4;
|
||||
this.host = '0.0.0.0';
|
||||
this.key = ZERO_KEY;
|
||||
this.hostname = IP.toHostname(this.host, this.port, this.key);
|
||||
|
|
@ -487,6 +538,74 @@ NetAddress.DEFAULT_SERVICES = 0
|
|||
| common.services.NETWORK
|
||||
| common.services.BLOOM;
|
||||
|
||||
/*
|
||||
* Helpers
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {NetAddress} addr
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
function groupKey(addr) {
|
||||
const raw = addr.raw;
|
||||
|
||||
// See: https://github.com/bitcoin/bitcoin/blob/e258ce7/src/netaddress.cpp#L413
|
||||
// Todo: Use IP->ASN mapping, see:
|
||||
// https://github.com/bitcoin/bitcoin/blob/adea5e1/src/addrman.h#L274
|
||||
let type = IP.networks.INET6; // NET_IPV6
|
||||
let start = 0;
|
||||
let bits = 16;
|
||||
let i = 0;
|
||||
|
||||
if (addr.isLocal()) {
|
||||
type = 255; // NET_LOCAL
|
||||
bits = 0;
|
||||
} else if (!addr.isRoutable()) {
|
||||
type = IP.networks.NONE; // NET_UNROUTABLE
|
||||
bits = 0;
|
||||
} else if (addr.isIPv4() || addr.isRFC6145() || addr.isRFC6052()) {
|
||||
type = IP.networks.INET4; // NET_IPV4
|
||||
start = 12;
|
||||
} else if (addr.isRFC3964()) {
|
||||
type = IP.networks.INET4; // NET_IPV4
|
||||
start = 2;
|
||||
} else if (addr.isRFC4380()) {
|
||||
const buf = Buffer.alloc(3);
|
||||
buf[0] = IP.networks.INET4; // NET_IPV4
|
||||
buf[1] = raw[12] ^ 0xff;
|
||||
buf[2] = raw[13] ^ 0xff;
|
||||
return buf;
|
||||
} else if (addr.isOnion()) {
|
||||
type = IP.networks.ONION; // NET_ONION
|
||||
start = 6;
|
||||
bits = 4;
|
||||
} else if (raw[0] === 0x20
|
||||
&& raw[1] === 0x01
|
||||
&& raw[2] === 0x04
|
||||
&& raw[3] === 0x70) {
|
||||
bits = 36;
|
||||
} else {
|
||||
bits = 32;
|
||||
}
|
||||
|
||||
const out = Buffer.alloc(1 + ((bits + 7) >>> 3));
|
||||
|
||||
out[i++] = type;
|
||||
|
||||
while (bits >= 8) {
|
||||
out[i++] = raw[start++];
|
||||
bits -= 8;
|
||||
}
|
||||
|
||||
if (bits > 0)
|
||||
out[i++] = raw[start] | ((1 << (8 - bits)) - 1);
|
||||
|
||||
assert(i === out.length);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ class Peer extends EventEmitter {
|
|||
constructor(options) {
|
||||
super();
|
||||
|
||||
this.options = options;
|
||||
this.options = new PeerOptions(options);
|
||||
this.network = this.options.network;
|
||||
this.logger = this.options.logger.context('peer');
|
||||
this.locker = new Lock();
|
||||
|
|
@ -164,16 +164,6 @@ class Peer extends EventEmitter {
|
|||
return peer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a peer from options.
|
||||
* @param {Object} options
|
||||
* @returns {Peer}
|
||||
*/
|
||||
|
||||
static fromOptions(options) {
|
||||
return new this(new PeerOptions(options));
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin peer initialization.
|
||||
* @private
|
||||
|
|
@ -2161,7 +2151,7 @@ class PeerOptions {
|
|||
this.compact = false;
|
||||
this.headers = false;
|
||||
this.banScore = common.BAN_SCORE;
|
||||
this.proofPRS = 100;
|
||||
this.maxProofRPS = 100;
|
||||
|
||||
this.getHeight = PeerOptions.getHeight;
|
||||
this.isFull = PeerOptions.isFull;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ const assert = require('bsert');
|
|||
const EventEmitter = require('events');
|
||||
const {Lock} = require('bmutex');
|
||||
const IP = require('binet');
|
||||
const dns = require('bdns');
|
||||
const tcp = require('btcp');
|
||||
const UPNP = require('bupnp');
|
||||
const socks = require('bsocks');
|
||||
|
|
@ -85,6 +84,7 @@ class Pool extends EventEmitter {
|
|||
this.pendingFilter = null;
|
||||
this.refillTimer = null;
|
||||
this.discoverTimer = null;
|
||||
this.connectedGroups = new BufferSet();
|
||||
|
||||
this.checkpoints = false;
|
||||
this.headerChain = new List();
|
||||
|
|
@ -342,7 +342,6 @@ class Pool extends EventEmitter {
|
|||
await this.hosts.open();
|
||||
|
||||
await this.discoverGateway();
|
||||
await this.discoverExternal();
|
||||
await this.discoverSeeds();
|
||||
|
||||
await this.listen();
|
||||
|
|
@ -595,52 +594,6 @@ class Pool extends EventEmitter {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to discover external IP via DNS.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
async discoverExternal() {
|
||||
const port = this.options.publicPort;
|
||||
|
||||
// Pointless if we're not listening.
|
||||
if (!this.options.listen)
|
||||
return;
|
||||
|
||||
// Never hit a DNS server if
|
||||
// we're using an outbound proxy.
|
||||
if (this.options.proxy)
|
||||
return;
|
||||
|
||||
// Try not to hit this if we can avoid it.
|
||||
if (this.hosts.local.size > 0)
|
||||
return;
|
||||
|
||||
let host4 = null;
|
||||
|
||||
try {
|
||||
host4 = await dns.getIPv4(2000);
|
||||
} catch (e) {
|
||||
this.logger.debug('Could not find external IPv4 (dns).');
|
||||
this.logger.debug(e);
|
||||
}
|
||||
|
||||
if (host4 && this.hosts.addLocal(host4, port, scores.DNS))
|
||||
this.logger.info('External IPv4 found (dns): %s.', host4);
|
||||
|
||||
let host6 = null;
|
||||
|
||||
try {
|
||||
host6 = await dns.getIPv6(2000);
|
||||
} catch (e) {
|
||||
this.logger.debug('Could not find external IPv6 (dns).');
|
||||
this.logger.debug(e);
|
||||
}
|
||||
|
||||
if (host6 && this.hosts.addLocal(host6, port, scores.DNS))
|
||||
this.logger.info('External IPv6 found (dns): %s.', host6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle incoming connection.
|
||||
* @private
|
||||
|
|
@ -710,6 +663,7 @@ class Pool extends EventEmitter {
|
|||
this.logger.info('Adding loader peer (%s).', peer.hostname());
|
||||
|
||||
this.peers.add(peer);
|
||||
this.connectedGroups.add(addr.getGroup());
|
||||
|
||||
this.setLoader(peer);
|
||||
}
|
||||
|
|
@ -1717,8 +1671,6 @@ class Pool extends EventEmitter {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.fillOutbound();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3395,7 +3347,23 @@ class Pool extends EventEmitter {
|
|||
const services = this.options.getRequiredServices();
|
||||
const now = this.network.now();
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
// Calculate maximum number of hosts we can get.
|
||||
let max = this.hosts.totalFresh + this.hosts.totalUsed;
|
||||
|
||||
// We don't want to loop a lot here as it's expensive on CPU.
|
||||
// If this gets high, such as 100, it could cause a local DoS
|
||||
// for incoming RPC calls.
|
||||
if (max > 10)
|
||||
max = 10;
|
||||
|
||||
// Work out a percentage based hit rate outside of the
|
||||
// loop to save CPU.
|
||||
// Subtract 1 because we're zero based.
|
||||
const pc1 = max / 100;
|
||||
const pc30 = (pc1 * 30) - 1;
|
||||
const pc50 = (pc1 * 50) - 1;
|
||||
|
||||
for (let i = 0; i < max; i++) {
|
||||
const entry = this.hosts.getHost();
|
||||
|
||||
if (!entry)
|
||||
|
|
@ -3424,10 +3392,14 @@ class Pool extends EventEmitter {
|
|||
if (this.options.brontideOnly && !addr.hasKey())
|
||||
continue;
|
||||
|
||||
if (i < 30 && now - entry.lastAttempt < 600)
|
||||
// Don't connect to outbound peers in the same group.
|
||||
if (this.connectedGroups.has(addr.getGroup()))
|
||||
continue;
|
||||
|
||||
if (i < 50 && addr.port !== this.network.port)
|
||||
if (i < pc30 && now - entry.lastAttempt < 600)
|
||||
continue;
|
||||
|
||||
if (i < pc50 && addr.port !== this.network.port)
|
||||
continue;
|
||||
|
||||
return entry.addr;
|
||||
|
|
@ -3462,6 +3434,7 @@ class Pool extends EventEmitter {
|
|||
const peer = this.createOutbound(addr);
|
||||
|
||||
this.peers.add(peer);
|
||||
this.connectedGroups.add(addr.getGroup());
|
||||
|
||||
this.emit('peer', peer);
|
||||
}
|
||||
|
|
@ -3516,6 +3489,9 @@ class Pool extends EventEmitter {
|
|||
removePeer(peer) {
|
||||
this.peers.remove(peer);
|
||||
|
||||
if (peer.outbound)
|
||||
this.connectedGroups.delete(peer.address.getGroup());
|
||||
|
||||
for (const hash of peer.blockMap.keys())
|
||||
this.resolveBlock(peer, hash);
|
||||
|
||||
|
|
@ -4378,6 +4354,11 @@ class PoolOptions {
|
|||
this.createSocket = this._createSocket.bind(this);
|
||||
this.createServer = tcp.createServer;
|
||||
this.resolve = this._resolve.bind(this);
|
||||
this.createNonce = this._createNonce.bind(this);
|
||||
this.hasNonce = this._hasNonce.bind(this);
|
||||
this.getHeight = this._getHeight.bind(this);
|
||||
this.isFull = this._isFull.bind(this);
|
||||
this.getRate = this._getRate.bind(this);
|
||||
this.proxy = null;
|
||||
this.onion = false;
|
||||
this.brontideOnly = false;
|
||||
|
|
@ -4670,7 +4651,7 @@ class PoolOptions {
|
|||
* @returns {Number}
|
||||
*/
|
||||
|
||||
getHeight() {
|
||||
_getHeight() {
|
||||
return this.chain.height;
|
||||
}
|
||||
|
||||
|
|
@ -4680,7 +4661,7 @@ class PoolOptions {
|
|||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
isFull() {
|
||||
_isFull() {
|
||||
return this.chain.synced;
|
||||
}
|
||||
|
||||
|
|
@ -4711,7 +4692,7 @@ class PoolOptions {
|
|||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
createNonce(hostname) {
|
||||
_createNonce(hostname) {
|
||||
return this.nonces.alloc(hostname);
|
||||
}
|
||||
|
||||
|
|
@ -4722,7 +4703,7 @@ class PoolOptions {
|
|||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
hasNonce(nonce) {
|
||||
_hasNonce(nonce) {
|
||||
return this.nonces.has(nonce);
|
||||
}
|
||||
|
||||
|
|
@ -4733,7 +4714,7 @@ class PoolOptions {
|
|||
* @returns {Rate}
|
||||
*/
|
||||
|
||||
getRate(hash) {
|
||||
_getRate(hash) {
|
||||
if (!this.mempool)
|
||||
return -1;
|
||||
|
||||
|
|
|
|||
479
package-lock.json
generated
479
package-lock.json
generated
|
|
@ -1,8 +1,479 @@
|
|||
{
|
||||
"name": "hsd",
|
||||
"version": "3.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "hsd",
|
||||
"version": "3.0.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bcfg": "~0.1.7",
|
||||
"bcrypto": "~5.4.0",
|
||||
"bdb": "~1.3.0",
|
||||
"bdns": "~0.1.5",
|
||||
"bevent": "~0.1.5",
|
||||
"bfile": "~0.2.2",
|
||||
"bfilter": "~1.0.5",
|
||||
"bheep": "~0.1.5",
|
||||
"binet": "~0.3.7",
|
||||
"blgr": "~0.2.0",
|
||||
"blru": "~0.1.6",
|
||||
"blst": "~0.1.5",
|
||||
"bmutex": "~0.1.6",
|
||||
"bns": "~0.15.0",
|
||||
"bsert": "~0.0.10",
|
||||
"bsock": "~0.1.9",
|
||||
"bsocks": "~0.2.6",
|
||||
"btcp": "~0.1.5",
|
||||
"buffer-map": "~0.0.7",
|
||||
"bufio": "~1.0.7",
|
||||
"bupnp": "~0.2.6",
|
||||
"bval": "~0.1.6",
|
||||
"bweb": "~0.1.10",
|
||||
"goosig": "~0.10.0",
|
||||
"hs-client": "~0.0.10",
|
||||
"n64": "~0.2.10",
|
||||
"urkel": "~0.7.0"
|
||||
},
|
||||
"bin": {
|
||||
"hs-seeder": "bin/hs-seeder",
|
||||
"hs-wallet": "bin/hsw",
|
||||
"hsd": "bin/hsd",
|
||||
"hsd-cli": "bin/hsd-cli",
|
||||
"hsd-node": "bin/node",
|
||||
"hsd-spvnode": "bin/spvnode",
|
||||
"hsw-cli": "bin/hsw-cli"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bmocha": "^2.1.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bcfg": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/bcfg/-/bcfg-0.1.7.tgz",
|
||||
"integrity": "sha512-+4beq5bXwfmxdcEoHYQsaXawh1qFzjLcRvPe5k5ww/NEWzZTm56Jk8LuPmfeGB7X584jZ8xGq6UgMaZnNDa5Ww==",
|
||||
"dependencies": {
|
||||
"bsert": "~0.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bcrypto": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/bcrypto/-/bcrypto-5.4.0.tgz",
|
||||
"integrity": "sha512-KDX2CR29o6ZoqpQndcCxFZAtYA1jDMnXU3jmCfzP44g++Cu7AHHtZN/JbrN/MXAg9SLvtQ8XISG+eVD9zH1+Jg==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"bufio": "~1.0.7",
|
||||
"loady": "~0.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bcurl": {
|
||||
"version": "0.1.9",
|
||||
"resolved": "https://registry.npmjs.org/bcurl/-/bcurl-0.1.9.tgz",
|
||||
"integrity": "sha512-WV9LKCqFPtmGwIOqHexJx3Mm/9H/G5bwSCZxJXq9WRrnVQmd58L+Ltxgp/2QicveDG6AgTfepP6JtNiYWbbeHQ==",
|
||||
"dependencies": {
|
||||
"brq": "~0.1.8",
|
||||
"bsert": "~0.0.10",
|
||||
"bsock": "~0.1.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bdb": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/bdb/-/bdb-1.3.0.tgz",
|
||||
"integrity": "sha512-oJnWnHOTcnJhazwpEzQvPFtSR1IdHtS3PczuLY3klgZTTtRUbARX7tdphQS8iNUUwEVMfuO93eHDWwTICoeJlg==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"bsert": "~0.0.10",
|
||||
"loady": "~0.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bdns": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/bdns/-/bdns-0.1.5.tgz",
|
||||
"integrity": "sha512-LNVkfM7ynlAD0CvPvO9cKxW8YXt1KOCRQZlRsGZWeMyymUWVdHQpZudAzH9chaFAz6HiwAnQxwDemCKDPy6Mag==",
|
||||
"dependencies": {
|
||||
"bsert": "~0.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bevent": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/bevent/-/bevent-0.1.5.tgz",
|
||||
"integrity": "sha512-hs6T3BjndibrAmPSoKTHmKa3tz/c6Qgjv9iZw+tAoxuP6izfTCkzfltBQrW7SuK5xnY22gv9jCEf51+mRH+Qvg==",
|
||||
"dependencies": {
|
||||
"bsert": "~0.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bfile": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/bfile/-/bfile-0.2.2.tgz",
|
||||
"integrity": "sha512-X205SsJ7zFAnjeJ/pBLqDqF10x/4Su3pBy8UdVKw4hdGJk7t5pLoRi+uG4rPaDAClGbrEfT/06PGUbYiMYKzTg==",
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bfilter": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/bfilter/-/bfilter-1.0.5.tgz",
|
||||
"integrity": "sha512-GupIidtCvLbKhXnA1sxvrwa+gh95qbjafy7P1U1x/2DHxNabXq4nGW0x3rmgzlJMYlVl+c8fMxoMRIwpKYlgcQ==",
|
||||
"dependencies": {
|
||||
"bsert": "~0.0.10",
|
||||
"bufio": "~1.0.6",
|
||||
"mrmr": "~0.1.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bheep": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/bheep/-/bheep-0.1.5.tgz",
|
||||
"integrity": "sha512-0KR5Zi8hgJBKL35+aYzndCTtgSGakOMxrYw2uszd5UmXTIfx3+drPGoETlVbQ6arTdAzSoQYA1j35vbaWpQXBg==",
|
||||
"dependencies": {
|
||||
"bsert": "~0.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/binet": {
|
||||
"version": "0.3.7",
|
||||
"resolved": "https://registry.npmjs.org/binet/-/binet-0.3.7.tgz",
|
||||
"integrity": "sha512-GF+QD4ajs3GWabaVzso7Kn9aZEbwI0e54FKU2ID8bM/7rIk7BpSJytB1KS7SMpix+fWAi9MAGkOgSFljl0aaKg==",
|
||||
"dependencies": {
|
||||
"bs32": "~0.1.5",
|
||||
"bsert": "~0.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/blgr": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/blgr/-/blgr-0.2.0.tgz",
|
||||
"integrity": "sha512-2jZdqajYCGD5rwGdOooQpxgjKsiAAV2g8LapwSnbTjAYTZAqmqBAS+GsVGFi+/y7t1Pspidv/5HsWBbJrsEuFw==",
|
||||
"dependencies": {
|
||||
"bsert": "~0.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/blru": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/blru/-/blru-0.1.6.tgz",
|
||||
"integrity": "sha512-34+xZ2u4ys/aUzWCU9m6Eee4nVuN1ywdxbi8b3Z2WULU6qvnfeHvCWEdGzlVfRbbhimG2xxJX6R77GD2cuVO6w==",
|
||||
"dependencies": {
|
||||
"bsert": "~0.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/blst": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/blst/-/blst-0.1.5.tgz",
|
||||
"integrity": "sha512-TPl04Cx3CHdPFAJ2x9Xx1Z1FOfpAzmNPfHkfo+pGAaNH4uLhS58ExvamVkZh3jadF+B7V5sMtqvrqdf9mHINYA==",
|
||||
"dependencies": {
|
||||
"bsert": "~0.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bmocha": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/bmocha/-/bmocha-2.1.5.tgz",
|
||||
"integrity": "sha512-hEO+jQC+6CMxdxSqKPjqAdIDvRWHfdGgsMh4fUmatkMewbYr2O6qMIbW7Lhcmkcnz8bwRHZuEdDaBt/16NofoA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"_bmocha": "bin/_bmocha",
|
||||
"bmocha": "bin/bmocha"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bmutex": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/bmutex/-/bmutex-0.1.6.tgz",
|
||||
"integrity": "sha512-nXWOXtQHbfPaMl6jyEF/rmRMrcemj2qn+OCAI/uZYurjfx7Dg3baoXdPzHOL0U8Cfvn8CWxKcnM/rgxL7DR4zw==",
|
||||
"dependencies": {
|
||||
"bsert": "~0.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bns": {
|
||||
"version": "0.15.0",
|
||||
"resolved": "https://registry.npmjs.org/bns/-/bns-0.15.0.tgz",
|
||||
"integrity": "sha512-iJWQVE399vQzPfhalFMJGEQ7k5Ot2D6Mz8dkoPeLO8huWAMOiJNJ1tHzOu5j+ZyNNew6ITgG/LsSyaRPxvkXuw==",
|
||||
"dependencies": {
|
||||
"bcrypto": "~5.4.0",
|
||||
"bfile": "~0.2.2",
|
||||
"bheep": "~0.1.5",
|
||||
"binet": "~0.3.6",
|
||||
"bs32": "~0.1.6",
|
||||
"bsert": "~0.0.10",
|
||||
"btcp": "~0.1.5",
|
||||
"budp": "~0.1.6",
|
||||
"bufio": "~1.0.7"
|
||||
},
|
||||
"bin": {
|
||||
"bns-keygen": "bin/bns-keygen",
|
||||
"bns-prove": "bin/bns-prove",
|
||||
"dig.js": "bin/dig.js",
|
||||
"dig2json": "bin/dig2json",
|
||||
"json2dig": "bin/json2dig",
|
||||
"json2rr": "bin/json2rr",
|
||||
"json2zone": "bin/json2zone",
|
||||
"named.js": "bin/named.js",
|
||||
"rr2json": "bin/rr2json",
|
||||
"whois.js": "bin/whois.js",
|
||||
"zone2json": "bin/zone2json"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"unbound": "~0.4.3"
|
||||
}
|
||||
},
|
||||
"node_modules/brq": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/brq/-/brq-0.1.8.tgz",
|
||||
"integrity": "sha512-6SDY1lJMKXgt5TZ6voJQMH2zV1XPWWtm203PSkx3DSg9AYNYuRfOPFSBDkNemabzgpzFW9/neR4YhTvyJml8rQ==",
|
||||
"dependencies": {
|
||||
"bsert": "~0.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bs32": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/bs32/-/bs32-0.1.6.tgz",
|
||||
"integrity": "sha512-usjDesQqZ8ihHXOnOEQuAdymBHnJEfSd+aELFSg1jN/V3iAf12HrylHlRJwIt6DTMmXpBDQ+YBg3Q3DIYdhRgQ==",
|
||||
"dependencies": {
|
||||
"bsert": "~0.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bsert": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/bsert/-/bsert-0.0.10.tgz",
|
||||
"integrity": "sha512-NHNwlac+WPy4t2LoNh8pXk8uaIGH3NSaIUbTTRXGpE2WEbq0te/tDykYHkFK57YKLPjv/aGHmbqvnGeVWDz57Q==",
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bsock": {
|
||||
"version": "0.1.9",
|
||||
"resolved": "https://registry.npmjs.org/bsock/-/bsock-0.1.9.tgz",
|
||||
"integrity": "sha512-/l9Kg/c5o+n/0AqreMxh2jpzDMl1ikl4gUxT7RFNe3A3YRIyZkiREhwcjmqxiymJSRI/Qhew357xGn1SLw/xEw==",
|
||||
"dependencies": {
|
||||
"bsert": "~0.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bsocks": {
|
||||
"version": "0.2.6",
|
||||
"resolved": "https://registry.npmjs.org/bsocks/-/bsocks-0.2.6.tgz",
|
||||
"integrity": "sha512-66UkjoB9f7lhT+WKgYq8MQa6nkr96mlX64JYMlIsXe/X4VeqNwvsx7UOE3ZqD6lkwg8GvBhapRTWj0qWO3Pw8w==",
|
||||
"dependencies": {
|
||||
"binet": "~0.3.5",
|
||||
"bsert": "~0.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/btcp": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/btcp/-/btcp-0.1.5.tgz",
|
||||
"integrity": "sha512-tkrtMDxeJorn5p0KxaLXELneT8AbfZMpOFeoKYZ5qCCMMSluNuwut7pGccLC5YOJqmuk0DR774vNVQLC9sNq/A==",
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/budp": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/budp/-/budp-0.1.6.tgz",
|
||||
"integrity": "sha512-o+a8NPq3DhV91j4nInjht2md6mbU1XL+7ciPltP66rw5uD3KP1m5r8lA94LZVaPKcFdJ0l2HVVzRNxnY26Pefg==",
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-map": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/buffer-map/-/buffer-map-0.0.7.tgz",
|
||||
"integrity": "sha512-95try3p/vMRkIAAnJDaGkFhGpT/65NoeW6XelEPjAomWYR58RQtW4khn0SwKj34kZoE7uxL7w2koZSwbnszvQQ==",
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bufio": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/bufio/-/bufio-1.0.7.tgz",
|
||||
"integrity": "sha512-bd1dDQhiC+bEbEfg56IdBv7faWa6OipMs/AFFFvtFnB3wAYjlwQpQRZ0pm6ZkgtfL0pILRXhKxOiQj6UzoMR7A==",
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bupnp": {
|
||||
"version": "0.2.6",
|
||||
"resolved": "https://registry.npmjs.org/bupnp/-/bupnp-0.2.6.tgz",
|
||||
"integrity": "sha512-J6ykzJhZMxXKN78K+1NzFi3v/51X2Mvzp2hW42BWwmxIVfau6PaN99gyABZ8x05e8MObWbsAis23gShhj9qpbw==",
|
||||
"dependencies": {
|
||||
"binet": "~0.3.5",
|
||||
"brq": "~0.1.7",
|
||||
"bsert": "~0.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bval": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/bval/-/bval-0.1.6.tgz",
|
||||
"integrity": "sha512-jxNH9gSx7g749hQtS+nTxXYz/bLxwr4We1RHFkCYalNYcj12RfbW6qYWsKu0RYiKAdFcbNoZRHmWrIuXIyhiQQ==",
|
||||
"dependencies": {
|
||||
"bsert": "~0.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bweb": {
|
||||
"version": "0.1.10",
|
||||
"resolved": "https://registry.npmjs.org/bweb/-/bweb-0.1.10.tgz",
|
||||
"integrity": "sha512-3Kkz/rfsyAWUS+8DV5XYhwcgVN4DfDewrP+iFTcpQfdZzcF6+OypAq7dHOtXV0sW7U/3msA/sEEqz0MHZ9ERWg==",
|
||||
"dependencies": {
|
||||
"bsert": "~0.0.10",
|
||||
"bsock": "~0.1.8"
|
||||
},
|
||||
"bin": {
|
||||
"bweb": "bin/bweb"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/goosig": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/goosig/-/goosig-0.10.0.tgz",
|
||||
"integrity": "sha512-+BVVLfxmawAmGVjjJpXzu5LNcFIOfgXgP7kWEyc3qu/xn9RMqbPbNfYDdHBZKfZkDMIO7Q4vD790iNYQAXhoFA==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"bcrypto": "~5.4.0",
|
||||
"bsert": "~0.0.10",
|
||||
"loady": "~0.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hs-client": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/hs-client/-/hs-client-0.0.10.tgz",
|
||||
"integrity": "sha512-15tfeQEMRS1FZA0q9gFbQ1jYs8v4z9oKw9xFwVEyRuckn72hoVAglN4IrFxkOCDMYV7TWCY/nO/yNZp5njYFBw==",
|
||||
"dependencies": {
|
||||
"bcfg": "~0.1.7",
|
||||
"bcurl": "~0.1.9",
|
||||
"bsert": "~0.0.10"
|
||||
},
|
||||
"bin": {
|
||||
"hsd-cli": "bin/hsd-cli",
|
||||
"hsd-rpc": "bin/hsd-rpc",
|
||||
"hsw-cli": "bin/hsw-cli",
|
||||
"hsw-rpc": "bin/hsw-rpc"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/loady": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/loady/-/loady-0.0.5.tgz",
|
||||
"integrity": "sha512-uxKD2HIj042/HBx77NBcmEPsD+hxCgAtjEWlYNScuUjIsh/62Uyu39GOR68TBR68v+jqDL9zfftCWoUo4y03sQ==",
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mrmr": {
|
||||
"version": "0.1.10",
|
||||
"resolved": "https://registry.npmjs.org/mrmr/-/mrmr-0.1.10.tgz",
|
||||
"integrity": "sha512-NJRJs+yJyRWwcTqLRf7O32n56UP1+UQoTrGVEoB3LMj0h2jlon790drDbxKvi5mK5k4HfC0cpNkxqHcrJK/evg==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"bsert": "~0.0.10",
|
||||
"loady": "~0.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/n64": {
|
||||
"version": "0.2.10",
|
||||
"resolved": "https://registry.npmjs.org/n64/-/n64-0.2.10.tgz",
|
||||
"integrity": "sha512-uH9geV4+roR1tohsrrqSOLCJ9Mh1iFcDI+9vUuydDlDxUS1UCAWUfuGb06p3dj3flzywquJNrGsQ7lHP8+4RVQ==",
|
||||
"engines": {
|
||||
"node": ">=2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unbound": {
|
||||
"version": "0.4.3",
|
||||
"resolved": "https://registry.npmjs.org/unbound/-/unbound-0.4.3.tgz",
|
||||
"integrity": "sha512-2ISqZLXtzp1l9f1V8Yr6S+zuhXxEwE1CjKHjXULFDHJcfhc9Gm3mn19hdPp4rlNGEdCivKYGKjYe3WRGnafYdA==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"loady": "~0.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/urkel": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/urkel/-/urkel-0.7.0.tgz",
|
||||
"integrity": "sha512-7Z3Gor4DkKKi0Ehp6H9xehWXqyL12+PA4JM41dcVc1LWks4zI4PGWv6DWgxaLCC+otpEuGdq3Vh5ayD/Mvzfbg==",
|
||||
"dependencies": {
|
||||
"bfile": "~0.2.1",
|
||||
"bmutex": "~0.1.6",
|
||||
"bsert": "~0.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"bcfg": {
|
||||
"version": "0.1.7",
|
||||
|
|
@ -80,9 +551,9 @@
|
|||
}
|
||||
},
|
||||
"binet": {
|
||||
"version": "0.3.6",
|
||||
"resolved": "https://registry.npmjs.org/binet/-/binet-0.3.6.tgz",
|
||||
"integrity": "sha512-6pm+Gc3uNiiJZEv0k8JDWqQlo9ki/o9UNAkLmr0EGm7hI5MboOJVIOlO1nw3YuDkLHWN78OPsaC4JhRkn2jMLw==",
|
||||
"version": "0.3.7",
|
||||
"resolved": "https://registry.npmjs.org/binet/-/binet-0.3.7.tgz",
|
||||
"integrity": "sha512-GF+QD4ajs3GWabaVzso7Kn9aZEbwI0e54FKU2ID8bM/7rIk7BpSJytB1KS7SMpix+fWAi9MAGkOgSFljl0aaKg==",
|
||||
"requires": {
|
||||
"bs32": "~0.1.5",
|
||||
"bsert": "~0.0.10"
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
"bfile": "~0.2.2",
|
||||
"bfilter": "~1.0.5",
|
||||
"bheep": "~0.1.5",
|
||||
"binet": "~0.3.6",
|
||||
"binet": "~0.3.7",
|
||||
"blgr": "~0.2.0",
|
||||
"blru": "~0.1.6",
|
||||
"blst": "~0.1.5",
|
||||
|
|
|
|||
|
|
@ -69,6 +69,17 @@ describe('Chain Timelocks', function() {
|
|||
});
|
||||
|
||||
describe('Relative (CSV)', function() {
|
||||
let timeOffset;
|
||||
|
||||
// make sure we recover proper regtest Network.
|
||||
before(() => {
|
||||
timeOffset = network.time.offset;
|
||||
});
|
||||
|
||||
after(() => {
|
||||
network.time.offset = timeOffset;
|
||||
});
|
||||
|
||||
// Relative timelock by height
|
||||
const csvHeightScript = new Script([
|
||||
Opcode.fromInt(2),
|
||||
|
|
|
|||
335
test/data/netaddress-data.js
Normal file
335
test/data/netaddress-data.js
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
'use strict';
|
||||
|
||||
const Network = require('../../lib/protocol/network');
|
||||
const netaddressVectors = exports;
|
||||
|
||||
const main = Network.get('main');
|
||||
const regtest = Network.get('regtest');
|
||||
|
||||
// [passedOptions, expectedValues]
|
||||
netaddressVectors.options = [
|
||||
[null, {
|
||||
host: '0.0.0.0',
|
||||
port: 0,
|
||||
hostname: '0.0.0.0:0',
|
||||
isNull: true,
|
||||
isIPv6: false,
|
||||
isLocal: true,
|
||||
isValid: false,
|
||||
isRoutable: false
|
||||
}],
|
||||
[{
|
||||
host: '0.0.0.0',
|
||||
port: 0
|
||||
}, {
|
||||
host: '0.0.0.0',
|
||||
port: 0,
|
||||
hostname: '0.0.0.0:0',
|
||||
isNull: true,
|
||||
isIPv6: false,
|
||||
isLocal: true,
|
||||
isValid: false,
|
||||
isRoutable: false
|
||||
}],
|
||||
[{
|
||||
host: '2345:0425:2CA1:0000:0000:0567:5673:23b5',
|
||||
port: 1000
|
||||
}, {
|
||||
host: '2345:425:2ca1::567:5673:23b5',
|
||||
port: 1000,
|
||||
hostname: '[2345:425:2ca1::567:5673:23b5]:1000',
|
||||
isIPv6: true,
|
||||
isLocal: false,
|
||||
isValid: true,
|
||||
isRoutable: true
|
||||
}],
|
||||
[{
|
||||
host: '1.1.1.1',
|
||||
port: 1,
|
||||
services: 1,
|
||||
key: Buffer.alloc(33, 1)
|
||||
}, {
|
||||
hostname:
|
||||
'aeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqc@1.1.1.1:1',
|
||||
key: Buffer.alloc(33, 1),
|
||||
services: 1,
|
||||
isIPv6: false,
|
||||
isLocal: false,
|
||||
isValid: true,
|
||||
isRoutable: true
|
||||
}],
|
||||
[{
|
||||
host: '2.2.2.2',
|
||||
port: 2,
|
||||
key: Buffer.alloc(33, 2),
|
||||
services: 2
|
||||
}, {
|
||||
hostname:
|
||||
'aibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibae@2.2.2.2:2',
|
||||
key: Buffer.alloc(33, 2),
|
||||
services: 2,
|
||||
isIPv6: false,
|
||||
isLocal: false,
|
||||
isValid: true,
|
||||
isRoutable: true
|
||||
}], [{
|
||||
host: '127.0.0.1',
|
||||
port: 1000,
|
||||
services: 3
|
||||
}, {
|
||||
hostname: '127.0.0.1:1000',
|
||||
services: 3,
|
||||
isIPv6: false,
|
||||
isLocal: true,
|
||||
isValid: true,
|
||||
isRoutable: false
|
||||
}], [{
|
||||
host: '127.1.1.1',
|
||||
port: 1000
|
||||
}, {
|
||||
hostname: '127.1.1.1:1000',
|
||||
isIPv6: false,
|
||||
isLocal: true,
|
||||
isValid: true,
|
||||
isRoutable: false
|
||||
}], [{
|
||||
host: '::1',
|
||||
port: 1000
|
||||
}, {
|
||||
hostname: '[::1]:1000',
|
||||
isIPv6: true,
|
||||
isLocal: true,
|
||||
isValid: true,
|
||||
isRoutable: false
|
||||
}], [{
|
||||
host: 'fd87:d87e:eb43::1',
|
||||
port: 1000
|
||||
}, {
|
||||
host: 'aaaaaaaaaaaaaaab.onion',
|
||||
hostname: 'aaaaaaaaaaaaaaab.onion:1000',
|
||||
isIPv6: false,
|
||||
isIPV4: false,
|
||||
isLocal: false,
|
||||
isValid: true,
|
||||
isRoutable: true,
|
||||
isOnion: true
|
||||
}]
|
||||
];
|
||||
|
||||
const goodOptions = {
|
||||
host: '0.0.0.0',
|
||||
port: 12038
|
||||
};
|
||||
|
||||
// [passedOptions, message]
|
||||
netaddressVectors.failOptions = [
|
||||
[{ port: goodOptions.port }, 'NetAddress requires host string.'],
|
||||
[{ host: 1234 }, 'NetAddress requires host string.'],
|
||||
[{ host: goodOptions.host }, 'NetAddress requires port number.'],
|
||||
[{ host: goodOptions.host, port: '32' },
|
||||
'NetAddress requires port number.'],
|
||||
[{ host: goodOptions.host, port: -1 }, 'port number is incorrect.'],
|
||||
[{ host: goodOptions.host, port: 0xffff + 1 },
|
||||
'port number is incorrect.'],
|
||||
[{ ...goodOptions, services: '12' }, 'services must be a number.'],
|
||||
[{ ...goodOptions, services: {} }, 'services must be a number.'],
|
||||
[{ ...goodOptions, key: '12' }, 'key must be a buffer.'],
|
||||
[{ ...goodOptions, key: 11 }, 'key must be a buffer.']
|
||||
];
|
||||
|
||||
// [options, expected]
|
||||
netaddressVectors.fromHost = [
|
||||
[
|
||||
['172.104.214.189', 1000, Buffer.alloc(33, 1)],
|
||||
{
|
||||
host: '172.104.214.189',
|
||||
port: 1000,
|
||||
key: Buffer.alloc(33, 1),
|
||||
hostname: 'aeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqc'
|
||||
+ '@172.104.214.189:1000'
|
||||
}
|
||||
],
|
||||
[
|
||||
['15.152.162.66', 1001, Buffer.alloc(33, 2)],
|
||||
{
|
||||
host: '15.152.162.66',
|
||||
port: 1001,
|
||||
key: Buffer.alloc(33, 2),
|
||||
hostname: 'aibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibae'
|
||||
+ '@15.152.162.66:1001'
|
||||
}
|
||||
],
|
||||
[
|
||||
['2345:0425:2CA1:0000:0000:0567:5673:23b5', 0xffff],
|
||||
{
|
||||
host: '2345:425:2ca1::567:5673:23b5',
|
||||
port: 0xffff,
|
||||
key: Buffer.alloc(33, 0),
|
||||
hostname: '[2345:425:2ca1::567:5673:23b5]:65535'
|
||||
}
|
||||
]
|
||||
];
|
||||
|
||||
// [options, expected]
|
||||
netaddressVectors.fromHostname = [
|
||||
[['127.0.0.1:100', 'main'], {
|
||||
hostname: '127.0.0.1:100',
|
||||
host: '127.0.0.1',
|
||||
port: 100,
|
||||
key: Buffer.alloc(33, 0)
|
||||
}],
|
||||
[
|
||||
[
|
||||
'aeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqc@127.0.0.1:100',
|
||||
'main'
|
||||
], {
|
||||
hostname: 'aeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqc'
|
||||
+ '@127.0.0.1:100',
|
||||
host: '127.0.0.1',
|
||||
port: 100,
|
||||
key: Buffer.alloc(33, 1)
|
||||
}
|
||||
],
|
||||
[['127.0.0.1', 'main'], {
|
||||
hostname: `127.0.0.1:${main.port}`,
|
||||
host: '127.0.0.1',
|
||||
port: main.port,
|
||||
key: Buffer.alloc(33, 0)
|
||||
}],
|
||||
[
|
||||
[
|
||||
'aeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqc@127.0.0.1',
|
||||
'main'
|
||||
], {
|
||||
hostname: 'aeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqc'
|
||||
+ `@127.0.0.1:${main.brontidePort}`,
|
||||
host: '127.0.0.1',
|
||||
port: main.brontidePort,
|
||||
key: Buffer.alloc(33, 1)
|
||||
}
|
||||
],
|
||||
[['127.0.0.1', 'regtest'], {
|
||||
hostname: `127.0.0.1:${regtest.port}`,
|
||||
host: '127.0.0.1',
|
||||
port: regtest.port,
|
||||
key: Buffer.alloc(33, 0)
|
||||
}],
|
||||
[
|
||||
[
|
||||
'aeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqc@127.0.0.1',
|
||||
'regtest'
|
||||
], {
|
||||
hostname: 'aeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqc'
|
||||
+ `@127.0.0.1:${regtest.brontidePort}`,
|
||||
host: '127.0.0.1',
|
||||
port: regtest.brontidePort,
|
||||
key: Buffer.alloc(33, 1)
|
||||
}
|
||||
]
|
||||
];
|
||||
|
||||
// [args, expected]
|
||||
netaddressVectors.fromSocket = [
|
||||
[[{
|
||||
remoteAddress: '2001:4860:a005::68',
|
||||
remotePort: 1000
|
||||
}, 'main'], {
|
||||
hostname: '[2001:4860:a005::68]:1000',
|
||||
host: '2001:4860:a005::68',
|
||||
port: 1000
|
||||
}],
|
||||
[[{
|
||||
remoteAddress: '74.125.127.100',
|
||||
remotePort: 2000
|
||||
}, 'main'], {
|
||||
hostname: '74.125.127.100:2000',
|
||||
host: '74.125.127.100',
|
||||
port: 2000
|
||||
}]
|
||||
];
|
||||
|
||||
// [addrA, addrB, expectedCompareResults]
|
||||
netaddressVectors.compare = [
|
||||
[['127.0.0.1', 10], ['127.1.1.1', 9], -1],
|
||||
[['0.0.0.0', 10], ['1.1.1.1', 9], -1],
|
||||
[['0.0.0.1', 10], ['0.0.0.1', 9], 1],
|
||||
// IPV4 has two 0xff in the buffer before last 4 bytes.
|
||||
// So any IPV6 from ::1 to :ffff:0:0 will be lower than IPV4.
|
||||
// And any IPV6 from :ffff:0:0 to :ffff:ffff:ffff will be IPV4.
|
||||
[['::1', 1], ['0.0.0.1', 1], -1],
|
||||
[['::ffff:ffff', 1], ['0.0.0.1', 1], -1],
|
||||
[['::ffff:ffff:ffff', 1], ['0.0.0.1', 1], 1],
|
||||
[['::ffff:0:1', 1], ['0.0.0.1', 1], 0],
|
||||
[['::ffff:ffff:ffff', 1], ['255.255.255.255', 1], 0],
|
||||
// If IPs are same, then we compare ports.
|
||||
[['::1', 102], ['::1', 101], 1],
|
||||
[['::1', 100], ['::1', 101], -1],
|
||||
[['::1', 100], ['::1', 100], 0]
|
||||
];
|
||||
|
||||
// Reachability scores
|
||||
const rscores = {
|
||||
UNREACHABLE: 0,
|
||||
DEFAULT: 1,
|
||||
TEREDO: 2,
|
||||
IPV6_WEAK: 3,
|
||||
IPV4: 4,
|
||||
IPV6_STRONG: 5,
|
||||
PRIVATE: 6
|
||||
};
|
||||
|
||||
// reachability IPs
|
||||
const rips = {
|
||||
ipv4: {
|
||||
src: '74.125.127.100',
|
||||
dest: '45.79.134.225'
|
||||
},
|
||||
ipv6: {
|
||||
src: 'ffff::1',
|
||||
dest: 'ffff::ffff'
|
||||
},
|
||||
onion: {
|
||||
src: 'aaaaaaaaaaaaaaaa.onion',
|
||||
dest: 'bbbbbbbbbbbbbbbb.onion'
|
||||
},
|
||||
teredo: {
|
||||
src: '2001::1',
|
||||
dest: '2001:ffff::1'
|
||||
}
|
||||
};
|
||||
|
||||
netaddressVectors.getReachability = [
|
||||
// unroutable, destination does not matter
|
||||
['127.0.0.1', rips.ipv4.dest, rscores.UNREACHABLE],
|
||||
|
||||
// IPv4 dest - DEFAULT
|
||||
[rips.ipv4.src, rips.ipv4.dest, rscores.IPV4],
|
||||
[rips.ipv6.src, rips.ipv4.dest, rscores.DEFAULT],
|
||||
[rips.onion.src, rips.ipv4.dest, rscores.DEFAULT],
|
||||
[rips.teredo.src, rips.ipv4.dest, rscores.DEFAULT],
|
||||
|
||||
// IPv6 dest
|
||||
[rips.ipv4.src, rips.ipv6.dest, rscores.IPV4],
|
||||
['2002::1', rips.ipv6.dest, rscores.IPV6_WEAK],
|
||||
[rips.ipv6.src, rips.ipv6.dest, rscores.IPV6_STRONG],
|
||||
[rips.onion.src, rips.ipv6.dest, rscores.DEFAULT],
|
||||
[rips.teredo.src, rips.ipv6.dest, rscores.TEREDO],
|
||||
|
||||
// ONION Dest
|
||||
[rips.ipv4.src, rips.onion.src, rscores.IPV4],
|
||||
[rips.ipv6.src, rips.onion.src, rscores.DEFAULT],
|
||||
[rips.onion.src, rips.onion.src, rscores.PRIVATE],
|
||||
[rips.teredo.src, rips.onion.src, rscores.DEFAULT],
|
||||
|
||||
// TEREDO Dest
|
||||
[rips.ipv4.src, rips.teredo.src, rscores.IPV4],
|
||||
[rips.ipv6.src, rips.teredo.src, rscores.IPV6_WEAK],
|
||||
[rips.onion.src, rips.teredo.src, rscores.DEFAULT],
|
||||
[rips.teredo.src, rips.teredo.src, rscores.TEREDO],
|
||||
|
||||
// UNREACHABLE Dest
|
||||
[rips.ipv4.src, '127.0.0.1', rscores.IPV4],
|
||||
[rips.ipv6.src, '127.0.0.1', rscores.IPV6_WEAK],
|
||||
[rips.onion.src, '127.0.0.1', rscores.PRIVATE],
|
||||
[rips.teredo.src, '127.0.0.1', rscores.TEREDO]
|
||||
];
|
||||
1782
test/net-hostlist-test.js
Normal file
1782
test/net-hostlist-test.js
Normal file
File diff suppressed because it is too large
Load diff
55
test/net-lookup-test.js
Normal file
55
test/net-lookup-test.js
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
'use strict';
|
||||
|
||||
const assert = require('bsert');
|
||||
const Network = require('../lib/protocol/network');
|
||||
const {lookup, resolve} = require('../lib/net/lookup');
|
||||
|
||||
const main = Network.get('main');
|
||||
|
||||
const notAHost = 'not-a-domain.not-a-domain';
|
||||
|
||||
describe('Lookup', function() {
|
||||
this.timeout(10000);
|
||||
it('should lookup seed', async () => {
|
||||
for (const host of main.seeds) {
|
||||
const addresses = await lookup(host);
|
||||
assert(addresses.length > 0, 'addresses not found.');
|
||||
}
|
||||
});
|
||||
|
||||
it('should fail lookup', async () => {
|
||||
let err;
|
||||
|
||||
try {
|
||||
await lookup(notAHost);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
|
||||
assert(err);
|
||||
assert.strictEqual(err.message, 'No DNS results.');
|
||||
});
|
||||
|
||||
it('should lookup seed', async () => {
|
||||
for (const host of main.seeds) {
|
||||
const addresses = await resolve(host);
|
||||
|
||||
assert(addresses.length > 0, 'addresses not found.');
|
||||
}
|
||||
});
|
||||
|
||||
it('should fail resolve', async () => {
|
||||
let err;
|
||||
|
||||
try {
|
||||
await resolve(notAHost);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
|
||||
assert(err);
|
||||
assert.strictEqual(err.message, `Query error: NXDOMAIN (${notAHost} A).`);
|
||||
|
||||
// TODO: Host that does not have A/AAAA records?
|
||||
});
|
||||
});
|
||||
515
test/net-netaddress-test.js
Normal file
515
test/net-netaddress-test.js
Normal file
|
|
@ -0,0 +1,515 @@
|
|||
'use strict';
|
||||
|
||||
/* Parts of this software are based on bitcoin/bitcoin:
|
||||
* Copyright (c) 2009-2019, The Bitcoin Core Developers (MIT License).
|
||||
* Copyright (c) 2009-2019, The Bitcoin Developers (MIT License).
|
||||
* https://github.com/bitcoin/bitcoin
|
||||
*
|
||||
* Resources:
|
||||
* https://github.com/bitcoin/bitcoin/blob/46fc4d1a24c88e797d6080336e3828e45e39c3fd/src/test/netbase_tests.cpp
|
||||
*/
|
||||
|
||||
const assert = require('bsert');
|
||||
const NetAddress = require('../lib/net/netaddress');
|
||||
const Network = require('../lib/protocol/network');
|
||||
const util = require('../lib/utils/util');
|
||||
|
||||
const netaddressVectors = require('./data/netaddress-data');
|
||||
|
||||
// 16 bytes (ipv6) - 4 (ipv4) byte - 2 ff = 10
|
||||
const IPV4_PREFIX = Buffer.from(`${'00'.repeat(10)}ffff`, 'hex');
|
||||
|
||||
const main = Network.get('main');
|
||||
|
||||
describe('NetAddress', function() {
|
||||
it('should parse options', () => {
|
||||
const {options} = netaddressVectors;
|
||||
|
||||
for (const [i, [opts, expected]] of options.entries()) {
|
||||
const naddr = new NetAddress(opts);
|
||||
|
||||
if (expected.host == null)
|
||||
expected.host = opts.host;
|
||||
|
||||
if (expected.port == null)
|
||||
expected.port = opts.port;
|
||||
|
||||
assert.strictEqual(naddr.host, expected.host, `Failed #${i}`);
|
||||
assert.strictEqual(naddr.port, expected.port, `Failed #${i}`);
|
||||
assert.strictEqual(naddr.hostname, expected.hostname, `Failed #${i}`);
|
||||
|
||||
const expectedKey = opts && opts.key;
|
||||
assert.strictEqual(naddr.hasKey(), Boolean(expectedKey), `Failed #${i}`);
|
||||
|
||||
if (expectedKey)
|
||||
assert.bufferEqual(naddr.key, expectedKey, `Failed #${i}`);
|
||||
|
||||
if (expected.isIPv6 != null) {
|
||||
const isIPV4 = expected.isIPV4 != null
|
||||
? expected.isIPV4
|
||||
: !expected.isIPv6;
|
||||
|
||||
assert.strictEqual(naddr.isIPv4(), isIPV4, `Failed #${i}`);
|
||||
assert.strictEqual(naddr.isIPv6(), expected.isIPv6, `Failed #${i}`);
|
||||
}
|
||||
|
||||
if (opts && opts.services != null) {
|
||||
assert.strictEqual(true, naddr.hasServices(expected.services),
|
||||
`Failed #${i}`);
|
||||
}
|
||||
|
||||
assert.strictEqual(naddr.isRoutable(), expected.isRoutable, `Failed #${i}`);
|
||||
assert.strictEqual(naddr.isValid(), expected.isValid, `Failed #${i}`);
|
||||
assert.strictEqual(naddr.isNull(), Boolean(expected.isNull),
|
||||
`Failed #${i}`);
|
||||
assert.strictEqual(naddr.isOnion(), Boolean(expected.isOnion),
|
||||
`Failed #${i}`);
|
||||
assert.strictEqual(true, naddr.equal(naddr), `Failed #${i}`);
|
||||
|
||||
assert.strictEqual(naddr.isLocal(), expected.isLocal, `Failed #${i}`);
|
||||
}
|
||||
});
|
||||
|
||||
it('should fail parsing options', () => {
|
||||
const {failOptions} = netaddressVectors;
|
||||
|
||||
for (const [opts, msg] of failOptions) {
|
||||
let err;
|
||||
try {
|
||||
new NetAddress(opts);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
|
||||
assert(err, 'Expected err');
|
||||
assert.strictEqual(err.message, msg);
|
||||
}
|
||||
});
|
||||
|
||||
it('should check services', async () => {
|
||||
const naddr = new NetAddress();
|
||||
|
||||
const serviceList = [];
|
||||
for (let i = 0; i < 10; i++)
|
||||
serviceList.push(1 << i);
|
||||
|
||||
naddr.services = serviceList[7] | serviceList[8] | serviceList[9];
|
||||
|
||||
for (let i = 7; i < 10; i++)
|
||||
assert.strictEqual(true, naddr.hasServices(serviceList[i]));
|
||||
|
||||
for (let i = 0; i < 7; i++)
|
||||
assert.strictEqual(false, naddr.hasServices(serviceList[i]));
|
||||
|
||||
assert.strictEqual(true,
|
||||
naddr.hasServices(serviceList[7] | serviceList[8]));
|
||||
assert.strictEqual(false,
|
||||
naddr.hasServices(serviceList[1] | serviceList[8]));
|
||||
});
|
||||
|
||||
it('should set null', async () => {
|
||||
const oldRaw = Buffer.from('2d4f86e1', 'hex');
|
||||
const nullRaw = Buffer.alloc(4, 0);
|
||||
const naddr = new NetAddress({
|
||||
host: '45.79.134.225',
|
||||
port: 1
|
||||
});
|
||||
|
||||
assert.strictEqual(false, naddr.isNull());
|
||||
assert.bufferEqual(naddr.raw, Buffer.concat([IPV4_PREFIX, oldRaw]));
|
||||
assert.strictEqual(naddr.hostname, '45.79.134.225:1');
|
||||
|
||||
naddr.setNull();
|
||||
assert.strictEqual(true, naddr.isNull());
|
||||
assert.bufferEqual(naddr.raw, Buffer.concat([IPV4_PREFIX, nullRaw]));
|
||||
assert.strictEqual(naddr.hostname, '0.0.0.0:1');
|
||||
});
|
||||
|
||||
it('should set host', async () => {
|
||||
const oldHost = '45.79.134.225';
|
||||
const oldRaw = Buffer.from('2d4f86e1', 'hex');
|
||||
const newHost = '15.152.112.161';
|
||||
const newRaw = Buffer.from('0f9870a1', 'hex');
|
||||
|
||||
const naddr = new NetAddress({
|
||||
host: oldHost,
|
||||
port: 12038
|
||||
});
|
||||
|
||||
assert.strictEqual(naddr.host, oldHost);
|
||||
assert.bufferEqual(naddr.raw, Buffer.concat([IPV4_PREFIX, oldRaw]));
|
||||
naddr.setHost(newHost);
|
||||
assert.strictEqual(naddr.host, newHost);
|
||||
assert.bufferEqual(naddr.raw, Buffer.concat([IPV4_PREFIX, newRaw]));
|
||||
});
|
||||
|
||||
it('should set port', async () => {
|
||||
const naddr = new NetAddress({
|
||||
host: '45.79.134.225',
|
||||
port: 1000
|
||||
});
|
||||
|
||||
const badPorts = [
|
||||
-1,
|
||||
-0xffff,
|
||||
0xffff + 1,
|
||||
0xffffff
|
||||
];
|
||||
|
||||
for (const port of badPorts) {
|
||||
let err;
|
||||
try {
|
||||
naddr.setPort(port);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
|
||||
assert(err, `Error not found for ${port}.`);
|
||||
}
|
||||
|
||||
const goodPorts = [
|
||||
0,
|
||||
0xffff,
|
||||
12038,
|
||||
44806
|
||||
];
|
||||
|
||||
for (const port of goodPorts) {
|
||||
naddr.setPort(port);
|
||||
assert.strictEqual(naddr.port, port);
|
||||
assert.strictEqual(naddr.hostname, `${naddr.host}:${port}`);
|
||||
}
|
||||
});
|
||||
|
||||
it('should set/get key', async () => {
|
||||
const testKey = Buffer.alloc(33, 1);
|
||||
|
||||
const naddr = new NetAddress({
|
||||
host: '0.0.0.0',
|
||||
port: 1000
|
||||
});
|
||||
|
||||
assert.strictEqual(naddr.getKey(), null);
|
||||
|
||||
naddr.setKey(testKey);
|
||||
assert.bufferEqual(naddr.getKey(), testKey);
|
||||
assert.strictEqual(naddr.getKey('base32'),
|
||||
'aeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqcaibaeaqc');
|
||||
assert.strictEqual(naddr.getKey('hex'),
|
||||
'01'.repeat(33));
|
||||
assert.strictEqual(naddr.hostname,
|
||||
`${naddr.getKey('base32')}@${naddr.host}:${naddr.port}`);
|
||||
|
||||
naddr.setKey();
|
||||
assert.strictEqual(naddr.getKey(), null);
|
||||
assert.strictEqual(naddr.getKey('base32'), null);
|
||||
assert.strictEqual(naddr.getKey('hex'), null);
|
||||
assert.strictEqual(naddr.hostname, `${naddr.host}:${naddr.port}`);
|
||||
|
||||
const badKeys = [
|
||||
'badkey',
|
||||
Buffer.alloc(32, 0),
|
||||
Buffer.alloc(34, 11)
|
||||
];
|
||||
|
||||
for (const key of badKeys) {
|
||||
let err;
|
||||
try {
|
||||
naddr.setKey(key);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
|
||||
assert(err);
|
||||
}
|
||||
});
|
||||
|
||||
it('should create from host', () => {
|
||||
const {fromHost} = netaddressVectors;
|
||||
const naddr = new NetAddress();
|
||||
|
||||
for (const [params, expected] of fromHost) {
|
||||
naddr.fromHost(...params);
|
||||
const naddr2 = NetAddress.fromHost(...params);
|
||||
|
||||
for (const addr of [naddr, naddr2]) {
|
||||
assert.strictEqual(addr.host, expected.host);
|
||||
assert.strictEqual(addr.port, expected.port);
|
||||
assert.bufferEqual(addr.key, expected.key);
|
||||
assert.strictEqual(addr.hostname, expected.hostname);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should create from hostname', () => {
|
||||
const {fromHostname} = netaddressVectors;
|
||||
|
||||
for (const [args, expected] of fromHostname) {
|
||||
const addr1 = new NetAddress();
|
||||
addr1.fromHostname(...args);
|
||||
|
||||
const addr2 = NetAddress.fromHostname(...args);
|
||||
|
||||
for (const addr of [addr1, addr2]) {
|
||||
assert.strictEqual(addr.hostname, expected.hostname);
|
||||
assert.strictEqual(addr.host, expected.host);
|
||||
assert.strictEqual(addr.port, expected.port);
|
||||
assert.bufferEqual(addr.key, expected.key);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should create from socket', () => {
|
||||
const {fromSocket} = netaddressVectors;
|
||||
|
||||
for (const [args, expected] of fromSocket) {
|
||||
const addr = NetAddress.fromSocket(...args);
|
||||
|
||||
assert.strictEqual(addr.hostname, expected.hostname);
|
||||
assert.strictEqual(addr.host, expected.host);
|
||||
assert.strictEqual(addr.port, expected.port);
|
||||
}
|
||||
});
|
||||
|
||||
it('should compare addresses', () => {
|
||||
const {compare} = netaddressVectors;
|
||||
|
||||
for (const [[hosta, porta], [hostb, portb], expected] of compare) {
|
||||
const addrA = new NetAddress({
|
||||
host: hosta,
|
||||
port: porta
|
||||
});
|
||||
|
||||
const addrB = new NetAddress({
|
||||
host: hostb,
|
||||
port: portb
|
||||
});
|
||||
|
||||
assert.strictEqual(addrA.compare(addrB), expected,
|
||||
`Failed for ${hosta}:${portb} compare to ${hostb}:${portb}.`);
|
||||
}
|
||||
});
|
||||
|
||||
it('should serialize/deserialize raw', () => {
|
||||
const options = {
|
||||
host: '::1',
|
||||
port: 1000,
|
||||
services: 0xff,
|
||||
time: main.now(),
|
||||
key: Buffer.alloc(33, 1)
|
||||
};
|
||||
|
||||
const check = (addr, incorrectHost) => {
|
||||
if (incorrectHost)
|
||||
assert.notStrictEqual(addr.host, options.host);
|
||||
else
|
||||
assert.strictEqual(addr.host, options.host);
|
||||
assert.strictEqual(addr.port, options.port);
|
||||
assert.strictEqual(addr.time, options.time);
|
||||
assert.strictEqual(addr.services, options.services);
|
||||
assert.bufferEqual(addr.key, options.key);
|
||||
};
|
||||
|
||||
{
|
||||
const addr = new NetAddress(options);
|
||||
const encoded = addr.encode();
|
||||
const decoded = NetAddress.decode(encoded);
|
||||
|
||||
assert.strictEqual(decoded.equal(addr), true);
|
||||
assert.strictEqual(decoded.compare(addr), 0);
|
||||
assert.bufferEqual(decoded.encode(), encoded);
|
||||
check(decoded);
|
||||
}
|
||||
|
||||
{
|
||||
// Do not decode IP.
|
||||
const addr = new NetAddress(options);
|
||||
const encoded = addr.encode();
|
||||
// time(8) + services(4) + service bits(4)
|
||||
encoded[8 + 8] = 1;
|
||||
|
||||
const decoded = NetAddress.decode(encoded);
|
||||
|
||||
assert.strictEqual(decoded.equal(addr), false);
|
||||
assert.strictEqual(decoded.compare(addr), -1);
|
||||
assert.notBufferEqual(decoded.encode(), encoded);
|
||||
|
||||
check(decoded, true);
|
||||
}
|
||||
});
|
||||
|
||||
it('should serialize/deserialize JSON', () => {
|
||||
const options = {
|
||||
host: '::1',
|
||||
port: 1000,
|
||||
services: 0xff,
|
||||
time: main.now(),
|
||||
key: Buffer.alloc(33, 1)
|
||||
};
|
||||
|
||||
const check = (addr, hex) => {
|
||||
assert.strictEqual(addr.host, options.host);
|
||||
assert.strictEqual(addr.port, options.port);
|
||||
assert.strictEqual(addr.time, options.time);
|
||||
assert.strictEqual(addr.services, options.services);
|
||||
|
||||
if (hex)
|
||||
assert.strictEqual(addr.key, options.key.toString('hex'));
|
||||
else
|
||||
assert.bufferEqual(addr.key, options.key);
|
||||
};
|
||||
|
||||
const addr = new NetAddress(options);
|
||||
const json = addr.getJSON();
|
||||
const decoded = NetAddress.fromJSON(json);
|
||||
|
||||
assert.strictEqual(decoded.equal(addr), true);
|
||||
assert.strictEqual(decoded.compare(addr), 0);
|
||||
assert.bufferEqual(decoded.encode(), addr.encode());
|
||||
check(decoded);
|
||||
check(json, true);
|
||||
});
|
||||
|
||||
it('should inspect/format', () => {
|
||||
const options = {
|
||||
host: '::1',
|
||||
port: 1000,
|
||||
services: 0xff,
|
||||
time: main.now(),
|
||||
key: Buffer.alloc(33, 1)
|
||||
};
|
||||
|
||||
const addr = new NetAddress(options);
|
||||
const formatted = addr.format();
|
||||
|
||||
assert.strictEqual(formatted.startsWith('<NetAddress'), true);
|
||||
assert.strictEqual(formatted.endsWith('>'), true);
|
||||
assert.strictEqual(formatted.indexOf(`hostname=${addr.hostname}`) > 0,
|
||||
true);
|
||||
assert.strictEqual(
|
||||
formatted.indexOf(`services=${addr.services.toString(2)}`) > 0,
|
||||
true
|
||||
);
|
||||
assert.strictEqual(formatted.indexOf(`date=${util.date(addr.time)}`) > 0,
|
||||
true);
|
||||
});
|
||||
|
||||
it('should get reachability score', () => {
|
||||
// see: binet.getReachability for details.
|
||||
// tests for the getReachability are covered in binet.
|
||||
//
|
||||
// Here we only test single case for all.
|
||||
const {getReachability} = netaddressVectors;
|
||||
for (const [source, destination, reachability] of getReachability) {
|
||||
const src = new NetAddress({
|
||||
host: source,
|
||||
port: 1000
|
||||
});
|
||||
|
||||
const dest = new NetAddress({
|
||||
host: destination,
|
||||
port: 1000
|
||||
});
|
||||
|
||||
assert.strictEqual(src.getReachability(dest), reachability,
|
||||
`${source}->${destination} - ${reachability}`);
|
||||
}
|
||||
});
|
||||
|
||||
it('should return the correct group', () => {
|
||||
// Local -> !Routable()
|
||||
assert.bufferEqual(
|
||||
NetAddress.fromHost('127.0.0.1', 13038, null, 'testnet').getGroup(),
|
||||
Buffer.from([0xff])
|
||||
);
|
||||
|
||||
// RFC1918 -> !Routable()
|
||||
assert.bufferEqual(
|
||||
NetAddress.fromHost('169.254.1.1', 13038, null, 'testnet').getGroup(),
|
||||
Buffer.from([0])
|
||||
);
|
||||
|
||||
// IPv4
|
||||
assert.bufferEqual(
|
||||
NetAddress.fromHost('1.2.3.4', 13038, null, 'testnet').getGroup(),
|
||||
Buffer.from([1, 1, 2])
|
||||
);
|
||||
|
||||
// RFC6145
|
||||
assert.bufferEqual(
|
||||
NetAddress.fromHost(
|
||||
'::FFFF:0:102:304',
|
||||
13038,
|
||||
null,
|
||||
'testnet'
|
||||
).getGroup(),
|
||||
Buffer.from([1, 1, 2])
|
||||
);
|
||||
|
||||
// RFC6052
|
||||
assert.bufferEqual(
|
||||
NetAddress.fromHost(
|
||||
'64:FF9B::102:304',
|
||||
13038,
|
||||
null,
|
||||
'testnet'
|
||||
).getGroup(),
|
||||
Buffer.from([1, 1, 2])
|
||||
);
|
||||
|
||||
// RFC3964
|
||||
assert.bufferEqual(
|
||||
NetAddress.fromHost(
|
||||
'2002:102:304:9999:9999:9999:9999:9999',
|
||||
13038,
|
||||
null,
|
||||
'testnet'
|
||||
).getGroup(),
|
||||
Buffer.from([1, 1, 2])
|
||||
);
|
||||
|
||||
// RFC4380
|
||||
assert.bufferEqual(
|
||||
NetAddress.fromHost(
|
||||
'2001:0:9999:9999:9999:9999:FEFD:FCFB',
|
||||
13038,
|
||||
null,
|
||||
'testnet'
|
||||
).getGroup(),
|
||||
Buffer.from([1, 1, 2])
|
||||
);
|
||||
|
||||
// Tor
|
||||
assert.bufferEqual(
|
||||
NetAddress.fromHost(
|
||||
'FD87:D87E:EB43:edb1:8e4:3588:e546:35ca',
|
||||
13038,
|
||||
null,
|
||||
'testnet'
|
||||
).getGroup(),
|
||||
Buffer.from([3, 239])
|
||||
);
|
||||
|
||||
// he.net
|
||||
assert.bufferEqual(
|
||||
NetAddress.fromHost(
|
||||
'2001:470:abcd:9999:9999:9999:9999:9999',
|
||||
13038,
|
||||
null,
|
||||
'testnet'
|
||||
).getGroup(),
|
||||
Buffer.from([2, 32, 1, 4, 112, 175])
|
||||
);
|
||||
|
||||
// IPv6
|
||||
assert.bufferEqual(
|
||||
NetAddress.fromHost(
|
||||
'2001:2001:9999:9999:9999:9999:9999:9999',
|
||||
13038,
|
||||
null,
|
||||
'testnet'
|
||||
).getGroup(),
|
||||
Buffer.from([2, 32, 1, 32, 1])
|
||||
);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue