From 4f8d24ba36331264c9b732c701774dec1d1c46ec Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Wed, 13 Jan 2016 16:01:15 -0800 Subject: [PATCH] more int and packet work. --- lib/bcoin/block.js | 7 + lib/bcoin/output.js | 8 + lib/bcoin/peer.js | 48 +++--- lib/bcoin/pool.js | 86 +++++++---- lib/bcoin/protocol/framer.js | 85 ++++------ lib/bcoin/protocol/parser.js | 27 +--- lib/bcoin/utils.js | 290 +++++++++++++++++++++-------------- package.json | 6 +- test/protocol-test.js | 6 +- test/wallet-test.js | 5 +- 10 files changed, 328 insertions(+), 240 deletions(-) diff --git a/lib/bcoin/block.js b/lib/bcoin/block.js index ee7ddbc6..07316bb1 100644 --- a/lib/bcoin/block.js +++ b/lib/bcoin/block.js @@ -47,6 +47,13 @@ function Block(data, subtype) { this.valid = null; this._hash = null; + // https://gist.github.com/sipa/bf69659f43e763540550 + // http://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-August/010396.html + this.versionBits = (this.version >>> 29) & 7; + this.realVersion = this.version & 0x1fffffff; + this.highVersion = this.version & 0x1ffffff8; + this.lowVersion = this.version & 7; + // List of matched TXs this.tx = []; diff --git a/lib/bcoin/output.js b/lib/bcoin/output.js index c99c6d31..98539ec2 100644 --- a/lib/bcoin/output.js +++ b/lib/bcoin/output.js @@ -7,6 +7,7 @@ var bn = require('bn.js'); var bcoin = require('../bcoin'); var utils = bcoin.utils; +var assert = utils.assert; /** * Output @@ -30,6 +31,13 @@ function Output(options) { this.value = utils.satoshi(value || new bn(0)); this.script = options.script ? options.script.slice() : []; + // For safety: do not allow usage of + // Numbers, do not allow negative values. + assert(typeof value !== 'number'); + assert(!this.value.isNeg()) + assert(this.value.bitLength() <= 63); + assert(!(this.value.toArray('be', 8)[0] & 0x80)); + if (options.script && options.script._raw) utils.hidden(this.script, '_raw', options.script._raw); } diff --git a/lib/bcoin/peer.js b/lib/bcoin/peer.js index 35576fbf..e8f153a7 100644 --- a/lib/bcoin/peer.js +++ b/lib/bcoin/peer.js @@ -160,6 +160,7 @@ Peer.prototype._init = function init() { self.ack = true; self.emit('ack'); self.ts = utils.now(); + self._write(self.framer.packet('getaddr', [])); }); }; @@ -423,26 +424,45 @@ Peer.prototype._handleGetData = function handleGetData(items) { Peer.prototype._handleAddr = function handleAddr(addrs) { var now = utils.now(); + addrs.forEach(function(addr) { + var ip, address4, address6; + if (addr.ts <= 100000000 || addr.ts > now + 10 * 60) addr.ts = now - 5 * 24 * 60 * 60; + ip = addr.ipv4 !== '0.0.0.0' + ? addr.ipv4 + : addr.ipv6; + + address4 = addr.ipv4 !== '0.0.0.0' + ? addr.ipv4 + ':' + addr.port + : null; + + address6 = '[' + addr.ipv6 + ']:' + addr.port; + this.emit('addr', { date: new Date(addr.ts * 1000), ts: addr.ts, services: addr.services, + ip: ip, ipv4: addr.ipv4, ipv6: addr.ipv6, - host: addr.ipv4, + host: ip, + host4: addr.ipv4, host6: addr.ipv6, - port: addr.port, - addr: addr.ipv4 + ':' + addr.port, - addr6: '[' + addr.ipv6 + ']:' + addr.port, - // Deprecated: - address: addr.ipv4, - address6: addr.ipv6 + port: addr.port || network.port, + address: address4 || address6, + address4: address4, + address6: address6 }); }, this); + + this.pool.emit('debug', + 'Recieved %d peers (seeds=%d, peers=%d).', + addrs.length, + this.pool.seeds.length, + this.pool.peers.all.length); }; Peer.prototype._handlePing = function handlePing(data) { @@ -466,7 +486,7 @@ Peer.prototype._handleGetAddr = function handleGetAddr() { var peers; peers = this.pool.peers.all.map(function(peer) { - var ip, version, ipv4, ipv6; + var ip, version; if (!peer.socket || !peer.socket.remoteAddress) return; @@ -482,19 +502,11 @@ Peer.prototype._handleGetAddr = function handleGetAddr() { hosts[ip] = true; - if (version === 4) { - ipv4 = utils.ip2array(ip, 4); - ipv6 = utils.ip2array(ipv4, 6); - } else if (version === 6) { - ipv6 = utils.ip2array(ip, 6); - ipv4 = utils.ip2array(ipv6, 4); - } - return { ts: peer.ts, services: peer.version ? peer.version.services : null, - ipv4: ipv4, - ipv6: ipv6, + ipv4: version === 4 ? ip : null, + ipv6: version === 6 ? ip : null, port: peer.socket.remotePort || network.port }; }).filter(Boolean); diff --git a/lib/bcoin/pool.js b/lib/bcoin/pool.js index 547948ec..dea50f57 100644 --- a/lib/bcoin/pool.js +++ b/lib/bcoin/pool.js @@ -37,15 +37,15 @@ function Pool(options) { this.options.relay = this.options.relay == null ? (this.options.fullNode ? true : false) : this.options.relay; + this.options.seeds = options.seeds || network.seeds; + + this.setSeeds(this.options.seeds); this.storage = this.options.storage; this.destroyed = false; this.size = options.size || 32; this.parallel = options.parallel || 2000; this.redundancy = options.redundancy || 1; - this.seeds = options.seeds - ? options.seeds.slice() - : network.seeds.slice(); this._createConnection = options.createConnection; this._createSocket = options.createSocket; @@ -251,29 +251,25 @@ Pool.prototype._stopInterval = function _stopInterval() { }; Pool.prototype.createConnection = function createConnection(peer, pool) { - var addr, parts, host, net, socket, port; + var addr, net, socket; if (pool._createConnection) return pool._createConnection(peer, pool); addr = pool.usableSeed(true); - parts = addr.split(':'); - host = parts[0]; - port = +parts[1] || network.port; - - peer.host = host; - peer.port = port; + peer.host = addr.host; + peer.port = addr.port; if (this._createSocket) { - socket = this._createSocket(port, host); + socket = this._createSocket(addr.port, addr.host); } else { net = require('net'); - socket = net.connect(port, host); + socket = net.connect(addr.port, addr.host); } socket.on('connect', function() { - pool.emit('debug', 'Connected to %s:%d', host, port); + pool.emit('debug', 'Connected to %s:%d', addr.host, addr.port); }); return socket; @@ -667,7 +663,7 @@ Pool.prototype._createPeer = function _createPeer(backoff) { }); peer.on('reject', function(payload) { - payload.data = utils.toHex(payload.data); + payload.data = utils.revHex(utils.toHex(payload.data)); self.emit('debug', 'Reject: msg=%s ccode=%s reason=%s data=%s', @@ -695,18 +691,13 @@ Pool.prototype._createPeer = function _createPeer(backoff) { self.emit('watched', tx, peer); }); - peer.on('addr', function(addr) { - var host = addr.ipv4 + ':' + addr.port; + peer.on('addr', function(data) { + if (self.seeds.length > 1000) + self.setSeeds(self.options.seeds.concat(self.seeds.slice(-500))); - if (self.seeds.length > self.size * 2) - self.seeds = network.seeds.slice(); + self.addSeed(data); - if (self.seeds.indexOf(host) !== -1) { - self.emit('debug', 'Found new peer: %s', host); - self.seeds.push(host); - } - - self.emit('addr', addr, peer); + self.emit('addr', data, peer); }); peer.on('txs', function(txs) { @@ -1444,18 +1435,16 @@ Pool.prototype.destroy = function destroy() { }; Pool.prototype.getPeer = function getPeer(addr) { - var parts, host, port, i, peer; + var i, peer; if (!addr) return; - parts = addr.split(':'); - host = parts[0]; - port = +parts[1] || network.port; + addr = utils.parseHost(addr); for (i = 0; i < this.peers.all.length; i++) { peer = this.peers.all[i]; - if (peer.host === host) + if (peer.host === addr.host) return peer; } }; @@ -1471,6 +1460,8 @@ Pool.prototype.usableSeed = function usableSeed(addrs, force) { if (!addrs) addrs = this.seeds; + assert(addrs.length); + addrs = addrs.slice().sort(function() { return Math.random() > 0.50 ? 1 : -1; }); @@ -1495,6 +1486,43 @@ Pool.prototype.usableSeed = function usableSeed(addrs, force) { return addr; }; +Pool.prototype.setSeeds = function setSeeds(seeds) { + this.seeds = []; + this.hosts = {}; + seeds.forEach(function(seed) { + this.addSeed(seed); + }, this); +}; + +Pool.prototype.addSeed = function addSeed(seed) { + seed = utils.parseHost(seed); + + if (this.hosts[seed.host] != null) + return false; + + this.seeds.push({ + host: seed.host, + port: seed.port + }); + + this.hosts[seed.host] = this.seeds.length - 1; + + return true; +}; + +Pool.prototype.removeSeed = function removeSeed(seed) { + seed = utils.parseHost(seed); + + if (this.hosts[seed.host] == null) + return false; + + this.seeds.splice(this.hosts[seed.host], 1); + + delete this.hosts[seed.host]; + + return true; +}; + Pool.prototype.toJSON = function toJSON() { return { v: 1, diff --git a/lib/bcoin/protocol/framer.js b/lib/bcoin/protocol/framer.js index 3a3e37de..c410c78a 100644 --- a/lib/bcoin/protocol/framer.js +++ b/lib/bcoin/protocol/framer.js @@ -73,9 +73,6 @@ Framer.prototype._addr = function addr(p, off, data, full) { if (!data.ipv4) data.ipv4 = []; - if (!data.ipv6) - data.ipv6 = []; - if (!data.port) data.port = network.port; @@ -86,19 +83,19 @@ Framer.prototype._addr = function addr(p, off, data, full) { // NODE_NETWORK services off += utils.writeU64(p, data.services, off); - // Empty bytes after services - // (services takes the place of ts) - if (!full) - off += utils.writeU32(p, 0, off); - // ipv6 - off += utils.writeU32BE(p, utils.readU32BE(data.ipv6, 0), off); - off += utils.writeU32BE(p, utils.readU32BE(data.ipv6, 4), off); - off += utils.writeU32BE(p, utils.readU32BE(data.ipv6, 8), off); - - // ipv4 - if (full) + if (data.ipv6) { + data.ipv6 = utils.ip2array(data.ipv6, 6); + off += utils.writeU64BE(p, utils.readU64BE(data.ipv6, 0), off); + off += utils.writeU64BE(p, utils.readU64BE(data.ipv6, 8), off); + } else { + data.ipv4 = utils.ip2array(data.ipv4, 4); + // We don't have an ipv6, convert ipv4 to ipv4-mapped ipv6 address + off += utils.writeU32BE(p, 0x00000000, off); + off += utils.writeU32BE(p, 0x00000000, off); + off += utils.writeU32BE(p, 0x0000ffff, off); off += utils.writeU32BE(p, utils.readU32BE(data.ipv4, 0), off); + } // port off += utils.writeU16BE(p, data.port, off); @@ -280,7 +277,7 @@ Framer.tx = function tx(tx) { var p = []; var off, i, input, s, output, value, j; - off = writeU32(p, tx.version, 0); + off = utils.write32(p, tx.version, 0); off += utils.writeIntv(p, tx.inputs.length, off); for (i = 0; i < tx.inputs.length; i++) { @@ -300,14 +297,8 @@ Framer.tx = function tx(tx) { for (i = 0; i < tx.outputs.length; i++) { output = tx.outputs[i]; - // off += utils.write64(p, output.value, off); - - // Put LE value - value = output.value.toArray().slice().reverse(); - assert(value.length <= 8); - off += utils.copy(value, p, off, true); - for (j = value.length; j < 8; j++, off++) - p[off] = 0; + off += utils.write64(p, output.value, off); + assert(output.value.byteLength() <= 8); s = bcoin.script.encode(output.script); off += utils.writeIntv(p, s.length, off); @@ -325,22 +316,19 @@ Framer.prototype.tx = function tx(tx) { Framer.block = function _block(block, type) { var p = []; var off = 0; + var i; if (!type) type = block.subtype; // version - off += writeU32(p, block.version, off); + off += utils.write32(p, block.version, off); // prev_block - utils.toArray(block.prevBlock, 'hex').forEach(function(ch) { - p[off++] = ch; - }); + off += utils.copy(utils.toArray(block.prevBlock, 'hex'), p, off, true); // merkle_root - utils.toArray(block.merkleRoot, 'hex').forEach(function(ch) { - p[off++] = ch; - }); + off += utils.copy(utils.toArray(block.merkleRoot, 'hex'), p, off, true); // timestamp off += writeU32(p, block.ts, off); @@ -359,27 +347,19 @@ Framer.block = function _block(block, type) { // hash count off += utils.writeIntv(p, block.hashes.length, off); // hashes - block.hashes.forEach(function(hash) { - utils.toArray(hash, 'hex').forEach(function(ch) { - p[off++] = ch; - }); - }); + for (i = 0; i < block.hashes.length; i++) + off += utils.copy(utils.toArray(block.hashes[i], 'hex'), p, off, true); // flag count off += utils.writeIntv(p, block.flags.length, off); // flags - block.flags.forEach(function(flag) { - p[off++] = flag; - }); - } else if (type === 'block') { + for (i = 0; i < block.flags.length; i++) + p[off++] = block.flags[i]; + } else { // txn_count - off += utils.writeIntv(p, block.totalTX, off); + off += utils.writeIntv(p, block.txs.length, off); // txs - block.txs.forEach(function(tx) { - var raw = tx._raw || tx.render(); - raw.forEach(function(ch) { - p[off++] = ch; - }); - }); + for (i = 0; i < block.txs.length; i++) + off += utils.copy(block.txs[i].render(), p, off, true); } return p; @@ -390,8 +370,6 @@ Framer.prototype.block = function _block(block) { }; Framer.prototype.merkleBlock = function merkleBlock(block) { - // XXX Technically we're also supposed to send `tx` packets accompanying the - // merkleblock here if we have them, as per the offical bitcoin client. return this.packet('merkleblock', Framer.block(block, 'merkleblock')); }; @@ -405,18 +383,15 @@ Framer.prototype.reject = function reject(details) { var data = details.data || []; off += utils.writeIntv(p, message.length, off); - utils.writeAscii(p, message, off); - off += message.length; + off += utils.writeAscii(p, message, off); p[off] = ccode; off++; off += utils.writeIntv(p, reason.length, off); - utils.writeAscii(p, reason, off); - off += reason.length; + off += utils.writeAscii(p, reason, off); - utils.copy(data, p, off, true); - off += data.length; + off += utils.copy(data, p, off, true); return this.packet('reject', p); }; @@ -433,7 +408,7 @@ Framer.prototype.addr = function addr(peers) { off += this._addr(p, off, { ts: peer.ts, - services: 1, + services: peer.services, ipv6: peer.ipv6, ipv4: peer.ipv4, port: peer.port diff --git a/lib/bcoin/protocol/parser.js b/lib/bcoin/protocol/parser.js index bf89fd05..461a635d 100644 --- a/lib/bcoin/protocol/parser.js +++ b/lib/bcoin/protocol/parser.js @@ -275,7 +275,7 @@ Parser.prototype.parseMerkleBlock = function parseMerkleBlock(p) { flags = utils.toArray(p.slice(off, off + flagCount)); return { - version: readU32(p, 0), + version: utils.read32(p, 0), prevBlock: utils.toArray(p.slice(4, 36)), merkleRoot: utils.toArray(p.slice(36, 68)), ts: readU32(p, 68), @@ -348,7 +348,7 @@ Parser.prototype.parseBlock = function parseBlock(p) { } return { - version: readU32(p, 0), + version: utils.read32(p, 0), prevBlock: utils.toArray(p.slice(4, 36)), merkleRoot: utils.toArray(p.slice(36, 68)), ts: readU32(p, 68), @@ -461,7 +461,7 @@ Parser.prototype.parseTX = function parseTX(p) { return { _raw: p.slice(0, off + 4), - version: readU32(p, 0), + version: utils.read32(p, 0), inputs: txIn, outputs: txOut, lock: readU32(p, off), @@ -511,7 +511,7 @@ Parser.prototype.parseReject = function parseReject(p) { }; Parser.prototype._parseAddr = function _parseAddr(p, off, full) { - var ts, services, ip, ipv6, ipv4, port; + var ts, services, ip, port; if (!off) off = 0; @@ -528,20 +528,9 @@ Parser.prototype._parseAddr = function _parseAddr(p, off, full) { services = utils.readU64(p, off); off += 8; - // Empty bytes after services - // (services takes the place of ts) - if (!full) - off += 4; - // ipv6 - BE - ipv6 = utils.toArray(p.slice(off, off + 12)); - off += 12; - - // ipv4 - BE - if (full) { - ipv4 = utils.toArray(p.slice(off, off + 4)); - off += 4; - } + ip = utils.toArray(p.slice(off, off + 16)); + off += 16; // port - BE port = utils.readU16BE(p, off); @@ -556,8 +545,8 @@ Parser.prototype._parseAddr = function _parseAddr(p, off, full) { return { ts: ts, services: services, - ipv6: utils.array2ip(ipv6, 6), - ipv4: utils.array2ip(ipv4 || ipv6, 4), + ipv6: utils.array2ip(ip, 6), + ipv4: utils.array2ip(ip, 4), port: port }; }; diff --git a/lib/bcoin/utils.js b/lib/bcoin/utils.js index f1536a5d..7b199d48 100644 --- a/lib/bcoin/utils.js +++ b/lib/bcoin/utils.js @@ -6,6 +6,7 @@ var utils = exports; +var bcoin = require('../bcoin'); var bn = require('bn.js'); var hash = require('hash.js'); var util = require('util'); @@ -528,6 +529,25 @@ utils.toFloat = function toFloat(val) { throw new Error('Could not convert ' + val + ' to float'); }; +utils.parseHost = function parseHost(addr) { + var parts; + + utils.assert(addr); + + if (typeof addr === 'object') + return addr; + + if (addr.indexOf(']') !== -1) + parts = addr.split(/\]:?/); + else + parts = addr.split(':'); + + return { + host: parts[0].replace(/[\[\]]/g, ''), + port: +parts[1] || bcoin.protocol.network.port + }; +}; + utils.isIP = function isIP(ip) { if (typeof ip !== 'string') return 0; @@ -541,67 +561,89 @@ utils.isIP = function isIP(ip) { return 0; }; -utils.ip2array = function ip2array(ip, version) { - if (Array.isArray(ip)) { - ip = ip.slice(); +utils.ip2version = function ip2version(ip, version) { + utils.assert(Array.isArray(ip)); + utils.assert(version === 4 || version === 6); - utils.assert(version === 4 || version === 6); - - if (version === 4) { - ip = ip.slice(-4); - - while (ip.length < 4) - ip.unshift(0); - - return ip; - } - - if (version === 6) { - while (ip.length < 4) - ip.unshift(0); - - while (ip.length < 6) - ip.unshift(0xff); - - while (ip.length < 16) - ip.unshift(0); - - return ip; - } - - return; - } - - version = utils.isIP(ip); - - if (!version) - return ip; + ip = ip.slice(); if (version === 4) { + // Check to see if this an + // ipv4-mapped ipv6 address. + if (ip.length > 4) { + while (ip[0] === 0) + ip.shift(); + + // Found an ipv4 address + if (ip.length === 6 && ip[0] === 0xff && ip[1] === 0xff) + return ip.slice(-4); + + // No ipv4 address + return [0, 0, 0, 0]; + } + + // Pad to 4 bytes + while (ip.length < 4) + ip.unshift(0); + + return ip; + } + + if (version === 6) { + // Pad to 4 bytes + while (ip.length < 4) + ip.unshift(0); + + // Try to convert ipv4 address to + // ipv4-mapped ipv6 address. + if (ip.length === 4) { + while (ip.length < 6) + ip.unshift(0xff); + } + + // Pad to 16 bytes + while (ip.length < 16) + ip.unshift(0); + + return ip; + } +}; + +utils.ip2array = function ip2array(ip, version) { + var type = utils.isIP(ip); + + utils.assert(version === 4 || version === 6); + + if (type === 0) { + if (!Array.isArray(ip)) + ip = [0, 0, 0, 0]; + } else if (type === 4) { ip = ip.split('.').map(function(n) { return +n; }); utils.assert(ip.length <= 4); - return utils.ip2array(ip, 4); - } - - if (version === 6) { + } else if (type === 6) { ip = utils.toArray(ip.replace(/:/g, ''), 'hex'); utils.assert(ip.length <= 16); - return utils.ip2array(ip, 6); } + + return utils.ip2version(ip, version); }; utils.array2ip = function array2ip(ip, version) { var out, i, hi, lo; - if (!Array.isArray(ip)) - return ip; + if (!Array.isArray(ip)) { + if (utils.isIP(ip)) + ip = utils.ip2array(ip, version); + else + ip = [0, 0, 0, 0]; + } utils.assert(version === 4 || version === 6); utils.assert(ip.length <= 16); - ip = utils.ip2array(ip, version); + ip = utils.ip2version(ip, version); if (version === 4) return ip.join('.'); @@ -819,7 +861,7 @@ utils.hash = function hash(obj, enc) { throw new Error('Cannot get hash of object'); }; -utils.U64 = new bn(0xffffffff).ushln(32).uor(new bn(0xffffffff)); +utils.U64 = new bn('ffffffffffffffff', 'hex'); utils.nonce = function nonce() { var nonce = utils.U64.clone(); @@ -852,6 +894,21 @@ utils.nonce = function nonce() { // IN THE SOFTWARE. // +utils.isNegZero = function isNegZero(bytes, order) { + var s = 0; + + if (order === 'le') + s = bytes.length - 1; + + if (bytes[s] & 0x80) { + bytes = bytes.slice(); + bytes[s] &= ~0x80; + return new bn(bytes, order).cmpn(0) === 0; + } + + return false; +}; + utils.readU8 = function readU8(arr, off) { off = off >>> 0; return arr[off]; @@ -888,15 +945,15 @@ utils.readU32BE = function readU32BE(arr, off) { utils.readU64 = function readU64(arr, off) { var num; off = off >>> 0; - num = utils.toArray(arr.slice(off, off + 8)).reverse(); - return new bn(num); + num = utils.toArray(arr.slice(off, off + 8)); + return new bn(num, 'le'); }; utils.readU64BE = function readU64BE(arr, off) { var num; off = off >>> 0; num = utils.toArray(arr.slice(off, off + 8)); - return new bn(num); + return new bn(num, 'be'); }; utils.read8 = function read8(arr, off) { @@ -943,16 +1000,18 @@ utils.read64 = function read64(arr, off) { off = off >>> 0; - num = utils.toArray(arr.slice(off, off + 8)).reverse(); + num = utils.toArray(arr.slice(off, off + 8)); - if (num[0] & 0x80) { - num[0] &= ~0x80; - num = new bn(num); - num = num.neg(); - return num; + // If we are signed, do (~num + 1) to get + // the positive counterpart and set bn's + // negative flag. + if (num[num.length - 1] & 0x80) { + if (utils.isNegZero(num, 'le')) + return new bn(0); + return new bn(num, 'le').notn(64).addn(1).neg(); } - return new bn(num); + return new bn(num, 'le'); }; utils.read64BE = function read64BE(arr, off) { @@ -962,11 +1021,13 @@ utils.read64BE = function read64BE(arr, off) { num = utils.toArray(arr.slice(off, off + 8)); + // If we are signed, do (~num + 1) to get + // the positive counterpart and set bn's + // negative flag. if (num[0] & 0x80) { - num[0] &= ~0x80; - num = new bn(num); - num = num.neg(); - return num; + if (utils.isNegZero(num, 'be')) + return new bn(0); + return new bn(num, 'be').notn(64).addn(1).neg(); } return new bn(num); @@ -1018,38 +1079,48 @@ utils.writeU32BE = function writeU32BE(dst, num, off) { utils.writeU64 = function writeU64(dst, num, off) { var i; - if (!(num instanceof bn)) { - num = +num; - num = new bn(num); - } + if (!(num instanceof bn)) + num = new bn(+num); off = off >>> 0; - num = num.toArray().slice(-8); + // We shouldn't think of + // this as negative. + if (num.isNeg()) + num = num.neg(); - for (i = num.length - 1; i >= 0; i--) + if (num.bitLength() > 64) + num = num.uand(utils.U64); + + num = num.toArray('le', 8); + + utils.assert.equal(num.length, 8); + + for (i = 0; i < num.length; i++) dst[off++] = num[i] & 0xff; - for (i = num.length; i < 8; i++) - dst[off++] = 0; - return 8; }; utils.writeU64BE = function writeU64BE(dst, num, off) { var i; - if (!(num instanceof bn)) { - num = +num; - num = new bn(num); - } + if (!(num instanceof bn)) + num = new bn(+num); off = off >>> 0; - num = num.toArray().slice(-8); + // We shouldn't think of + // this as negative. + if (num.isNeg()) + num = num.neg(); - for (i = num.length; i < 8; i++) - dst[off++] = 0; + if (num.bitLength() > 64) + num = num.uand(utils.U64); + + num = num.toArray('be', 8); + + utils.assert.equal(num.length, 8); for (i = 0; i < num.length; i++) dst[off++] = num[i] & 0xff; @@ -1101,64 +1172,61 @@ utils.write32BE = function write32BE(dst, num, off) { }; utils.write64 = function write64(dst, num, off) { - var i, bytes; + var i; - if (!(num instanceof bn)) { - num = +num; - if (num < 0) { - num &= ~0x80000000; - num = new bn(num); - num = num.neg(); - } else { - num = new bn(num); - } - } + if (!(num instanceof bn)) + num = new bn(+num); off = off >>> 0; - bytes = num.toArray().slice(-8); + // Convert the number to the + // negative byte representation. + if (num.isNeg()) { + if (num.cmpn(0) === 0) + num = new bn(0); + else + num = num.neg().notn(64).addn(1); + } - if (num.isNeg()) - bytes[0] |= 0x80; + if (num.bitLength() > 64) + num = num.uand(utils.U64); - for (i = bytes.length - 1; i >= 0; i--) - dst[off++] = bytes[i] & 0xff; + num = num.toArray('le', 8); - for (i = bytes.length; i < 8; i++) - dst[off++] = 0; + utils.assert.equal(num.length, 8); - if (num.isNeg()) - dst[off - 1] |= 0x80; + for (i = 0; i < num.length; i++) + dst[off++] = num[i] & 0xff; return 8; }; utils.write64BE = function write64BE(dst, num, off) { - var i, bytes; + var i; - if (!(num instanceof bn)) { - num = +num; - if (num < 0) { - num &= ~0x80000000; - num = new bn(num); - num = num.neg(); - } else { - num = new bn(num); - } - } + if (!(num instanceof bn)) + num = new bn(+num); off = off >>> 0; - bytes = num.toArray().slice(-8); + // Convert the number to the + // negative byte representation. + if (num.isNeg()) { + if (num.cmpn(0) === 0) + num = new bn(0); + else + num = num.neg().notn(64).addn(1); + } - for (i = bytes.length; i < 8; i++) - dst[off++] = 0; + if (num.bitLength() > 64) + num = num.uand(utils.U64); - for (i = 0; i < bytes.length; i++) - dst[off++] = bytes[i] & 0xff; + num = num.toArray('be', 8); - if (num.isNeg()) - dst[off - 8] |= 0x80; + utils.assert.equal(num.length, 8); + + for (i = 0; i < num.length; i++) + dst[off++] = num[i] & 0xff; return 8; }; diff --git a/package.json b/package.json index 4e256420..2d270196 100644 --- a/package.json +++ b/package.json @@ -22,9 +22,9 @@ "homepage": "https://github.com/indutny/bcoin", "dependencies": { "async": "^0.8.0", - "bn.js": "^4.5.0", - "elliptic": "^6.0.2", - "hash.js": "^1.0.3", + "bn.js": "4.6.3", + "elliptic": "6.0.2", + "hash.js": "1.0.3", "inherits": "^2.0.1" }, "devDependencies": { diff --git a/test/protocol-test.js b/test/protocol-test.js index add994d5..0c8e41fc 100644 --- a/test/protocol-test.js +++ b/test/protocol-test.js @@ -45,13 +45,13 @@ describe('Protocol', function() { var peers = [ { ipv6: '0000:0000:0000:0000:0000:ffff:0000:0000', - ipv4: '127.0.0.1', + ipv4: '0.0.0.0', port: 8333, ts: Date.now() / 1000 | 0 }, { ipv6: '0000:0000:0000:0000:0000:ffff:7f00:0001', - ipv4: '10.0.0.1', + ipv4: '127.0.0.1', port: 18333, ts: Date.now() / 1000 | 0 } @@ -78,7 +78,7 @@ describe('Protocol', function() { assert.equal(payload[0].port, peers[0].port); assert.equal(typeof payload[1].ts, 'number'); - assert.equal(payload[1].service, 1); + assert.equal(payload[1].services, 1); assert.equal(payload[1].ipv6, peers[1]._ipv6); assert.equal(payload[1].ipv4, peers[1]._ipv4); assert.equal(payload[1].port, peers[1].port); diff --git a/test/wallet-test.js b/test/wallet-test.js index 07543c52..eecaf26c 100644 --- a/test/wallet-test.js +++ b/test/wallet-test.js @@ -1,6 +1,7 @@ var assert = require('assert'); var bn = require('bn.js'); var bcoin = require('../'); +var constants = bcoin.protocol.constants; function printScript(input) { var scripts = []; @@ -219,7 +220,7 @@ describe('Wallet', function() { tx.out(to, 5460); var cost = tx.funds('out'); - var total = cost.add(new bn(bcoin.tx.fee)); + var total = cost.add(new bn(constants.tx.fee)); var unspent1 = w1.unspent(); var unspent2 = w2.unspent(); @@ -233,7 +234,7 @@ describe('Wallet', function() { tx.input(unspent2[0]); var left = tx.funds('in').sub(total); - if (left.cmpn(bcoin.tx.dust) < 0) { + if (left.cmpn(constants.tx.dust) < 0) { tx.outputs[tx.outputs.length - 2].value.iadd(left); left = new bn(0); }