misc. alert.

This commit is contained in:
Christopher Jeffrey 2016-03-26 16:47:22 -07:00
parent 85af68d2ef
commit e1fd556ff6
8 changed files with 196 additions and 34 deletions

View File

@ -1231,8 +1231,10 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
self.total += total;
// Take heap snapshot for debugging.
if (self.total % 20 === 0)
if (self.total % 20 === 0) {
bcoin.profiler.snapshot();
utils.gc();
}
utils.nextTick(function() {
if (self.isFull())

View File

@ -411,6 +411,9 @@ Peer.prototype._onPacket = function onPacket(packet) {
if (cmd === 'reject')
return this._handleReject(payload);
if (cmd === 'alert')
return this._handleAlert(payload);
if (cmd === 'block') {
payload = bcoin.compactblock(payload);
} else if (cmd === 'merkleblock') {
@ -589,29 +592,23 @@ Peer.prototype._handleInv = function handleInv(items) {
this.emit('inv', items);
// Always request advertised TXs
txs = items.filter(function(item) {
return item.type === 'tx';
});
// Emit new blocks to schedule them between multiple peers
blocks = items.filter(function(item) {
return item.type === 'block';
}, this).map(function(item) {
}).map(function(item) {
return item.hash;
});
if (blocks.length === 1)
this.bestHash = utils.toHex(blocks[0]);
blocks = items.filter(function(item) {
return item.type === 'block';
}).map(function(item) {
return item.hash;
});
this.emit('blocks', blocks);
if (blocks.length > 0)
this.emit('blocks', blocks);
if (txs.length === 0)
return;
this.emit('txs', txs.map(function(tx) {
return tx.hash;
}));
if (txs.length > 0)
this.emit('txs', txs);
};
Peer.prototype._handleHeaders = function handleHeaders(headers) {
@ -634,14 +631,20 @@ Peer.prototype._handleReject = function handleReject(payload) {
entry.e.emit('reject', payload);
};
Peer.prototype._handleAlert = function handleAlert(payload) {
this.emit('alert', payload);
};
Peer.prototype.getHeaders = function getHeaders(hashes, stop) {
utils.debug(
'Requesting headers packet from %s with getheaders',
this.host);
utils.debug('Height: %s, Hash: %s, Stop: %s',
this.pool.chain.getHeight(hashes[0]),
hashes ? utils.revHex(hashes[0]) : 0,
stop ? utils.revHex(stop) : 0);
this._write(this.framer.getHeaders(hashes, stop));
};
@ -649,10 +652,12 @@ Peer.prototype.getBlocks = function getBlocks(hashes, stop) {
utils.debug(
'Requesting inv packet from %s with getblocks',
this.host);
utils.debug('Height: %s, Hash: %s, Stop: %s',
this.pool.chain.getHeight(hashes[0]),
hashes ? utils.revHex(hashes[0]) : 0,
stop ? utils.revHex(stop) : 0);
this._write(this.framer.getBlocks(hashes, stop));
};
@ -660,6 +665,7 @@ Peer.prototype.getMempool = function getMempool() {
utils.debug(
'Requesting inv packet from %s with mempool',
this.host);
this._write(this.framer.mempool());
};
@ -679,8 +685,8 @@ Peer.prototype.setMisbehavior = function setMisbehavior(dos) {
return this.pool.setMisbehavior(this, dos);
};
Peer.prototype.sendReject = function sendReject(obj, code, reason, dos) {
return this.pool.reject(this, obj, code, reason, dos);
Peer.prototype.sendReject = function sendReject(obj, code, reason, score) {
return this.pool.reject(this, obj, code, reason, score);
};
/**

View File

@ -804,6 +804,12 @@ Pool.prototype._createPeer = function _createPeer(options) {
self.emit('reject', payload, peer);
});
peer.on('alert', function(payload) {
utils.debug('Received alert from: %s', peer.host);
utils.debug(payload);
self.emit('alert', payload, peer);
});
peer.on('notfound', function(items) {
items.forEach(function(item) {
var req = self.request.map[utils.toHex(item.hash)];
@ -1850,8 +1856,8 @@ Pool.prototype.removeSeed = function removeSeed(seed) {
return true;
};
Pool.prototype.setMisbehavior = function setMisbehavior(peer, dos) {
peer.banScore += dos;
Pool.prototype.setMisbehavior = function setMisbehavior(peer, score) {
peer.banScore += score;
if (peer.banScore >= constants.banScore) {
this.peers.misbehaving[peer.host] = utils.now();
@ -1885,9 +1891,9 @@ Pool.prototype.isMisbehaving = function isMisbehaving(host) {
return false;
};
Pool.prototype.reject = function reject(peer, obj, code, reason, dos) {
if (dos != null)
peer.setMisbehavior(dos);
Pool.prototype.reject = function reject(peer, obj, code, reason, score) {
if (score != null)
peer.setMisbehavior(score);
utils.debug('Rejecting %s %s: ccode=%s reason=%s',
obj.type, obj.hash('hex'), code, reason);

View File

@ -624,6 +624,49 @@ Framer.mempool = function mempool() {
return new Buffer([]);
};
Framer.alert = function alert(data, writer) {
var p, i, payload;
if (!data.payload) {
p = new BufferWriter();
p.write32(data.version);
p.write64(data.relayUntil);
p.write64(data.expiration);
p.write32(data.id);
p.write32(data.cancel);
p.writeVarint(data.cancels.length);
for (i = 0; i < data.cancels.length; i++)
p.write32(data.cancels[i]);
p.write32(data.minVer);
p.write32(data.maxVer);
p.writeVarint(data.subVers.length);
for (i = 0; i < data.subVers.length; i++)
p.writeVarString(data.subVers[i], 'ascii');
p.write32(data.priority);
p.writeVarString(data.comment, 'ascii');
p.writeVarString(data.statusBar, 'ascii');
p.writeVarString('', 'ascii');
payload = p.render();
} else {
payload = data.payload;
}
p = new BufferWriter(writer);
p.writeVarBytes(payload);
if (data.signature)
p.writeVarBytes(data.signature);
else if (data.key)
p.writeVarBytes(bcoin.ec.sign(payload, data.key));
else
assert(false, 'No key or signature.');
if (!writer)
p = p.render();
return p;
};
/**
* Expose
*/

View File

@ -26,6 +26,7 @@ function Parser() {
this.pendingTotal = 0;
this.waiting = 24;
this.packet = null;
this.version = constants.minVersion;
}
utils.inherits(Parser, EventEmitter);
@ -64,6 +65,35 @@ Parser.prototype.feed = function feed(data) {
}
};
Parser.prototype._feed = function feed(data) {
var chunk;
while (data) {
this.pendingTotal += data.length;
this.pending.push(data);
if (this.pendingTotal < this.waiting)
return;
if (this.pending.length === 1)
chunk = this.pending[0];
else
chunk = Buffer.concat(this.pending);
if (chunk.length > this.waiting) {
data = chunk.slice(this.waiting);
chunk = chunk.slice(0, this.waiting);
//chunk = utils.slice(chunk, 0, this.waiting);
} else {
data = null;
}
this.pending.length = 0;
this.pendingTotal = 0;
this.parse(chunk);
}
};
Parser.prototype.parse = function parse(chunk) {
if (chunk.length > constants.maxMessage)
return this._error('Packet too large: %dmb.', utils.mb(chunk.length));
@ -149,6 +179,9 @@ Parser.prototype.parsePayload = function parsePayload(cmd, p) {
if (cmd === 'pong')
return Parser.parsePong(p);
if (cmd === 'alert')
return Parser.parseAlert(p);
return p;
};
@ -187,11 +220,10 @@ Parser.parseVersion = function parseVersion(p) {
agent = p.readVarString('ascii');
height = p.read32();
try {
if (p.left() > 0)
relay = p.readU8() === 1;
} catch (e) {
else
relay = true;
}
try {
ts = ts.toNumber();
@ -209,6 +241,8 @@ Parser.parseVersion = function parseVersion(p) {
assert(ts >= 0, 'Timestamp is negative.');
assert(height >= 0, 'Height is negative.');
this.version = version;
return {
version: version,
services: services,
@ -322,8 +356,8 @@ Parser.parseBlock = function parseBlock(p) {
p.start();
version = p.read32();
prevBlock = p.readHash();
merkleRoot = p.readHash();
prevBlock = p.readHash('hex');
merkleRoot = p.readHash('hex');
ts = p.readU32();
bits = p.readU32();
nonce = p.readU32();
@ -358,8 +392,8 @@ Parser.parseBlockCompact = function parseBlockCompact(p) {
p.start();
version = p.read32();
prevBlock = p.readHash();
merkleRoot = p.readHash();
prevBlock = p.readHash('hex');
merkleRoot = p.readHash('hex');
ts = p.readU32();
bits = p.readU32();
nonce = p.readU32();
@ -404,7 +438,7 @@ Parser.parseInput = function parseInput(p) {
p = new BufferReader(p);
p.start();
hash = p.readHash();
hash = p.readHash('hex');
index = p.readU32();
script = new bcoin.script(p.readVarBytes());
sequence = p.readU32();
@ -661,7 +695,7 @@ Parser.parseAddress = function parseAddress(p, full) {
p = new BufferReader(p);
p.start();
if (full)
if (full && this.version >= 31402)
ts = p.readU32();
else
ts = 0;
@ -675,7 +709,7 @@ Parser.parseAddress = function parseAddress(p, full) {
try {
services = services.toNumber();
} catch (e) {
services = 0;
services = services.uand(utils.MAX_SAFE_BN).toNumber();
}
return {
@ -713,6 +747,65 @@ Parser.parseMempool = function parseMempool(p) {
return {};
};
Parser.parseAlert = function parseAlert(p) {
var version, relayUntil, expiration, id, cancel;
var cancels, count, i, minVer, maxVer, subVers;
var priority, comment, statusBar, msg;
var payload, p2, size;
p = new BufferReader(p);
p.start();
payload = p.readVarBytes();
signature = p.readVarBytes();
size = p.end();
assert(
bcoin.ec.verify(payload, signature, network.alertKey),
'Alert does not verify.');
p = new BufferReader(payload);
p.start();
version = p.read32();
relayUntil = p.read64();
expiration = p.read64();
id = p.read32();
cancel = p.read32();
cancels = [];
count = p.readVarint();
for (i = 0; i < count; i++)
cancels.push(p.read32());
minVer = p.read32();
maxVer = p.read32();
subVers = [];
count = p.readVarint();
for (i = 0; i < count; i++)
subVers.push(p.readVarString('ascii'));
priority = p.read32();
comment = p.readVarString('ascii');
statusBar = p.readVarString('ascii');
p.readVarString('ascii');
p.end();
return {
version: version,
relayUntil: relayUntil,
expiration: expiration,
id: id,
cancel: cancel,
cancels: cancels,
minVer: minVer,
maxVer: maxVer,
subVers: subVers,
priority: priority,
comment: comment,
statusBar: statusBar,
payload: payload,
signature: signature,
_size: size
};
};
/**
* Expose
*/

View File

@ -54,6 +54,9 @@ BufferReader.prototype.endData = function endData() {
if (size === data.length)
return data;
// if (this.zeroCopy)
// return data.slice(start, end);
return utils.slice(data, start, end);
};
@ -258,6 +261,7 @@ BufferReader.prototype.getSize = function getSize() {
};
BufferReader.prototype.seek = function seek(off) {
assert(this.offset + off >= 0);
assert(this.offset + off <= this.data.length);
this.offset += off;
return off;

View File

@ -25,6 +25,11 @@ else
utils.nop = function() {};
utils.gc = !utils.isBrowser && typeof gc === 'function' ? gc : utils.nop;
if (utils.gc !== utils.nop)
console.error('bcoin started with --expose-gc enabled.');
utils.slice = function slice(buf, start, end) {
var clone;
@ -974,6 +979,7 @@ utils.host = function host(addr) {
return addr.split(':')[0];
};
utils.U32 = new bn(0xffffffff);
utils.U64 = new bn('ffffffffffffffff', 'hex');
utils.nonce = function nonce() {
@ -1209,6 +1215,7 @@ utils.writeU64NBE = function writeU64NBE(dst, num, off) {
};
utils.MAX_SAFE_INTEGER = 0x1fffffffffffff;
utils.MAX_SAFE_BN = new bn(utils.MAX_SAFE_INTEGER);
utils.MAX_SAFE_HI = 0x1fffff;
utils.write64N = function write64N(dst, num, off) {

View File

@ -177,6 +177,7 @@ BufferWriter.prototype.writeVarint = function writeVarint(value) {
};
BufferWriter.prototype.fill = function fill(value, size) {
assert(size >= 0);
var buf = new Buffer(size);
buf.fill(value);
this.written += buf.length;