net: use linked lists.
This commit is contained in:
parent
67ffecc989
commit
69a9b5873f
@ -327,7 +327,7 @@ RPC.prototype.getinfo = co(function* getinfo(args) {
|
|||||||
balance: Amount.btc(balance.unconfirmed, true),
|
balance: Amount.btc(balance.unconfirmed, true),
|
||||||
blocks: this.chain.height,
|
blocks: this.chain.height,
|
||||||
timeoffset: this.network.time.offset,
|
timeoffset: this.network.time.offset,
|
||||||
connections: this.pool.peers.all.length,
|
connections: this.pool.peers.size(),
|
||||||
proxy: '',
|
proxy: '',
|
||||||
difficulty: this._getDifficulty(),
|
difficulty: this._getDifficulty(),
|
||||||
testnet: this.network.type !== Network.main,
|
testnet: this.network.type !== Network.main,
|
||||||
@ -379,7 +379,7 @@ RPC.prototype.getnetworkinfo = co(function* getnetworkinfo(args) {
|
|||||||
protocolversion: constants.VERSION,
|
protocolversion: constants.VERSION,
|
||||||
localservices: this.pool.services,
|
localservices: this.pool.services,
|
||||||
timeoffset: this.network.time.offset,
|
timeoffset: this.network.time.offset,
|
||||||
connections: this.pool.peers.all.length,
|
connections: this.pool.peers.size(),
|
||||||
networks: [],
|
networks: [],
|
||||||
relayfee: Amount.btc(this.network.getMinRelay(), true),
|
relayfee: Amount.btc(this.network.getMinRelay(), true),
|
||||||
localaddresses: [],
|
localaddresses: [],
|
||||||
@ -413,7 +413,7 @@ RPC.prototype.addnode = co(function* addnode(args) {
|
|||||||
case 'onetry':
|
case 'onetry':
|
||||||
if (!this.pool.peers.get(addr)) {
|
if (!this.pool.peers.get(addr)) {
|
||||||
peer = this.pool.createPeer(addr);
|
peer = this.pool.createPeer(addr);
|
||||||
this.pool.peers.addPending(peer);
|
this.pool.peers.addOutbound(peer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -450,47 +450,46 @@ RPC.prototype.getaddednodeinfo = co(function* getaddednodeinfo(args) {
|
|||||||
peer = this.pool.peers.get(addr);
|
peer = this.pool.peers.get(addr);
|
||||||
if (!peer)
|
if (!peer)
|
||||||
throw new RPCError('Node has not been added.');
|
throw new RPCError('Node has not been added.');
|
||||||
peers = [peer];
|
return [this._toAddedNode(peer)];
|
||||||
} else {
|
|
||||||
peers = this.pool.peers.all;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < peers.length; i++) {
|
for (peer = this.pool.peers.head(); peer; peer = peer.next)
|
||||||
peer = peers[i];
|
out.push(this._toAddedNode(peer));
|
||||||
out.push({
|
|
||||||
addednode: peer.hostname,
|
|
||||||
connected: peer.connected,
|
|
||||||
addresses: [
|
|
||||||
{
|
|
||||||
address: peer.hostname,
|
|
||||||
connected: peer.outbound
|
|
||||||
? 'outbound'
|
|
||||||
: 'inbound'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
RPC.prototype._toAddedNode = function _toAddedNode(peer) {
|
||||||
|
return {
|
||||||
|
addednode: peer.hostname,
|
||||||
|
connected: peer.connected,
|
||||||
|
addresses: [
|
||||||
|
{
|
||||||
|
address: peer.hostname,
|
||||||
|
connected: peer.outbound
|
||||||
|
? 'outbound'
|
||||||
|
: 'inbound'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
RPC.prototype.getconnectioncount = co(function* getconnectioncount(args) {
|
RPC.prototype.getconnectioncount = co(function* getconnectioncount(args) {
|
||||||
if (args.help || args.length !== 0)
|
if (args.help || args.length !== 0)
|
||||||
throw new RPCError('getconnectioncount');
|
throw new RPCError('getconnectioncount');
|
||||||
|
|
||||||
return this.pool.peers.all.length;
|
return this.pool.peers.size();
|
||||||
});
|
});
|
||||||
|
|
||||||
RPC.prototype.getnettotals = co(function* getnettotals(args) {
|
RPC.prototype.getnettotals = co(function* getnettotals(args) {
|
||||||
var sent = 0;
|
var sent = 0;
|
||||||
var recv = 0;
|
var recv = 0;
|
||||||
var i, peer;
|
var peer;
|
||||||
|
|
||||||
if (args.help || args.length > 0)
|
if (args.help || args.length > 0)
|
||||||
throw new RPCError('getnettotals');
|
throw new RPCError('getnettotals');
|
||||||
|
|
||||||
for (i = 0; i < this.pool.peers.all.length; i++) {
|
for (peer = this.pool.peers.head(); peer; peer = peer.next) {
|
||||||
peer = this.pool.peers.all[i];
|
|
||||||
sent += peer.socket.bytesWritten;
|
sent += peer.socket.bytesWritten;
|
||||||
recv += peer.socket.bytesRead;
|
recv += peer.socket.bytesRead;
|
||||||
}
|
}
|
||||||
@ -504,13 +503,12 @@ RPC.prototype.getnettotals = co(function* getnettotals(args) {
|
|||||||
|
|
||||||
RPC.prototype.getpeerinfo = co(function* getpeerinfo(args) {
|
RPC.prototype.getpeerinfo = co(function* getpeerinfo(args) {
|
||||||
var peers = [];
|
var peers = [];
|
||||||
var i, peer;
|
var peer;
|
||||||
|
|
||||||
if (args.help || args.length !== 0)
|
if (args.help || args.length !== 0)
|
||||||
throw new RPCError('getpeerinfo');
|
throw new RPCError('getpeerinfo');
|
||||||
|
|
||||||
for (i = 0; i < this.pool.peers.all.length; i++) {
|
for (peer = this.pool.peers.head(); peer; peer = peer.next) {
|
||||||
peer = this.pool.peers.all[i];
|
|
||||||
peers.push({
|
peers.push({
|
||||||
id: peer.id,
|
id: peer.id,
|
||||||
addr: peer.hostname,
|
addr: peer.hostname,
|
||||||
@ -538,13 +536,11 @@ RPC.prototype.getpeerinfo = co(function* getpeerinfo(args) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
RPC.prototype.ping = co(function* ping(args) {
|
RPC.prototype.ping = co(function* ping(args) {
|
||||||
var i;
|
|
||||||
|
|
||||||
if (args.help || args.length !== 0)
|
if (args.help || args.length !== 0)
|
||||||
throw new RPCError('ping');
|
throw new RPCError('ping');
|
||||||
|
|
||||||
for (i = 0; i < this.pool.peers.all.length; i++)
|
for (peer = this.pool.peers.head(); peer; peer = peer.next)
|
||||||
this.pool.peers.all[i].sendPing();
|
peer.sendPing();
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -1538,7 +1534,7 @@ RPC.prototype.getblocktemplate = co(function* getblocktemplate(args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!this.network.selfConnect) {
|
if (!this.network.selfConnect) {
|
||||||
if (this.pool.peers.all.length === 0)
|
if (this.pool.peers.size() === 0)
|
||||||
throw new RPCError('Bitcoin is not connected!');
|
throw new RPCError('Bitcoin is not connected!');
|
||||||
|
|
||||||
if (!this.chain.isFull())
|
if (!this.chain.isFull())
|
||||||
|
|||||||
@ -631,7 +631,6 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
this.get('/', function(req, res, send, next) {
|
this.get('/', function(req, res, send, next) {
|
||||||
var totalTX = this.mempool ? this.mempool.totalTX : 0;
|
var totalTX = this.mempool ? this.mempool.totalTX : 0;
|
||||||
var size = this.mempool ? this.mempool.getSize() : 0;
|
var size = this.mempool ? this.mempool.getSize() : 0;
|
||||||
var loader = this.pool.peers.load ? 1 : 0;
|
|
||||||
|
|
||||||
send(200, {
|
send(200, {
|
||||||
version: constants.USER_VERSION,
|
version: constants.USER_VERSION,
|
||||||
@ -644,9 +643,9 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
},
|
},
|
||||||
pool: {
|
pool: {
|
||||||
services: this.pool.services.toString(2),
|
services: this.pool.services.toString(2),
|
||||||
outbound: this.pool.peers.outbound.length + loader,
|
outbound: this.pool.peers.outbound,
|
||||||
pending: this.pool.peers.pending.length,
|
pending: this.pool.peers.pending,
|
||||||
inbound: this.pool.peers.inbound.length
|
inbound: this.pool.peers.inbound
|
||||||
},
|
},
|
||||||
mempool: {
|
mempool: {
|
||||||
tx: totalTX,
|
tx: totalTX,
|
||||||
|
|||||||
@ -26,6 +26,7 @@ var BIP152 = require('./bip152');
|
|||||||
var Block = require('../primitives/block');
|
var Block = require('../primitives/block');
|
||||||
var TX = require('../primitives/tx');
|
var TX = require('../primitives/tx');
|
||||||
var errors = require('../btc/errors');
|
var errors = require('../btc/errors');
|
||||||
|
var List = require('../utils/list');
|
||||||
var packetTypes = packets.types;
|
var packetTypes = packets.types;
|
||||||
var VerifyResult = errors.VerifyResult;
|
var VerifyResult = errors.VerifyResult;
|
||||||
|
|
||||||
@ -93,6 +94,7 @@ function Peer(pool, addr, socket) {
|
|||||||
this.version = null;
|
this.version = null;
|
||||||
this.destroyed = false;
|
this.destroyed = false;
|
||||||
this.ack = false;
|
this.ack = false;
|
||||||
|
this.pending = true;
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
this.ts = 0;
|
this.ts = 0;
|
||||||
this.preferHeaders = false;
|
this.preferHeaders = false;
|
||||||
@ -119,6 +121,9 @@ function Peer(pool, addr, socket) {
|
|||||||
this.drainSize = 0;
|
this.drainSize = 0;
|
||||||
this.drainQueue = [];
|
this.drainQueue = [];
|
||||||
|
|
||||||
|
this.next = null;
|
||||||
|
this.prev = null;
|
||||||
|
|
||||||
this.challenge = null;
|
this.challenge = null;
|
||||||
this.lastPong = -1;
|
this.lastPong = -1;
|
||||||
this.lastPing = -1;
|
this.lastPing = -1;
|
||||||
@ -134,8 +139,8 @@ function Peer(pool, addr, socket) {
|
|||||||
this.requestTimeout = 10000;
|
this.requestTimeout = 10000;
|
||||||
this.requestMap = {};
|
this.requestMap = {};
|
||||||
|
|
||||||
this.queueBlock = [];
|
this.queueBlock = new List();
|
||||||
this.queueTX = [];
|
this.queueTX = new List();
|
||||||
|
|
||||||
this.uid = 0;
|
this.uid = 0;
|
||||||
this.id = Peer.uid++;
|
this.id = Peer.uid++;
|
||||||
@ -154,6 +159,7 @@ function Peer(pool, addr, socket) {
|
|||||||
} else {
|
} else {
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
this.connected = true;
|
this.connected = true;
|
||||||
|
this.pending = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.options.bip151) {
|
if (this.options.bip151) {
|
||||||
@ -491,7 +497,7 @@ Peer.prototype._finalize = co(function* _finalize() {
|
|||||||
yield this.updateWatch();
|
yield this.updateWatch();
|
||||||
|
|
||||||
// Announce our currently broadcasted items.
|
// Announce our currently broadcasted items.
|
||||||
yield this.announce(this.pool.invItems);
|
yield this.announce(this.pool.invItems.toArray());
|
||||||
|
|
||||||
// Set a fee rate filter.
|
// Set a fee rate filter.
|
||||||
if (this.pool.feeRate !== -1)
|
if (this.pool.feeRate !== -1)
|
||||||
@ -1883,7 +1889,7 @@ Peer.prototype._handleAddr = function _handleAddr(packet) {
|
|||||||
'Received %d addrs (hosts=%d, peers=%d) (%s).',
|
'Received %d addrs (hosts=%d, peers=%d) (%s).',
|
||||||
addrs.length,
|
addrs.length,
|
||||||
this.pool.hosts.items.length,
|
this.pool.hosts.items.length,
|
||||||
this.pool.peers.all.length,
|
this.pool.peers.size(),
|
||||||
this.hostname);
|
this.hostname);
|
||||||
|
|
||||||
this.fire('addr', addrs);
|
this.fire('addr', addrs);
|
||||||
|
|||||||
293
lib/net/pool.js
293
lib/net/pool.js
@ -29,6 +29,7 @@ var tcp = require('./tcp');
|
|||||||
var request = require('../http/request');
|
var request = require('../http/request');
|
||||||
var VerifyError = errors.VerifyError;
|
var VerifyError = errors.VerifyError;
|
||||||
var VerifyResult = errors.VerifyResult;
|
var VerifyResult = errors.VerifyResult;
|
||||||
|
var List = require('../utils/list');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pool of peers for handling all network activity.
|
* A pool of peers for handling all network activity.
|
||||||
@ -145,7 +146,7 @@ function Pool(options) {
|
|||||||
|
|
||||||
// Currently broadcasted objects.
|
// Currently broadcasted objects.
|
||||||
this.invMap = {};
|
this.invMap = {};
|
||||||
this.invItems = [];
|
this.invItems = new List();
|
||||||
this.invTimeout = 60000;
|
this.invTimeout = 60000;
|
||||||
|
|
||||||
this.scheduled = false;
|
this.scheduled = false;
|
||||||
@ -327,14 +328,14 @@ Pool.prototype._open = co(function* _open() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Pool.prototype._close = co(function* close() {
|
Pool.prototype._close = co(function* close() {
|
||||||
var i, items, hashes, hash;
|
var i, next, item, hashes, hash;
|
||||||
|
|
||||||
this.stopSync();
|
this.stopSync();
|
||||||
|
|
||||||
items = this.invItems.slice();
|
for (item = this.invItems.head; item; item = next) {
|
||||||
|
next = item.next;
|
||||||
for (i = 0; i < items.length; i++)
|
item.finish();
|
||||||
items[i].finish();
|
}
|
||||||
|
|
||||||
hashes = Object.keys(this.requestMap);
|
hashes = Object.keys(this.requestMap);
|
||||||
|
|
||||||
@ -467,7 +468,7 @@ Pool.prototype._handleLeech = function _handleLeech(socket) {
|
|||||||
|
|
||||||
addr = NetworkAddress.fromSocket(socket, this.network);
|
addr = NetworkAddress.fromSocket(socket, this.network);
|
||||||
|
|
||||||
if (this.peers.inbound.length >= this.maxInbound) {
|
if (this.peers.inbound >= this.maxInbound) {
|
||||||
this.logger.debug('Ignoring leech: too many inbound (%s).', addr.hostname);
|
this.logger.debug('Ignoring leech: too many inbound (%s).', addr.hostname);
|
||||||
socket.destroy();
|
socket.destroy();
|
||||||
return;
|
return;
|
||||||
@ -613,7 +614,9 @@ Pool.prototype.addLoader = function addLoader() {
|
|||||||
|
|
||||||
this.logger.info('Added loader peer (%s).', peer.hostname);
|
this.logger.info('Added loader peer (%s).', peer.hostname);
|
||||||
|
|
||||||
this.peers.addLoader(peer);
|
assert(!this.peers.load);
|
||||||
|
this.peers.load = peer;
|
||||||
|
this.peers.add(peer);
|
||||||
this.fillPeers();
|
this.fillPeers();
|
||||||
|
|
||||||
util.nextTick(function() {
|
util.nextTick(function() {
|
||||||
@ -675,13 +678,13 @@ Pool.prototype.startSync = function startSync() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Pool.prototype.sync = function sync() {
|
Pool.prototype.sync = function sync() {
|
||||||
var i;
|
var peer;
|
||||||
|
|
||||||
if (this.peers.load)
|
for (peer = this.peers.head(); peer; peer = peer.next) {
|
||||||
this.peers.load.trySync();
|
if (!peer.outbound || peer.pending)
|
||||||
|
continue;
|
||||||
for (i = 0; i < this.peers.outbound.length; i++)
|
peer.trySync();
|
||||||
this.peers.outbound[i].trySync();
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -690,15 +693,11 @@ Pool.prototype.sync = function sync() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Pool.prototype.forceSync = function forceSync() {
|
Pool.prototype.forceSync = function forceSync() {
|
||||||
var i, peer;
|
var peer;
|
||||||
|
|
||||||
if (this.peers.load) {
|
for (peer = this.peers.head(); peer; peer = peer.next) {
|
||||||
this.peers.load.syncSent = false;
|
if (!peer.outbound || peer.pending)
|
||||||
this.peers.load.trySync();
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < this.peers.outbound.length; i++) {
|
|
||||||
peer = this.peers.outbound[i];
|
|
||||||
peer.syncSent = false;
|
peer.syncSent = false;
|
||||||
peer.trySync();
|
peer.trySync();
|
||||||
}
|
}
|
||||||
@ -709,7 +708,7 @@ Pool.prototype.forceSync = function forceSync() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Pool.prototype.stopSync = function stopSync() {
|
Pool.prototype.stopSync = function stopSync() {
|
||||||
var i;
|
var peer;
|
||||||
|
|
||||||
if (!this.syncing)
|
if (!this.syncing)
|
||||||
return;
|
return;
|
||||||
@ -722,11 +721,11 @@ Pool.prototype.stopSync = function stopSync() {
|
|||||||
this.stopInterval();
|
this.stopInterval();
|
||||||
this.stopTimeout();
|
this.stopTimeout();
|
||||||
|
|
||||||
if (this.peers.load)
|
for (peer = this.peers.head(); peer; peer = peer.next) {
|
||||||
this.peers.load.syncSent = false;
|
if (!peer.outbound || peer.pending)
|
||||||
|
continue;
|
||||||
for (i = 0; i < this.peers.outbound.length; i++)
|
peer.syncSent = false;
|
||||||
this.peers.outbound[i].syncSent = false;
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -991,9 +990,9 @@ Pool.prototype._handleBlock = co(function* _handleBlock(block, peer) {
|
|||||||
this.chain.total,
|
this.chain.total,
|
||||||
this.chain.orphan.count,
|
this.chain.orphan.count,
|
||||||
this.activeBlocks,
|
this.activeBlocks,
|
||||||
peer.queueBlock.length,
|
peer.queueBlock.size,
|
||||||
block.bits,
|
block.bits,
|
||||||
this.peers.all.length,
|
this.peers.size(),
|
||||||
this.chain.locker.pending.length,
|
this.chain.locker.pending.length,
|
||||||
this.chain.locker.jobs.length);
|
this.chain.locker.jobs.length);
|
||||||
}
|
}
|
||||||
@ -1011,13 +1010,13 @@ Pool.prototype._handleBlock = co(function* _handleBlock(block, peer) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Pool.prototype.sendMempool = function sendMempool() {
|
Pool.prototype.sendMempool = function sendMempool() {
|
||||||
var i;
|
var peer;
|
||||||
|
|
||||||
if (this.peers.load)
|
for (peer = this.peers.head(); peer; peer = peer.next) {
|
||||||
this.peers.load.sendMempool();
|
if (!peer.outbound || peer.pending)
|
||||||
|
continue;
|
||||||
for (i = 0; i < this.peers.outbound.length; i++)
|
peer.sendMempool();
|
||||||
this.peers.outbound[i].sendMempool();
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1026,16 +1025,10 @@ Pool.prototype.sendMempool = function sendMempool() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Pool.prototype.sendAlert = function sendAlert(alert) {
|
Pool.prototype.sendAlert = function sendAlert(alert) {
|
||||||
var i;
|
var peer;
|
||||||
|
|
||||||
if (this.peers.load)
|
for (peer = this.peers.head(); peer; peer = peer.next)
|
||||||
this.peers.load.sendAlert(alert);
|
peer.sendAlert(alert);
|
||||||
|
|
||||||
for (i = 0; i < this.peers.outbound.length; i++)
|
|
||||||
this.peers.outbound[i].sendAlert(alert);
|
|
||||||
|
|
||||||
for (i = 0; i < this.peers.inbound.length; i++)
|
|
||||||
this.peers.inbound[i].sendAlert(alert);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1077,7 +1070,7 @@ Pool.prototype.createPeer = function createPeer(addr, socket) {
|
|||||||
self.stopInterval();
|
self.stopInterval();
|
||||||
self.stopTimeout();
|
self.stopTimeout();
|
||||||
|
|
||||||
if (self.peers.size() === 0) {
|
if (self.peers.outbound === 0) {
|
||||||
self.logger.warning('%s %s %s',
|
self.logger.warning('%s %s %s',
|
||||||
'Could not connect to any peers.',
|
'Could not connect to any peers.',
|
||||||
'Do you have a network connection?',
|
'Do you have a network connection?',
|
||||||
@ -1415,7 +1408,7 @@ Pool.prototype.addLeech = function addLeech(addr, socket) {
|
|||||||
|
|
||||||
this.logger.info('Added leech peer (%s).', peer.hostname);
|
this.logger.info('Added leech peer (%s).', peer.hostname);
|
||||||
|
|
||||||
this.peers.addLeech(peer);
|
this.peers.add(peer);
|
||||||
|
|
||||||
util.nextTick(function() {
|
util.nextTick(function() {
|
||||||
self.emit('leech', peer);
|
self.emit('leech', peer);
|
||||||
@ -1435,7 +1428,7 @@ Pool.prototype.addPeer = function addPeer() {
|
|||||||
if (!this.loaded)
|
if (!this.loaded)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (this.peers.isFull())
|
if (this.peers.outbound >= this.maxOutbound)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Hang back if we don't have a loader peer yet.
|
// Hang back if we don't have a loader peer yet.
|
||||||
@ -1449,7 +1442,7 @@ Pool.prototype.addPeer = function addPeer() {
|
|||||||
|
|
||||||
peer = this.createPeer(addr);
|
peer = this.createPeer(addr);
|
||||||
|
|
||||||
this.peers.addPending(peer);
|
this.peers.add(peer);
|
||||||
|
|
||||||
util.nextTick(function() {
|
util.nextTick(function() {
|
||||||
self.emit('peer', peer);
|
self.emit('peer', peer);
|
||||||
@ -1465,7 +1458,7 @@ Pool.prototype.fillPeers = function fillPeers() {
|
|||||||
var i;
|
var i;
|
||||||
|
|
||||||
this.logger.debug('Refilling peers (%d/%d).',
|
this.logger.debug('Refilling peers (%d/%d).',
|
||||||
this.peers.all.length - this.peers.inbound.length,
|
this.peers.outbound,
|
||||||
this.maxOutbound);
|
this.maxOutbound);
|
||||||
|
|
||||||
for (i = 0; i < this.maxOutbound - 1; i++)
|
for (i = 0; i < this.maxOutbound - 1; i++)
|
||||||
@ -1541,19 +1534,18 @@ Pool.prototype.unwatch = function unwatch() {
|
|||||||
|
|
||||||
Pool.prototype.updateWatch = function updateWatch() {
|
Pool.prototype.updateWatch = function updateWatch() {
|
||||||
var self = this;
|
var self = this;
|
||||||
var i;
|
var peer;
|
||||||
|
|
||||||
if (this.pendingWatch != null)
|
if (this.pendingWatch != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.pendingWatch = setTimeout(function() {
|
this.pendingWatch = setTimeout(function() {
|
||||||
self.pendingWatch = null;
|
self.pendingWatch = null;
|
||||||
|
for (peer = self.peers.head(); peer; peer = peer.next) {
|
||||||
if (self.peers.load)
|
if (!peer.outbound || peer.pending)
|
||||||
self.peers.load.updateWatch();
|
continue;
|
||||||
|
peer.updateWatch();
|
||||||
for (i = 0; i < self.peers.outbound.length; i++)
|
}
|
||||||
self.peers.outbound[i].updateWatch();
|
|
||||||
}, 50);
|
}, 50);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1634,16 +1626,15 @@ Pool.prototype.getTX = function getTX(peer, hash) {
|
|||||||
|
|
||||||
item = new LoadRequest(this, peer, this.txType, hash);
|
item = new LoadRequest(this, peer, this.txType, hash);
|
||||||
|
|
||||||
if (peer.queueTX.length === 0) {
|
if (peer.queueTX.size === 0) {
|
||||||
util.nextTick(function() {
|
util.nextTick(function() {
|
||||||
self.logger.debug(
|
self.logger.debug(
|
||||||
'Requesting %d/%d txs from peer with getdata (%s).',
|
'Requesting %d/%d txs from peer with getdata (%s).',
|
||||||
peer.queueTX.length,
|
peer.queueTX.size,
|
||||||
self.activeTX,
|
self.activeTX,
|
||||||
peer.hostname);
|
peer.hostname);
|
||||||
|
|
||||||
peer.getData(peer.queueTX);
|
peer.getData(peer.queueTX.slice());
|
||||||
peer.queueTX.length = 0;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1709,29 +1700,29 @@ Pool.prototype.scheduleRequests = co(function* scheduleRequests(peer) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Pool.prototype.sendRequests = function sendRequests(peer) {
|
Pool.prototype.sendRequests = function sendRequests(peer) {
|
||||||
var i, size, items;
|
var i, size, items, item;
|
||||||
|
|
||||||
if (peer.queueBlock.length === 0)
|
if (peer.queueBlock.size === 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (this.options.spv) {
|
if (this.options.spv) {
|
||||||
if (this.activeBlocks >= 500)
|
if (this.activeBlocks >= 2000)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
items = peer.queueBlock.slice();
|
size = peer.queueBlock.size;
|
||||||
peer.queueBlock.length = 0;
|
|
||||||
} else {
|
} else {
|
||||||
size = this.network.getBatchSize(this.chain.height);
|
size = this.network.getBatchSize(this.chain.height);
|
||||||
|
|
||||||
if (this.activeBlocks >= size)
|
if (this.activeBlocks >= size)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
items = peer.queueBlock.slice(0, size);
|
|
||||||
peer.queueBlock = peer.queueBlock.slice(size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < items.length; i++)
|
items = peer.queueBlock.slice(size);
|
||||||
items[i] = items[i].start();
|
|
||||||
|
for (i = 0; i < items.length; i++) {
|
||||||
|
item = items[i];
|
||||||
|
item.start();
|
||||||
|
}
|
||||||
|
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
'Requesting %d/%d blocks from peer with getdata (%s).',
|
'Requesting %d/%d blocks from peer with getdata (%s).',
|
||||||
@ -1799,13 +1790,13 @@ Pool.prototype.broadcast = function broadcast(msg) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Pool.prototype.announce = function announce(msg) {
|
Pool.prototype.announce = function announce(msg) {
|
||||||
var i;
|
var peer;
|
||||||
|
|
||||||
if (this.peers.load)
|
for (peer = this.peers.head(); peer; peer = peer.next) {
|
||||||
this.peers.load.tryAnnounce(msg);
|
if (!peer.outbound || peer.pending)
|
||||||
|
continue;
|
||||||
for (i = 0; i < this.peers.outbound.length; i++)
|
peer.tryAnnounce(msg);
|
||||||
this.peers.outbound[i].tryAnnounce(msg);
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1814,15 +1805,15 @@ Pool.prototype.announce = function announce(msg) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Pool.prototype.setFeeRate = function setFeeRate(rate) {
|
Pool.prototype.setFeeRate = function setFeeRate(rate) {
|
||||||
var i;
|
var peer;
|
||||||
|
|
||||||
this.feeRate = rate;
|
this.feeRate = rate;
|
||||||
|
|
||||||
if (this.peers.load)
|
for (peer = this.peers.head(); peer; peer = peer.next) {
|
||||||
this.peers.load.sendFeeRate(rate);
|
if (!peer.outbound || peer.pending)
|
||||||
|
continue;
|
||||||
for (i = 0; i < this.peers.outbound.length; i++)
|
peer.sendFeeRate(rate);
|
||||||
this.peers.outbound[i].sendFeeRate(rate);
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1978,52 +1969,48 @@ Pool.prototype.getIP2 = co(function* getIP2() {
|
|||||||
|
|
||||||
function PeerList(pool) {
|
function PeerList(pool) {
|
||||||
this.pool = pool;
|
this.pool = pool;
|
||||||
// Peers that are loading blocks themselves
|
|
||||||
this.outbound = [];
|
|
||||||
// Peers that are still connecting
|
|
||||||
this.pending = [];
|
|
||||||
// Peers that connected to us
|
|
||||||
this.inbound = [];
|
|
||||||
// Peers that are loading block ids
|
|
||||||
this.load = null;
|
|
||||||
// All peers
|
|
||||||
this.all = [];
|
|
||||||
// Map of hostnames
|
|
||||||
this.map = {};
|
this.map = {};
|
||||||
|
this.list = new List();
|
||||||
|
this.load = null;
|
||||||
|
this.inbound = 0;
|
||||||
|
this.outbound = 0;
|
||||||
|
this.pending = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PeerList.prototype.addLoader = function addLoader(peer) {
|
PeerList.prototype.head = function head() {
|
||||||
this.load = peer;
|
return this.list.head;
|
||||||
this.all.push(peer);
|
|
||||||
assert(!this.map[peer.hostname]);
|
|
||||||
this.map[peer.hostname] = peer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerList.prototype.addPending = function addPending(peer) {
|
PeerList.prototype.tail = function tail() {
|
||||||
this.pending.push(peer);
|
return this.list.tail;
|
||||||
this.all.push(peer);
|
|
||||||
assert(!this.map[peer.hostname]);
|
|
||||||
this.map[peer.hostname] = peer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerList.prototype.addLeech = function addLeech(peer) {
|
PeerList.prototype.size = function size() {
|
||||||
this.inbound.push(peer);
|
return this.list.size;
|
||||||
this.all.push(peer);
|
|
||||||
assert(!this.map[peer.hostname]);
|
|
||||||
this.map[peer.hostname] = peer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerList.prototype.promote = function promote(peer) {
|
PeerList.prototype.promote = function promote(peer) {
|
||||||
if (util.binaryRemove(this.pending, peer, compare))
|
assert(peer.outbound);
|
||||||
util.binaryInsert(this.outbound, peer, compare);
|
assert(peer.pending);
|
||||||
|
peer.pending = false;
|
||||||
|
this.pending--;
|
||||||
|
};
|
||||||
|
|
||||||
|
PeerList.prototype.add = function add(peer) {
|
||||||
|
assert(this.list.push(peer));
|
||||||
|
assert(!this.map[peer.hostname]);
|
||||||
|
this.map[peer.hostname] = peer;
|
||||||
|
if (peer.outbound) {
|
||||||
|
this.outbound++;
|
||||||
|
if (peer.pending)
|
||||||
|
this.pending++;
|
||||||
|
} else {
|
||||||
|
this.inbound++;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerList.prototype.remove = function remove(peer) {
|
PeerList.prototype.remove = function remove(peer) {
|
||||||
util.binaryRemove(this.pending, peer, compare);
|
assert(this.list.remove(peer));
|
||||||
util.binaryRemove(this.outbound, peer, compare);
|
|
||||||
util.binaryRemove(this.inbound, peer, compare);
|
|
||||||
util.binaryRemove(this.all, peer, compare);
|
|
||||||
|
|
||||||
assert(this.map[peer.hostname]);
|
assert(this.map[peer.hostname]);
|
||||||
delete this.map[peer.hostname];
|
delete this.map[peer.hostname];
|
||||||
|
|
||||||
@ -2031,66 +2018,38 @@ PeerList.prototype.remove = function remove(peer) {
|
|||||||
this.pool.logger.info('Removed loader peer (%s).', peer.hostname);
|
this.pool.logger.info('Removed loader peer (%s).', peer.hostname);
|
||||||
this.load = null;
|
this.load = null;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
PeerList.prototype.demoteLoader = function demoteLoader() {
|
if (peer.outbound) {
|
||||||
var peer = this.load;
|
this.outbound--;
|
||||||
assert(peer);
|
if (peer.pending)
|
||||||
this.load = null;
|
this.pending--;
|
||||||
if (peer.ack)
|
} else {
|
||||||
util.binaryInsert(this.outbound, peer, compare);
|
this.inbound--;
|
||||||
else
|
}
|
||||||
util.binaryInsert(this.pending, peer, compare);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerList.prototype.repurpose = function repurpose(peer) {
|
PeerList.prototype.repurpose = function repurpose(peer) {
|
||||||
var r1, r2;
|
|
||||||
|
|
||||||
assert(peer.outbound);
|
assert(peer.outbound);
|
||||||
|
|
||||||
if (this.load)
|
|
||||||
this.demoteLoader();
|
|
||||||
|
|
||||||
r1 = util.binaryRemove(this.pending, peer, compare);
|
|
||||||
r2 = util.binaryRemove(this.outbound, peer, compare);
|
|
||||||
|
|
||||||
assert(r1 || r2);
|
|
||||||
|
|
||||||
this.load = peer;
|
this.load = peer;
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerList.prototype.isFull = function isFull() {
|
|
||||||
return this.size() >= this.pool.maxOutbound - 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
PeerList.prototype.size = function size() {
|
|
||||||
return this.outbound.length + this.pending.length;
|
|
||||||
};
|
|
||||||
|
|
||||||
PeerList.prototype.get = function get(addr) {
|
PeerList.prototype.get = function get(addr) {
|
||||||
return this.map[addr.hostname];
|
return this.map[addr.hostname];
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerList.prototype.destroy = function destroy() {
|
PeerList.prototype.destroy = function destroy() {
|
||||||
var i, peers;
|
var peer, next;
|
||||||
|
|
||||||
if (this.load)
|
this.map = {};
|
||||||
this.load.destroy();
|
this.load = null;
|
||||||
|
this.inbound = 0;
|
||||||
|
this.outbound = 0;
|
||||||
|
this.pending = 0;
|
||||||
|
|
||||||
peers = this.outbound.slice();
|
for (peer = this.list.head; peer; peer = next) {
|
||||||
|
next = peer.next;
|
||||||
for (i = 0; i < peers.length; i++)
|
peer.destroy();
|
||||||
peers[i].destroy();
|
}
|
||||||
|
|
||||||
peers = this.pending.slice();
|
|
||||||
|
|
||||||
for (i = 0; i < peers.length; i++)
|
|
||||||
peers[i].destroy();
|
|
||||||
|
|
||||||
peers = this.inbound.slice();
|
|
||||||
|
|
||||||
for (i = 0; i < peers.length; i++)
|
|
||||||
peers[i].destroy();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2341,10 +2300,12 @@ function LoadRequest(pool, peer, type, hash) {
|
|||||||
this.type = type;
|
this.type = type;
|
||||||
this.hash = hash;
|
this.hash = hash;
|
||||||
this.active = false;
|
this.active = false;
|
||||||
this.id = this.pool.uid++;
|
|
||||||
this.timeout = null;
|
this.timeout = null;
|
||||||
this.onTimeout = this._onTimeout.bind(this);
|
this.onTimeout = this._onTimeout.bind(this);
|
||||||
|
|
||||||
|
this.next = null;
|
||||||
|
this.prev = null;
|
||||||
|
|
||||||
assert(!this.pool.requestMap[this.hash]);
|
assert(!this.pool.requestMap[this.hash]);
|
||||||
this.pool.requestMap[this.hash] = this;
|
this.pool.requestMap[this.hash] = this;
|
||||||
}
|
}
|
||||||
@ -2408,9 +2369,9 @@ LoadRequest.prototype.finish = function finish() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.type === this.pool.txType)
|
if (this.type === this.pool.txType)
|
||||||
util.binaryRemove(this.peer.queueTX, this, compare);
|
this.peer.queueTX.remove(this);
|
||||||
else
|
else
|
||||||
util.binaryRemove(this.peer.queueBlock, this, compare);
|
this.peer.queueBlock.remove(this);
|
||||||
|
|
||||||
if (this.timeout != null) {
|
if (this.timeout != null) {
|
||||||
clearTimeout(this.timeout);
|
clearTimeout(this.timeout);
|
||||||
@ -2502,7 +2463,7 @@ BroadcastItem.prototype.start = function start() {
|
|||||||
assert(!this.pool.invMap[this.hash], 'Already started.');
|
assert(!this.pool.invMap[this.hash], 'Already started.');
|
||||||
|
|
||||||
this.pool.invMap[this.hash] = this;
|
this.pool.invMap[this.hash] = this;
|
||||||
util.binaryInsert(this.pool.invItems, this, compare);
|
assert(this.pool.invItems.push(this));
|
||||||
|
|
||||||
this.refresh();
|
this.refresh();
|
||||||
|
|
||||||
@ -2550,7 +2511,7 @@ BroadcastItem.prototype.finish = function finish(err) {
|
|||||||
this.timeout = null;
|
this.timeout = null;
|
||||||
|
|
||||||
delete this.pool.invMap[this.hash];
|
delete this.pool.invMap[this.hash];
|
||||||
util.binaryRemove(this.pool.invItems, this, compare);
|
assert(this.pool.invItems.remove(this));
|
||||||
|
|
||||||
for (i = 0; i < this.callback.length; i++)
|
for (i = 0; i < this.callback.length; i++)
|
||||||
this.callback[i](err);
|
this.callback[i](err);
|
||||||
|
|||||||
237
lib/utils/list.js
Normal file
237
lib/utils/list.js
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A linked list.
|
||||||
|
* @exports List
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
|
||||||
|
function List() {
|
||||||
|
if (!(this instanceof List))
|
||||||
|
return new List();
|
||||||
|
|
||||||
|
this.head = null;
|
||||||
|
this.tail = null;
|
||||||
|
this.size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the cache. Clear all items.
|
||||||
|
*/
|
||||||
|
|
||||||
|
List.prototype.reset = function reset() {
|
||||||
|
var item, next;
|
||||||
|
|
||||||
|
for (item = this.head; item; item = next) {
|
||||||
|
next = item.next;
|
||||||
|
item.prev = null;
|
||||||
|
item.next = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!item);
|
||||||
|
|
||||||
|
this.head = null;
|
||||||
|
this.tail = null;
|
||||||
|
this.size = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the first item in the list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
List.prototype.shift = function shift() {
|
||||||
|
var item = this.head;
|
||||||
|
|
||||||
|
if (!item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.remove(item);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepend an item to the linked list (sets new head).
|
||||||
|
* @private
|
||||||
|
* @param {ListItem}
|
||||||
|
*/
|
||||||
|
|
||||||
|
List.prototype.unshift = function unshift(item) {
|
||||||
|
return this.insert(null, item);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append an item to the linked list (sets new tail).
|
||||||
|
* @private
|
||||||
|
* @param {ListItem}
|
||||||
|
*/
|
||||||
|
|
||||||
|
List.prototype.push = function push(item) {
|
||||||
|
return this.insert(this.tail, item);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the last item in the list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
List.prototype.pop = function pop() {
|
||||||
|
var item = this.tail;
|
||||||
|
|
||||||
|
if (!item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.remove(item);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert item into the linked list.
|
||||||
|
* @private
|
||||||
|
* @param {ListItem|null} ref
|
||||||
|
* @param {ListItem} item
|
||||||
|
*/
|
||||||
|
|
||||||
|
List.prototype.insert = function insert(ref, item) {
|
||||||
|
if (item.prev || item.next || item === this.head)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
assert(!item.prev);
|
||||||
|
assert(!item.next);
|
||||||
|
|
||||||
|
if (ref == null) {
|
||||||
|
if (!this.head) {
|
||||||
|
this.head = item;
|
||||||
|
this.tail = item;
|
||||||
|
} else {
|
||||||
|
this.head.prev = item;
|
||||||
|
item.next = this.head;
|
||||||
|
this.head = item;
|
||||||
|
}
|
||||||
|
this.size++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.next = ref.next;
|
||||||
|
item.prev = ref;
|
||||||
|
ref.next = item;
|
||||||
|
|
||||||
|
if (ref === this.tail)
|
||||||
|
this.tail = item;
|
||||||
|
|
||||||
|
this.size++;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove item from the linked list.
|
||||||
|
* @private
|
||||||
|
* @param {ListItem}
|
||||||
|
*/
|
||||||
|
|
||||||
|
List.prototype.remove = function remove(item) {
|
||||||
|
if (!item.prev && !item.next && item !== this.head)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (item.prev)
|
||||||
|
item.prev.next = item.next;
|
||||||
|
|
||||||
|
if (item.next)
|
||||||
|
item.next.prev = item.prev;
|
||||||
|
|
||||||
|
if (item === this.head)
|
||||||
|
this.head = item.next;
|
||||||
|
|
||||||
|
if (item === this.tail)
|
||||||
|
this.tail = item.prev || this.head;
|
||||||
|
|
||||||
|
if (!this.head)
|
||||||
|
assert(!this.tail);
|
||||||
|
|
||||||
|
if (!this.tail)
|
||||||
|
assert(!this.head);
|
||||||
|
|
||||||
|
item.prev = null;
|
||||||
|
item.next = null;
|
||||||
|
|
||||||
|
this.size--;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slice the list to an array of items.
|
||||||
|
* @param {Number} total
|
||||||
|
* @returns {Object[]}
|
||||||
|
*/
|
||||||
|
|
||||||
|
List.prototype.slice = function slice(total) {
|
||||||
|
var items = [];
|
||||||
|
var item, next;
|
||||||
|
|
||||||
|
if (total == null)
|
||||||
|
total = Infinity;
|
||||||
|
|
||||||
|
for (item = this.head; item; item = next) {
|
||||||
|
next = item.next;
|
||||||
|
item.prev = null;
|
||||||
|
item.next = null;
|
||||||
|
|
||||||
|
this.size--;
|
||||||
|
|
||||||
|
items.push(item);
|
||||||
|
|
||||||
|
if (items.length === total)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next) {
|
||||||
|
this.head = next;
|
||||||
|
next.prev = null;
|
||||||
|
} else {
|
||||||
|
this.head = null;
|
||||||
|
this.tail = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the list to an array of items.
|
||||||
|
* @returns {Object[]}
|
||||||
|
*/
|
||||||
|
|
||||||
|
List.prototype.toArray = function toArray() {
|
||||||
|
var items = [];
|
||||||
|
var item;
|
||||||
|
|
||||||
|
for (item = this.head; item; item = item.next)
|
||||||
|
items.push(item);
|
||||||
|
|
||||||
|
return items;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an LRU item.
|
||||||
|
* @constructor
|
||||||
|
* @private
|
||||||
|
* @param {String} key
|
||||||
|
* @param {Object} value
|
||||||
|
*/
|
||||||
|
|
||||||
|
function ListItem(value) {
|
||||||
|
this.next = null;
|
||||||
|
this.prev = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Expose
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports = List;
|
||||||
|
exports.Item = ListItem;
|
||||||
|
|
||||||
|
module.exports = exports;
|
||||||
Loading…
Reference in New Issue
Block a user