Add FilterLoad, FilterAdd, and FilterClear Messages + BloomFilter
This commit is contained in:
parent
e19734593e
commit
abbe63666f
47
lib/bloomfilter.js
Normal file
47
lib/bloomfilter.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var bitcore = require('bitcore');
|
||||||
|
var BloomFilter = require('bloom-filter');
|
||||||
|
var BufferReader = bitcore.encoding.BufferReader;
|
||||||
|
var BufferWriter = bitcore.encoding.BufferWriter;
|
||||||
|
var $ = bitcore.util.preconditions;
|
||||||
|
|
||||||
|
|
||||||
|
BloomFilter.fromBuffer = function fromBuffer(payload) {
|
||||||
|
var parser = new BufferReader(payload);
|
||||||
|
var data = parser.readVarLengthBuffer();
|
||||||
|
$.checkState(data.length <= BloomFilter.MAX_BLOOM_FILTER_SIZE,
|
||||||
|
'Filter data must be <= MAX_BLOOM_FILTER_SIZE bytes');
|
||||||
|
var nHashFuncs = parser.readUInt32LE();
|
||||||
|
$.checkState(nHashFuncs <= BloomFilter.MAX_HASH_FUNCS,
|
||||||
|
'Filter nHashFuncs must be <= MAX_HASH_FUNCS');
|
||||||
|
var nTweak = parser.readUInt32LE();
|
||||||
|
var nFlags = parser.readUInt8();
|
||||||
|
|
||||||
|
var vData = [];
|
||||||
|
var dataParser = new BufferReader(data);
|
||||||
|
for(var i = 0; i < data.length; i++) {
|
||||||
|
vData.push(dataParser.readUInt8());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BloomFilter({
|
||||||
|
vData: vData,
|
||||||
|
nHashFuncs: nHashFuncs,
|
||||||
|
nTweak: nTweak,
|
||||||
|
nFlags: nFlags
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
BloomFilter.prototype.toBuffer = function toBuffer() {
|
||||||
|
var bw = new BufferWriter();
|
||||||
|
bw.writeVarintNum(this.vData.length);
|
||||||
|
for(var i = 0; i < this.vData.length; i++) {
|
||||||
|
bw.writeUInt8(this.vData[i]);
|
||||||
|
}
|
||||||
|
bw.writeUInt32LE(this.nHashFuncs);
|
||||||
|
bw.writeUInt32LE(this.nTweak);
|
||||||
|
bw.writeUInt8(this.nFlags);
|
||||||
|
return bw.concat();
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = BloomFilter;
|
||||||
@ -4,5 +4,6 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
Messages: require('./messages'),
|
Messages: require('./messages'),
|
||||||
Peer: require('./peer'),
|
Peer: require('./peer'),
|
||||||
Pool: require('./pool')
|
Pool: require('./pool'),
|
||||||
|
BloomFilter: require('./bloomfilter')
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
var Buffers = require('buffers');
|
var Buffers = require('buffers');
|
||||||
var Put = require('bufferput');
|
var Put = require('bufferput');
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
|
var BloomFilter = require('./bloomfilter');
|
||||||
|
|
||||||
var bitcore = require('bitcore');
|
var bitcore = require('bitcore');
|
||||||
var _ = bitcore.deps._;
|
var _ = bitcore.deps._;
|
||||||
@ -14,6 +15,7 @@ var _ = bitcore.deps._;
|
|||||||
var BlockHeaderModel = bitcore.BlockHeader;
|
var BlockHeaderModel = bitcore.BlockHeader;
|
||||||
var BlockModel = bitcore.Block;
|
var BlockModel = bitcore.Block;
|
||||||
var BufferReader = bitcore.encoding.BufferReader;
|
var BufferReader = bitcore.encoding.BufferReader;
|
||||||
|
var BufferWriter = bitcore.encoding.BufferWriter;
|
||||||
var BufferUtil = bitcore.util.buffer;
|
var BufferUtil = bitcore.util.buffer;
|
||||||
var $ = bitcore.util.preconditions;
|
var $ = bitcore.util.preconditions;
|
||||||
var Hash = bitcore.crypto.Hash;
|
var Hash = bitcore.crypto.Hash;
|
||||||
@ -826,6 +828,80 @@ function GetHeaders(starts, stop) {
|
|||||||
util.inherits(GetHeaders, GetBlocks);
|
util.inherits(GetHeaders, GetBlocks);
|
||||||
module.exports.GetHeaders = Message.COMMANDS.getheaders = GetHeaders;
|
module.exports.GetHeaders = Message.COMMANDS.getheaders = GetHeaders;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request peer to apply a bloom filter to 'inv' messages sent back
|
||||||
|
*
|
||||||
|
* @name P2P.Message.filterload
|
||||||
|
* @param{BloomFilter} filter - a BloomFilter object
|
||||||
|
*/
|
||||||
|
function FilterLoad(filter) {
|
||||||
|
this.command = 'filterload';
|
||||||
|
$.checkArgument(_.isUndefined() || filter instanceof BloomFilter,
|
||||||
|
'BloomFilter object or undefined required for FilterLoad');
|
||||||
|
this.filter = filter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
util.inherits(FilterLoad, Message);
|
||||||
|
|
||||||
|
FilterLoad.prototype.fromBuffer = function(payload) {
|
||||||
|
this.filter = BloomFilter.fromBuffer(payload);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
FilterLoad.prototype.getPayload = function() {
|
||||||
|
if(this.filter) {
|
||||||
|
return this.filter.toBuffer()
|
||||||
|
} else {
|
||||||
|
return BufferUtil.EMPTY_BUFFER;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.FilterLoad = Message.COMMANDS.filterload = FilterLoad;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request peer to add data to a bloom filter already set by 'filterload'
|
||||||
|
*
|
||||||
|
* @name P2P.Message.filteradd
|
||||||
|
* @param{Buffer} data - Array of bytes representing bloom filter data
|
||||||
|
*/
|
||||||
|
function FilterAdd(data) {
|
||||||
|
this.command = 'filteradd';
|
||||||
|
this.data = data || new Buffer(0,'hex');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
util.inherits(FilterAdd, Message);
|
||||||
|
|
||||||
|
FilterAdd.prototype.fromBuffer = function(payload) {
|
||||||
|
$.checkArgument(payload);
|
||||||
|
var parser = new BufferReader(payload);
|
||||||
|
this.data = parser.readVarLengthBuffer();
|
||||||
|
$.checkState(this.data.length <= BloomFilter.MAX_BLOOM_FILTER_SIZE,
|
||||||
|
'FilterAdd data must be <= 520 bytes');
|
||||||
|
this._checkFinished(parser);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
FilterAdd.prototype.getPayload = function() {
|
||||||
|
var bw = new BufferWriter();
|
||||||
|
bw.writeVarintNum(this.data.length);
|
||||||
|
bw.write(this.data);
|
||||||
|
return bw.concat();
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.FilterAdd = Message.COMMANDS.filterload = FilterAdd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request peer to apply a bloom filter to 'inv' messages sent back
|
||||||
|
*
|
||||||
|
* @name P2P.Message.filterclear
|
||||||
|
*/
|
||||||
|
function FilterClear() {
|
||||||
|
this.command = 'filterclear';
|
||||||
|
}
|
||||||
|
util.inherits(FilterClear, Message);
|
||||||
|
|
||||||
|
module.exports.FilterClear = Message.COMMANDS.filterclear = FilterClear;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request for transactions on the mempool
|
* Request for transactions on the mempool
|
||||||
*
|
*
|
||||||
|
|||||||
@ -86,7 +86,8 @@ Pool.MaxConnectedPeers = 8;
|
|||||||
Pool.RetrySeconds = 30;
|
Pool.RetrySeconds = 30;
|
||||||
Pool.PeerEvents = ['version', 'inv', 'getdata', 'ping', 'pong', 'addr',
|
Pool.PeerEvents = ['version', 'inv', 'getdata', 'ping', 'pong', 'addr',
|
||||||
'getaddr', 'verack', 'reject', 'alert', 'headers', 'block',
|
'getaddr', 'verack', 'reject', 'alert', 'headers', 'block',
|
||||||
'tx', 'getblocks', 'getheaders', 'error'
|
'tx', 'getblocks', 'getheaders', 'error', 'filterload', 'filteradd',
|
||||||
|
'filterclear'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -53,6 +53,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bitcore": "^0.10.2",
|
"bitcore": "^0.10.2",
|
||||||
|
"bloom-filter": "^0.1.1",
|
||||||
"bufferput": "^0.1.2",
|
"bufferput": "^0.1.2",
|
||||||
"buffers": "^0.1.1",
|
"buffers": "^0.1.1",
|
||||||
"socks5-client": "^0.3.6"
|
"socks5-client": "^0.3.6"
|
||||||
|
|||||||
17
test/bloomfilter.js
Normal file
17
test/bloomfilter.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var chai = require('chai');
|
||||||
|
|
||||||
|
var Data = require('./data/messages');
|
||||||
|
var P2P = require('../');
|
||||||
|
var BloomFilter = P2P.BloomFilter;
|
||||||
|
|
||||||
|
|
||||||
|
describe('BloomFilter', function() {
|
||||||
|
it('BloomFilter#fromBuffer and toBuffer methods work', function() {
|
||||||
|
var testPayload = Data.FILTERLOAD.payload;
|
||||||
|
var filter = new BloomFilter.fromBuffer(new Buffer(testPayload, 'hex'));
|
||||||
|
filter.toBuffer().toString('hex').should.equal(testPayload);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
@ -62,5 +62,17 @@
|
|||||||
"PONG": {
|
"PONG": {
|
||||||
"message": "f9beb4d9706f6e67000000000000000008000000c6466f1e6b86480ae969867c",
|
"message": "f9beb4d9706f6e67000000000000000008000000c6466f1e6b86480ae969867c",
|
||||||
"payload": "6b86480ae969867c"
|
"payload": "6b86480ae969867c"
|
||||||
|
},
|
||||||
|
"FILTERLOAD": {
|
||||||
|
"message": "f9beb4d966696c7465726c6f61640000210000002ef97a71170000000000000000000000000000000000000000000000060000000000000000",
|
||||||
|
"payload": "170000000000000000000000000000000000000000000000060000000000000000"
|
||||||
|
},
|
||||||
|
"FILTERADD": {
|
||||||
|
"message": "f9beb4d966696c7465726c6f61640000150000009727ea0a1499108ad8ed9bb6274d3980bab5a85c048f0950c8",
|
||||||
|
"payload": "1499108ad8ed9bb6274d3980bab5a85c048f0950c8"
|
||||||
|
},
|
||||||
|
"FILTERCLEAR": {
|
||||||
|
"message": "f9beb4d966696c7465726c6365617200000000005df6e0e2",
|
||||||
|
"payload": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ var Buffers = require('buffers');
|
|||||||
var bitcore = require('bitcore');
|
var bitcore = require('bitcore');
|
||||||
var Data = require('./data/messages');
|
var Data = require('./data/messages');
|
||||||
var P2P = require('../');
|
var P2P = require('../');
|
||||||
|
var BloomFilter = P2P.BloomFilter;
|
||||||
var Messages = P2P.Messages;
|
var Messages = P2P.Messages;
|
||||||
var Networks = bitcore.Networks;
|
var Networks = bitcore.Networks;
|
||||||
var BufferUtils = bitcore.util.buffer;
|
var BufferUtils = bitcore.util.buffer;
|
||||||
@ -26,6 +27,9 @@ describe('Messages', function() {
|
|||||||
Alert: 'alert',
|
Alert: 'alert',
|
||||||
Reject: 'reject',
|
Reject: 'reject',
|
||||||
Block: 'block',
|
Block: 'block',
|
||||||
|
FilterLoad: 'filterload',
|
||||||
|
FilterAdd: 'filteradd',
|
||||||
|
FilterClear: 'filterclear',
|
||||||
GetBlocks: 'getblocks',
|
GetBlocks: 'getblocks',
|
||||||
GetHeaders: 'getheaders',
|
GetHeaders: 'getheaders',
|
||||||
GetData: 'getdata',
|
GetData: 'getdata',
|
||||||
@ -34,7 +38,7 @@ describe('Messages', function() {
|
|||||||
Transaction: 'tx',
|
Transaction: 'tx',
|
||||||
NotFound: 'notfound'
|
NotFound: 'notfound'
|
||||||
};
|
};
|
||||||
// TODO: add data for these
|
// TODO: add data for these
|
||||||
var noPayload = ['Reject', 'GetBlocks', 'GetHeaders'];
|
var noPayload = ['Reject', 'GetBlocks', 'GetHeaders'];
|
||||||
var names = Object.keys(commands);
|
var names = Object.keys(commands);
|
||||||
describe('named', function() {
|
describe('named', function() {
|
||||||
@ -116,4 +120,10 @@ describe('Messages', function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('FilterLoad#fromBuffer method works', function() {
|
||||||
|
var testPayload = Data.FILTERLOAD.payload;
|
||||||
|
var msg = new Messages.FilterLoad().fromBuffer(new Buffer(testPayload, 'hex'));
|
||||||
|
msg.getPayload().toString('hex').should.equal(testPayload);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user