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 scryptAsync = require('./scrypt-async');
var utils = require('../utils/utils'); var utils = require('../utils/utils');
var native = require('../utils/native'); var native = require('../utils/native');
var nativeCrypto, supersha, hash, aes; var nativeCrypto, hash, aes;
var isBrowser = var isBrowser =
(typeof process !== 'undefined' && process.browser) (typeof process !== 'undefined' && process.browser)

View File

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

View File

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

View File

@ -12,12 +12,10 @@ var EventEmitter = require('events').EventEmitter;
var bcoin = require('../env'); var bcoin = require('../env');
var utils = require('../utils/utils'); var utils = require('../utils/utils');
var crypto = require('../crypto/crypto'); var crypto = require('../crypto/crypto');
var packets = require('./packets');
var assert = utils.assert; var assert = utils.assert;
var constants = bcoin.constants; var constants = bcoin.constants;
var ZERO_SIG = new Buffer(64);
ZERO_SIG.fill(0);
/** /**
* Represents a BIP150 input and output stream. * Represents a BIP150 input and output stream.
* @exports BIP150 * @exports BIP150
@ -76,9 +74,7 @@ BIP150.prototype.isAuthed = function isAuthed() {
return this.challengeReceived && this.replyReceived; return this.challengeReceived && this.replyReceived;
}; };
BIP150.prototype.challenge = function challenge(payload) { BIP150.prototype.challenge = function challenge(hash) {
var p = bcoin.reader(payload);
var hash = p.readHash();
var type = this.outbound ? 'r' : 'i'; var type = this.outbound ? 'r' : 'i';
var msg, sig; var msg, sig;
@ -92,7 +88,7 @@ BIP150.prototype.challenge = function challenge(payload) {
msg = this.hash(this.input.sid, type, this.publicKey); msg = this.hash(this.input.sid, type, this.publicKey);
if (!crypto.ccmp(hash, msg)) if (!crypto.ccmp(hash, msg))
return ZERO_SIG; return constants.ZERO_SIG64;
if (this.isAuthed()) { if (this.isAuthed()) {
this.auth = true; this.auth = true;
@ -105,9 +101,7 @@ BIP150.prototype.challenge = function challenge(payload) {
return bcoin.ec.fromDER(sig); return bcoin.ec.fromDER(sig);
}; };
BIP150.prototype.reply = function reply(payload) { BIP150.prototype.reply = function reply(data) {
var p = bcoin.reader(payload);
var data = p.readBytes(64);
var type = this.outbound ? 'i' : 'r'; var type = this.outbound ? 'i' : 'r';
var sig, msg, result; var sig, msg, result;
@ -115,7 +109,7 @@ BIP150.prototype.reply = function reply(payload) {
assert(!this.replyReceived, 'Peer replied twice.'); assert(!this.replyReceived, 'Peer replied twice.');
this.replyReceived = true; this.replyReceived = true;
if (utils.equal(data, ZERO_SIG)) if (utils.equal(data, constants.ZERO_SIG64))
throw new Error('Auth failure.'); throw new Error('Auth failure.');
if (!this.peerIdentity) if (!this.peerIdentity)
@ -141,9 +135,7 @@ BIP150.prototype.reply = function reply(payload) {
return this.hash(this.input.sid, 'p', this.publicKey); return this.hash(this.input.sid, 'p', this.publicKey);
}; };
BIP150.prototype.propose = function propose(payload) { BIP150.prototype.propose = function propose(hash) {
var p = bcoin.reader(payload);
var hash = p.readHash();
var match; var match;
assert(!this.outbound, 'Outbound peer tried to propose.'); 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); return this.hash(this.output.sid, 'r', this.peerIdentity);
}; };
BIP150.prototype.toChallenge = function toChallenge(writer) { BIP150.prototype.toChallenge = function toChallenge() {
var p = new bcoin.writer(writer);
var msg; var msg;
assert(this.bip151.handshake, 'No BIP151 handshake before challenge.'); 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.'); assert(!this.challengeSent, 'Cannot initiate challenge twice.');
this.challengeSent = true; this.challengeSent = true;
p.writeBytes(msg); return new packets.AuthChallengePacket(msg);
if (!writer)
p = p.render();
return p;
}; };
BIP150.prototype.rekey = function rekey(sid, key, req, res) { 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 assert = utils.assert;
var constants = bcoin.constants; var constants = bcoin.constants;
var chachapoly = require('../crypto/chachapoly'); var chachapoly = require('../crypto/chachapoly');
var packets = require('./packets');
/* /*
* Constants * Constants
@ -526,19 +527,10 @@ BIP151.prototype.isReady = function isReady() {
* @returns {Buffer} * @returns {Buffer}
*/ */
BIP151.prototype.toEncinit = function toEncinit(writer) { BIP151.prototype.toEncinit = function toEncinit() {
var p = bcoin.writer(writer);
p.writeBytes(this.input.getPublicKey());
p.writeU8(this.input.cipher);
if (!writer)
p = p.render();
assert(!this.initSent, 'Cannot init twice.'); assert(!this.initSent, 'Cannot init twice.');
this.initSent = true; this.initSent = true;
return new packets.EncinitPacket(this.input.getPublicKey(), this.input.cipher);
return p;
}; };
/** /**
@ -547,16 +539,8 @@ BIP151.prototype.toEncinit = function toEncinit(writer) {
* @returns {Buffer} * @returns {Buffer}
*/ */
BIP151.prototype.toEncack = function toEncack(writer) { BIP151.prototype.toEncack = function toEncack() {
var p = bcoin.writer(writer);
assert(this.output.prk, 'Cannot ack before init.'); assert(this.output.prk, 'Cannot ack before init.');
p.writeBytes(this.output.getPublicKey());
if (!writer)
p = p.render();
assert(!this.ackSent, 'Cannot ack twice.'); assert(!this.ackSent, 'Cannot ack twice.');
this.ackSent = true; this.ackSent = true;
@ -565,7 +549,7 @@ BIP151.prototype.toEncack = function toEncack(writer) {
this.emit('handshake'); this.emit('handshake');
} }
return p; return new packets.EncackPacket(this.output.getPublicKey());
}; };
/** /**
@ -575,17 +559,9 @@ BIP151.prototype.toEncack = function toEncack(writer) {
* @returns {Buffer} * @returns {Buffer}
*/ */
BIP151.prototype.toRekey = function toRekey(writer) { BIP151.prototype.toRekey = function toRekey() {
var p = bcoin.writer(writer);
assert(this.handshake, 'Cannot rekey before handshake.'); assert(this.handshake, 'Cannot rekey before handshake.');
return new packets.EncackPacket(constants.ZERO_KEY);
p.writeBytes(constants.ZERO_KEY);
if (!writer)
p = p.render();
return p;
}; };
/** /**
@ -593,16 +569,10 @@ BIP151.prototype.toRekey = function toRekey(writer) {
* @param {Buffer} * @param {Buffer}
*/ */
BIP151.prototype.encinit = function encinit(data) { BIP151.prototype.encinit = function encinit(publicKey, cipher) {
var p = bcoin.reader(data); assert(cipher === this.output.cipher, 'Cipher mismatch.');
var publicKey = p.readBytes(33);
var cipher = p.readU8();
assert(!this.initReceived, 'Already initialized.'); assert(!this.initReceived, 'Already initialized.');
this.initReceived = true; this.initReceived = true;
assert(cipher === this.output.cipher, 'Cipher mismatch.');
this.output.init(publicKey); this.output.init(publicKey);
}; };
@ -611,10 +581,7 @@ BIP151.prototype.encinit = function encinit(data) {
* @param {Buffer} data * @param {Buffer} data
*/ */
BIP151.prototype.encack = function encack(data) { BIP151.prototype.encack = function encack(publicKey) {
var p = bcoin.reader(data);
var publicKey = p.readBytes(33);
assert(this.initSent, 'Unsolicited ACK.'); assert(this.initSent, 'Unsolicited ACK.');
if (utils.equal(publicKey, constants.ZERO_KEY)) { if (utils.equal(publicKey, constants.ZERO_KEY)) {

View File

@ -552,43 +552,6 @@ TXResponse.prototype.toRaw = function toRaw(witness, writer) {
return p; 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 * Expose
*/ */
@ -596,4 +559,3 @@ SendCompact.prototype.toRaw = function toRaw(writer) {
exports.CompactBlock = CompactBlock; exports.CompactBlock = CompactBlock;
exports.TXRequest = TXRequest; exports.TXRequest = TXRequest;
exports.TXResponse = TXResponse; exports.TXResponse = TXResponse;
exports.SendCompact = SendCompact;

View File

@ -11,8 +11,6 @@ var bcoin = require('../env');
var utils = require('../utils/utils'); var utils = require('../utils/utils');
var crypto = require('../crypto/crypto'); var crypto = require('../crypto/crypto');
var assert = utils.assert; var assert = utils.assert;
var BufferWriter = require('../utils/writer');
var DUMMY = new Buffer(0);
/** /**
* Protocol packet framer * Protocol packet framer
@ -77,436 +75,6 @@ Framer.prototype.packet = function packet(cmd, payload, checksum) {
return packet; 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 * 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 crypto = require('../crypto/crypto');
var assert = utils.assert; var assert = utils.assert;
var constants = require('../protocol/constants'); var constants = require('../protocol/constants');
var BufferReader = require('../utils/reader');
var packets = require('./packets'); var packets = require('./packets');
/** /**
@ -40,7 +39,7 @@ function Parser(options) {
this.pending = []; this.pending = [];
this.total = 0; this.total = 0;
this.waiting = 24; this.waiting = 24;
this.packet = null; this.header = null;
this._init(); this._init();
} }
@ -60,13 +59,13 @@ Parser.prototype._init = function _init(str) {
return; return;
this.bip151.on('packet', function(cmd, body) { this.bip151.on('packet', function(cmd, body) {
var packet = new Packet(cmd, body.length); var payload;
try { try {
packet.payload = self.parsePayload(cmd, body); payload = self.parsePayload(cmd, body);
} catch (e) { } 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 * @param {String} str
*/ */
Parser.prototype._error = function _error(str) { Parser.prototype.error = function error(str) {
this.emit('error', new Error(str)); this.emit('error', new Error(str));
}; };
@ -120,42 +119,37 @@ Parser.prototype.feed = function feed(data) {
* @param {Buffer} chunk * @param {Buffer} chunk
*/ */
Parser.prototype.parse = function parse(chunk) { Parser.prototype.parse = function parse(data) {
var checksum; var payload, checksum;
if (chunk.length > constants.MAX_MESSAGE) { assert(data.length <= constants.MAX_MESSAGE);
this.waiting = 24;
this.packet = null;
return this._error('Packet too large: %dmb.', utils.mb(chunk.length));
}
if (!this.packet) { if (!this.header) {
this.packet = this.parseHeader(chunk); this.header = this.parseHeader(data);
this.waiting = this.header.size;
return; return;
} }
this.packet.payload = chunk; checksum = crypto.checksum(data).readUInt32LE(0, true);
checksum = crypto.checksum(this.packet.payload).readUInt32LE(0, true); if (checksum !== this.header.checksum) {
if (checksum !== this.packet.checksum) {
this.waiting = 24; this.waiting = 24;
this.packet = null; this.header = null;
return this._error('Invalid checksum'); return this.error('Invalid checksum');
} }
try { try {
this.packet.payload = this.parsePayload(this.packet.cmd, this.packet.payload); payload = this.parsePayload(this.header.cmd, data);
} catch (e) { } catch (e) {
this.emit('error', e); this.emit('error', e);
this.waiting = 24; this.waiting = 24;
this.packet = null; this.header = null;
return; return;
} }
this.emit('packet', this.packet); this.emit('packet', payload);
this.waiting = 24; 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) { Parser.prototype.parseHeader = function parseHeader(h) {
var i, magic, cmd, chk; var i, magic, cmd, size, checksum;
magic = h.readUInt32LE(0, true); magic = h.readUInt32LE(0, true);
if (magic !== this.network.magic) 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 // Count length of the cmd
for (i = 0; h[i + 4] !== 0 && i < 12; i++); for (i = 0; h[i + 4] !== 0 && i < 12; i++);
if (i === 12) if (i === 12)
return this._error('Not NULL-terminated cmd'); return this.error('Not NULL-terminated cmd');
cmd = h.toString('ascii', 4, 4 + i); 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; 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) { Parser.prototype.parsePayload = function parsePayload(cmd, data) {
switch (cmd) { return packets.fromRaw(cmd, data);
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;
}
}; };
/*
* 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 * Packet
* @constructor * @constructor
* @private * @private
*/ */
function Packet(cmd, size, checksum) { function Header(cmd, size, checksum) {
this.cmd = cmd; this.cmd = cmd;
this.size = size; this.size = size;
this.checksum = checksum; this.checksum = checksum;

View File

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

View File

@ -8,10 +8,7 @@
'use strict'; 'use strict';
var constants = require('../protocol/constants'); var constants = require('../protocol/constants');
var assert = require('assert'); var murmur3 = require('./murmur3');
var BufferReader = require('../utils/reader');
var BufferWriter = require('../utils/writer');
var murmur3 = require('../utils/murmur3');
var sum32 = murmur3.sum32; var sum32 = murmur3.sum32;
var mul32 = murmur3.mul32; var mul32 = murmur3.mul32;
@ -147,66 +144,6 @@ Bloom.prototype.added = function added(val, enc) {
return ret; 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. * Create a filter from a false positive rate.
* @param {Number} items - Expeected number of items. * @param {Number} items - Expeected number of items.
@ -415,11 +352,15 @@ RollingFilter.prototype.added = function added(val, enc) {
* Helpers * Helpers
*/ */
function U64(hi, lo) {
this.hi = hi;
this.lo = lo;
}
function read(data, off) { function read(data, off) {
return { var hi = data.readUInt32LE(off + 4, true);
hi: data.readUInt32LE(off + 4, true), var lo = data.readUInt32LE(off, true);
lo: data.readUInt32LE(off, true) return new U64(hi, lo);
};
} }
function write(data, value, off) { function write(data, value, off) {

View File

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

View File

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

View File

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