bitcoin-inventory
Advanced tools
Comparing version 0.0.0 to 1.0.0
@@ -18,2 +18,3 @@ 'use strict'; | ||
// TODO: prevent DoS (e.g. rate limiting, cap on stored data) | ||
// TODO: add optional tx verification (user-provided function), and broadcast valid txs | ||
@@ -41,2 +42,3 @@ var Inventory = function (_EventEmitter) { | ||
_this.peers.on('tx', _this._onTx.bind(_this)); | ||
_this.peers.on('getdata', _this._onGetdata.bind(_this)); | ||
@@ -95,3 +97,3 @@ _this.lastCount = 0; | ||
if (this.data.has(hash)) return; | ||
this.add(tx, false); | ||
this._add(tx, false); | ||
this.emit('tx', tx, peer); | ||
@@ -101,2 +103,36 @@ this.emit('tx:' + hash, tx, peer); | ||
}, { | ||
key: '_onGetdata', | ||
value: function _onGetdata(items) { | ||
var peer = arguments.length <= 1 || arguments[1] === undefined ? this.peers : arguments[1]; | ||
var _iteratorNormalCompletion2 = true; | ||
var _didIteratorError2 = false; | ||
var _iteratorError2 = undefined; | ||
try { | ||
for (var _iterator2 = items[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { | ||
var item = _step2.value; | ||
if (item.type !== INV.MSG_TX) continue; | ||
var hash = getHash(item.hash); | ||
if (!this.data.has(hash)) continue; | ||
var entry = this.data.get(hash); | ||
if (!entry.broadcast) continue; | ||
peer.send('tx', this.data.get(hash).tx); | ||
} | ||
} catch (err) { | ||
_didIteratorError2 = true; | ||
_iteratorError2 = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion2 && _iterator2.return) { | ||
_iterator2.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError2) { | ||
throw _iteratorError2; | ||
} | ||
} | ||
} | ||
} | ||
}, { | ||
key: '_removeOld', | ||
@@ -110,16 +146,28 @@ value: function _removeOld() { | ||
}, { | ||
key: 'add', | ||
value: function add(data) { | ||
var announce = arguments.length <= 1 || arguments[1] === undefined ? true : arguments[1]; | ||
var hash = getHash(data.getHash()); | ||
if (this.data.has(hash)) return; | ||
this.data.push(hash, data); | ||
if (!announce) return; | ||
this.peers.send('inv', [{ hash: data.getHash(), type: INV.MSG_TX }]); | ||
key: '_add', | ||
value: function _add(tx, broadcast) { | ||
var hashBuf = tx.getHash(); | ||
var hash = getHash(hashBuf); | ||
if (!this.data.has(hash)) { | ||
this.data.push(hash, { tx: tx, broadcast: broadcast }); | ||
} else { | ||
this.data.get(hash).broadcast = true; | ||
} | ||
} | ||
}, { | ||
key: 'broadcast', | ||
value: function broadcast(tx) { | ||
this._add(tx, true); | ||
this._sendInv(tx, this.peers); | ||
} | ||
}, { | ||
key: '_sendInv', | ||
value: function _sendInv(tx, peer) { | ||
peer.send('inv', [{ hash: tx.getHash(), type: INV.MSG_TX }]); | ||
} | ||
}, { | ||
key: 'get', | ||
value: function get(hash) { | ||
return this.data.get(getHash(hash)); | ||
var entry = this.data.get(getHash(hash)); | ||
if (entry) return entry.tx; | ||
} | ||
@@ -130,2 +178,3 @@ }, { | ||
clearInterval(this.interval); | ||
// TODO: stop listening to peers | ||
} | ||
@@ -132,0 +181,0 @@ }]); |
{ | ||
"name": "bitcoin-inventory", | ||
"version": "0.0.0", | ||
"description": "Relay and store transactions received from peers", | ||
"version": "1.0.0", | ||
"description": "Exchange transactions with peers", | ||
"main": "index.js", | ||
@@ -6,0 +6,0 @@ "scripts": { |
@@ -10,2 +10,3 @@ 'use strict' | ||
// TODO: prevent DoS (e.g. rate limiting, cap on stored data) | ||
// TODO: add optional tx verification (user-provided function), and broadcast valid txs | ||
@@ -25,2 +26,3 @@ class Inventory extends EventEmitter { | ||
this.peers.on('tx', this._onTx.bind(this)) | ||
this.peers.on('getdata', this._onGetdata.bind(this)) | ||
@@ -49,3 +51,3 @@ this.lastCount = 0 | ||
if (this.data.has(hash)) return | ||
this.add(tx, false) | ||
this._add(tx, false) | ||
this.emit('tx', tx, peer) | ||
@@ -55,2 +57,13 @@ this.emit(`tx:${hash}`, tx, peer) | ||
_onGetdata (items, peer = this.peers) { | ||
for (let item of items) { | ||
if (item.type !== INV.MSG_TX) continue | ||
let hash = getHash(item.hash) | ||
if (!this.data.has(hash)) continue | ||
let entry = this.data.get(hash) | ||
if (!entry.broadcast) continue | ||
peer.send('tx', this.data.get(hash).tx) | ||
} | ||
} | ||
_removeOld () { | ||
@@ -63,9 +76,20 @@ for (let i = 0; i < this.lastCount; i++) { | ||
add (data, announce = true) { | ||
var hash = getHash(data.getHash()) | ||
if (this.data.has(hash)) return | ||
this.data.push(hash, data) | ||
if (!announce) return | ||
this.peers.send('inv', [ | ||
{ hash: data.getHash(), type: INV.MSG_TX } | ||
_add (tx, broadcast) { | ||
var hashBuf = tx.getHash() | ||
var hash = getHash(hashBuf) | ||
if (!this.data.has(hash)) { | ||
this.data.push(hash, { tx, broadcast }) | ||
} else { | ||
this.data.get(hash).broadcast = true | ||
} | ||
} | ||
broadcast (tx) { | ||
this._add(tx, true) | ||
this._sendInv(tx, this.peers) | ||
} | ||
_sendInv (tx, peer) { | ||
peer.send('inv', [ | ||
{ hash: tx.getHash(), type: INV.MSG_TX } | ||
]) | ||
@@ -75,3 +99,4 @@ } | ||
get (hash) { | ||
return this.data.get(getHash(hash)) | ||
var entry = this.data.get(getHash(hash)) | ||
if (entry) return entry.tx | ||
} | ||
@@ -81,2 +106,3 @@ | ||
clearInterval(this.interval) | ||
// TODO: stop listening to peers | ||
} | ||
@@ -83,0 +109,0 @@ } |
@@ -123,2 +123,7 @@ var EventEmitter = require('events') | ||
t.equal(peer2, peer, 'got peer') | ||
peerEvents.removeAll() | ||
peerEvents.once('send', function (command, message) { | ||
t.fail('should not have sent message') | ||
}) | ||
peer.emit('getdata', [{ hash: hash, type: INV.MSG_TX }]) | ||
}) | ||
@@ -170,2 +175,7 @@ invEvents.once('tx:' + hash.toString('hex'), function (tx2, peer2) { | ||
t.equal(peer2, peer, 'got peer') | ||
peerEvents.once('send', function (command, message) { | ||
t.fail('should not have sent message') | ||
}) | ||
peer.emit('getdata', [{ hash: hash, type: INV.MSG_TX }]) | ||
t.end() | ||
@@ -183,3 +193,3 @@ }) | ||
test('direct add', function (t) { | ||
test('broadcast', function (t) { | ||
var peer = new MockPeer() | ||
@@ -190,6 +200,4 @@ var inv = new Inventory(peer) | ||
var tx = { getHash: function () { return hash } } | ||
var hash2 = Buffer(32).fill('b') | ||
var tx2 = { getHash: function () { return hash2 } } | ||
t.test('add and announce', function (t) { | ||
t.test('broadcast', function (t) { | ||
peer.once('send', function (command, message) { | ||
@@ -201,18 +209,37 @@ t.equal(command, 'inv', 'sent inv') | ||
}) | ||
inv.add(tx) | ||
inv.broadcast(tx) | ||
}) | ||
t.test('add without announce', function (t) { | ||
t.test('respond to getdata', function (t) { | ||
peer.once('send', function (command, message) { | ||
t.equal(command, 'tx', 'sent tx message') | ||
t.equal(message, tx, 'correct tx') | ||
t.end() | ||
}) | ||
peer.emit('getdata', [{ hash: hash, type: INV.MSG_TX }]) | ||
}) | ||
t.test('broadcast existing tx', function (t) { | ||
peer.once('send', function (command, message) { | ||
t.equal(command, 'inv', 'sent inv') | ||
t.equal(message.length, 1, 'message has length 1') | ||
t.equal(message[0].hash.toString('hex'), hash.toString('hex'), 'correct hash') | ||
t.end() | ||
}) | ||
inv.broadcast(tx) | ||
}) | ||
t.test('getdata with wrong type', function (t) { | ||
peer.once('send', function (command, message) { | ||
t.fail('should not have sent message') | ||
}) | ||
inv.add(tx2, false) | ||
peer.emit('getdata', [{ hash: hash, type: INV.MSG_BLOCK }]) | ||
t.end() | ||
}) | ||
t.test('add duplicate', function (t) { | ||
t.test('getdata with wrong hash', function (t) { | ||
peer.once('send', function (command, message) { | ||
t.fail('should not have sent message') | ||
}) | ||
inv.add(tx) | ||
peer.emit('getdata', [{ hash: Buffer(32).fill('b'), type: INV.MSG_TX }]) | ||
t.end() | ||
@@ -261,2 +288,16 @@ }) | ||
test('get', function (t) { | ||
var peer = new MockPeer() | ||
var inv = new Inventory(peer) | ||
t.test('get nonexistent tx', function (t) { | ||
t.notOk(inv.get(Buffer(32).fill('a')), 'no tx returned') | ||
t.end() | ||
}) | ||
t.test('close', function (t) { | ||
inv.close() | ||
t.end() | ||
}) | ||
t.end() | ||
}) | ||
function MockPeer () { | ||
@@ -263,0 +304,0 @@ EventEmitter.call(this) |
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
24468
10
534
1
1
61