net: add addrman serialization.

This commit is contained in:
Christopher Jeffrey 2016-12-27 14:29:46 -08:00
parent d26204479a
commit 74dbff2377
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
3 changed files with 385 additions and 16 deletions

View File

@ -1036,7 +1036,7 @@ Pool.prototype.handleAddr = function handleAddr(addrs, peer) {
for (i = 0; i < addrs.length; i++) {
addr = addrs[i];
if (addr.isNull())
if (!addr.isRoutable())
continue;
if (!addr.hasServices(this.needed))
@ -1574,7 +1574,7 @@ Pool.prototype.getHost = function getHost(unique) {
continue;
}
if (addr.isNull())
if (!addr.isValid())
continue;
if (!addr.hasServices(this.needed))
@ -1820,7 +1820,6 @@ Pool.prototype.hasBlock = co(function* hasBlock(hash) {
*/
Pool.prototype.getTX = function getTX(peer, hash) {
var self = this;
var item;
if (!this.loaded)
@ -2889,6 +2888,136 @@ HostList.prototype.populate = co(function* populate(seed) {
}
});
/**
* Convert host list to json-friendly object.
* @returns {Object}
*/
HostList.prototype.toJSON = function toJSON() {
var addrs = [];
var fresh = [];
var used = [];
var i, keys, key, bucket, entry;
keys = Object.keys(this.map);
for (i = 0; i < keys.length; i++) {
key = keys[i];
entry = this.map[key];
addrs.push(entry.toJSON());
}
for (i = 0; i < this.fresh.length; i++) {
bucket = this.fresh[i];
keys = bucket.keys();
fresh.push(keys);
}
for (i = 0; i < this.used.length; i++) {
bucket = this.used[i];
keys = [];
for (entry = bucket.head; entry; entry = entry.next)
keys.push(entry.key());
used.push(keys);
}
return {
version: 1,
addrs: addrs,
fresh: fresh,
used: used
};
};
/**
* Inject properties from json object.
* @private
* @param {Object} json
* @returns {HostList}
*/
HostList.prototype.fromJSON = function fromJSON(json) {
var sources = {};
var i, j, bucket, keys, key, addr, entry, src;
assert(json && typeof json === 'object');
assert(json.version === 1, 'Bad address serialization version.');
assert(Array.isArray(json.addrs));
for (i = 0; i < json.addrs.length; i++) {
addr = json.addrs[i];
entry = HostEntry.fromJSON(addr, this.network);
src = sources[entry.src.hostname];
// Save some memory.
if (!src) {
src = entry.src;
sources[src.hostname] = src;
}
entry.src = src;
this.map[entry.key()] = entry;
}
assert(Array.isArray(json.fresh));
for (i = 0; i < json.fresh.length; i++) {
keys = json.fresh[i];
bucket = this.fresh[i];
assert(bucket, 'No bucket available.');
for (j = 0; j < keys.length; j++) {
key = keys[j];
entry = this.map[key];
assert(entry);
if (entry.refCount === 0)
this.totalFresh++;
entry.refCount++;
bucket.set(key, entry);
}
}
assert(Array.isArray(json.used));
for (i = 0; i < json.used.length; i++) {
keys = json.used[i];
bucket = this.used[i];
assert(bucket, 'No bucket available.');
for (j = 0; j < keys.length; j++) {
key = keys[j];
entry = this.map[key];
assert(entry);
assert(entry.refCount === 0);
assert(!entry.used);
entry.used = true;
this.totalUsed++;
bucket.push(entry);
}
}
keys = Object.keys(this.map);
for (i = 0; i < keys.length; i++) {
key = keys[i];
entry = this.map[key];
assert(entry.used || entry.refCount > 0);
}
return this;
};
/**
* Instantiate host list from json object.
* @param {Object} options
* @param {Object} json
* @returns {HostList}
*/
HostList.fromJSON = function fromJSON(options, json) {
return new HostEntry(options).fromJSON(json);
};
/**
* MapBucket
* @constructor
@ -2981,14 +3110,15 @@ MapBucket.prototype.reset = function reset() {
* HostEntry
* @constructor
* @param {NetAddress} addr
* @param {NetAddress} src
*/
function HostEntry(addr, src) {
assert(addr instanceof NetAddress);
assert(src instanceof NetAddress);
if (!(this instanceof HostEntry))
return new HostEntry(addr, src);
this.addr = addr;
this.src = src;
this.addr = addr || new NetAddress();
this.src = src || new NetAddress();
this.prev = null;
this.next = null;
this.used = false;
@ -2996,8 +3126,38 @@ function HostEntry(addr, src) {
this.attempts = 0;
this.lastSuccess = 0;
this.lastAttempt = 0;
if (addr)
this.fromOptions(addr, src);
}
/**
* Inject properties from options.
* @private
* @param {NetAddress} addr
* @param {NetAddress} src
* @returns {HostEntry}
*/
HostEntry.prototype.fromOptions = function fromOptions(addr, src) {
assert(addr instanceof NetAddress);
assert(src instanceof NetAddress);
this.addr = addr;
this.src = src;
return this;
};
/**
* Instantiate host entry from options.
* @param {NetAddress} addr
* @param {NetAddress} src
* @returns {HostEntry}
*/
HostEntry.fromOptions = function fromOptions(addr, src) {
return new HostEntry().fromOptions(addr, src);
};
/**
* Get key suitable for a hash table (hostname).
* @returns {String}
@ -3042,6 +3202,84 @@ HostEntry.prototype.inspect = function inspect() {
};
};
/**
* Convert host entry to json-friendly object.
* @returns {Object}
*/
HostEntry.prototype.toJSON = function toJSON() {
return {
addr: this.addr.hostname,
src: this.src.hostname,
services: this.addr.services.toString(2),
ts: this.addr.ts,
attempts: this.attempts,
lastSuccess: this.lastSuccess,
lastAttempt: this.lastAttempt
};
};
/**
* Inject properties from json object.
* @private
* @param {Object} json
* @param {Network} network
* @returns {HostEntry}
*/
HostEntry.prototype.fromJSON = function fromJSON(json, network) {
assert(json && typeof json === 'object');
assert(typeof json.addr === 'string');
assert(typeof json.src === 'string');
this.addr.fromHostname(json.addr, network);
if (json.services != null) {
assert(typeof json.services === 'string');
assert(json.services.length > 0);
assert(json.services.length < 64);
this.addr.services = parseInt(json.services, 2);
}
if (json.ts != null) {
assert(util.isNumber(json.ts));
this.addr.ts = json.ts;
}
if (json.src != null) {
assert(typeof json.src === 'string');
this.src.fromHostname(json.src, network);
}
if (json.attempts != null) {
assert(util.isNumber(json.attempts));
this.attempts = json.attempts;
}
if (json.lastSuccess != null) {
assert(util.isNumber(json.lastSuccess));
this.lastSuccess = json.lastSuccess;
}
if (json.lastAttempt != null) {
assert(util.isNumber(json.lastAttempt));
this.lastAttempt = json.lastAttempt;
}
return this;
};
/**
* Instantiate host entry from json object.
* @param {Object} json
* @param {Network} network
* @returns {HostEntry}
*/
HostEntry.fromJSON = function fromJSON(json, network) {
return new HostEntry().fromJSON(json, network);
};
/**
* Represents an in-flight block or transaction.
* @exports LoadRequest

View File

@ -135,7 +135,52 @@ NetAddress.prototype.hasServices = function hasServices(services) {
*/
NetAddress.prototype.isNull = function isNull() {
return this.host === '0.0.0.0' || this.host === '::';
return IP.isNull(this.host);
};
/**
* Test whether the host is a broadcast address.
* @returns {Boolean}
*/
NetAddress.prototype.isBroadcast = function isBroadcast() {
return IP.isBroadcast(this.host);
};
/**
* Test whether the host is a local address.
* @returns {Boolean}
*/
NetAddress.prototype.isLoopback = function isLoopback() {
return IP.isLoopback(this.host);
};
/**
* Test whether the host is a private address.
* @returns {Boolean}
*/
NetAddress.prototype.isPrivate = function isPrivate() {
return IP.isPrivate(this.host);
};
/**
* Test whether the host is valid.
* @returns {Boolean}
*/
NetAddress.prototype.isValid = function isValid() {
return IP.isValid(this.host);
};
/**
* Test whether the host is routable.
* @returns {Boolean}
*/
NetAddress.prototype.isRoutable = function isRoutable() {
return IP.isRoutable(this.host);
};
/**
@ -335,6 +380,51 @@ NetAddress.prototype.toRaw = function toRaw(full) {
return this.toWriter(new StaticWriter(size), full).render();
};
/**
* Convert net address to json-friendly object.
* @returns {Object}
*/
NetAddress.prototype.toJSON = function toJSON() {
return {
host: this.host,
port: this.port,
services: this.services,
ts: this.ts
};
};
/**
* Inject properties from json object.
* @private
* @param {Object} json
* @returns {NetAddress}
*/
NetAddress.prototype.fromJSON = function fromJSON(json) {
assert(IP.version(json.host) !== -1);
assert(util.isNumber(json.port));
assert(json.port >= 0 && json.port <= 0xffff);
assert(util.isNumber(json.services));
assert(util.isNumber(json.ts));
this.host = json.host;
this.port = json.port;
this.services = json.services;
this.ts = json.ts;
this.hostname = IP.hostname(this.host, this.port);
return this;
};
/**
* Instantiate net address from json object.
* @param {Object} json
* @returns {NetAddress}
*/
NetAddress.fromJSON = function fromJSON(json) {
return new NetAddress().fromJSON(json);
};
/**
* Inspect the network address.
* @returns {Object}

View File

@ -157,7 +157,7 @@ IP.version = function version(str) {
* @returns {Boolean}
*/
IP.isV4Format = function(str) {
IP.isV4Format = function isV4Format(str) {
assert(typeof str === 'string');
if (str.length < 7)
@ -175,7 +175,7 @@ IP.isV4Format = function(str) {
* @returns {Boolean}
*/
IP.isV6Format = function(str) {
IP.isV6Format = function isV6Format(str) {
assert(typeof str === 'string');
if (str.length < 2)
@ -216,7 +216,7 @@ IP.isMapped = function isMapped(buf) {
* @returns {Buffer}
*/
IP.toBuffer = function(str) {
IP.toBuffer = function toBuffer(str) {
var buf = new Buffer(16);
assert(typeof str === 'string');
@ -336,7 +336,7 @@ IP.parseV6 = function parseV6(str, buf, offset) {
* @returns {String}
*/
IP.toString = function(buf) {
IP.toString = function toString(buf) {
var str = '';
var i;
@ -385,13 +385,54 @@ IP.normalize = function normalize(str) {
return IP.toString(IP.toBuffer(str));
};
/**
* Test whether an IP is null.
* @param {String} str - Normalized ip.
* @returns {Boolean}
*/
IP.isNull = function isNull(str) {
return str === '0.0.0.0' || str === '::';
};
/**
* Test whether the IP is a broadcast address.
* @param {String} str - Normalized ip.
* @returns {Boolean}
*/
IP.isBroadcast = function isBroadcast(str) {
return str === '255.255.255.255'
|| str === '::ffff:ffff:ffff';
};
/**
* Test whether the IP is valid.
* @param {String} str - Normalized ip.
* @returns {Boolean}
*/
IP.isValid = function isValid(str) {
return !IP.isNull(str) && !IP.isBroadcast(str);
};
/**
* Test whether the IP is routable.
* @param {String} str - Normalized ip.
* @returns {Boolean}
*/
IP.isRoutable = function isRoutable(str) {
return IP.isValid(str) && !IP.isLoopback(str);
};
/**
* Test whether a string is a private address.
* @param {String} str
* @returns {Boolean}
*/
IP.isPrivate = function(str) {
IP.isPrivate = function isPrivate(str) {
assert(typeof str === 'string');
return /^(::f{4}:)?10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(str)
@ -411,7 +452,7 @@ IP.isPrivate = function(str) {
* @returns {Boolean}
*/
IP.isPublic = function(str) {
IP.isPublic = function isPublic(str) {
return !IP.isPrivate(str);
};
@ -421,7 +462,7 @@ IP.isPublic = function(str) {
* @returns {Boolean}
*/
IP.isLoopback = function(str) {
IP.isLoopback = function isLoopback(str) {
assert(typeof str === 'string');
return /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/.test(str)
@ -436,7 +477,7 @@ IP.isLoopback = function(str) {
* @returns {String}
*/
IP.loopback = function(family) {
IP.loopback = function loopback(family) {
if (!family)
family = 'ipv4';