improve int functions and usage in parser and framer.

This commit is contained in:
Christopher Jeffrey 2016-01-12 12:16:39 -08:00
parent c94457cf1f
commit de455fa3e9
6 changed files with 477 additions and 202 deletions

View File

@ -8,6 +8,7 @@ var inherits = require('inherits');
var EventEmitter = require('events').EventEmitter;
var bcoin = require('../bcoin');
var bn = require('bn.js');
var utils = bcoin.utils;
var assert = utils.assert;
var constants = bcoin.protocol.constants;
@ -46,6 +47,9 @@ function Peer(pool, createSocket, options) {
this.host = null;
this.port = 0;
this.challenge = null;
this.lastPong = 0;
if (this.options.backoff) {
setTimeout(function() {
self.socket = createSocket(self, pool);
@ -135,10 +139,10 @@ Peer.prototype._init = function init() {
}
this._ping.timer = setInterval(function() {
self._write(self.framer.ping([
0xde, 0xad, 0xbe, 0xef,
0xde, 0xad, 0xbe, 0xef
]));
self.challenge = self._nonce();
self._write(self.framer.ping({
nonce: self.challenge
}));
}, this._ping.interval);
// Send hello
@ -441,12 +445,20 @@ Peer.prototype._handleAddr = function handleAddr(addrs) {
}, this);
};
Peer.prototype._handlePing = function handlePing() {
// No-op for now
Peer.prototype._handlePing = function handlePing(data) {
this._write(this.framer.pong({
nonce: data.nonce
}));
this.emit('ping', data);
};
Peer.prototype._handlePong = function handlePong() {
// No-op for now
Peer.prototype._handlePong = function handlePong(data) {
if (!this.challenge || this.challenge.cmp(data.nonce) !== 0)
return this.emit('pong', false);
this.lastPong = utils.now();
return this.emit('pong', true);
};
Peer.prototype._handleGetAddr = function handleGetAddr() {
@ -586,6 +598,14 @@ Peer.prototype.reject = function reject(details) {
this._write(this.framer.reject(details));
};
Peer.nonce = new bn(0xffffffff).ushln(32).uor(new bn(0xffffffff));
Peer.prototype._nonce = function _nonce() {
var nonce = Peer.nonce.clone();
nonce.imuln(Math.random());
return nonce;
};
/**
* Expose
*/

View File

@ -667,10 +667,15 @@ Pool.prototype._createPeer = function _createPeer(backoff) {
});
peer.on('reject', function(payload) {
payload.data = utils.toHex(payload.data);
self.emit('debug',
'Reject: msg=%s ccode=%s reason=%s data=%s',
payload.message, payload.ccode, payload.reason,
utils.toHex(payload.data));
payload.message,
payload.ccode,
payload.reason,
payload.data);
self.emit('reject', payload, peer);
});

View File

@ -158,12 +158,16 @@ Framer.prototype.notFound = function notFound(items) {
return this._inv('notfound', items);
};
Framer.prototype.ping = function ping(nonce) {
return this.packet('ping', nonce);
Framer.prototype.ping = function ping(data) {
var p = [];
utils.writeU64(p, data.nonce, 0);
return this.packet('ping', p);
};
Framer.prototype.pong = function pong(nonce) {
return this.packet('pong', nonce.slice(0, 8));
Framer.prototype.pong = function pong(data) {
var p = [];
utils.writeU64(p, data.nonce, 0);
return this.packet('pong', p);
};
Framer.prototype.filterLoad = function filterLoad(bloom, update) {

View File

@ -139,9 +139,33 @@ Parser.prototype.parsePayload = function parsePayload(cmd, p) {
if (cmd === 'addr')
return this.parseAddr(p);
if (cmd === 'ping')
return this.parsePing(p);
if (cmd === 'pong')
return this.parsePong(p);
return p;
};
Parser.prototype.parsePing = function parsePing(p) {
if (p.length < 8)
return this._error('pong packet is too small');
return {
nonce: readU64(p, 0)
};
};
Parser.prototype.parsePong = function parsePong(p) {
if (p.length < 8)
return this._error('ping packet is too small');
return {
nonce: readU64(p, 0)
};
};
Parser.prototype.parseVersion = function parseVersion(p) {
var v, services, ts, nonce, result, off, agent, height, relay;
@ -152,10 +176,10 @@ Parser.prototype.parseVersion = function parseVersion(p) {
services = readU64(p, 4);
// Timestamp
ts = readU64(p, 12);
ts = utils.read64(p, 12);
// Nonce, very dramatic
nonce = { lo: readU32(p, 72), hi: readU32(p, 76) };
nonce = readU64(p, 72);
// User agent length
result = utils.readIntv(p, 80);
@ -356,7 +380,7 @@ Parser.prototype.parseTXOut = function parseTXOut(p) {
return {
size: off + scriptLen,
value: new bn(utils.toArray(p.slice(0, 8)).reverse()),
value: utils.read64(p, 0),
script: bcoin.script.decode(utils.toArray(p.slice(off, off + scriptLen)))
};
};

View File

@ -1288,7 +1288,7 @@ TX.prototype.toRaw = function toRaw(enc) {
TX.fromRaw = function fromRaw(raw, enc) {
if (enc === 'hex')
raw = utils.toArray(raw, 'hex');
return new bcoin.protocol.parser().parseTX(raw);
return new bcoin.tx(new bcoin.protocol.parser().parseTX(raw));
};
/**

View File

@ -188,134 +188,6 @@ utils.dsha256 = function dsha256(data, enc) {
return utils.sha256(utils.sha256(data, enc));
};
utils.readU16 = function readU16(arr, off) {
if (!off)
off = 0;
return arr[off] | (arr[off + 1] << 8);
};
utils.readU32 = function readU32(arr, off) {
if (!off)
off = 0;
var r = arr[off]
| (arr[off + 1] << 8)
| (arr[off + 2] << 16)
| (arr[off + 3] << 24);
if (r < 0)
r += 0x100000000;
return r;
};
utils.readU64 = function readU64(arr, off) {
if (!off)
off = 0;
return utils.readU32(arr, off) + utils.readU32(arr, off + 4) * 0x100000000;
};
utils.writeU16 = function writeU16(dst, num, off) {
if (!off)
off = 0;
dst[off] = num & 0xff;
dst[off + 1] = (num >>> 8) & 0xff;
return 2;
};
utils.writeU32 = function writeU32(dst, num, off) {
if (!off)
off = 0;
dst[off] = num & 0xff;
dst[off + 1] = (num >>> 8) & 0xff;
dst[off + 2] = (num >>> 16) & 0xff;
dst[off + 3] = (num >>> 24) & 0xff;
return 4;
};
utils.writeU64 = function writeU64(dst, num, off) {
var i = 0;
if (!off)
off = 0;
num = new bn(num).maskn(64).toArray();
while (num.length < 8)
num.unshift(0);
num.reverse().forEach(function(ch) {
dst[off++] = ch;
});
i = num.length;
while (i--)
dst[off++] = num[i];
return 8;
};
utils.writeU16BE = function writeU16BE(dst, num, off) {
if (!off)
off = 0;
dst[off] = (num >>> 8) & 0xff;
dst[off + 1] = num & 0xff;
return 2;
};
utils.writeU32BE = function writeU32BE(dst, num, off) {
if (!off)
off = 0;
dst[off] = (num >>> 24) & 0xff;
dst[off + 1] = (num >>> 16) & 0xff;
dst[off + 2] = (num >>> 8) & 0xff;
dst[off + 3] = num & 0xff;
return 4;
};
utils.writeU64BE = function writeU64BE(dst, num, off) {
var i = 0;
if (!off)
off = 0;
num = new bn(num).maskn(64).toArray();
while (num.length < 8)
num.unshift(0);
for (; i < num.length; i++)
dst[off++] = num[i];
return 8;
};
utils.readU16BE = function readU16BE(arr, off) {
if (!off)
off = 0;
return (arr[off] << 8) | arr[off + 1];
};
utils.readU32BE = function readU32BE(arr, off) {
if (!off)
off = 0;
var r = (arr[off] << 24)
| (arr[off + 1] << 16)
| (arr[off + 2] << 8)
| arr[off + 3];
if (r < 0)
r += 0x100000000;
return r;
};
utils.readU64BE = function readU64BE(arr, off) {
if (!off)
off = 0;
return utils.readU32BE(arr, off) * 0x100000000 + utils.readU32BE(arr, off + 4);
};
utils.writeAscii = function writeAscii(dst, str, off) {
var i = 0;
var c;
@ -660,10 +532,10 @@ utils.isIP = function isIP(ip) {
if (typeof ip !== 'string')
return 0;
if (~ip.indexOf('.'))
if (ip.indexOf('.') !== -1)
return 4;
if (~ip.indexOf(':'))
if (ip.indexOf(':') !== -1)
return 6;
return 0;
@ -759,65 +631,12 @@ utils.sortKeys = function sortKeys(keys) {
});
};
utils.readIntv = function readIntv(p, off) {
var r, bytes;
if (!off)
off = 0;
if (p[off] < 0xfd) {
r = p[off];
bytes = 1;
} else if (p[off] === 0xfd) {
r = p[off + 1] | (p[off + 2] << 8);
bytes = 3;
} else if (p[off] === 0xfe) {
r = utils.readU32(p, off + 1);
bytes = 5;
} else {
r = 0;
bytes = 9;
}
return { off: off + bytes, r: r };
};
utils.writeIntv = function writeIntv(arr, value, off) {
if (!off)
off = 0;
if (value < 0xfd) {
arr[off] = value;
return 1;
}
if (value <= 0xffff) {
arr[off] = 0xfd;
arr[off + 1] = value & 0xff;
arr[off + 2] = value >>> 8;
return 3;
}
if (value <= 0xffffffff) {
arr[off] = 0xfe;
arr[off + 1] = value & 0xff;
arr[off + 2] = (value >>> 8) & 0xff;
arr[off + 3] = (value >>> 16) & 0xff;
arr[off + 4] = value >>> 24;
return 5;
}
arr[off] = 0xff;
utils.writeU64(arr, value, off + 1);
return 9;
};
utils.uniq = function(obj) {
var out = [];
var i = 0;
for (; i < obj.length; i++) {
if (!~out.indexOf(obj[i]))
if (out.indexOf(obj[i]) === -1)
out.push(obj[i]);
}
@ -917,3 +736,406 @@ utils.hash = function hash(obj, enc) {
throw new Error('Cannot get hash of object');
};
//
// Integer Functions
//
// Non-64-bit functions originally taken from the node.js tree:
//
// Copyright Joyent, Inc. and other Node contributors. All rights reserved.
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
utils.readU8 = function readU8(arr, off) {
off = off >>> 0;
return arr[off];
};
utils.readU16 = function readU16(arr, off) {
off = off >>> 0;
return arr[off] | (arr[off + 1] << 8);
};
utils.readU16BE = function readU16BE(arr, off) {
off = off >>> 0;
return (arr[off] << 8) | arr[off + 1];
};
utils.readU32 = function readU32(arr, off) {
off = off >>> 0;
return ((arr[off])
| (arr[off + 1] << 8)
| (arr[off + 2] << 16))
+ (arr[off + 3] * 0x1000000);
};
utils.readU32BE = function readU32BE(arr, off) {
off = off >>> 0;
return (arr[off] * 0x1000000)
+ ((arr[off + 1] << 16)
| (arr[off + 2] << 8)
| arr[off + 3]);
};
utils.readU64 = function readU64(arr, off) {
var num;
off = off >>> 0;
num = utils.toArray(arr.slice(off, off + 8)).reverse();
return new bn(num);
};
utils.readU64BE = function readU64BE(arr, off) {
var num;
off = off >>> 0;
num = utils.toArray(arr.slice(off, off + 8));
return new bn(num);
};
utils.read8 = function read8(arr, off) {
var num;
off = off >>> 0;
num = arr[off];
return !(num & 0x80) ? num : (0xff - num + 1) * -1;
};
utils.read16 = function read16(arr, off) {
var num;
off = off >>> 0;
num = arr[off] | (arr[off + 1] << 8);
return (num & 0x8000) ? num | 0xffff0000 : num;
};
utils.read16BE = function read16BE(arr, off) {
var num;
off = off >>> 0;
num = arr[off + 1] | (arr[off] << 8);
return (num & 0x8000) ? num | 0xffff0000 : num;
};
utils.read32 = function read32(arr, off) {
off = off >>> 0;
return (arr[off])
| (arr[off + 1] << 8)
| (arr[off + 2] << 16)
| (arr[off + 3] << 24);
};
utils.read32BE = function read32BE(arr, off) {
off = off >>> 0;
return (arr[off] << 24)
| (arr[off + 1] << 16)
| (arr[off + 2] << 8)
| (arr[off + 3]);
};
utils.read64 = function read64(arr, off) {
var num;
off = off >>> 0;
num = utils.toArray(arr.slice(off, off + 8)).reverse();
if (num[0] & 0x80) {
num[0] &= ~0x80;
num = new bn(num);
num = num.neg();
return num;
}
return new bn(num);
};
utils.read64BE = function read64BE(arr, off) {
var num;
off = off >>> 0;
num = utils.toArray(arr.slice(off, off + 8));
if (num[0] & 0x80) {
num[0] &= ~0x80;
num = new bn(num);
num = num.neg();
return num;
}
return new bn(num);
};
utils.writeU8 = function readU8(dst, num, off) {
num = +num;
off = off >>> 0;
dst[off] = num & 0xff;
return 1;
};
utils.writeU16 = function readU16(dst, num, off) {
num = +num;
off = off >>> 0;
dst[off] = num & 0xff;
dst[off + 1] = (num >>> 8) & 0xff;
return 2;
};
utils.writeU16BE = function read16BE(dst, num, off) {
num = +num;
off = off >>> 0;
dst[off] = (num >>> 8) & 0xff;
dst[off + 1] = num & 0xff;
return 2;
};
utils.writeU32 = function writeU32(dst, num, off) {
num = +num;
off = off >>> 0;
dst[off + 3] = (num >>> 24) & 0xff;
dst[off + 2] = (num >>> 16) & 0xff;
dst[off + 1] = (num >>> 8) & 0xff;
dst[off] = num & 0xff;
return 4;
};
utils.writeU32BE = function writeU32BE(dst, num, off) {
num = +num;
off = off >>> 0;
dst[off] = (num >>> 24) & 0xff;
dst[off + 1] = (num >>> 16) & 0xff;
dst[off + 2] = (num >>> 8) & 0xff;
dst[off + 3] = num & 0xff;
return 4;
};
utils.writeU64 = function writeU64(dst, num, off) {
var i;
if (!(num instanceof bn)) {
num = +num;
num = new bn(num);
}
off = off >>> 0;
num = num.maskn(64).toArray();
while (num.length < 8)
num.unshift(0);
for (i = num.length - 1; i >= 0; i--)
dst[off++] = num[i] & 0xff;
return 8;
};
utils.writeU64BE = function writeU64BE(dst, num, off) {
var i;
if (!(num instanceof bn)) {
num = +num;
bn = new bn(num);
}
off = off >>> 0;
num = num.maskn(64).toArray();
while (num.length < 8)
num.unshift(0);
for (i = 0; i < num.length; i++)
dst[off++] = num[i] & 0xff;
return 8;
};
utils.write8 = function write8(dst, num, off) {
num = +num;
off = off >>> 0;
dst[off] = num & 0xff;
return 1;
};
utils.write16 = function write16(dst, num, off) {
num = +num;
off = off >>> 0;
dst[off] = num & 0xff;
dst[off + 1] = (num >>> 8) & 0xff;
return 2;
};
utils.write16BE = function write16BE(dst, num, off) {
num = +num;
off = off >>> 0;
dst[off] = (num >>> 8) & 0xff;
dst[off + 1] = num & 0xff;
return 2;
};
utils.write32 = function write32(dst, num, off) {
num = +num;
off = off >>> 0;
dst[off] = num & 0xff;
dst[off + 1] = (num >>> 8) & 0xff;
dst[off + 2] = (num >>> 16) & 0xff;
dst[off + 3] = (num >>> 24) & 0xff;
return 4;
};
utils.write32BE = function write32BE(dst, num, off) {
num = +num;
off = off >>> 0;
dst[off] = (num >>> 24) & 0xff;
dst[off + 1] = (num >>> 16) & 0xff;
dst[off + 2] = (num >>> 8) & 0xff;
dst[off + 3] = num & 0xff;
return 4;
};
utils.write64 = function write64(dst, num, off) {
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);
}
}
off = off >>> 0;
num = num.maskn(64).toArray();
while (num.length < 8)
num.unshift(0);
if (num.isNeg())
num[0] |= 0x80;
for (i = num.length - 1; i >= 0; i--)
dst[off++] = num[i] & 0xff;
return 8;
};
utils.write64BE = function write64BE(dst, num, off) {
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);
}
}
off = off >>> 0;
num = num.maskn(64).toArray();
while (num.length < 8)
num.unshift(0);
if (num.isNeg())
num[0] |= 0x80;
for (i = 0; i < num.length; i++)
dst[off++] = num[i] & 0xff;
return 8;
};
utils.readIntv = function readIntv(arr, off) {
var r, bytes;
off = off >>> 0;
if (arr[off] < 0xfd) {
r = arr[off];
bytes = 1;
} else if (arr[off] === 0xfd) {
r = arr[off + 1] | (arr[off + 2] << 8);
bytes = 3;
} else if (arr[off] === 0xfe) {
r = utils.readU32(arr, off + 1);
bytes = 5;
} else if (arr[off] === 0xff) {
try {
r = utils.readU64(arr, off + 1).toNumber();
} catch (e) {
r = 0;
}
bytes = 9;
} else {
// Malformed
r = arr[off];
bytes = 1;
}
return { off: off + bytes, r: r };
};
utils.writeIntv = function writeIntv(dst, num, off) {
off = off >>> 0;
if (num instanceof bn) {
if (num.cmpn(0xffffffff) > 0) {
dst[off] = 0xff;
utils.writeU64(dst, num, off + 1);
return 9;
}
num = num.toNumber();
}
num = +num;
if (num < 0xfd) {
dst[off] = num & 0xff;
return 1;
}
if (num <= 0xffff) {
dst[off] = 0xfd;
dst[off + 1] = num & 0xff;
dst[off + 2] = (num >>> 8) & 0xff;
return 3;
}
if (num <= 0xffffffff) {
dst[off] = 0xfe;
dst[off + 1] = num & 0xff;
dst[off + 2] = (num >>> 8) & 0xff;
dst[off + 3] = (num >>> 16) & 0xff;
dst[off + 4] = (num >>> 24) & 0xff;
return 5;
}
dst[off] = 0xff;
utils.writeU64(dst, num, off + 1);
return 9;
};