From 7f0ea92a43f715c0fd12dfc05b39f4e9e2f26ccd Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Tue, 6 May 2014 00:55:24 +0400 Subject: [PATCH] peer: improvements --- lib/bcoin/peer.js | 23 ++++++++++++-- lib/bcoin/pool.js | 2 +- lib/bcoin/script.js | 75 ++++++++++++++++++++++++++++++++++++++++++--- lib/bcoin/wallet.js | 27 +++++++++------- test/script-test.js | 8 +++++ 5 files changed, 115 insertions(+), 20 deletions(-) diff --git a/lib/bcoin/peer.js b/lib/bcoin/peer.js index bc1d5796..cef862fa 100644 --- a/lib/bcoin/peer.js +++ b/lib/bcoin/peer.js @@ -30,7 +30,8 @@ function Peer(pool, socket, options) { this.options = options || {}; this._broadcast = { - timout: this.options.broadcastTimeout || 30000, + timeout: this.options.broadcastTimeout || 30000, + interval: this.options.broadcastInterval || 3000, map: {} }; @@ -96,8 +97,15 @@ Peer.prototype.broadcast = function broadcast(items) { var result = items.map(function(item) { var key = item.hash('hex'); var old = this._broadcast.map[key]; - if (old) + if (old) { clearTimeout(old.timer); + clearInterval(old.interval); + } + + var inv = this.framer.inv([{ + type: item.type, + hash: item.hash() + }]) // Auto-cleanup broadcast map after timeout var entry = { @@ -105,7 +113,13 @@ Peer.prototype.broadcast = function broadcast(items) { timeout: setTimeout(function() { entry.e.emit('timeout'); delete self._broadcast.map[key]; - }, this._broadcast.timout), + }, this._broadcast.timeout), + + // Retransmit + interval: setInterval(function() { + self._write(inv); + }, this._broadcast.interval), + type: item.type, value: item.render() }; @@ -141,6 +155,7 @@ Peer.prototype.destroy = function destroy() { // Clean-up timeouts Object.keys(this._broadcast.map).forEach(function(key) { clearTimeout(this._broadcast.map[key].timer); + clearInterval(this._broadcast.map[key].interval); }, this); clearInterval(this._ping.timer); @@ -236,6 +251,8 @@ Peer.prototype._onPacket = function onPacket(packet) { if (this._res(cmd, payload)) { return; } else { + if (cmd === 'reject') + console.log(cmd, payload); this.emit(cmd, payload); } }; diff --git a/lib/bcoin/pool.js b/lib/bcoin/pool.js index ae020954..e68429f0 100644 --- a/lib/bcoin/pool.js +++ b/lib/bcoin/pool.js @@ -13,7 +13,7 @@ function Pool(options) { EventEmitter.call(this); this.options = options || {}; - this.size = options.size || 16; + this.size = options.size || 32; this.parallel = options.parallel || 2000; this.redundancy = 2; this.load = { diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index a86eb2a3..81dac2b5 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -1,6 +1,6 @@ var bcoin = require('../bcoin'); var constants = bcoin.protocol.constants; -var utils = bcoin.protocol.utils; +var utils = bcoin.utils; var script = exports; script.decode = function decode(s) { @@ -11,12 +11,24 @@ script.decode = function decode(s) { var b = s[i++]; // Next `b` bytes should be pushed to stack - if (b >= 0x01 && b <= 0x75) { + if (b >= 0x01 && b <= 0x4b) { opcodes.push(s.slice(i, i + b)); i += b; continue; } + // Zero + if (b === 0) { + opcodes.push([]); + continue; + } + + // Raw number + if (b >= 0x51 && b <= 0x60) { + opcodes.push([ b - 0x50 ]); + continue; + } + var opcode = constants.opcodesByVal[b]; if (opcode === 'pushdata1') { var len = s[i++]; @@ -49,7 +61,11 @@ script.encode = function encode(s) { // Push value to stack if (Array.isArray(instr)) { - if (1 <= instr.length && instr.length <= 0x75) { + if (instr.length === 0) { + res.push(0); + } else if (instr.length === 1 && 0 < instr[0] && instr[0] <= 16) { + res.push(0x50 + instr[0]); + } else if (1 <= instr.length && instr.length <= 0x4b) { res = res.concat(instr.length, instr); } else if (instr.length <= 0xff) { res = res.concat(opcodes['pushdata1'], instr.length, instr); @@ -109,12 +125,12 @@ script.execute = function execute(s, stack, tx) { if (stack.length === 0) return false; - stack.push(bcoin.utils.ripesha(stack.pop())); + stack.push(utils.ripesha(stack.pop())); } else if (o === 'eqverify' || o === 'eq') { if (stack.length < 2) return false; - var res = bcoin.utils.isEqual(stack.pop(), stack.pop()); + var res = utils.isEqual(stack.pop(), stack.pop()); if (o === 'eqverify') { if (!res) return false; @@ -147,3 +163,52 @@ script.execute = function execute(s, stack, tx) { return true; }; + +script.isPubkeyhash = function isPubkeyhash(s, hash) { + if (s.length !== 5) + return false; + + var match = s[0] === 'dup' && + s[1] === 'hash160' && + Array.isArray(s[2]) && + s[3] === 'eqverify' && + s[4] === 'checksig'; + if (!match) + return false; + + if (hash) + return utils.isEqual(s[2], hash); + else + return s[2]; +} + +script.isMultisig = function isMultisig(s, key) { + if (s.length < 4) + return false; + + var m = s[0]; + if (!Array.isArray(m) || m.length !== 1) + return false; + m = m[0]; + + if (m + 3 !== s.length || s[s.length - 1] !== 'checkmultisig') + return false; + + var n = s[s.length - 2]; + if (!Array.isArray(n) || n.length !== 1) + return false; + + var keys = s.slice(1, m); + var isArray = keys.every(function(k) { + return Array.isArray(k); + }); + if (!isArray) + return false; + + if (!key) + return keys; + + return keys.some(function(k) { + return utils.isEqual(k, key); + }); +} diff --git a/lib/bcoin/wallet.js b/lib/bcoin/wallet.js index fa81ff02..71119db8 100644 --- a/lib/bcoin/wallet.js +++ b/lib/bcoin/wallet.js @@ -17,6 +17,7 @@ function Wallet(options, passphrase) { if (!options) options = {}; + this.compressed = true; this.key = null; if (options.passphrase) { @@ -38,8 +39,10 @@ Wallet.prototype.getPrivateKey = function getPrivateKey(enc) { return priv; if (enc === 'base58') { - // We'll be using compressed public key as an address - var arr = [ 128 ].concat(priv, 1); + // We'll be using ncompressed public key as an address + var arr = [ 128 ].concat(priv); + if (this.compressed) + arr.push(1); var chk = utils.checksum(arr); return utils.toBase58(arr.concat(chk)); } else { @@ -48,7 +51,7 @@ Wallet.prototype.getPrivateKey = function getPrivateKey(enc) { }; Wallet.prototype.getPublicKey = function getPublicKey() { - return this.key.getPublic(true, 'array'); + return this.key.getPublic(this.compressed, 'array'); }; Wallet.prototype.getHash = function getHash() { @@ -92,16 +95,18 @@ Wallet.prototype.validateAddress = function validateAddress(addr) { Wallet.validateAddress = Wallet.prototype.validateAddress; Wallet.prototype.own = function own(tx) { + var hash = this.getHash(); + var key = this.getPublicKey(); var outputs = tx.outputs.filter(function(output) { - if (output.script.length < 5) - return false; + var s = output.script; - var s = output.script.slice(-5); - return s[0] === 'dup' && - s[1] === 'hash160' && - utils.isEqual(s[2], this.getHash()) && - s[3] === 'eqverify' && - s[4] === 'checksig'; + if (bcoin.script.isPubkeyhash(s, hash)) + return true; + + if (bcoin.script.isMultisig(s, key)) + return true; + + return false; }, this); if (outputs.length === 0) return false; diff --git a/test/script-test.js b/test/script-test.js index ede7ec74..40b581ed 100644 --- a/test/script-test.js +++ b/test/script-test.js @@ -22,4 +22,12 @@ describe('Script', function() { var dst = bcoin.script.encode(decoded); assert.equal(bcoin.utils.toHex(dst), src); }); + + it('should encode/decode numbers', function() { + var script = [ [], [1], [2], [16] ]; + var encoded = bcoin.script.encode(script); + assert.deepEqual(encoded, [ 0, 0x51, 0x52, 0x60 ]); + var decoded = bcoin.script.decode(encoded); + assert.deepEqual(decoded, script); + }); });