misc. alert.
This commit is contained in:
parent
85af68d2ef
commit
e1fd556ff6
@ -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())
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user