http: add chain watching and scanning.
This commit is contained in:
parent
59d4fa22ce
commit
487efb6639
@ -189,7 +189,7 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
assert(typeof params.hash === 'string', 'Hash must be a string.');
|
assert(typeof params.hash === 'string', 'Hash must be a string.');
|
||||||
if (params.hash.length !== 64) {
|
if (params.hash.length !== 64) {
|
||||||
options.height = Number(params.hash);
|
options.height = Number(params.hash);
|
||||||
assert(utils.isUInt32(options.height), 'Hash must be a number.');
|
assert(utils.isUInt32(options.height), 'Height must be a number.');
|
||||||
} else {
|
} else {
|
||||||
options.hash = utils.revHex(params.hash);
|
options.hash = utils.revHex(params.hash);
|
||||||
}
|
}
|
||||||
@ -247,8 +247,6 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
if (typeof params.subtractFee === 'number') {
|
if (typeof params.subtractFee === 'number') {
|
||||||
options.subtractFee = params.subtractFee;
|
options.subtractFee = params.subtractFee;
|
||||||
assert(utils.isUInt32(options.subtractFee), 'subtractFee must be a number.');
|
assert(utils.isUInt32(options.subtractFee), 'subtractFee must be a number.');
|
||||||
} else if (params.subtractFee === 'true') {
|
|
||||||
options.subtractFee = true;
|
|
||||||
} else {
|
} else {
|
||||||
assert(typeof options.subtractFee === 'boolean', 'subtractFee must be a boolean.');
|
assert(typeof options.subtractFee === 'boolean', 'subtractFee must be a boolean.');
|
||||||
options.subtractFee = params.subtractFee;
|
options.subtractFee = params.subtractFee;
|
||||||
@ -917,6 +915,10 @@ HTTPServer.prototype._initIO = function _initIO() {
|
|||||||
self.emit('error', err);
|
self.emit('error', err);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on('disconnect', function() {
|
||||||
|
socket.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
socket.once('auth', function(apiKey, callback) {
|
socket.once('auth', function(apiKey, callback) {
|
||||||
if (typeof callback !== 'function')
|
if (typeof callback !== 'function')
|
||||||
return socket.destroy();
|
return socket.destroy();
|
||||||
@ -990,6 +992,50 @@ HTTPServer.prototype._initIO = function _initIO() {
|
|||||||
|
|
||||||
return callback();
|
return callback();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on('watch chain', function() {
|
||||||
|
socket.watchChain();
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('unwatch chain', function() {
|
||||||
|
socket.unwatchChain();
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('watch address', function(addresses) {
|
||||||
|
if (!Array.isArray(addresses))
|
||||||
|
return socket.destroy();
|
||||||
|
|
||||||
|
try {
|
||||||
|
socket.addFilter(addresses);
|
||||||
|
} catch (e) {
|
||||||
|
return socket.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('unwatch address', function(addresses) {
|
||||||
|
if (!Array.isArray(addresses))
|
||||||
|
return socket.destroy();
|
||||||
|
|
||||||
|
try {
|
||||||
|
socket.removeFilter(addresses);
|
||||||
|
} catch (e) {
|
||||||
|
return socket.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('scan chain', function(start, callback) {
|
||||||
|
if (typeof callback !== 'function')
|
||||||
|
return socket.destroy();
|
||||||
|
|
||||||
|
if (typeof start !== 'string')
|
||||||
|
return callback({ error: 'Invalid parameter.' });
|
||||||
|
|
||||||
|
try {
|
||||||
|
socket.scan(start, callback);
|
||||||
|
} catch (e) {
|
||||||
|
return callback({ error: e.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.walletdb.on('tx', function(id, tx, info) {
|
this.walletdb.on('tx', function(id, tx, info) {
|
||||||
@ -1138,6 +1184,20 @@ function ClientSocket(server, socket) {
|
|||||||
this.host = socket.conn.remoteAddress;
|
this.host = socket.conn.remoteAddress;
|
||||||
this.timeout = null;
|
this.timeout = null;
|
||||||
this.auth = false;
|
this.auth = false;
|
||||||
|
this.filter = {};
|
||||||
|
this.filterCount = 0;
|
||||||
|
|
||||||
|
this.node = this.server.node;
|
||||||
|
this.network = this.server.network;
|
||||||
|
this.chain = this.server.chain;
|
||||||
|
this.mempool = this.server.mempool;
|
||||||
|
this.pool = this.server.pool;
|
||||||
|
this.fees = this.server.fees;
|
||||||
|
this.miner = this.server.miner;
|
||||||
|
this.wallet = this.server.wallet;
|
||||||
|
this.walletdb = this.server.walletdb;
|
||||||
|
this.logger = this.server.logger;
|
||||||
|
this.events = [];
|
||||||
|
|
||||||
this._init();
|
this._init();
|
||||||
}
|
}
|
||||||
@ -1149,12 +1209,162 @@ ClientSocket.prototype._init = function _init() {
|
|||||||
var socket = this.socket;
|
var socket = this.socket;
|
||||||
var emit = EventEmitter.prototype.emit;
|
var emit = EventEmitter.prototype.emit;
|
||||||
var onevent = socket.onevent.bind(socket);
|
var onevent = socket.onevent.bind(socket);
|
||||||
|
|
||||||
socket.onevent = function(packet) {
|
socket.onevent = function(packet) {
|
||||||
var result = onevent(packet);
|
var result = onevent(packet);
|
||||||
var args = packet.data || [];
|
var args = packet.data || [];
|
||||||
emit.apply(self, args);
|
emit.apply(self, args);
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
socket.on('error', function(err) {
|
||||||
|
emit.call(self, 'error', err);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('disconnect', function() {
|
||||||
|
emit.call(self, 'disconnect');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientSocket.prototype.addFilter = function addFilter(addresses) {
|
||||||
|
var i, hash;
|
||||||
|
|
||||||
|
for (i = 0; i < addresses.length; i++) {
|
||||||
|
hash = bcoin.address.getHash(addresses[i], 'hex');
|
||||||
|
|
||||||
|
if (!hash)
|
||||||
|
throw new Error('Bad address.');
|
||||||
|
|
||||||
|
if (!this.filter[hash]) {
|
||||||
|
this.filter[hash] = true;
|
||||||
|
this.filterCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientSocket.prototype.removeFilter = function removeFilter(addresses) {
|
||||||
|
var i, hash;
|
||||||
|
|
||||||
|
for (i = 0; i < addresses.length; i++) {
|
||||||
|
hash = bcoin.address.getHash(addresses[i], 'hex');
|
||||||
|
|
||||||
|
if (!hash)
|
||||||
|
throw new Error('Bad address.');
|
||||||
|
|
||||||
|
if (this.filter[hash]) {
|
||||||
|
delete this.filter[hash];
|
||||||
|
this.filterCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientSocket.prototype.bind = function bind(obj, event, listener) {
|
||||||
|
this.events.push([obj, event, listener]);
|
||||||
|
obj.on(event, listener);
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientSocket.prototype.unbind = function unbind(obj, event) {
|
||||||
|
var i, event;
|
||||||
|
|
||||||
|
for (i = this.events.length - 1; i >= 0; i--) {
|
||||||
|
event = this.events[i]
|
||||||
|
if (event[0] === obj && event[1] === event) {
|
||||||
|
obj.removeListener(event, event[2]);
|
||||||
|
this.events.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientSocket.prototype.unbindAll = function unbindAll() {
|
||||||
|
var i, event;
|
||||||
|
|
||||||
|
for (i = 0; i < this.events.length; i++) {
|
||||||
|
event = this.events[i];
|
||||||
|
event[0].removeListener(event[1], event[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.events.length = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientSocket.prototype.watchChain = function watchChain() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.bind(this.chain, 'connect', function(entry, block) {
|
||||||
|
var txs;
|
||||||
|
|
||||||
|
self.emit('block connect', entry.toJSON());
|
||||||
|
|
||||||
|
txs = self.testBlock(block);
|
||||||
|
|
||||||
|
if (txs)
|
||||||
|
self.emit('block tx', txs, entry.toJSON());
|
||||||
|
});
|
||||||
|
|
||||||
|
this.bind(this.chain, 'disconnect', function(entry, block) {
|
||||||
|
self.emit('block disconnect', entry.toJSON());
|
||||||
|
});
|
||||||
|
|
||||||
|
this.bind(this.mempool, 'tx', function(tx) {
|
||||||
|
if (self.testFilter(tx))
|
||||||
|
self.emit('mempool tx', tx.toJSON());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientSocket.prototype.unwatchChain = function unwatchChain() {
|
||||||
|
this.unbind(this.chain, 'connect');
|
||||||
|
this.unbind(this.chain, 'disconnect');
|
||||||
|
this.unbind(this.mempool, 'tx');
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientSocket.prototype.testBlock = function testBlock(tx) {
|
||||||
|
var txs = [];
|
||||||
|
var i, tx;
|
||||||
|
|
||||||
|
if (this.filterCount === 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < block.txs.length; i++) {
|
||||||
|
tx = block.txs[i];
|
||||||
|
if (this.testFilter(tx))
|
||||||
|
txs.push(tx.toJSON());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (txs.length === 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
return txs;
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientSocket.prototype.testFilter = function testFilter(tx) {
|
||||||
|
var i, hashes, hash;
|
||||||
|
|
||||||
|
if (this.filterCount === 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
hashes = tx.getHashes('hex');
|
||||||
|
|
||||||
|
for (i = 0; i < hashes.length; i++) {
|
||||||
|
hash = hashes[i];
|
||||||
|
if (this.filter[hash])
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientSocket.prototype.scan = function scan(start, callback) {
|
||||||
|
var self = this;
|
||||||
|
var hash;
|
||||||
|
|
||||||
|
hashes = Object.keys(this.filter);
|
||||||
|
start = utils.revHex(start);
|
||||||
|
|
||||||
|
this.chain.db.scan(start, hashes, function(tx, entry, next) {
|
||||||
|
self.emit('block tx', [tx.toJSON()], entry.toJSON());
|
||||||
|
next();
|
||||||
|
}, function(err) {
|
||||||
|
if (err)
|
||||||
|
return callback({ error: err.message });
|
||||||
|
callback();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
ClientSocket.prototype.join = function join(id) {
|
ClientSocket.prototype.join = function join(id) {
|
||||||
@ -1186,6 +1396,7 @@ ClientSocket.prototype.stop = function stop() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ClientSocket.prototype.destroy = function() {
|
ClientSocket.prototype.destroy = function() {
|
||||||
|
this.unbindAll();
|
||||||
this.stop();
|
this.stop();
|
||||||
this.socket.disconnect();
|
this.socket.disconnect();
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user