This commit is contained in:
Christopher Jeffrey 2016-08-26 16:49:38 -07:00
parent 9b097f97b9
commit 5da0aceb38
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
17 changed files with 2662 additions and 1298 deletions

View File

@ -13,7 +13,7 @@ var scrypt = require('./scrypt');
var scryptAsync = require('./scrypt-async');
var utils = require('../utils/utils');
var native = require('../utils/native');
var nativeCrypto, supersha, hash, aes;
var nativeCrypto, hash, aes;
var isBrowser =
(typeof process !== 'undefined' && process.browser)

View File

@ -123,6 +123,7 @@ function Environment() {
this.require('reader', './utils/reader');
this.require('writer', './utils/writer');
this.require('lru', './utils/lru');
this.require('bloom', './utils/bloom');
this.require('uri', './utils/uri');
this.require('errors', './utils/errors');
@ -147,7 +148,6 @@ function Environment() {
this.require('sc', './script/sigcache');
// Primitives
this.require('bloom', './primitives/bloom');
this.require('address', './primitives/address');
this.require('outpoint', './primitives/outpoint');
this.require('input', './primitives/input');
@ -162,6 +162,7 @@ function Environment() {
this.require('merkleblock', './primitives/merkleblock');
this.require('headers', './primitives/headers');
this.require('keyring', './primitives/keyring');
this.require('netaddress', './primitives/netaddress');
// HD
this.require('hd', './hd/hd');

View File

@ -11,7 +11,7 @@ var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var assert = utils.assert;
var constants = bcoin.constants;
var NetworkAddress = bcoin.packets.NetworkAddress;
var NetworkAddress = require('../primitives/netaddress');
var fs;
try {

View File

@ -12,12 +12,10 @@ var EventEmitter = require('events').EventEmitter;
var bcoin = require('../env');
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var packets = require('./packets');
var assert = utils.assert;
var constants = bcoin.constants;
var ZERO_SIG = new Buffer(64);
ZERO_SIG.fill(0);
/**
* Represents a BIP150 input and output stream.
* @exports BIP150
@ -76,9 +74,7 @@ BIP150.prototype.isAuthed = function isAuthed() {
return this.challengeReceived && this.replyReceived;
};
BIP150.prototype.challenge = function challenge(payload) {
var p = bcoin.reader(payload);
var hash = p.readHash();
BIP150.prototype.challenge = function challenge(hash) {
var type = this.outbound ? 'r' : 'i';
var msg, sig;
@ -92,7 +88,7 @@ BIP150.prototype.challenge = function challenge(payload) {
msg = this.hash(this.input.sid, type, this.publicKey);
if (!crypto.ccmp(hash, msg))
return ZERO_SIG;
return constants.ZERO_SIG64;
if (this.isAuthed()) {
this.auth = true;
@ -105,9 +101,7 @@ BIP150.prototype.challenge = function challenge(payload) {
return bcoin.ec.fromDER(sig);
};
BIP150.prototype.reply = function reply(payload) {
var p = bcoin.reader(payload);
var data = p.readBytes(64);
BIP150.prototype.reply = function reply(data) {
var type = this.outbound ? 'i' : 'r';
var sig, msg, result;
@ -115,7 +109,7 @@ BIP150.prototype.reply = function reply(payload) {
assert(!this.replyReceived, 'Peer replied twice.');
this.replyReceived = true;
if (utils.equal(data, ZERO_SIG))
if (utils.equal(data, constants.ZERO_SIG64))
throw new Error('Auth failure.');
if (!this.peerIdentity)
@ -141,9 +135,7 @@ BIP150.prototype.reply = function reply(payload) {
return this.hash(this.input.sid, 'p', this.publicKey);
};
BIP150.prototype.propose = function propose(payload) {
var p = bcoin.reader(payload);
var hash = p.readHash();
BIP150.prototype.propose = function propose(hash) {
var match;
assert(!this.outbound, 'Outbound peer tried to propose.');
@ -167,8 +159,7 @@ BIP150.prototype.propose = function propose(payload) {
return this.hash(this.output.sid, 'r', this.peerIdentity);
};
BIP150.prototype.toChallenge = function toChallenge(writer) {
var p = new bcoin.writer(writer);
BIP150.prototype.toChallenge = function toChallenge() {
var msg;
assert(this.bip151.handshake, 'No BIP151 handshake before challenge.');
@ -180,12 +171,7 @@ BIP150.prototype.toChallenge = function toChallenge(writer) {
assert(!this.challengeSent, 'Cannot initiate challenge twice.');
this.challengeSent = true;
p.writeBytes(msg);
if (!writer)
p = p.render();
return p;
return new packets.AuthChallengePacket(msg);
};
BIP150.prototype.rekey = function rekey(sid, key, req, res) {

View File

@ -19,6 +19,7 @@ var crypto = require('../crypto/crypto');
var assert = utils.assert;
var constants = bcoin.constants;
var chachapoly = require('../crypto/chachapoly');
var packets = require('./packets');
/*
* Constants
@ -526,19 +527,10 @@ BIP151.prototype.isReady = function isReady() {
* @returns {Buffer}
*/
BIP151.prototype.toEncinit = function toEncinit(writer) {
var p = bcoin.writer(writer);
p.writeBytes(this.input.getPublicKey());
p.writeU8(this.input.cipher);
if (!writer)
p = p.render();
BIP151.prototype.toEncinit = function toEncinit() {
assert(!this.initSent, 'Cannot init twice.');
this.initSent = true;
return p;
return new packets.EncinitPacket(this.input.getPublicKey(), this.input.cipher);
};
/**
@ -547,16 +539,8 @@ BIP151.prototype.toEncinit = function toEncinit(writer) {
* @returns {Buffer}
*/
BIP151.prototype.toEncack = function toEncack(writer) {
var p = bcoin.writer(writer);
BIP151.prototype.toEncack = function toEncack() {
assert(this.output.prk, 'Cannot ack before init.');
p.writeBytes(this.output.getPublicKey());
if (!writer)
p = p.render();
assert(!this.ackSent, 'Cannot ack twice.');
this.ackSent = true;
@ -565,7 +549,7 @@ BIP151.prototype.toEncack = function toEncack(writer) {
this.emit('handshake');
}
return p;
return new packets.EncackPacket(this.output.getPublicKey());
};
/**
@ -575,17 +559,9 @@ BIP151.prototype.toEncack = function toEncack(writer) {
* @returns {Buffer}
*/
BIP151.prototype.toRekey = function toRekey(writer) {
var p = bcoin.writer(writer);
BIP151.prototype.toRekey = function toRekey() {
assert(this.handshake, 'Cannot rekey before handshake.');
p.writeBytes(constants.ZERO_KEY);
if (!writer)
p = p.render();
return p;
return new packets.EncackPacket(constants.ZERO_KEY);
};
/**
@ -593,16 +569,10 @@ BIP151.prototype.toRekey = function toRekey(writer) {
* @param {Buffer}
*/
BIP151.prototype.encinit = function encinit(data) {
var p = bcoin.reader(data);
var publicKey = p.readBytes(33);
var cipher = p.readU8();
BIP151.prototype.encinit = function encinit(publicKey, cipher) {
assert(cipher === this.output.cipher, 'Cipher mismatch.');
assert(!this.initReceived, 'Already initialized.');
this.initReceived = true;
assert(cipher === this.output.cipher, 'Cipher mismatch.');
this.output.init(publicKey);
};
@ -611,10 +581,7 @@ BIP151.prototype.encinit = function encinit(data) {
* @param {Buffer} data
*/
BIP151.prototype.encack = function encack(data) {
var p = bcoin.reader(data);
var publicKey = p.readBytes(33);
BIP151.prototype.encack = function encack(publicKey) {
assert(this.initSent, 'Unsolicited ACK.');
if (utils.equal(publicKey, constants.ZERO_KEY)) {

View File

@ -552,43 +552,6 @@ TXResponse.prototype.toRaw = function toRaw(witness, writer) {
return p;
};
/**
* Represents a SendCompact message (bip152): `sendcmpct` packet.
* @see https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki
* @constructor
*/
function SendCompact(mode, version) {
if (!(this instanceof SendCompact))
return new SendCompact(mode, version);
this.mode = mode || 0;
this.version = version || 1;
}
SendCompact.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
this.mode = p.readU8();
this.version = p.readU53();
return this;
};
SendCompact.fromRaw = function fromRaw(data) {
return new SendCompact().fromRaw(data);
};
SendCompact.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
p.writeU8(this.mode);
p.writeU64(this.version);
if (!writer)
p = p.render();
return p;
};
/*
* Expose
*/
@ -596,4 +559,3 @@ SendCompact.prototype.toRaw = function toRaw(writer) {
exports.CompactBlock = CompactBlock;
exports.TXRequest = TXRequest;
exports.TXResponse = TXResponse;
exports.SendCompact = SendCompact;

View File

@ -11,8 +11,6 @@ var bcoin = require('../env');
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var assert = utils.assert;
var BufferWriter = require('../utils/writer');
var DUMMY = new Buffer(0);
/**
* Protocol packet framer
@ -77,436 +75,6 @@ Framer.prototype.packet = function packet(cmd, payload, checksum) {
return packet;
};
/**
* Create a version packet with a header.
* @param {VersionPacket} payload
* @returns {Buffer} version packet.
*/
Framer.prototype.version = function version(payload) {
return this.packet('version', payload.toRaw());
};
/**
* Create a verack packet with a header.
* @returns {Buffer} verack packet.
*/
Framer.prototype.verack = function verack() {
return this.packet('verack', DUMMY);
};
/**
* Create a ping packet with a header.
* @param {BN} nonce
* @returns {Buffer} ping packet.
*/
Framer.prototype.ping = function ping(nonce) {
if (!nonce)
return this.packet('ping', DUMMY);
return this.packet('ping', framePing(nonce));
};
/**
* Create a pong packet with a header.
* @param {BN} nonce
* @returns {Buffer} pong packet.
*/
Framer.prototype.pong = function pong(nonce) {
return this.packet('pong', framePing(nonce));
};
/**
* Create an alert packet with a header.
* @param {AlertPacket} alert
* @returns {Buffer} alert packet.
*/
Framer.prototype.alert = function _alert(alert) {
return this.packet('alert', alert.toRaw());
};
/**
* Create a getaddr packet with a header.
* @returns {Buffer} getaddr packet.
*/
Framer.prototype.getAddr = function getAddr() {
return this.packet('getaddr', DUMMY);
};
/**
* Create an addr packet with a header.
* @param {NetworkAddress[]} hosts
* @returns {Buffer} addr packet.
*/
Framer.prototype.addr = function addr(hosts) {
return this.packet('addr', frameAddr(hosts));
};
/**
* Create an inv packet with a header.
* @param {InvItem[]} items
* @returns {Buffer} inv packet.
*/
Framer.prototype.inv = function inv(items) {
return this.packet('inv', frameItems(items));
};
/**
* Create a getdata packet with a header.
* @param {InvItem[]} items
* @returns {Buffer} getdata packet.
*/
Framer.prototype.getData = function getData(items) {
return this.packet('getdata', frameItems(items));
};
/**
* Create a notfound packet with a header.
* @param {InvItem[]} items
* @returns {Buffer} notfound packet.
*/
Framer.prototype.notFound = function notFound(items) {
return this.packet('notfound', frameItems(items));
};
/**
* Create a getblocks packet with a header.
* @param {GetBlocksPacket} data
* @returns {Buffer} getblocks packet.
*/
Framer.prototype.getBlocks = function getBlocks(data) {
return this.packet('getblocks', data.toRaw());
};
/**
* Create a getheaders packet with a header.
* @param {GetBlocksPacket} data
* @returns {Buffer} getheaders packet.
*/
Framer.prototype.getHeaders = function getHeaders(data) {
return this.packet('getheaders', data.toRaw());
};
/**
* Create a headers packet with a header.
* @param {Headers[]} headers
* @returns {Buffer} headers packet.
*/
Framer.prototype.headers = function _headers(headers) {
return this.packet('headers', frameItems(headers));
};
/**
* Create a sendheaders packet with a header.
* @returns {Buffer} sendheaders packet.
*/
Framer.prototype.sendHeaders = function sendHeaders() {
return this.packet('sendheaders', DUMMY);
};
/**
* Create a block packet with a header.
* @param {Block} block
* @returns {Buffer} block packet.
*/
Framer.prototype.block = function _block(block) {
return this.packet('block', block.toNormal());
};
/**
* Create a block packet with a header,
* using witness serialization.
* @param {Block} block
* @returns {Buffer} block packet.
*/
Framer.prototype.witnessBlock = function witnessBlock(block) {
return this.packet('block', block.toRaw());
};
/**
* Create a tx packet with a header.
* @param {TX} tx
* @returns {Buffer} tx packet.
*/
Framer.prototype.tx = function _tx(tx) {
return this.packet('tx', tx.toNormal(), tx.hash());
};
/**
* Create a tx packet with a header,
* using witness serialization.
* @param {TX} tx
* @returns {Buffer} tx packet.
*/
Framer.prototype.witnessTX = function witnessTX(tx) {
var checksum;
// Save some time by using the
// cached hash as our checksum.
if (tx.hasWitness()) {
// We can't use the coinbase
// hash since it is all zeroes.
// We really shouldn't be
// relaying coinbases in the
// first place, but oh well.
if (!tx.isCoinbase())
checksum = tx.witnessHash();
} else {
checksum = tx.hash();
}
return this.packet('tx', tx.toRaw(), checksum);
};
/**
* Create a reject packet with a header.
* @param {RejectPacket} details
* @returns {Buffer} reject packet.
*/
Framer.prototype.reject = function reject(details) {
return this.packet('reject', details.toRaw());
};
/**
* Create a mempool packet with a header.
* @returns {Buffer} mempool packet.
*/
Framer.prototype.mempool = function mempool() {
return this.packet('mempool', DUMMY);
};
/**
* Create a filterload packet with a header.
* @param {Bloom} filter
* @returns {Buffer} filterload packet.
*/
Framer.prototype.filterLoad = function filterLoad(filter) {
return this.packet('filterload', filter.toRaw());
};
/**
* Create a filteradd packet with a header.
* @param {Buffer} data
* @returns {Buffer} filteradd packet.
*/
Framer.prototype.filterAdd = function filterAdd(data) {
return this.packet('filteradd', frameFilterAdd(data));
};
/**
* Create a filterclear packet with a header.
* @returns {Buffer} filterclear packet.
*/
Framer.prototype.filterClear = function filterClear() {
return this.packet('filterclear', DUMMY);
};
/**
* Create a merkleblock packet with a header.
* @param {MerkleBlock} block
* @returns {Buffer} merkleblock packet.
*/
Framer.prototype.merkleBlock = function merkleBlock(block) {
return this.packet('merkleblock', block.toRaw());
};
/**
* Create a getutxos packet with a header.
* @param {GetUTXOsPacket} data
* @returns {Buffer} getutxos packet.
*/
Framer.prototype.getUTXOs = function getUTXOs(data) {
return this.packet('getutxos', data.toRaw());
};
/**
* Create a utxos packet with a header.
* @param {UTXOsPacket} utxos
* @returns {Buffer} utxos packet.
*/
Framer.prototype.UTXOs = function UTXOs(utxos) {
return this.packet('utxos', utxos.toRaw());
};
/**
* Create a havewitness packet with a header.
* @returns {Buffer} havewitness packet.
*/
Framer.prototype.haveWitness = function haveWitness() {
return this.packet('havewitness', DUMMY);
};
/**
* Create a feefilter packet with a header.
* @param {Rate} rate
* @returns {Buffer} feefilter packet.
*/
Framer.prototype.feeFilter = function feeFilter(rate) {
return this.packet('feefilter', frameFeeFilter(rate));
};
/**
* Create a sendcmpct packet with a header.
* @param {SendCompact} data
* @returns {Buffer} sendcmpct packet.
*/
Framer.prototype.sendCmpct = function sendCmpct(data) {
return this.packet('sendcmpct', data.toRaw());
};
/**
* Create a cmpctblock packet with a header.
* @param {CompactBlock} block
* @returns {Buffer} cmpctblock packet.
*/
Framer.prototype.cmpctBlock = function cmpctBlock(block) {
return this.packet('cmpctblock', block.toRaw(false));
};
/**
* Create a getblocktxn packet with a header.
* @param {TXRequest} req
* @returns {Buffer} getblocktxn packet.
*/
Framer.prototype.getBlockTxn = function getBlockTxn(req) {
return this.packet('getblocktxn', req.toRaw());
};
/**
* Create a blocktxn packet with a header.
* @param {TXResponse} res
* @returns {Buffer} blocktxn packet.
*/
Framer.prototype.blockTxn = function blockTxn(res) {
return this.packet('blocktxn', res.toRaw(false));
};
/**
* Create an encinit packet with a header.
* @param {Buffer} data
* @returns {Buffer} encinit packet.
*/
Framer.prototype.encinit = function encinit(data) {
return this.packet('encinit', data);
};
/**
* Create an encack packet with a header.
* @param {Buffer} data
* @returns {Buffer} encack packet.
*/
Framer.prototype.encack = function encack(data) {
return this.packet('encack', data);
};
/**
* Create a authchallenge packet with a header.
* @param {Buffer} data
* @returns {Buffer} authchallenge packet.
*/
Framer.prototype.authChallenge = function authChallenge(data) {
return this.packet('authchallenge', data);
};
/**
* Create a authreply packet with a header.
* @param {Buffer} data
* @returns {Buffer} authreply packet.
*/
Framer.prototype.authReply = function authReply(data) {
return this.packet('authreply', data);
};
/**
* Create a authpropose packet with a header.
* @param {Buffer} data
* @returns {Buffer} authpropose packet.
*/
Framer.prototype.authPropose = function authPropose(data) {
return this.packet('authpropose', data);
};
/*
* Helpers
*/
function frameItems(items) {
var p = new BufferWriter();
var i;
p.writeVarint(items.length);
for (i = 0; i < items.length; i++)
items[i].toRaw(p);
return p.render();
}
function framePing(nonce) {
var p = new BufferWriter();
p.writeU64(nonce);
return p.render();
}
function frameAddr(hosts) {
var p = new BufferWriter();
var i;
p.writeVarint(hosts.length);
for (i = 0; i < hosts.length; i++)
hosts[i].toRaw(true, p);
return p.render();
}
function frameFilterAdd(data) {
var p = new BufferWriter();
p.writeVarBytes(data);
return p.render();
}
function frameFeeFilter(rate) {
var p = new BufferWriter();
p.write64(rate);
return p.render();
}
/*
* Expose
*/

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,6 @@ var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var assert = utils.assert;
var constants = require('../protocol/constants');
var BufferReader = require('../utils/reader');
var packets = require('./packets');
/**
@ -40,7 +39,7 @@ function Parser(options) {
this.pending = [];
this.total = 0;
this.waiting = 24;
this.packet = null;
this.header = null;
this._init();
}
@ -60,13 +59,13 @@ Parser.prototype._init = function _init(str) {
return;
this.bip151.on('packet', function(cmd, body) {
var packet = new Packet(cmd, body.length);
var payload;
try {
packet.payload = self.parsePayload(cmd, body);
payload = self.parsePayload(cmd, body);
} catch (e) {
return self._error(e);
return self.error(e);
}
self.emit('packet', packet);
self.emit('packet', payload);
});
};
@ -76,7 +75,7 @@ Parser.prototype._init = function _init(str) {
* @param {String} str
*/
Parser.prototype._error = function _error(str) {
Parser.prototype.error = function error(str) {
this.emit('error', new Error(str));
};
@ -120,42 +119,37 @@ Parser.prototype.feed = function feed(data) {
* @param {Buffer} chunk
*/
Parser.prototype.parse = function parse(chunk) {
var checksum;
Parser.prototype.parse = function parse(data) {
var payload, checksum;
if (chunk.length > constants.MAX_MESSAGE) {
this.waiting = 24;
this.packet = null;
return this._error('Packet too large: %dmb.', utils.mb(chunk.length));
}
assert(data.length <= constants.MAX_MESSAGE);
if (!this.packet) {
this.packet = this.parseHeader(chunk);
if (!this.header) {
this.header = this.parseHeader(data);
this.waiting = this.header.size;
return;
}
this.packet.payload = chunk;
checksum = crypto.checksum(data).readUInt32LE(0, true);
checksum = crypto.checksum(this.packet.payload).readUInt32LE(0, true);
if (checksum !== this.packet.checksum) {
if (checksum !== this.header.checksum) {
this.waiting = 24;
this.packet = null;
return this._error('Invalid checksum');
this.header = null;
return this.error('Invalid checksum');
}
try {
this.packet.payload = this.parsePayload(this.packet.cmd, this.packet.payload);
payload = this.parsePayload(this.header.cmd, data);
} catch (e) {
this.emit('error', e);
this.waiting = 24;
this.packet = null;
this.header = null;
return;
}
this.emit('packet', this.packet);
this.emit('packet', payload);
this.waiting = 24;
this.packet = null;
this.header = null;
};
/**
@ -166,31 +160,31 @@ Parser.prototype.parse = function parse(chunk) {
*/
Parser.prototype.parseHeader = function parseHeader(h) {
var i, magic, cmd, chk;
var i, magic, cmd, size, checksum;
magic = h.readUInt32LE(0, true);
if (magic !== this.network.magic)
return this._error('Invalid magic value: ' + magic.toString(16));
return this.error('Invalid magic value: ' + magic.toString(16));
// Count length of the cmd
for (i = 0; h[i + 4] !== 0 && i < 12; i++);
if (i === 12)
return this._error('Not NULL-terminated cmd');
return this.error('Not NULL-terminated cmd');
cmd = h.toString('ascii', 4, 4 + i);
this.waiting = h.readUInt32LE(16, true);
size = h.readUInt32LE(16, true);
if (this.waiting > constants.MAX_MESSAGE) {
if (size > constants.MAX_MESSAGE) {
this.waiting = 24;
return this._error('Packet length too large: %dmb', utils.mb(this.waiting));
return this.error('Packet length too large: %dmb', utils.mb(size));
}
chk = h.readUInt32LE(20, true);
checksum = h.readUInt32LE(20, true);
return new Packet(cmd, this.waiting, chk);
return new Header(cmd, size, checksum);
};
/**
@ -201,156 +195,16 @@ Parser.prototype.parseHeader = function parseHeader(h) {
*/
Parser.prototype.parsePayload = function parsePayload(cmd, data) {
switch (cmd) {
case 'version':
return packets.VersionPacket.fromRaw(data);
case 'verack':
return null;
case 'ping':
return parsePing(data);
case 'pong':
return parsePing(data);
case 'alert':
return packets.AlertPacket.fromRaw(data);
case 'getaddr':
return null;
case 'addr':
return parseAddr(data);
case 'inv':
return parseInv(data);
case 'getdata':
return parseInv(data);
case 'notfound':
return parseInv(data);
case 'getblocks':
return packets.GetBlocksPacket.fromRaw(data);
case 'getheaders':
return packets.GetBlocksPacket.fromRaw(data);
case 'headers':
return parseHeaders(data);
case 'sendheaders':
return null;
case 'block':
return bcoin.memblock.fromRaw(data);
case 'tx':
return bcoin.tx.fromRaw(data);
case 'reject':
return packets.RejectPacket.fromRaw(data);
case 'mempool':
return null;
case 'filterload':
return bcoin.bloom.fromRaw(data);
case 'filteradd':
return parseFilterAdd(data);
case 'filterclear':
return null;
case 'merkleblock':
return bcoin.merkleblock.fromRaw(data);
case 'getutxos':
return packets.GetUTXOsPacket.fromRaw(data);
case 'utxos':
return packets.UTXOsPacket.fromRaw(data);
case 'havewitness':
return null;
case 'feefilter':
return parseFeeFilter(data);
case 'sendcmpct':
return bcoin.bip152.SendCompact.fromRaw(data);
case 'cmpctblock':
return bcoin.bip152.CompactBlock.fromRaw(data);
case 'getblocktxn':
return bcoin.bip152.TXRequest.fromRaw(data);
case 'blocktxn':
return bcoin.bip152.TXResponse.fromRaw(data);
case 'encinit':
assert(data.length >= 34);
return data;
case 'encack':
assert(data.length >= 33);
return data;
case 'authchallenge':
assert(data.length >= 32);
return data;
case 'authreply':
assert(data.length >= 64);
return data;
case 'authpropose':
assert(data.length >= 32);
return data;
default:
return data;
}
return packets.fromRaw(cmd, data);
};
/*
* Helpers
*/
function parsePing(data) {
var p = new BufferReader(data);
return p.readU64();
}
function parseInv(data) {
var p = new BufferReader(data);
var items = [];
var i, count;
count = p.readVarint();
assert(count <= 50000, 'Item count too high.');
for (i = 0; i < count; i++)
items.push(bcoin.invitem.fromRaw(p));
return items;
}
function parseHeaders(data) {
var p = new BufferReader(data);
var headers = [];
var i, count;
count = p.readVarint();
for (i = 0; i < count; i++)
headers.push(bcoin.headers.fromRaw(p));
return headers;
}
function parseAddr(data) {
var p = new BufferReader(data);
var addrs = [];
var i, count;
count = p.readVarint();
assert(count <= 10000, 'Too many addresses.');
for (i = 0; i < count; i++)
addrs.push(packets.NetworkAddress.fromRaw(p, true));
return addrs;
}
function parseFeeFilter(data) {
var p = new BufferReader(data);
return p.read64N();
}
function parseFilterAdd(data) {
var p = new BufferReader(data);
return p.readVarBytes();
}
/**
* Packet
* @constructor
* @private
*/
function Packet(cmd, size, checksum) {
function Header(cmd, size, checksum) {
this.cmd = cmd;
this.size = size;
this.checksum = checksum;

View File

@ -12,14 +12,12 @@ var EventEmitter = require('events').EventEmitter;
var utils = require('../utils/utils');
var Parser = require('./parser');
var Framer = require('./framer');
var packets = require('./packets');
var packetTypes = packets.types;
var NetworkAddress = require('../primitives/netaddress');
var assert = utils.assert;
var constants = bcoin.constants;
var InvItem = bcoin.invitem;
var VersionPacket = bcoin.packets.VersionPacket;
var GetBlocksPacket = bcoin.packets.GetBlocksPacket;
var RejectPacket = bcoin.packets.RejectPacket;
var NetworkAddress = bcoin.packets.NetworkAddress;
var GetUTXOsPacket = bcoin.packets.GetUTXOsPacket;
/**
* Represents a remote peer.
@ -225,7 +223,7 @@ Peer.prototype._init = function init() {
});
this.bip151.on('rekey', function() {
self.logger.debug('Rekeying with peer (%s).', self.hostname);
self.write(self.framer.encack(self.bip151.toRekey()));
self.send(self.bip151.toRekey());
});
}
@ -268,7 +266,7 @@ Peer.prototype._onConnect = function _onConnect() {
if (this.bip151) {
assert(!this.bip151.completed);
this.logger.info('Attempting BIP151 handshake (%s).', this.hostname);
this.write(this.framer.encinit(this.bip151.toEncinit()));
this.send(this.bip151.toEncinit());
return this.bip151.wait(3000, function(err) {
if (err)
self.error(err, true);
@ -306,7 +304,7 @@ Peer.prototype._onBIP151 = function _onBIP151() {
if (this.bip150.outbound) {
if (!this.bip150.peerIdentity)
return this.error('No known identity for peer.');
this.write(this.framer.authChallenge(this.bip150.toChallenge()));
this.send(this.bip150.toChallenge());
}
return this.bip150.wait(3000, function(err) {
@ -348,7 +346,7 @@ Peer.prototype._onHandshake = function _onHandshake() {
if (this.pool.address.host !== '0.0.0.0'
&& !this.options.selfish
&& this.pool.server) {
this.write(this.framer.addr([this.pool.address]));
this.send(new packets.AddrPacket([this.pool.address]));
}
};
@ -384,7 +382,7 @@ Peer.prototype._onAck = function _onAck(err) {
// Ask for headers-only.
if (this.options.headers) {
if (this.version.version >= 70012)
this.write(this.framer.sendHeaders());
this.send(new packets.SendHeadersPacket());
}
// Let them know we support segwit (old
@ -392,7 +390,7 @@ Peer.prototype._onAck = function _onAck(err) {
// of service bits).
if (this.options.witness && this.network.oldWitness) {
if (this.version.version >= 70012)
this.write(this.framer.haveWitness());
this.send(new packets.HaveWitnessPacket());
}
// We want compact blocks!
@ -402,7 +400,7 @@ Peer.prototype._onAck = function _onAck(err) {
}
// Find some more peers.
this.write(this.framer.getAddr());
this.write(new packets.GetAddrPacket());
// Relay our spv filter if we have one.
this.updateWatch();
@ -564,7 +562,7 @@ Peer.prototype.sendInv = function sendInv(items) {
for (i = 0; i < items.length; i += 50000) {
chunk = items.slice(i, i + 50000);
this.write(this.framer.inv(chunk));
this.send(new packets.InvPacket(chunk));
}
};
@ -593,16 +591,25 @@ Peer.prototype.sendHeaders = function sendHeaders(items) {
for (i = 0; i < items.length; i += 2000) {
chunk = items.slice(i, i + 2000);
this.write(this.framer.headers(chunk));
this.send(new packets.HeadersPacket(chunk));
}
};
/**
* Send a packet.
* @param {Packet} packet
*/
Peer.prototype.send = function send(packet) {
this.write(this.framer.packet(packet.cmd, packet.toRaw()));
};
/**
* Send a `version` packet.
*/
Peer.prototype.sendVersion = function sendVersion() {
var packet = new VersionPacket({
var packet = new packets.VersionPacket({
version: constants.VERSION,
services: this.pool.services,
ts: bcoin.now(),
@ -613,8 +620,7 @@ Peer.prototype.sendVersion = function sendVersion() {
height: this.chain.height,
relay: this.options.relay
});
this.write(this.framer.version(packet));
this.send(packet);
};
/**
@ -626,7 +632,7 @@ Peer.prototype.sendPing = function sendPing() {
return;
if (this.version.version <= 60000) {
this.write(this.framer.ping());
this.send(new packets.PingPacket());
return;
}
@ -638,7 +644,7 @@ Peer.prototype.sendPing = function sendPing() {
this.lastPing = utils.ms();
this.challenge = utils.nonce();
this.write(this.framer.ping(this.challenge));
this.send(new packets.PingPacket(this.challenge));
};
/**
@ -671,7 +677,7 @@ Peer.prototype.updateWatch = function updateWatch() {
if (!this.options.spv)
return;
this.write(this.framer.filterLoad(this.pool.spvFilter));
this.send(packets.FilterLoadPacket.fromFilter(this.pool.spvFilter));
};
/**
@ -680,7 +686,7 @@ Peer.prototype.updateWatch = function updateWatch() {
*/
Peer.prototype.sendFeeRate = function sendFeeRate(rate) {
this.write(this.framer.feeFilter(rate));
this.send(new packets.FeeFilterPacket(rate));
};
/**
@ -847,7 +853,7 @@ Peer.prototype.getData = function getData(items) {
data[i] = item;
}
this.write(this.framer.getData(data));
this.send(new packets.GetDataPacket(data));
};
/**
@ -857,123 +863,120 @@ Peer.prototype.getData = function getData(items) {
*/
Peer.prototype._onPacket = function onPacket(packet) {
var cmd = packet.cmd;
var payload = packet.payload;
if (this.bip151
&& !this.bip151.completed
&& cmd !== 'encinit'
&& cmd !== 'encack') {
&& packet.type !== packetTypes.ENCINIT
&& packet.type !== packetTypes.ENCACK) {
this.bip151.complete(new Error('Message before handshake.'));
}
if (this.bip150
&& !this.bip150.completed
&& cmd !== 'authchallenge'
&& cmd !== 'authreply'
&& cmd !== 'authpropose') {
&& packet.type !== packetTypes.AUTHCHALLENGE
&& packet.type !== packetTypes.AUTHREPLY
&& packet.type !== packetTypes.AUTHPROPOSE) {
this.bip150.complete(new Error('Message before auth.'));
}
if (this.lastBlock && cmd !== 'tx')
if (this.lastBlock && packet.type !== packetTypes.TX)
this._flushMerkle();
this.lastRecv = utils.ms();
switch (cmd) {
case 'version':
return this._handleVersion(payload);
case 'verack':
this.fire(cmd);
switch (packet.type) {
case packetTypes.VERSION:
return this._handleVersion(packet);
case packetTypes.VERACK:
this.fire(packet.cmd);
break;
case 'ping':
return this._handlePing(payload);
case 'pong':
return this._handlePong(payload);
case 'alert':
return this._handleAlert(payload);
case 'getaddr':
case packetTypes.PING:
return this._handlePing(packet);
case packetTypes.PONG:
return this._handlePong(packet);
case packetTypes.ALERT:
return this._handleAlert(packet);
case packetTypes.GETADDR:
return this._handleGetAddr();
case 'addr':
return this._handleAddr(payload);
case 'inv':
return this._handleInv(payload);
case 'getdata':
return this._handleGetData(payload);
case 'notfound':
this.fire(cmd, payload);
case packetTypes.ADDR:
return this._handleAddr(packet);
case packetTypes.INV:
return this._handleInv(packet);
case packetTypes.GETDATA:
return this._handleGetData(packet);
case packetTypes.NOTFOUND:
this.fire(packet.cmd, packet.items);
break;
case 'getblocks':
return this._handleGetBlocks(payload);
case 'getheaders':
return this._handleGetHeaders(payload);
case 'headers':
return this._handleHeaders(payload);
case 'sendheaders':
case packetTypes.GETBLOCKS:
return this._handleGetBlocks(packet);
case packetTypes.GETHEADERS:
return this._handleGetHeaders(packet);
case packetTypes.HEADERS:
return this._handleHeaders(packet);
case packetTypes.SENDHEADERS:
this.preferHeaders = true;
this.fire(cmd);
this.fire(packet.cmd);
break;
case 'block':
this.fire(cmd, payload);
case packetTypes.BLOCK:
this.fire(packet.cmd, packet.block);
break;
case 'tx':
case packetTypes.TX:
if (this.lastBlock) {
if (this.lastBlock.hasTX(payload)) {
this.lastBlock.addTX(payload);
if (this.lastBlock.hasTX(packet.tx)) {
this.lastBlock.addTX(packet.tx);
if (--this.waiting === 0)
this._flushMerkle();
break;
}
}
this.fire(cmd, payload);
this.fire(packet.cmd, packet.tx);
break;
case 'reject':
return this._handleReject(payload);
case 'mempool':
case packetTypes.REJECT:
return this._handleReject(packet);
case packetTypes.MEMPOOL:
return this._handleMempool();
case 'filterload':
return this._handleFilterLoad(payload);
case 'filteradd':
return this._handleFilterAdd(payload);
case 'filterclear':
case packetTypes.FILTERLOAD:
return this._handleFilterLoad(packet);
case packetTypes.FILTERADD:
return this._handleFilterAdd(packet);
case packetTypes.FILTERCLEAR:
return this._handleFilterClear();
case 'merkleblock':
payload.verifyPartial();
this.lastBlock = payload;
this.waiting = payload.matches.length;
case packetTypes.MERKLEBLOCK:
packet.block.verifyPartial();
this.lastBlock = packet.block;
this.waiting = packet.block.matches.length;
if (this.waiting === 0)
this._flushMerkle();
break;
case 'getutxos':
return this._handleGetUTXOs(payload);
case 'utxos':
return this._handleUTXOs(payload);
case 'havewitness':
case packetTypes.GETUTXOS:
return this._handleGetUTXOs(packet);
case packetTypes.UTXOS:
return this._handleUTXOs(packet);
case packetTypes.HAVEWITNESS:
this.haveWitness = true;
this.fire(cmd);
this.fire(packet.cmd);
break;
case 'feefilter':
return this._handleFeeFilter(payload);
case 'sendcmpct':
return this._handleSendCmpct(payload);
case 'cmpctblock':
return this._handleCmpctBlock(payload);
case 'getblocktxn':
return this._handleGetBlockTxn(payload);
case 'blocktxn':
return this._handleBlockTxn(payload);
case 'encinit':
return this._handleEncinit(payload);
case 'encack':
return this._handleEncack(payload);
case 'authchallenge':
return this._handleAuthChallenge(payload);
case 'authreply':
return this._handleAuthReply(payload);
case 'authpropose':
return this._handleAuthPropose(payload);
default:
this.logger.warning('Unknown packet: %s.', cmd);
case packetTypes.FEEFILTER:
return this._handleFeeFilter(packet);
case packetTypes.SENDCMPCT:
return this._handleSendCmpct(packet);
case packetTypes.CMPCTBLOCK:
return this._handleCmpctBlock(packet);
case packetTypes.GETBLOCKTXN:
return this._handleGetBlockTxn(packet);
case packetTypes.BLOCKTXN:
return this._handleBlockTxn(packet);
case packetTypes.ENCINIT:
return this._handleEncinit(packet);
case packetTypes.ENCACK:
return this._handleEncack(packet);
case packetTypes.AUTHCHALLENGE:
return this._handleAuthChallenge(packet);
case packetTypes.AUTHREPLY:
return this._handleAuthReply(packet);
case packetTypes.AUTHPROPOSE:
return this._handleAuthPropose(packet);
case packetTypes.UNKNOWN:
this.logger.warning('Unknown packet: %s.', packet.cmd);
break;
}
};
@ -1008,13 +1011,13 @@ Peer.prototype.fire = function fire(cmd, payload) {
* @param {Object}
*/
Peer.prototype._handleFilterLoad = function _handleFilterLoad(filter) {
if (!filter.isWithinConstraints()) {
Peer.prototype._handleFilterLoad = function _handleFilterLoad(packet) {
if (!packet.isWithinConstraints()) {
this.setMisbehavior(100);
return;
}
this.spvFilter = filter;
this.spvFilter = packet.toFilter();
this.relay = true;
};
@ -1024,7 +1027,9 @@ Peer.prototype._handleFilterLoad = function _handleFilterLoad(filter) {
* @param {Object}
*/
Peer.prototype._handleFilterAdd = function _handleFilterAdd(data) {
Peer.prototype._handleFilterAdd = function _handleFilterAdd(packet) {
var data = packet.data;
if (data.length > constants.script.MAX_PUSH) {
this.setMisbehavior(100);
return;
@ -1055,7 +1060,9 @@ Peer.prototype._handleFilterClear = function _handleFilterClear() {
* @param {Object}
*/
Peer.prototype._handleFeeFilter = function _handleFeeFilter(rate) {
Peer.prototype._handleFeeFilter = function _handleFeeFilter(packet) {
var rate = packet.rate;
if (!(rate >= 0 && rate <= constants.MAX_MONEY)) {
this.setMisbehavior(100);
return;
@ -1111,7 +1118,7 @@ Peer.prototype._handleGetUTXOs = function _handleGetUTXOs(payload) {
if (payload.prevout.length > 15)
return done();
utxos = new GetUTXOsPacket();
utxos = new packets.GetUTXOsPacket();
utils.forEachSerial(payload.prevout, function(prevout, next) {
var hash = prevout.hash;
@ -1154,7 +1161,7 @@ Peer.prototype._handleGetUTXOs = function _handleGetUTXOs(payload) {
utxos.height = self.chain.height;
utxos.tip = self.chain.tip.hash;
self.write(self.framer.UTXOs(utxos));
self.send(new packets.UTXOsPacket(utxos));
done();
});
@ -1378,8 +1385,7 @@ Peer.prototype._handleVersion = function _handleVersion(version) {
if (!version.relay)
this.relay = false;
// ACK
this.write(this.framer.verack());
this.send(new packets.VerackPacket());
this.version = version;
this.fire('version', version);
};
@ -1482,10 +1488,11 @@ Peer.prototype._getItem = function _getItem(item, callback) {
* @param {Object}
*/
Peer.prototype._handleGetData = function _handleGetData(items) {
Peer.prototype._handleGetData = function _handleGetData(packet) {
var self = this;
var notFound = [];
var unlock = this._lock(_handleGetData, [items, utils.nop]);
var items = packet.items;
var unlock = this._lock(_handleGetData, [packet, utils.nop]);
if (!unlock)
return;
@ -1528,10 +1535,7 @@ Peer.prototype._handleGetData = function _handleGetData(items) {
return next();
}
if (item.hasWitness())
self.write(self.framer.witnessTX(tx));
else
self.write(self.framer.tx(tx));
self.send(new packets.TXPacket(tx, item.hasWitness()));
return next();
}
@ -1541,10 +1545,7 @@ Peer.prototype._handleGetData = function _handleGetData(items) {
switch (item.type) {
case constants.inv.BLOCK:
case constants.inv.WITNESS_BLOCK:
if (item.hasWitness())
self.write(self.framer.witnessBlock(block));
else
self.write(self.framer.block(block));
self.send(new packets.BlockPacket(block, item.hasWitness()));
break;
case constants.inv.FILTERED_BLOCK:
case constants.inv.WITNESS_FILTERED_BLOCK:
@ -1555,22 +1556,18 @@ Peer.prototype._handleGetData = function _handleGetData(items) {
block = block.toMerkle(self.spvFilter);
self.write(self.framer.merkleBlock(block));
self.send(new packets.MerkleBlockPacket(block));
for (i = 0; i < block.txs.length; i++) {
tx = block.txs[i];
if (item.hasWitness())
self.write(self.framer.witnessTX(tx));
else
self.write(self.framer.tx(tx));
self.send(new packets.TXPacket(tx, item.hasWitness()));
}
break;
case constants.inv.CMPCT_BLOCK:
// Fallback to full block.
if (block.height < self.chain.tip.height - 10) {
self.write(self.framer.block(block));
self.send(new packets.BlockPacket(block, false));
break;
}
@ -1585,7 +1582,7 @@ Peer.prototype._handleGetData = function _handleGetData(items) {
break;
}
self.write(self.framer.cmpctBlock(block));
self.send(new packets.CmpctBlockPacket(block, false));
break;
default:
self.logger.warning(
@ -1614,7 +1611,7 @@ Peer.prototype._handleGetData = function _handleGetData(items) {
self.hostname);
if (notFound.length > 0)
self.write(self.framer.notFound(notFound));
self.send(new packets.NotFoundPacket(notFound));
done();
});
@ -1626,7 +1623,8 @@ Peer.prototype._handleGetData = function _handleGetData(items) {
* @param {Object}
*/
Peer.prototype._handleAddr = function _handleAddr(addrs) {
Peer.prototype._handleAddr = function _handleAddr(packet) {
var addrs = packet.items;
var i;
for (i = 0; i < addrs.length; i++)
@ -1648,8 +1646,8 @@ Peer.prototype._handleAddr = function _handleAddr(addrs) {
* @param {Object}
*/
Peer.prototype._handlePing = function _handlePing(nonce) {
this.write(this.framer.pong(nonce));
Peer.prototype._handlePing = function _handlePing(packet) {
this.send(new packets.PongPacket(packet.nonce));
this.fire('ping', this.minPing);
};
@ -1659,7 +1657,8 @@ Peer.prototype._handlePing = function _handlePing(nonce) {
* @param {Object}
*/
Peer.prototype._handlePong = function _handlePong(nonce) {
Peer.prototype._handlePong = function _handlePong(packet) {
var nonce = packet.nonce;
var now = utils.ms();
if (!this.challenge) {
@ -1734,7 +1733,7 @@ Peer.prototype._handleGetAddr = function _handleGetAddr() {
items.length,
this.hostname);
this.write(this.framer.addr(items));
this.send(new packets.AddrPacket(items));
};
/**
@ -1743,10 +1742,12 @@ Peer.prototype._handleGetAddr = function _handleGetAddr() {
* @param {Object}
*/
Peer.prototype._handleInv = function _handleInv(items) {
Peer.prototype._handleInv = function _handleInv(packet) {
var items = packet.items;
var blocks = [];
var txs = [];
var i, item, unknown;
var unknown = -1;
var i, item;
if (items.length > 50000) {
this.setMisbehavior(100);
@ -1755,13 +1756,16 @@ Peer.prototype._handleInv = function _handleInv(items) {
for (i = 0; i < items.length; i++) {
item = items[i];
if (item.type === constants.inv.TX) {
txs.push(item.hash);
} else if (item.type === constants.inv.BLOCK) {
blocks.push(item.hash);
} else {
unknown = item.type;
continue;
switch (item.type) {
case constants.inv.TX:
txs.push(item.hash);
break;
case constants.inv.BLOCK:
blocks.push(item.hash);
break;
default:
unknown = item.type;
continue;
}
this.invFilter.add(item.hash, 'hex');
}
@ -1774,7 +1778,7 @@ Peer.prototype._handleInv = function _handleInv(items) {
if (txs.length > 0)
this.emit('txs', txs);
if (unknown != null) {
if (unknown !== -1) {
this.logger.warning(
'Peer sent an unknown inv type: %d (%s).',
unknown, this.hostname);
@ -1787,7 +1791,8 @@ Peer.prototype._handleInv = function _handleInv(items) {
* @param {Object}
*/
Peer.prototype._handleHeaders = function _handleHeaders(headers) {
Peer.prototype._handleHeaders = function _handleHeaders(packet) {
var headers = packet.items;
if (headers.length > 2000) {
this.setMisbehavior(100);
return;
@ -1835,20 +1840,20 @@ Peer.prototype._handleAlert = function _handleAlert(alert) {
* @param {Object}
*/
Peer.prototype._handleEncinit = function _handleEncinit(data) {
Peer.prototype._handleEncinit = function _handleEncinit(packet) {
if (!this.bip151)
return;
try {
this.bip151.encinit(data);
this.bip151.encinit(packet.publicKey, packet.cipher);
} catch (e) {
this.error(e);
return;
}
this.write(this.framer.encack(this.bip151.toEncack()));
this.send(this.bip151.toEncack());
this.fire('encinit', data);
this.fire('encinit', packet);
};
/**
@ -1857,18 +1862,18 @@ Peer.prototype._handleEncinit = function _handleEncinit(data) {
* @param {Object}
*/
Peer.prototype._handleEncack = function _handleEncack(data) {
Peer.prototype._handleEncack = function _handleEncack(packet) {
if (!this.bip151)
return;
try {
this.bip151.encack(data);
this.bip151.encack(packet.publicKey);
} catch (e) {
this.error(e);
return;
}
this.fire('encack', data);
this.fire('encack', packet);
};
/**
@ -1877,22 +1882,22 @@ Peer.prototype._handleEncack = function _handleEncack(data) {
* @param {Object}
*/
Peer.prototype._handleAuthChallenge = function _handleAuthChallenge(data) {
var result;
Peer.prototype._handleAuthChallenge = function _handleAuthChallenge(packet) {
var sig;
if (!this.bip150)
return;
try {
result = this.bip150.challenge(data);
sig = this.bip150.challenge(packet.hash);
} catch (e) {
this.error(e);
return;
}
this.write(this.framer.authReply(result));
this.send(new packets.AuthReplyPacket(sig));
this.fire('authchallenge', data);
this.fire('authchallenge', packet.hash);
};
/**
@ -1901,23 +1906,23 @@ Peer.prototype._handleAuthChallenge = function _handleAuthChallenge(data) {
* @param {Object}
*/
Peer.prototype._handleAuthReply = function _handleAuthReply(data) {
var result;
Peer.prototype._handleAuthReply = function _handleAuthReply(packet) {
var hash;
if (!this.bip150)
return;
try {
result = this.bip150.reply(data);
hash = this.bip150.reply(packet.signature);
} catch (e) {
this.error(e);
return;
}
if (result)
this.write(this.framer.authPropose(result));
if (hash)
this.send(new packets.AuthProposePacket(hash));
this.fire('authreply', data);
this.fire('authreply', packet.signature);
};
/**
@ -1926,22 +1931,22 @@ Peer.prototype._handleAuthReply = function _handleAuthReply(data) {
* @param {Object}
*/
Peer.prototype._handleAuthPropose = function _handleAuthPropose(data) {
var result;
Peer.prototype._handleAuthPropose = function _handleAuthPropose(packet) {
var hash;
if (!this.bip150)
return;
try {
result = this.bip150.propose(data);
hash = this.bip150.propose(packet.hash);
} catch (e) {
this.error(e);
return;
}
this.write(this.framer.authChallenge(result));
this.send(new packets.AuthChallengePacket(hash));
this.fire('authpropose', data);
this.fire('authpropose', packet.hash);
};
/**
@ -1950,25 +1955,25 @@ Peer.prototype._handleAuthPropose = function _handleAuthPropose(data) {
* @param {Object}
*/
Peer.prototype._handleSendCmpct = function _handleSendCmpct(cmpct) {
if (cmpct.version !== 1) {
Peer.prototype._handleSendCmpct = function _handleSendCmpct(packet) {
if (packet.version !== 1) {
// Ignore
this.logger.info('Peer request compact blocks version %d (%s).',
cmpct.version, this.hostname);
packet.version, this.hostname);
return;
}
if (cmpct.mode !== 0) {
if (packet.mode !== 0) {
// Ignore (we can't do mode 1 yet).
this.logger.info('Peer request compact blocks mode %d (%s).',
cmpct.mode, this.hostname);
packet.mode, this.hostname);
return;
}
this.logger.info('Peer initialized compact blocks (%s).', this.hostname);
this.compactMode = cmpct;
this.fire('sendcmpct', cmpct);
this.compactMode = packet;
this.fire('sendcmpct', packet);
};
/**
@ -1977,8 +1982,9 @@ Peer.prototype._handleSendCmpct = function _handleSendCmpct(cmpct) {
* @param {Object}
*/
Peer.prototype._handleCmpctBlock = function _handleCmpctBlock(block) {
Peer.prototype._handleCmpctBlock = function _handleCmpctBlock(packet) {
var self = this;
var block = packet.block;
var hash = block.hash('hex');
var result;
@ -2013,7 +2019,7 @@ Peer.prototype._handleCmpctBlock = function _handleCmpctBlock(block) {
return;
}
this.write(this.framer.getBlockTxn(block.toRequest()));
this.send(block.toRequest());
this.logger.debug(
'Received semi-full compact block %s (%s).',
@ -2033,8 +2039,9 @@ Peer.prototype._handleCmpctBlock = function _handleCmpctBlock(block) {
* @param {Object}
*/
Peer.prototype._handleGetBlockTxn = function _handleGetBlockTxn(req) {
Peer.prototype._handleGetBlockTxn = function _handleGetBlockTxn(packet) {
var self = this;
var req = packet.request;
var res, item;
function done(err) {
@ -2077,7 +2084,7 @@ Peer.prototype._handleGetBlockTxn = function _handleGetBlockTxn(req) {
res = bcoin.bip152.TXResponse.fromBlock(block, req);
self.write(self.framer.blockTxn(res));
self.send(new packets.BlockTxnPacket(res, false));
done();
});
@ -2089,7 +2096,8 @@ Peer.prototype._handleGetBlockTxn = function _handleGetBlockTxn(req) {
* @param {Object}
*/
Peer.prototype._handleBlockTxn = function _handleBlockTxn(res) {
Peer.prototype._handleBlockTxn = function _handleBlockTxn(packet) {
var res = packet.response;
var block = this.compactBlocks[res.hash];
if (!block) {
@ -2124,7 +2132,7 @@ Peer.prototype.sendAlert = function sendAlert(alert) {
if (!this.invFilter.added(alert.hash()))
return;
this.write(this.framer.alert(alert));
this.send(alert);
};
/**
@ -2135,7 +2143,7 @@ Peer.prototype.sendAlert = function sendAlert(alert) {
*/
Peer.prototype.sendGetHeaders = function sendGetHeaders(locator, stop) {
var packet = new GetBlocksPacket(locator, stop);
var packet = new packets.GetHeadersPacket(locator, stop);
var height = -1;
var hash = null;
@ -2153,7 +2161,7 @@ Peer.prototype.sendGetHeaders = function sendGetHeaders(locator, stop) {
this.logger.debug('Height: %d, Hash: %s, Stop: %s', height, hash, stop);
this.write(this.framer.getHeaders(packet));
this.send(packet);
};
/**
@ -2163,7 +2171,7 @@ Peer.prototype.sendGetHeaders = function sendGetHeaders(locator, stop) {
*/
Peer.prototype.sendGetBlocks = function getBlocks(locator, stop) {
var packet = new GetBlocksPacket(locator, stop);
var packet = new packets.GetBlocksPacket(locator, stop);
var height = -1;
var hash = null;
@ -2181,7 +2189,7 @@ Peer.prototype.sendGetBlocks = function getBlocks(locator, stop) {
this.logger.debug('Height: %d, Hash: %s, Stop: %s', height, hash, stop);
this.write(this.framer.getBlocks(packet));
this.send(packet);
};
/**
@ -2203,7 +2211,7 @@ Peer.prototype.sendMempool = function sendMempool() {
'Requesting inv packet from peer with mempool (%s).',
this.hostname);
this.write(this.framer.mempool());
this.send(new packets.MempoolPacket());
};
/**
@ -2212,7 +2220,7 @@ Peer.prototype.sendMempool = function sendMempool() {
*/
Peer.prototype.sendReject = function sendReject(code, reason, obj) {
var reject = RejectPacket.fromReason(code, reason, obj);
var reject = packets.RejectPacket.fromReason(code, reason, obj);
if (obj) {
this.logger.debug('Rejecting %s %s (%s): ccode=%s reason=%s.',
@ -2226,7 +2234,7 @@ Peer.prototype.sendReject = function sendReject(code, reason, obj) {
'Sending reject packet to peer (%s).',
this.hostname);
this.write(this.framer.reject(reject));
this.send(reject);
};
/**
@ -2234,9 +2242,9 @@ Peer.prototype.sendReject = function sendReject(code, reason, obj) {
*/
Peer.prototype.sendCompact = function sendCompact() {
var cmpct = new bcoin.bip152.SendCompact(0, 1);
var cmpct = new packets.SendCmpctPacket(0, 1);
this.logger.info('Initializing compact blocks (%s).', this.hostname);
this.write(this.framer.sendCmpct(cmpct));
this.send(cmpct);
};
/**

View File

@ -15,7 +15,7 @@ var IP = require('../utils/ip');
var assert = utils.assert;
var constants = bcoin.constants;
var VerifyError = bcoin.errors.VerifyError;
var NetworkAddress = bcoin.packets.NetworkAddress;
var NetworkAddress = require('../primitives/netaddress');
var InvItem = bcoin.invitem;
var VerifyResult = utils.VerifyResult;

View File

@ -0,0 +1,304 @@
/*!
* packets.js - packets for bcoin
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var bcoin = require('../env');
var constants = require('../protocol/constants');
var utils = require('../utils/utils');
var IP = require('../utils/ip');
var assert = utils.assert;
/**
* Represents a network address.
* @exports NetworkAddress
* @constructor
* @param {Object} options
* @param {Number?} options.ts - Timestamp.
* @param {Number?} options.services - Service bits.
* @param {String?} options.host - IP address (IPv6 or IPv4).
* @param {Number?} options.port - Port.
* @property {Number} id
* @property {Host} host
* @property {Number} port
* @property {Number} services
* @property {Number} ts
*/
function NetworkAddress(options) {
if (!(this instanceof NetworkAddress))
return new NetworkAddress(options);
this.id = NetworkAddress.uid++;
this.host = '0.0.0.0';
this.port = 0;
this.services = 0;
this.ts = 0;
this.hostname = '0.0.0.0:0';
if (options)
this.fromOptions(options);
}
/**
* Globally incremented unique id.
* @private
* @type {Number}
*/
NetworkAddress.uid = 0;
/**
* Inject properties from options object.
* @private
* @param {Object} options
*/
NetworkAddress.prototype.fromOptions = function fromOptions(options) {
var host = options.host;
assert(typeof options.host === 'string');
assert(typeof options.port === 'number');
if (IP.version(host) !== -1)
host = IP.normalize(host);
this.host = host;
this.port = options.port;
if (options.services) {
assert(typeof options.services === 'number');
this.services = options.services;
}
if (options.ts) {
assert(typeof options.ts === 'number');
this.ts = options.ts;
}
this.hostname = IP.hostname(this.host, this.port);
return this;
};
/**
* Instantiate network address from options.
* @param {Object} options
* @returns {NetworkAddress}
*/
NetworkAddress.fromOptions = function fromOptions(options) {
return new NetworkAddress().fromOptions(options);
};
/**
* Test whether the `host` field is an ip address.
* @returns {Boolean}
*/
NetworkAddress.prototype.isIP = function isIP() {
return IP.version(this.host) !== -1;
};
/**
* Test whether the NETWORK service bit is set.
* @returns {Boolean}
*/
NetworkAddress.prototype.hasNetwork = function hasNetwork() {
return (this.services & constants.services.NETWORK) !== 0;
};
/**
* Test whether the BLOOM service bit is set.
* @returns {Boolean}
*/
NetworkAddress.prototype.hasBloom = function hasBloom() {
return (this.services & constants.services.BLOOM) !== 0;
};
/**
* Test whether the GETUTXO service bit is set.
* @returns {Boolean}
*/
NetworkAddress.prototype.hasUTXO = function hasUTXO() {
return (this.services & constants.services.GETUTXO) !== 0;
};
/**
* Test whether the WITNESS service bit is set.
* @returns {Boolean}
*/
NetworkAddress.prototype.hasWitness = function hasWitness() {
return (this.services & constants.services.WITNESS) !== 0;
};
/**
* Set host.
* @param {String} host
*/
NetworkAddress.prototype.setHost = function setHost(host) {
this.host = host;
this.hostname = IP.hostname(host, this.port);
};
/**
* Set port.
* @param {Number} port
*/
NetworkAddress.prototype.setPort = function setPort(port) {
this.port = port;
this.hostname = IP.hostname(this.host, port);
};
/**
* Inspect the network address.
* @returns {Object}
*/
NetworkAddress.prototype.inspect = function inspect() {
return '<NetworkAddress:'
+ ' id=' + this.id
+ ' hostname=' + IP.hostname(this.host, this.port)
+ ' services=' + this.services.toString(2)
+ ' date=' + utils.date(this.ts)
+ '>';
};
/**
* Inject properties from hostname and network.
* @private
* @param {String} hostname
* @param {(Network|NetworkType)?} network
*/
NetworkAddress.prototype.fromHostname = function fromHostname(hostname, network) {
var address = IP.parseHost(hostname);
network = bcoin.network.get(network);
this.host = address.host;
this.port = address.port || network.port;
this.services = constants.services.NETWORK
| constants.services.BLOOM
| constants.services.WITNESS;
this.ts = bcoin.now();
this.hostname = IP.hostname(this.host, this.port);
return this;
};
/**
* Instantiate a network address
* from a hostname (i.e. 127.0.0.1:8333).
* @param {String} hostname
* @param {(Network|NetworkType)?} network
* @returns {NetworkAddress}
*/
NetworkAddress.fromHostname = function fromHostname(hostname, network) {
return new NetworkAddress().fromHostname(hostname, network);
};
/**
* Inject properties from socket.
* @private
* @param {net.Socket} socket
*/
NetworkAddress.prototype.fromSocket = function fromSocket(socket) {
assert(typeof socket.remoteAddress === 'string');
assert(typeof socket.remotePort === 'number');
this.host = IP.normalize(socket.remoteAddress);
this.port = socket.remotePort;
this.services = constants.services.NETWORK
| constants.services.BLOOM
| constants.services.WITNESS;
this.ts = bcoin.now();
this.hostname = IP.hostname(this.host, this.port);
return this;
};
/**
* Instantiate a network address
* from a socket.
* @param {net.Socket} socket
* @returns {NetworkAddress}
*/
NetworkAddress.fromSocket = function fromSocket(hostname) {
return new NetworkAddress().fromSocket(hostname);
};
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} data
* @param {Boolean?} full - Include timestamp.
*/
NetworkAddress.prototype.fromRaw = function fromRaw(data, full) {
var p = bcoin.reader(data);
var now = bcoin.now();
// only version >= 31402
this.ts = full ? p.readU32() : 0;
this.services = p.readU53();
this.host = IP.toString(p.readBytes(16));
this.port = p.readU16BE();
if (this.ts <= 100000000 || this.ts > now + 10 * 60)
this.ts = now - 5 * 24 * 60 * 60;
this.hostname = IP.hostname(this.host, this.port);
return this;
};
/**
* Insantiate a network address from serialized data.
* @param {Buffer} data
* @param {Boolean?} full - Include timestamp.
* @returns {NetworkAddress}
*/
NetworkAddress.fromRaw = function fromRaw(data, full) {
return new NetworkAddress().fromRaw(data, full);
};
/**
* Serialize network address.
* @param {Boolean} full - Include timestamp.
* @returns {Buffer}
*/
NetworkAddress.prototype.toRaw = function toRaw(full, writer) {
var p = bcoin.writer(writer);
if (full)
p.writeU32(this.ts);
p.writeU64(this.services);
p.writeBytes(IP.toBuffer(this.host));
p.writeU16BE(this.port);
if (!writer)
p = p.render();
return p;
};
module.exports = NetworkAddress;

View File

@ -631,6 +631,17 @@ exports.ZERO_HASH160 = new Buffer(
'hex'
);
/**
* A hash of all 0xff.
* @const {String}
* @default
*/
exports.MAX_HASH160 = new Buffer(
'ffffffffffffffffffffffffffffffffffffffff',
'hex'
);
/**
* A hash of all zeroes.
* @const {String}
@ -639,6 +650,14 @@ exports.ZERO_HASH160 = new Buffer(
exports.NULL_HASH160 = '0000000000000000000000000000000000000000';
/**
* A hash of all 0xff.
* @const {String}
* @default
*/
exports.HIGH_HASH160 = 'ffffffffffffffffffffffffffffffffffffffff';
/**
* A compressed pubkey of all zeroes.
* @const {Buffer}
@ -650,6 +669,31 @@ exports.ZERO_KEY = new Buffer(
'hex'
);
/**
* A 73 byte signature of all zeroes.
* @const {Buffer}
* @default
*/
exports.ZERO_SIG = new Buffer(''
+ '0000000000000000000000000000000000000000000000000000000000000000'
+ '0000000000000000000000000000000000000000000000000000000000000000'
+ '000000000000000000',
'hex'
);
/**
* A 64 byte signature of all zeroes.
* @const {Buffer}
* @default
*/
exports.ZERO_SIG64 = new Buffer(''
+ '0000000000000000000000000000000000000000000000000000000000000000'
+ '0000000000000000000000000000000000000000000000000000000000000000',
'hex'
);
/**
* BCoin version.
* @const {String}

View File

@ -8,10 +8,7 @@
'use strict';
var constants = require('../protocol/constants');
var assert = require('assert');
var BufferReader = require('../utils/reader');
var BufferWriter = require('../utils/writer');
var murmur3 = require('../utils/murmur3');
var murmur3 = require('./murmur3');
var sum32 = murmur3.sum32;
var mul32 = murmur3.mul32;
@ -147,66 +144,6 @@ Bloom.prototype.added = function added(val, enc) {
return ret;
};
/**
* Ensure the filter is within the size limits.
* @returns {Boolean}
*/
Bloom.prototype.isWithinConstraints = function isWithinConstraints() {
if (this.filter.length > constants.bloom.MAX_BLOOM_FILTER_SIZE)
return false;
if (this.n > constants.bloom.MAX_HASH_FUNCS)
return false;
return true;
};
/**
* Serialize the filter in `filterload` packet format.
* @returns {Buffer}
*/
Bloom.prototype.toRaw = function toRaw(writer) {
var p = BufferWriter(writer);
p.writeVarBytes(this.filter);
p.writeU32(this.n);
p.writeU32(this.tweak);
p.writeU8(this.update);
if (!writer)
p = p.render();
return p;
};
/**
* Instantiate bloom filter from
* serialized data (filterload).
* @param {Buffer}
* @param {String?} enc
* @returns {Bloom}
*/
Bloom.fromRaw = function fromRaw(data, enc) {
var p, filter, n, tweak, update;
if (typeof data === 'string')
data = new Buffer(data, enc);
p = BufferReader(data);
filter = p.readVarBytes();
n = p.readU32();
tweak = p.readU32();
update = p.readU8();
assert(constants.filterFlagsByVal[update] != null, 'Bad filter flag.');
return new Bloom(filter, n, tweak, update);
};
/**
* Create a filter from a false positive rate.
* @param {Number} items - Expeected number of items.
@ -415,11 +352,15 @@ RollingFilter.prototype.added = function added(val, enc) {
* Helpers
*/
function U64(hi, lo) {
this.hi = hi;
this.lo = lo;
}
function read(data, off) {
return {
hi: data.readUInt32LE(off + 4, true),
lo: data.readUInt32LE(off, true)
};
var hi = data.readUInt32LE(off + 4, true);
var lo = data.readUInt32LE(off, true);
return new U64(hi, lo);
}
function write(data, value, off) {

View File

@ -27,15 +27,17 @@ describe('BIP150', function() {
}
it('should do encinit', function() {
client.encinit(server.toEncinit());
server.encinit(client.toEncinit());
var init = server.toEncinit();
client.encinit(init.publicKey, init.cipher);
var init = client.toEncinit();
server.encinit(init.publicKey, init.cipher);
assert(!client.handshake);
assert(!server.handshake);
});
it('should do encack', function() {
client.encack(server.toEncack());
server.encack(client.toEncack());
client.encack(server.toEncack().publicKey);
server.encack(client.toEncack().publicKey);
assert(client.handshake);
assert(server.handshake);
});
@ -49,7 +51,7 @@ describe('BIP150', function() {
it('should do BIP150 handshake', function() {
var challenge = client.bip150.toChallenge();
var reply = server.bip150.challenge(challenge);
var reply = server.bip150.challenge(challenge.hash);
var propose = client.bip150.reply(reply);
var challenge = server.bip150.propose(propose);
var reply = client.bip150.challenge(challenge);
@ -113,7 +115,7 @@ describe('BIP150', function() {
client.once('rekey', function() {
rekeyed = true;
var packet = client.packet('encack', client.toRekey());
var packet = client.packet('encack', client.toRekey().toRaw());
var emitted = false;
server.once('packet', function(cmd, body) {
emitted = true;

View File

@ -17,15 +17,17 @@ describe('BIP151', function() {
}
it('should do encinit', function() {
client.encinit(server.toEncinit());
server.encinit(client.toEncinit());
var init = server.toEncinit();
client.encinit(init.publicKey, init.cipher);
var init = client.toEncinit();
server.encinit(init.publicKey, init.cipher);
assert(!client.handshake);
assert(!server.handshake);
});
it('should do encack', function() {
client.encack(server.toEncack());
server.encack(client.toEncack());
client.encack(server.toEncack().publicKey);
server.encack(client.toEncack().publicKey);
assert(client.handshake);
assert(server.handshake);
});
@ -91,7 +93,7 @@ describe('BIP151', function() {
client.once('rekey', function() {
rekeyed = true;
var packet = client.packet('encack', client.toRekey());
var packet = client.packet('encack', client.toRekey().toRaw());
var emitted = false;
server.once('packet', function(cmd, body) {
emitted = true;

View File

@ -8,9 +8,10 @@ var utils = bcoin.utils;
var crypto = require('../lib/crypto/crypto');
var fs = require('fs');
var alertData = fs.readFileSync(__dirname + '/data/alertTests.raw');
var NetworkAddress = bcoin.packets.NetworkAddress;
var NetworkAddress = require('../lib/primitives/netaddress');
var Framer = require('../lib/net/framer');
var Parser = require('../lib/net/parser');
var packets = require('../lib/net/packets');
describe('Protocol', function() {
var version = require('../package.json').version;
@ -25,17 +26,17 @@ describe('Protocol', function() {
function packetTest(command, payload, test) {
it('should encode/decode ' + command, function(cb) {
var ver = new Buffer(framer[command](payload));
var ver = new Buffer(framer.packet(command, payload.toRaw()));
parser.once('packet', function(packet) {
assert.equal(packet.cmd, command);
test(packet.payload);
test(packet);
cb();
});
parser.feed(ver);
});
}
var v1 = bcoin.packets.VersionPacket.fromOptions({
var v1 = packets.VersionPacket.fromOptions({
version: constants.VERSION,
services: constants.LOCAL_SERVICES,
ts: bcoin.now(),
@ -54,7 +55,7 @@ describe('Protocol', function() {
assert.equal(payload.relay, false);
});
var v2 = bcoin.packets.VersionPacket.fromOptions({
var v2 = packets.VersionPacket.fromOptions({
version: constants.VERSION,
services: constants.LOCAL_SERVICES,
ts: bcoin.now(),
@ -73,7 +74,7 @@ describe('Protocol', function() {
assert.equal(payload.relay, true);
});
packetTest('verack', {}, function(payload) {
packetTest('verack', new packets.VerackPacket(), function(payload) {
});
var hosts = [
@ -91,19 +92,19 @@ describe('Protocol', function() {
})
];
packetTest('addr', hosts, function(payload) {
assert.equal(typeof payload.length, 'number');
assert.equal(payload.length, 2);
packetTest('addr', new packets.AddrPacket(hosts), function(payload) {
assert.equal(typeof payload.items.length, 'number');
assert.equal(payload.items.length, 2);
assert.equal(typeof payload[0].ts, 'number');
assert.equal(payload[0].services, constants.LOCAL_SERVICES);
assert.equal(payload[0].host, hosts[0].host);
assert.equal(payload[0].port, hosts[0].port);
assert.equal(typeof payload.items[0].ts, 'number');
assert.equal(payload.items[0].services, constants.LOCAL_SERVICES);
assert.equal(payload.items[0].host, hosts[0].host);
assert.equal(payload.items[0].port, hosts[0].port);
assert.equal(typeof payload[1].ts, 'number');
assert.equal(payload[1].services, constants.LOCAL_SERVICES);
assert.equal(payload[1].host, hosts[1].host);
assert.equal(payload[1].port, hosts[1].port);
assert.equal(typeof payload.items[1].ts, 'number');
assert.equal(payload.items[1].services, constants.LOCAL_SERVICES);
assert.equal(payload.items[1].host, hosts[1].host);
assert.equal(payload.items[1].port, hosts[1].port);
});
it('should include the raw data of only one transaction in a ' +
@ -209,12 +210,12 @@ describe('Protocol', function() {
var p = new bcoin.reader(alertData);
p.start();
while (p.left()) {
var alert = bcoin.packets.AlertPacket.fromRaw(p);
var alert = packets.AlertPacket.fromRaw(p);
assert(alert.verify(network.alertKey));
alert._payload = null;
alert._hash = null;
var data = alert.toRaw();
alert = bcoin.packets.AlertPacket.fromRaw(data);
alert = packets.AlertPacket.fromRaw(data);
assert(alert.verify(network.alertKey));
}
p.end();