more http things.
This commit is contained in:
parent
ed420e0769
commit
c2aa7b3727
@ -270,7 +270,7 @@ Chain.prototype._preload = function _preload(callback) {
|
||||
var self = this;
|
||||
var url = 'https://headers.electrum.org/blockchain_headers';
|
||||
var buf, height, stream;
|
||||
var request;
|
||||
var request = require('./http/request');
|
||||
|
||||
if (!this.options.preload)
|
||||
return callback();
|
||||
@ -281,19 +281,13 @@ Chain.prototype._preload = function _preload(callback) {
|
||||
if (network.type !== 'main')
|
||||
return callback(new Error('Electrum.org only offers `main` headers.'));
|
||||
|
||||
try {
|
||||
request = require('request');
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
|
||||
utils.debug('Loading %s', url);
|
||||
|
||||
this.db.getChainHeight(function(err, chainHeight) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
stream = request.get(url);
|
||||
stream = request({ method: 'GET', uri: url });
|
||||
height = 0;
|
||||
buf = {
|
||||
data: [],
|
||||
@ -386,7 +380,7 @@ Chain.prototype._preload = function _preload(callback) {
|
||||
// redundant blocks to disk!
|
||||
if (height <= chainHeight) {
|
||||
self.db.addCache(entry);
|
||||
self.db.bloom(entry.hash, 'hex');
|
||||
// self.db.bloom(entry.hash, 'hex');
|
||||
} else {
|
||||
self.db.save(entry);
|
||||
}
|
||||
|
||||
370
lib/bcoin/http/client.js
Normal file
370
lib/bcoin/http/client.js
Normal file
@ -0,0 +1,370 @@
|
||||
/**
|
||||
* client.js - http client for wallets
|
||||
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
|
||||
* https://github.com/indutny/bcoin
|
||||
*/
|
||||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var bcoin = require('../../bcoin');
|
||||
var constants = bcoin.protocol.constants;
|
||||
var network = bcoin.protocol.network;
|
||||
var utils = bcoin.utils;
|
||||
var assert = utils.assert;
|
||||
var request = require('./request');
|
||||
|
||||
/**
|
||||
* Client
|
||||
*/
|
||||
|
||||
function Client(uri) {
|
||||
if (!(this instanceof Client))
|
||||
return new Client(uri);
|
||||
|
||||
EventEmitter.call(this);
|
||||
|
||||
this.uri = uri;
|
||||
this.id = null;
|
||||
this._init();
|
||||
}
|
||||
|
||||
utils.inherits(Client, EventEmitter);
|
||||
|
||||
Client.prototype._init = function _init() {
|
||||
var self = this;
|
||||
var io;
|
||||
|
||||
try {
|
||||
io = require('socket.io');
|
||||
} catch (e) {
|
||||
;
|
||||
}
|
||||
|
||||
if (!io)
|
||||
return;
|
||||
|
||||
this.socket = new io.Socket(this.uri);
|
||||
|
||||
this.socket.on('open', function() {
|
||||
self.socket.on('tx', function(tx, map) {
|
||||
self.emit('tx', bcoin.tx.fromJSON(tx), map);
|
||||
});
|
||||
|
||||
self.socket.on('confirmed', function(tx, map) {
|
||||
self.emit('confirmed', bcoin.tx.fromJSON(tx), map);
|
||||
});
|
||||
|
||||
self.socket.on('updated', function(tx, map) {
|
||||
self.emit('updated', bcoin.tx.fromJSON(tx), map);
|
||||
});
|
||||
|
||||
self.socket.on('balance', function(balance, id) {
|
||||
self.emit('balance', utils.satoshi(balance), id);
|
||||
});
|
||||
|
||||
self.socket.on('balances', function(balances) {
|
||||
Object.keys(balances).forEach(function(id) {
|
||||
balances[id] = utils.satoshi(balances[id]);
|
||||
});
|
||||
self.emit('balances', balances);
|
||||
});
|
||||
|
||||
self.socket.on('error', function(err) {
|
||||
self.emit('error', err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.listenWallet = function listenWallet(id) {
|
||||
this.socket.join(id);
|
||||
};
|
||||
|
||||
Client.prototype.unlistenWallet = function unlistenWallet(id) {
|
||||
this.socket.leave(id);
|
||||
};
|
||||
|
||||
Client.prototype.listenAll = function listenAll(id) {
|
||||
this.listenWallet('!all');
|
||||
};
|
||||
|
||||
Client.prototype.unlistenAll = function unlistenAll(id) {
|
||||
this.unlistenWallet('!all');
|
||||
};
|
||||
|
||||
Client.prototype.destroy = function destroy() {
|
||||
this.socket.destroy();
|
||||
this.socket = null;
|
||||
};
|
||||
|
||||
Client.prototype._request = function _request(method, endpoint, json, callback) {
|
||||
var query;
|
||||
|
||||
if (!callback) {
|
||||
callback = json;
|
||||
json = null;
|
||||
}
|
||||
|
||||
if (json && method === 'get') {
|
||||
json = null;
|
||||
query = json;
|
||||
}
|
||||
|
||||
request({
|
||||
method: method,
|
||||
uri: this.uri + '/' + endpoint,
|
||||
query: query,
|
||||
json: json,
|
||||
expect: 'json'
|
||||
}, function(err, res, body) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (res.statusCode === 404)
|
||||
return callback();
|
||||
|
||||
if (!body)
|
||||
return callback(new Error('No body.'));
|
||||
|
||||
if (res.statusCode !== 200)
|
||||
return callback(new Error('Status code: ' + res.statusCode));
|
||||
|
||||
try {
|
||||
return callback(null, body);
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype._get = function _get(endpoint, json, callback) {
|
||||
return this._request('get', endpoint, json, callback);
|
||||
};
|
||||
|
||||
Client.prototype._post = function _post(endpoint, json, callback) {
|
||||
return this._request('post', endpoint, json, callback);
|
||||
};
|
||||
|
||||
Client.prototype._put = function _put(endpoint, json, callback) {
|
||||
return this._request('put', endpoint, json, callback);
|
||||
};
|
||||
|
||||
Client.prototype._del = function _del(endpoint, json, callback) {
|
||||
return this._request('delete', endpoint, json, callback);
|
||||
};
|
||||
|
||||
Client.prototype.getWalletAll = function getWalletAll(id, callback) {
|
||||
return this._get('/wallet/' + id + '/tx/all', function(err, body) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!body)
|
||||
return callback(null, []);
|
||||
|
||||
return callback(null, body.map(function(data) {
|
||||
return bcoin.tx.fromJSON(data);
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getWalletCoins = function getWalletCoins(id, callback) {
|
||||
return this._get('/wallet/' + id + '/coin', function(err, body) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!body)
|
||||
return callback(null, []);
|
||||
|
||||
return callback(null, body.map(function(data) {
|
||||
return bcoin.coin.fromJSON(data);
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getWalletPending = function getPending(id, callback) {
|
||||
return this._get('/wallet/' + id + '/tx/pending', function(err, body) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!body)
|
||||
return callback(null, []);
|
||||
|
||||
return callback(null, body.map(function(data) {
|
||||
return bcoin.coin.fromJSON(data);
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getWalletBalance = function getBalance(id, callback) {
|
||||
return this._get('/wallet/' + id + '/balance', function(err, body) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!body)
|
||||
return callback(new Error('Not found.'));
|
||||
|
||||
return callback(null, utils.satoshi(body.balance));
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getWalletLast = function getLast(id, limit, callback) {
|
||||
return this._get('/wallet/' + id + '/tx/last', options, function(err, body) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!body)
|
||||
return callback(null, []);
|
||||
|
||||
return callback(null, body.map(function(data) {
|
||||
return bcoin.tx.fromJSON(data);
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getWalletRange = function getWalletRange(id, options, callback) {
|
||||
return this._get('/wallet/' + id + '/tx/range', options, function(err, body) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!body)
|
||||
return callback(null, []);
|
||||
|
||||
return callback(null, body.map(function(data) {
|
||||
return bcoin.tx.fromJSON(data);
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getWalletTX = function getTX(id, hash, callback) {
|
||||
hash = utils.revHex(hash);
|
||||
|
||||
return this._get('/wallet/' + id + '/tx/' + hash, function(err, body) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!body)
|
||||
return callback(null, []);
|
||||
|
||||
return callback(null, bcoin.tx.fromJSON(body));
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getWalletCoin = function getCoin(id, hash, index, callback) {
|
||||
hash = utils.revHex(hash);
|
||||
|
||||
return this._get('/wallet/' + id + '/coin/' + hash + '/' + index, function(err, body) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!body)
|
||||
return callback(null, []);
|
||||
|
||||
return callback(null, bcoin.coin.fromJSON(body));
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.syncWallet = function syncWallet(id, options, callback) {
|
||||
var self = this;
|
||||
|
||||
var body = {
|
||||
receiveDepth: options.receiveDepth,
|
||||
changeDepth: options.changeDepth
|
||||
};
|
||||
|
||||
return this._put('/wallet/' + id, body, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
return callback();
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getCoinByAddress = function getCoinByAddress(address, callback) {
|
||||
var body = { addresses: address };
|
||||
|
||||
return this._post('/coin/address', body, function(err, body) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!body)
|
||||
return callback(null, []);
|
||||
|
||||
return callback(null, body.map(function(data) {
|
||||
return bcoin.coin.fromJSON(data);
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getCoin = function getCoin(hash, index, callback) {
|
||||
hash = utils.revHex(hash);
|
||||
|
||||
return this._get('/coin/' + hash + '/' + index, function(err, body) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!body)
|
||||
return callback(null, []);
|
||||
|
||||
return callback(null, bcoin.coin.fromJSON(body));
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getTXByAddress = function getTXByAddress(address, callback) {
|
||||
var body = { addresses: address };
|
||||
|
||||
return this._post('/tx/address', body, function(err, body) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!body)
|
||||
return callback(null, []);
|
||||
|
||||
return callback(null, body.map(function(data) {
|
||||
return bcoin.tx.fromJSON(data);
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getTX = function getTX(hash, callback) {
|
||||
hash = utils.revHex(hash);
|
||||
|
||||
return this._get('/tx/' + hash, function(err, body) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!body)
|
||||
return callback(null, []);
|
||||
|
||||
return callback(null, bcoin.tx.fromJSON(body));
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getBlock = function getBlock(hash, callback) {
|
||||
if (typeof hash !== 'number')
|
||||
hash = utils.revHex(hash);
|
||||
|
||||
return this._get('/block/' + hash, function(err, body) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!body)
|
||||
return callback(null, []);
|
||||
|
||||
return callback(null, bcoin.block.fromJSON(body));
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.broadcast = function broadcast(tx, callback) {
|
||||
var body = { tx: utils.toHex(tx.toRaw()) };
|
||||
|
||||
callback = utils.ensure(callback);
|
||||
|
||||
return this._post('/broadcast', body, function(err, body) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
return callback();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose
|
||||
*/
|
||||
|
||||
module.exports = Client;
|
||||
@ -5,35 +5,24 @@
|
||||
*/
|
||||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var StringDecoder = require('string_decoder').StringDecoder;
|
||||
var url = require('url');
|
||||
var engine;
|
||||
|
||||
try {
|
||||
engine = require('engine.io');
|
||||
} catch (e) {
|
||||
;
|
||||
}
|
||||
|
||||
var bcoin = require('../bcoin');
|
||||
var bn = require('bn.js');
|
||||
var constants = bcoin.protocol.constants;
|
||||
var network = bcoin.protocol.network;
|
||||
var bcoin = require('../../bcoin');
|
||||
var utils = bcoin.utils;
|
||||
var assert = utils.assert;
|
||||
|
||||
/**
|
||||
* HTTPServer
|
||||
*/
|
||||
|
||||
function HTTPServer(node, options) {
|
||||
function HTTPServer(options) {
|
||||
var self = this;
|
||||
|
||||
if (!(this instanceof HTTPServer))
|
||||
return new HTTPServer(options);
|
||||
|
||||
if (!options)
|
||||
options = {};
|
||||
|
||||
this.options = options;
|
||||
this.node = node;
|
||||
this.io = null;
|
||||
|
||||
this.routes = {
|
||||
get: [],
|
||||
@ -42,6 +31,8 @@ function HTTPServer(node, options) {
|
||||
del: []
|
||||
};
|
||||
|
||||
this.stack = [];
|
||||
|
||||
this.server = options.key
|
||||
? require('https').createServer(options)
|
||||
: require('http').createServer();
|
||||
@ -55,7 +46,7 @@ HTTPServer.prototype._init = function _init() {
|
||||
var self = this;
|
||||
|
||||
this._initRouter();
|
||||
this._initEngine();
|
||||
this._initIO();
|
||||
|
||||
this.server.on('connection', function(socket) {
|
||||
socket.on('error', function(err) {
|
||||
@ -67,348 +58,30 @@ HTTPServer.prototype._init = function _init() {
|
||||
});
|
||||
});
|
||||
|
||||
this.get('/', function(req, res, next, send) {
|
||||
send(200, {
|
||||
version: require('../../package.json').version,
|
||||
network: self.node.network.type
|
||||
});
|
||||
});
|
||||
|
||||
// UTXO by address
|
||||
this.get('/coin/address/:address', function(req, res, next, send) {
|
||||
var addresses = req.params.address.split(',');
|
||||
self.node.getCoinByAddress(addresses, function(err, coins) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!coins.length)
|
||||
return send(404);
|
||||
|
||||
send(200, coins.map(function(coin) { return coin.toJSON(); }));
|
||||
});
|
||||
});
|
||||
|
||||
// UTXO by id
|
||||
this.get('/coin/:hash/:index', function(req, res, next, send) {
|
||||
req.params.hash = utils.revHex(req.params.hash);
|
||||
self.node.getCoin(req.params.hash, +req.params.index, function(err, coin) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!coin)
|
||||
return send(404);
|
||||
|
||||
send(200, coin.toJSON());
|
||||
});
|
||||
});
|
||||
|
||||
// Bulk read UTXOs
|
||||
this.post('/coin/address', function(req, res, next, send) {
|
||||
self.node.getCoinByAddress(req.body.addresses, function(err, coins) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!coins.length)
|
||||
return send(404);
|
||||
|
||||
send(200, coins.map(function(coin) { return coin.toJSON(); }));
|
||||
});
|
||||
});
|
||||
|
||||
// TX by hash
|
||||
this.get('/tx/:hash', function(req, res, next, send) {
|
||||
req.params.hash = utils.revHex(req.params.hash);
|
||||
self.node.getTX(req.params.hash, function(err, tx) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!tx)
|
||||
return send(404);
|
||||
|
||||
send(200, tx.toJSON());
|
||||
});
|
||||
});
|
||||
|
||||
// TX by address
|
||||
this.get('/tx/address/:address', function(req, res, next, send) {
|
||||
var addresses = req.params.address.split(',');
|
||||
self.node.getTXByAddress(addresses, function(err, txs) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!txs.length)
|
||||
return send(404);
|
||||
|
||||
send(200, txs.map(function(tx) { return tx.toJSON(); }));
|
||||
});
|
||||
});
|
||||
|
||||
// Bulk read TXs
|
||||
this.post('/tx/address', function(req, res, next, send) {
|
||||
self.node.getTXByAddress(req.params.addresses, function(err, txs) {
|
||||
if (err)
|
||||
return next(err);
|
||||
if (!txs.length)
|
||||
return send(404);
|
||||
send(200, txs.map(function(tx) { return tx.toJSON(); }));
|
||||
});
|
||||
});
|
||||
|
||||
// Block by hash/height
|
||||
this.get('/block/:hash', function(req, res, next, send) {
|
||||
var hash = req.params.hash;
|
||||
|
||||
if (utils.isInt(hash))
|
||||
hash = +hash;
|
||||
else
|
||||
hash = utils.revHex(hash);
|
||||
|
||||
self.node.getFullBlock(hash, function(err, block) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!block)
|
||||
return send(404);
|
||||
|
||||
send(200, block.toJSON());
|
||||
});
|
||||
});
|
||||
|
||||
// Get wallet
|
||||
this.get('/wallet/:id', function(req, res, next, send) {
|
||||
self.node.walletdb.getJSON(req.params.id, function(err, json) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!json)
|
||||
return send(404);
|
||||
|
||||
send(200, json);
|
||||
});
|
||||
});
|
||||
|
||||
// Create/get wallet
|
||||
this.post('/wallet/:id', function(req, res, next, send) {
|
||||
req.body.id = req.params.id;
|
||||
self.node.walletdb.create(req.body, function(err, wallet) {
|
||||
var wallet;
|
||||
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!wallet)
|
||||
return send(404);
|
||||
|
||||
json = wallet.toJSON();
|
||||
wallet.destroy();
|
||||
|
||||
send(200, json);
|
||||
});
|
||||
});
|
||||
|
||||
// Update wallet / sync address depth
|
||||
this.put('/wallet/:id', function(req, res, next, send) {
|
||||
var id = req.params.id;
|
||||
var receive = req.body.receiveDepth >>> 0;
|
||||
var change = req.body.changeDepth >>> 0;
|
||||
self.node.walletdb.setDepth(id, receive, change, function(err) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!json)
|
||||
return send(404);
|
||||
|
||||
send(200, { success: true });
|
||||
});
|
||||
});
|
||||
|
||||
// Wallet Balance
|
||||
this.get('/wallet/:id/balance', function(req, res, next, send) {
|
||||
var id = req.params.id;
|
||||
if (id === '_all')
|
||||
id = null;
|
||||
self.node.walletdb.getBalance(req.params.id, function(err, balance) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!coins.length)
|
||||
return send(404);
|
||||
|
||||
send(200, { balance: utils.btc(balance) });
|
||||
});
|
||||
});
|
||||
|
||||
// Wallet UTXOs
|
||||
this.get('/wallet/:id/coin', function(req, res, next, send) {
|
||||
var id = req.params.id;
|
||||
if (id === '_all')
|
||||
id = null;
|
||||
self.node.walletdb.getCoins(req.params.id, function(err, coins) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!coins.length)
|
||||
return send(404);
|
||||
|
||||
send(200, coins.map(function(coin) { return coin.toJSON(); }));
|
||||
});
|
||||
});
|
||||
|
||||
// Wallet TX
|
||||
this.get('/wallet/:id/coin/:hash/:index', function(req, res, next, send) {
|
||||
var id = req.params.id;
|
||||
if (id === '_all')
|
||||
id = null;
|
||||
self.node.walletdb.getCoin(req.params.hash, +req.params.index, function(err, coin) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!coin)
|
||||
return send(404);
|
||||
|
||||
send(200, coin.toJSON());
|
||||
});
|
||||
});
|
||||
|
||||
// Wallet TXs
|
||||
this.get('/wallet/:id/tx/all', function(req, res, next, send) {
|
||||
var id = req.params.id;
|
||||
if (id === '_all')
|
||||
id = null;
|
||||
self.node.walletdb.getAll(req.params.id, function(err, txs) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!txs.length)
|
||||
return send(404);
|
||||
|
||||
send(200, txs.map(function(tx) { return tx.toJSON(); }));
|
||||
});
|
||||
});
|
||||
|
||||
// Wallet Pending TXs
|
||||
this.get('/wallet/:id/tx/pending', function(req, res, next, send) {
|
||||
var id = req.params.id;
|
||||
if (id === '_all')
|
||||
id = null;
|
||||
self.node.walletdb.getPending(req.params.id, function(err, txs) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!txs.length)
|
||||
return send(404);
|
||||
|
||||
send(200, txs.map(function(tx) { return tx.toJSON(); }));
|
||||
});
|
||||
});
|
||||
|
||||
// Wallet TXs within time range
|
||||
this.get('/wallet/:id/tx/range', function(req, res, next, send) {
|
||||
var id = req.params.id;
|
||||
if (id === '_all')
|
||||
id = null;
|
||||
|
||||
var options = {
|
||||
start: +req.query.start,
|
||||
end: +req.query.end,
|
||||
limit: +req.query.limit
|
||||
};
|
||||
|
||||
self.node.walletdb.getTimeRange(req.params.id, options, function(err, txs) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!txs.length)
|
||||
return send(404);
|
||||
|
||||
send(200, txs.map(function(tx) { return tx.toJSON(); }));
|
||||
});
|
||||
});
|
||||
|
||||
// Wallet TXs within time range
|
||||
this.get('/wallet/:id/tx/last', function(req, res, next, send) {
|
||||
var id = req.params.id;
|
||||
if (id === '_all')
|
||||
id = null;
|
||||
|
||||
self.node.walletdb.getTimeRange(id, +req.query.limit, function(err, txs) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!txs.length)
|
||||
return send(404);
|
||||
|
||||
send(200, txs.map(function(tx) { return tx.toJSON(); }));
|
||||
});
|
||||
});
|
||||
|
||||
// Wallet TX
|
||||
this.get('/wallet/:id/tx/:hash', function(req, res, next, send) {
|
||||
self.node.walletdb.getTX(req.params.hash, function(err, tx) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!tx)
|
||||
return send(404);
|
||||
|
||||
send(200, tx.toJSON());
|
||||
});
|
||||
});
|
||||
|
||||
this.post('/broadcast', function(req, res, next, send) {
|
||||
self.node.pool.broadcast(bcoin.tx.fromRaw(req.body.tx, 'hex'));
|
||||
send(200, { success: true });
|
||||
this.server.on('error', function(err) {
|
||||
self.emit('error', err);
|
||||
});
|
||||
};
|
||||
|
||||
HTTPServer.prototype._initEngine = function _initEngine() {
|
||||
HTTPServer.prototype._initIO = function _initIO() {
|
||||
var self = this;
|
||||
var io;
|
||||
|
||||
if (!engine)
|
||||
try {
|
||||
io = require('socket.io');
|
||||
} catch (e) {
|
||||
;
|
||||
}
|
||||
|
||||
if (!io)
|
||||
return;
|
||||
|
||||
this.clients = [];
|
||||
this.io = new io.Server();
|
||||
|
||||
this.engine = new engine.Server();
|
||||
this.io.attach(this.server);
|
||||
|
||||
this.engine.attach(this.server);
|
||||
|
||||
this.engine.on('connection', function(socket) {
|
||||
var s = new Socket(self, socket);
|
||||
|
||||
socket.on('message', function(data) {
|
||||
s.parse(data);
|
||||
});
|
||||
|
||||
socket.on('close', function() {
|
||||
s.destroy();
|
||||
});
|
||||
|
||||
socket.on('error', function(err) {
|
||||
self.emit('error', err);
|
||||
});
|
||||
|
||||
s.on('error', function(err) {
|
||||
self.emit('error', err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
HTTPServer.prototype.listen = function listen(port, host, callback) {
|
||||
var self = this;
|
||||
this.server.listen(port, host, function(err) {
|
||||
var address;
|
||||
|
||||
if (err)
|
||||
throw err;
|
||||
|
||||
address = self.server.address();
|
||||
|
||||
utils.debug('Listening - host=%s port=%d',
|
||||
address.address, address.port);
|
||||
|
||||
if (callback)
|
||||
callback();
|
||||
this.io.on('connection', function(socket) {
|
||||
self.emit('websocket', socket);
|
||||
});
|
||||
};
|
||||
|
||||
@ -485,19 +158,60 @@ HTTPServer.prototype._initRouter = function _initRouter() {
|
||||
req.params[i] = item;
|
||||
});
|
||||
|
||||
// Avoid stack overflows
|
||||
utils.nextTick(function() {
|
||||
try {
|
||||
callback(req, res, next, _send);
|
||||
} catch (e) {
|
||||
done(e);
|
||||
}
|
||||
self._handle(req, res, _send, function(err) {
|
||||
if (err)
|
||||
return done(err);
|
||||
|
||||
// Avoid stack overflows
|
||||
utils.nextTick(function() {
|
||||
try {
|
||||
callback(req, res, next, _send);
|
||||
} catch (e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
})();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
HTTPServer.prototype._handle = function _handle(req, res, _send, callback) {
|
||||
var self = this;
|
||||
var i = 0;
|
||||
var handler;
|
||||
|
||||
(function next(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (i === self.stack.length)
|
||||
return callback();
|
||||
|
||||
handler = self.stack[i++];
|
||||
|
||||
utils.nextTick(function() {
|
||||
if (handler.path && req.pathname.indexOf(handler.path) === -1)
|
||||
return next();
|
||||
|
||||
try {
|
||||
handler.callback(req, res, next, _send);
|
||||
} catch (e) {
|
||||
next(e);
|
||||
}
|
||||
});
|
||||
})();
|
||||
};
|
||||
|
||||
HTTPServer.prototype.use = function use(path, callback) {
|
||||
if (!callback) {
|
||||
callback = path;
|
||||
path = null;
|
||||
}
|
||||
|
||||
this.stack.push({ path: path, callback: callback });
|
||||
};
|
||||
|
||||
HTTPServer.prototype.get = function get(path, callback) {
|
||||
this.routes.get.push({ path: path, callback: callback });
|
||||
};
|
||||
@ -514,37 +228,21 @@ HTTPServer.prototype.del = function del(path, callback) {
|
||||
this.routes.del.push({ path: path, callback: callback });
|
||||
};
|
||||
|
||||
HTTPServer.prototype.sendWebhook = function sendWebhook(msg, callback) {
|
||||
var request, body, secret, hmac;
|
||||
HTTPServer.prototype.listen = function listen(port, host, callback) {
|
||||
var self = this;
|
||||
this.server.listen(port, host, function(err) {
|
||||
var address;
|
||||
|
||||
callback = utils.ensure(callback);
|
||||
|
||||
if (!this.options.webhook)
|
||||
return callback();
|
||||
|
||||
try {
|
||||
request = require('request');
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
|
||||
body = new Buffer(JSON.stringify(msg) + '\n', 'utf8');
|
||||
secret = new Buffer(this.options.webhook.secret || '', 'utf8');
|
||||
hmac = utils.sha512hmac(body, secret);
|
||||
|
||||
request({
|
||||
method: 'POST',
|
||||
uri: this.options.webhook.endpoint,
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
'Content-Length': body.length + '',
|
||||
'X-Bcoin-Hmac': hmac.toString('hex')
|
||||
},
|
||||
body: body
|
||||
}, function(err, res, body) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
return callback();
|
||||
throw err;
|
||||
|
||||
address = self.server.address();
|
||||
|
||||
utils.debug('Listening - host=%s port=%d',
|
||||
address.address, address.port);
|
||||
|
||||
if (callback)
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
@ -558,8 +256,10 @@ function send(res, code, msg) {
|
||||
|
||||
try {
|
||||
res.statusCode = code;
|
||||
msg = JSON.stringify(msg, null, 2) + '\n';
|
||||
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
||||
if (typeof msg === 'object') {
|
||||
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
||||
msg = JSON.stringify(msg, null, 2) + '\n';
|
||||
}
|
||||
res.setHeader('Content-Length', Buffer.byteLength(msg) + '');
|
||||
res.write(msg);
|
||||
res.end();
|
||||
@ -594,6 +294,7 @@ function compilePath(path) {
|
||||
}
|
||||
|
||||
function parseBody(req, callback) {
|
||||
var StringDecoder = require('string_decoder').StringDecoder;
|
||||
var decode = new StringDecoder('utf8');
|
||||
var total = 0;
|
||||
var body = '';
|
||||
@ -661,6 +362,7 @@ function parsePairs(str, del, eq) {
|
||||
}
|
||||
|
||||
function parsePath(req) {
|
||||
var url = require('url');
|
||||
var uri = url.parse(req.url);
|
||||
var pathname = uri.pathname || '/';
|
||||
|
||||
@ -706,215 +408,6 @@ function unescape(str) {
|
||||
}
|
||||
}
|
||||
|
||||
function Socket(server, socket) {
|
||||
this.server = server;
|
||||
this.engine = server.engine;
|
||||
this.node = server.node;
|
||||
this.walletdb = server.node.walletdb;
|
||||
this.socket = socket;
|
||||
this.listeners = {};
|
||||
this._init();
|
||||
}
|
||||
|
||||
Socket.prototype._init = function _init() {
|
||||
this.server.clients.push(this);
|
||||
};
|
||||
|
||||
Socket.prototype.parse = function parse(msg) {
|
||||
var size, off, header, payload;
|
||||
|
||||
size = utils.readIntv(msg, 0);
|
||||
off = size.off;
|
||||
size = size.r;
|
||||
|
||||
if (off + size > msg.length)
|
||||
return this.send({ event: 'error', msg: 'Size larger than message.' });
|
||||
|
||||
try {
|
||||
header = JSON.parse(msg.slice(off, off + size).toString('utf8'));
|
||||
off += size;
|
||||
} catch (e) {
|
||||
return this.send({ event: 'error', msg: 'Header malformed.' });
|
||||
}
|
||||
|
||||
payload = data.slice(off);
|
||||
|
||||
try {
|
||||
return this._handle(header, payload);
|
||||
} catch (e) {
|
||||
return this.send({ event: 'error', msg: e.message + '' });
|
||||
}
|
||||
};
|
||||
|
||||
Socket.prototype._handle = function _handle(header, payload) {
|
||||
if (header.cmd === 'handshake')
|
||||
return this._handleHandshake(header, payload);
|
||||
|
||||
if (header.cmd === 'listen')
|
||||
return this._handleListen(header, payload);
|
||||
|
||||
if (header.cmd === 'unlisten')
|
||||
return this._handleUnlisten(header, payload);
|
||||
|
||||
if (header.event)
|
||||
return this.emit(header.event, header, payload);
|
||||
|
||||
throw new Error('Not a valid command.');
|
||||
};
|
||||
|
||||
Socket.prototype.destroy = function destroy() {
|
||||
this.remove();
|
||||
this.cleanup();
|
||||
return this.clients.destroy();
|
||||
};
|
||||
|
||||
Socket.prototype.remove = function remove() {
|
||||
var i = this.server.clients.indexOf(this);
|
||||
if (i !== -1)
|
||||
this.server.clients.splice(i, 1);
|
||||
};
|
||||
|
||||
Socket.prototype.cleanup = function cleanup() {
|
||||
Object.keys(this.listeners).forEach(function(id) {
|
||||
this.unlistenWallet(id);
|
||||
}, this);
|
||||
};
|
||||
|
||||
Socket.prototype.unlistenWallet = function unlistenWallet(id) {
|
||||
this.listeners[id].forEach(function(listener) {
|
||||
this.walletdb.removeListener(listener[0], listener[1]);
|
||||
}, this);
|
||||
|
||||
delete this.listeners[id];
|
||||
};
|
||||
|
||||
Socket.prototype._listenWallet = function _listenWallet(id, event, listener) {
|
||||
if (!this.listeners[id])
|
||||
this.listeners[id] = [];
|
||||
|
||||
this.listeners[id].push([event, listener]);
|
||||
this.walletdb.on(event, listener);
|
||||
};
|
||||
|
||||
Socket.prototype.listenWallet = function listenWallet(event, id, listener) {
|
||||
if (id === '_all') {
|
||||
this._listenWallet(id, 'tx', function(tx, map) {
|
||||
self.send({ event: 'tx', map: map, id: id, _payload: tx.toExtended() });
|
||||
});
|
||||
|
||||
this._listenWallet(id, 'updated', function(tx, map) {
|
||||
self.send({ event: 'updated', map: map, id: id, _payload: tx.toExtended() });
|
||||
});
|
||||
|
||||
this._listenWallet(id, 'confirmed', function(tx, map) {
|
||||
self.send({ event: 'confirmed', map: map, id: id, _payload: tx.toExtended() });
|
||||
});
|
||||
|
||||
this._listenWallet(id, 'unconfirmed', function(tx, map) {
|
||||
self.send({ event: 'unconfirmed', map: map, id: id, _payload: tx.toExtended() });
|
||||
});
|
||||
|
||||
this._listenWallet(id, 'balances', function(balances) {
|
||||
Object.keys(balances).forEach(function(key) {
|
||||
balances[key] = utils.btc(balances[key]);
|
||||
});
|
||||
self.send({ event: 'balances', id: id, balances: balances });
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this._listenWallet(id, id + ' tx', function(tx) {
|
||||
self.send({ event: 'tx', id: id, _payload: tx.toExtended() });
|
||||
});
|
||||
|
||||
this._listenWallet(id, id + ' updated', function(tx) {
|
||||
self.send({ event: 'updated', id: id, _payload: tx.toExtended() });
|
||||
});
|
||||
|
||||
this._listenWallet(id, id + ' confirmed', function(tx) {
|
||||
self.send({ event: 'confirmed', id: id, _payload: tx.toExtended() });
|
||||
});
|
||||
|
||||
this._listenWallet(id, id + ' unconfirmed', function(tx) {
|
||||
self.send({ event: 'unconfirmed', id: id, _payload: tx.toExtended() });
|
||||
});
|
||||
|
||||
this._listenWallet(id, id + ' balance', function(balance) {
|
||||
self.send({ event: 'balance', id: id, balance: utils.btc(balance) });
|
||||
});
|
||||
};
|
||||
|
||||
Socket.prototype._onListen = function _onListen(header, payload) {
|
||||
var self = this;
|
||||
var id = header.id;
|
||||
|
||||
if (typeof id !== 'string')
|
||||
throw new Error('Wallet ID is not a string.');
|
||||
|
||||
if (id.length > 1000)
|
||||
throw new Error('Wallet ID too large.');
|
||||
|
||||
if (!/^[a-zA-Z0-9]+$/.test(id))
|
||||
throw new Error('Wallet ID must be alphanumeric.');
|
||||
|
||||
if (this.listeners[id])
|
||||
throw new Error('Already listening.');
|
||||
|
||||
this.listenWallet(id);
|
||||
};
|
||||
|
||||
Socket.prototype._onUnlisten = function _onUnlisten(header, payload) {
|
||||
var self = this;
|
||||
var id = header.id;
|
||||
|
||||
if (typeof id !== 'string')
|
||||
throw new Error('Wallet ID is not a string.');
|
||||
|
||||
if (id.length > 1000)
|
||||
throw new Error('Wallet ID too large.');
|
||||
|
||||
if (!/^[a-zA-Z0-9]+$/.test(id))
|
||||
throw new Error('Wallet ID must be alphanumeric.');
|
||||
|
||||
if (!this.listeners[id])
|
||||
throw new Error('Not listening.');
|
||||
|
||||
this.unlistenWallet(id);
|
||||
};
|
||||
|
||||
Socket.prototype._handleHandshake = function _handleHandshake(header, payload) {
|
||||
if (this._activated)
|
||||
throw new Error('Handshake already completed.');
|
||||
|
||||
if (payload.length > 0)
|
||||
throw new Error('Unexpected payload.');
|
||||
|
||||
this._activated = true;
|
||||
};
|
||||
|
||||
Socket.prototype.send = function send(data) {
|
||||
var header, payload, size, msg;
|
||||
|
||||
if (data._payload) {
|
||||
payload = data._payload;
|
||||
delete data._payload;
|
||||
} else {
|
||||
payload = new Buffer([]);
|
||||
}
|
||||
|
||||
assert(Buffer.isBuffer(payload));
|
||||
|
||||
header = new Buffer(JSON.stringify(data), 'utf8');
|
||||
|
||||
size = new Buffer(utils.sizeIntv(header.length));
|
||||
utils.writeIntv(size, header.length, 0);
|
||||
|
||||
msg = Buffer.concat([size, header, payload]);
|
||||
|
||||
return this.socket.send(msg);
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose
|
||||
*/
|
||||
|
||||
4
lib/bcoin/http/index.js
Normal file
4
lib/bcoin/http/index.js
Normal file
@ -0,0 +1,4 @@
|
||||
exports.http = require('./http');
|
||||
exports.server = require('./server');
|
||||
exports.client = require('./client');
|
||||
exports.request = require('./request');
|
||||
125
lib/bcoin/http/provider.js
Normal file
125
lib/bcoin/http/provider.js
Normal file
@ -0,0 +1,125 @@
|
||||
/**
|
||||
* provider.js - http provider for wallets
|
||||
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
|
||||
* https://github.com/indutny/bcoin
|
||||
*/
|
||||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
|
||||
var bcoin = require('../bcoin');
|
||||
var bn = require('bn.js');
|
||||
var constants = bcoin.protocol.constants;
|
||||
var network = bcoin.protocol.network;
|
||||
var utils = bcoin.utils;
|
||||
var assert = utils.assert;
|
||||
var Client = require('./client');
|
||||
|
||||
/**
|
||||
* Provider
|
||||
*/
|
||||
|
||||
function Provider(url) {
|
||||
if (!(this instanceof Provider))
|
||||
return new Provider(url);
|
||||
|
||||
EventEmitter.call(this);
|
||||
|
||||
this.client = new Client(url);
|
||||
this.url = url;
|
||||
this.id = null;
|
||||
this._init();
|
||||
}
|
||||
|
||||
utils.inherits(Provider, EventEmitter);
|
||||
|
||||
Provider.prototype._init = function _init() {
|
||||
var self = this;
|
||||
|
||||
this.client.on('tx', function(tx) {
|
||||
self.emit('tx', tx);
|
||||
});
|
||||
|
||||
this.client.on('confirmed', function(tx) {
|
||||
self.emit('confirmed', tx);
|
||||
});
|
||||
|
||||
this.client.on('updated', function(tx) {
|
||||
self.emit('updated', tx);
|
||||
});
|
||||
|
||||
this.client.on('balance', function(balance) {
|
||||
self.emit('balance', balance);
|
||||
});
|
||||
|
||||
this.client.on('error', function(err) {
|
||||
self.emit('error', err);
|
||||
});
|
||||
};
|
||||
|
||||
Provider.prototype.setID = function setID(id) {
|
||||
assert(!this.id)
|
||||
this.id = id;
|
||||
this.client.listenWallet(id);
|
||||
};
|
||||
|
||||
Provider.prototype.destroy = function destroy() {
|
||||
this.client.destroy();
|
||||
this.client = null;
|
||||
};
|
||||
|
||||
Provider.prototype.getAll = function getAll(callback) {
|
||||
return this.client.getWalletAll(this.id, callback);
|
||||
};
|
||||
|
||||
Provider.prototype.getCoins = function getCoins(callback) {
|
||||
return this.client.getWalletCoins(this.id, callback);
|
||||
};
|
||||
|
||||
Provider.prototype.getPending = function getPending(callback) {
|
||||
return this.client.getWalletPending(this.id, callback);
|
||||
};
|
||||
|
||||
Provider.prototype.getBalance = function getBalance(callback) {
|
||||
return this.client.getWalletBalance(this.id, callback);
|
||||
};
|
||||
|
||||
Provider.prototype.getLastTime = function getLastTime(callback) {
|
||||
assert(false);
|
||||
};
|
||||
|
||||
Provider.prototype.getLast = function getLast(limit, callback) {
|
||||
return this.client.getWalletLast(this.id, limit, callback);
|
||||
};
|
||||
|
||||
Provider.prototype.getRange = function getRange(options, callback) {
|
||||
return this.client.getWalletRange(this.id, options, callback);
|
||||
};
|
||||
|
||||
Provider.prototype.getTX = function getTX(hash, callback) {
|
||||
return this.client.getWalletTX(this.id, hash, callback);
|
||||
};
|
||||
|
||||
Provider.prototype.getCoin = function getCoin(hash, index, callback) {
|
||||
return this.client.getWalletCoin(this.id, hash, index, callback);
|
||||
};
|
||||
|
||||
Provider.prototype.fillTX = function fillTX(tx, callback) {
|
||||
assert(false);
|
||||
};
|
||||
|
||||
Provider.prototype.fillCoin = function fillCoin(tx, callback) {
|
||||
assert(false);
|
||||
};
|
||||
|
||||
Provider.prototype.sync = function sync(wallet, address) {
|
||||
return this.client.syncWallet(this.id, wallet, function(err) {
|
||||
if (err)
|
||||
self.emit('error', err);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose
|
||||
*/
|
||||
|
||||
module.exports = WalletDB;
|
||||
@ -1,13 +1,24 @@
|
||||
var StringDecoder = require('string_decoder').StringDecoder;
|
||||
/**
|
||||
* request.js - http request for bcoin
|
||||
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
|
||||
* https://github.com/indutny/bcoin
|
||||
*/
|
||||
|
||||
var Stream = require('stream').Stream;
|
||||
var qs = require('querystring');
|
||||
var url = require('url');
|
||||
|
||||
// Spoof by default
|
||||
var USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1)'
|
||||
+ ' AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36';
|
||||
|
||||
/**
|
||||
* Request
|
||||
*/
|
||||
|
||||
function request(options, callback, stream) {
|
||||
var StringDecoder = require('string_decoder').StringDecoder;
|
||||
var qs = require('querystring');
|
||||
var url = require('url');
|
||||
|
||||
var uri = options.uri;
|
||||
var query = options.query;
|
||||
var body = options.body;
|
||||
@ -57,7 +68,8 @@ function request(options, callback, stream) {
|
||||
path: uri.pathname + query,
|
||||
headers: {
|
||||
'User-Agent': options.agent || USER_AGENT
|
||||
}
|
||||
},
|
||||
rejectUnauthorized: options.strictSSL !== false
|
||||
};
|
||||
|
||||
if (body) {
|
||||
@ -99,6 +111,14 @@ function request(options, callback, stream) {
|
||||
opt.method = options.method || 'GET';
|
||||
}
|
||||
|
||||
if (options.auth)
|
||||
uri.auth = options.auth.username + ':' + options.auth.password;
|
||||
|
||||
if (uri.auth) {
|
||||
opt.headers['Authorization'] =
|
||||
'Basic ' + new Buffer(uri.auth, 'utf8').toString('base64');
|
||||
}
|
||||
|
||||
opt.method = opt.method.toUpperCase();
|
||||
|
||||
req = http.request(opt);
|
||||
@ -246,8 +266,16 @@ request._buffer = function(options, callback) {
|
||||
return stream;
|
||||
};
|
||||
|
||||
/**
|
||||
* ReqStream
|
||||
*/
|
||||
|
||||
function ReqStream(options) {
|
||||
if (!(this instanceof ReqStream))
|
||||
return new ReqStream(options);
|
||||
|
||||
Stream.call(this);
|
||||
|
||||
this.req = null;
|
||||
this.res = null;
|
||||
this.headers = null;
|
||||
@ -277,3 +305,9 @@ ReqStream.prototype.destroy = function destroy() {
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose
|
||||
*/
|
||||
|
||||
module.exports = request;
|
||||
|
||||
459
lib/bcoin/http/server.js
Normal file
459
lib/bcoin/http/server.js
Normal file
@ -0,0 +1,459 @@
|
||||
/**
|
||||
* server.js - http server for bcoin
|
||||
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
|
||||
* https://github.com/indutny/bcoin
|
||||
*/
|
||||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var bcoin = require('../../bcoin');
|
||||
var HTTPServer = require('./http');
|
||||
var constants = bcoin.protocol.constants;
|
||||
var network = bcoin.protocol.network;
|
||||
var utils = bcoin.utils;
|
||||
var assert = utils.assert;
|
||||
|
||||
/**
|
||||
* NodeServer
|
||||
*/
|
||||
|
||||
function NodeServer(node, options) {
|
||||
var self = this;
|
||||
|
||||
if (!options)
|
||||
options = {};
|
||||
|
||||
this.options = options;
|
||||
this.node = node;
|
||||
this.walletdb = node.walletdb;
|
||||
this.pool = node.pool;
|
||||
|
||||
this.server = new HTTPServer(options);
|
||||
this.io = null;
|
||||
|
||||
this._init();
|
||||
}
|
||||
|
||||
utils.inherits(NodeServer, EventEmitter);
|
||||
|
||||
NodeServer.prototype._init = function _init() {
|
||||
var self = this;
|
||||
|
||||
this.use(function(req, res, next, send) {
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
||||
res.setHeader(
|
||||
'Access-Control-Allow-Methods',
|
||||
'GET,HEAD,PUT,PATCH,POST,DELETE');
|
||||
|
||||
if (req.method === 'OPTIONS')
|
||||
return send(200);
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
this.use(function(req, res, next, send) {
|
||||
var params = utils.merge({}, req.query, req.body, req.params);
|
||||
var options = {};
|
||||
|
||||
if (params.id) {
|
||||
assert(params.id !== '!all');
|
||||
options.id = params.id;
|
||||
}
|
||||
|
||||
if (params.hash) {
|
||||
if (utils.isInt(params.hash))
|
||||
options.height = params.hash >>> 0;
|
||||
else
|
||||
options.hash = utils.revHex(params.hash);
|
||||
}
|
||||
|
||||
if (params.index != null)
|
||||
options.index = params.index >>> 0;
|
||||
|
||||
if (params.height != null)
|
||||
options.height = params.height >>> 0;
|
||||
|
||||
if (params.start != null)
|
||||
options.start = params.start >>> 0;
|
||||
|
||||
if (params.end != null)
|
||||
options.end = params.end >>> 0;
|
||||
|
||||
if (params.limit != null)
|
||||
options.limit = params.limit >>> 0;
|
||||
|
||||
if (params.changeDepth)
|
||||
options.changeDepth = params.changeDepth >>> 0;
|
||||
|
||||
if (params.receiveDepth)
|
||||
options.receiveDepth = params.receiveDepth >>> 0;
|
||||
|
||||
if (params.address)
|
||||
params.addresses = params.address;
|
||||
|
||||
if (params.addresses) {
|
||||
if (typeof params.addresses === 'string')
|
||||
options.addresses = params.addresses.split(',');
|
||||
else
|
||||
options.addresses = params.addresses;
|
||||
}
|
||||
|
||||
if (params.tx) {
|
||||
try {
|
||||
options.tx = bcoin.tx.fromRaw(params.tx, 'hex');
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (params.bin)
|
||||
options.bin = true;
|
||||
|
||||
req.options = options;
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
this.get('/', function(req, res, next, send) {
|
||||
send(200, {
|
||||
version: require('../../../package.json').version,
|
||||
network: self.node.network.type
|
||||
});
|
||||
});
|
||||
|
||||
// UTXO by address
|
||||
this.get('/coin/address/:address', function(req, res, next, send) {
|
||||
self.node.getCoinByAddress(req.options.addresses, function(err, coins) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!coins.length)
|
||||
return send(404);
|
||||
|
||||
send(200, coins.map(function(coin) { return coin.toJSON(); }));
|
||||
});
|
||||
});
|
||||
|
||||
// UTXO by id
|
||||
this.get('/coin/:hash/:index', function(req, res, next, send) {
|
||||
self.node.getCoin(req.options.hash, req.options.index, function(err, coin) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!coin)
|
||||
return send(404);
|
||||
|
||||
send(200, coin.toJSON());
|
||||
});
|
||||
});
|
||||
|
||||
// Bulk read UTXOs
|
||||
this.post('/coin/address', function(req, res, next, send) {
|
||||
self.node.getCoinByAddress(req.body.addresses, function(err, coins) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!coins.length)
|
||||
return send(404);
|
||||
|
||||
send(200, coins.map(function(coin) { return coin.toJSON(); }));
|
||||
});
|
||||
});
|
||||
|
||||
// TX by hash
|
||||
this.get('/tx/:hash', function(req, res, next, send) {
|
||||
self.node.getTX(req.options.hash, function(err, tx) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!tx)
|
||||
return send(404);
|
||||
|
||||
send(200, tx.toJSON());
|
||||
});
|
||||
});
|
||||
|
||||
// TX by address
|
||||
this.get('/tx/address/:address', function(req, res, next, send) {
|
||||
self.node.getTXByAddress(req.options.addresses, function(err, txs) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!txs.length)
|
||||
return send(404);
|
||||
|
||||
send(200, txs.map(function(tx) { return tx.toJSON(); }));
|
||||
});
|
||||
});
|
||||
|
||||
// Bulk read TXs
|
||||
this.post('/tx/address', function(req, res, next, send) {
|
||||
self.node.getTXByAddress(req.body.addresses, function(err, txs) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!txs.length)
|
||||
return send(404);
|
||||
|
||||
send(200, txs.map(function(tx) { return tx.toJSON(); }));
|
||||
});
|
||||
});
|
||||
|
||||
// Block by hash/height
|
||||
this.get('/block/:hash', function(req, res, next, send) {
|
||||
var hash = req.options.hash || req.options.height;
|
||||
self.node.getFullBlock(hash, function(err, block) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!block)
|
||||
return send(404);
|
||||
|
||||
send(200, block.toJSON());
|
||||
});
|
||||
});
|
||||
|
||||
// Get wallet
|
||||
this.get('/wallet/:id', function(req, res, next, send) {
|
||||
self.walletdb.getJSON(req.options.id, function(err, json) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!json)
|
||||
return send(404);
|
||||
|
||||
send(200, json);
|
||||
});
|
||||
});
|
||||
|
||||
// Create/get wallet
|
||||
this.post('/wallet/:id', function(req, res, next, send) {
|
||||
self.walletdb.create(req.options, function(err, wallet) {
|
||||
var json;
|
||||
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!wallet)
|
||||
return send(404);
|
||||
|
||||
json = wallet.toJSON();
|
||||
wallet.destroy();
|
||||
|
||||
send(200, json);
|
||||
});
|
||||
});
|
||||
|
||||
// Update wallet / sync address depth
|
||||
this.put('/wallet/:id', function(req, res, next, send) {
|
||||
var id = req.options.id;
|
||||
var receive = req.options.receiveDepth;
|
||||
var change = req.options.changeDepth;
|
||||
|
||||
self.walletdb.setDepth(id, receive, change, function(err) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!json)
|
||||
return send(404);
|
||||
|
||||
send(200, { success: true });
|
||||
});
|
||||
});
|
||||
|
||||
// Wallet Balance
|
||||
this.get('/wallet/:id/balance', function(req, res, next, send) {
|
||||
self.walletdb.getBalance(req.options.id, function(err, balance) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!coins.length)
|
||||
return send(404);
|
||||
|
||||
send(200, { balance: utils.btc(balance) });
|
||||
});
|
||||
});
|
||||
|
||||
// Wallet UTXOs
|
||||
this.get('/wallet/:id/coin', function(req, res, next, send) {
|
||||
self.walletdb.getCoins(req.options.id, function(err, coins) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!coins.length)
|
||||
return send(404);
|
||||
|
||||
send(200, coins.map(function(coin) { return coin.toJSON(); }));
|
||||
});
|
||||
});
|
||||
|
||||
// Wallet TX
|
||||
this.get('/wallet/:id/coin/:hash/:index', function(req, res, next, send) {
|
||||
self.walletdb.getCoin(req.options.hash, req.options.index, function(err, coin) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!coin)
|
||||
return send(404);
|
||||
|
||||
send(200, coin.toJSON());
|
||||
});
|
||||
});
|
||||
|
||||
// Wallet TXs
|
||||
this.get('/wallet/:id/tx/all', function(req, res, next, send) {
|
||||
self.walletdb.getAll(req.options.id, function(err, txs) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!txs.length)
|
||||
return send(404);
|
||||
|
||||
send(200, txs.map(function(tx) { return tx.toJSON(); }));
|
||||
});
|
||||
});
|
||||
|
||||
// Wallet Pending TXs
|
||||
this.get('/wallet/:id/tx/pending', function(req, res, next, send) {
|
||||
self.walletdb.getPending(req.options.id, function(err, txs) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!txs.length)
|
||||
return send(404);
|
||||
|
||||
send(200, txs.map(function(tx) { return tx.toJSON(); }));
|
||||
});
|
||||
});
|
||||
|
||||
// Wallet TXs within time range
|
||||
this.get('/wallet/:id/tx/range', function(req, res, next, send) {
|
||||
self.walletdb.getRange(req.options.id, req.options, function(err, txs) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!txs.length)
|
||||
return send(404);
|
||||
|
||||
send(200, txs.map(function(tx) { return tx.toJSON(); }));
|
||||
});
|
||||
});
|
||||
|
||||
// Wallet TXs within time range
|
||||
this.get('/wallet/:id/tx/last', function(req, res, next, send) {
|
||||
self.walletdb.getRange(req.options.id, req.options.limit, function(err, txs) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!txs.length)
|
||||
return send(404);
|
||||
|
||||
send(200, txs.map(function(tx) { return tx.toJSON(); }));
|
||||
});
|
||||
});
|
||||
|
||||
// Wallet TX
|
||||
this.get('/wallet/:id/tx/:hash', function(req, res, next, send) {
|
||||
self.walletdb.getTX(req.options.hash, function(err, tx) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!tx)
|
||||
return send(404);
|
||||
|
||||
send(200, tx.toJSON());
|
||||
});
|
||||
});
|
||||
|
||||
// Broadcast TX
|
||||
this.post('/broadcast', function(req, res, next, send) {
|
||||
var tx = req.options.tx;
|
||||
self.pool.broadcast(tx);
|
||||
send(200, { success: true });
|
||||
});
|
||||
|
||||
this.server.on('error', function(err) {
|
||||
self.emit('error', err);
|
||||
});
|
||||
|
||||
this._initIO();
|
||||
};
|
||||
|
||||
NodeServer.prototype._initIO = function _initIO() {
|
||||
if (!this.server.io)
|
||||
return;
|
||||
|
||||
this.server.on('websocket', function(socket) {
|
||||
socket.on('error', function(err) {
|
||||
self.emit('error', err);
|
||||
});
|
||||
self.emit('websocket', socket);
|
||||
});
|
||||
|
||||
this.walletdb.on('tx', function(tx, map) {
|
||||
tx = tx.toJSON();
|
||||
map.all.forEach(function(id) {
|
||||
self.server.io.to(id).emit('tx', tx);
|
||||
});
|
||||
self.server.io.to('!all').emit('tx', tx, map);
|
||||
});
|
||||
|
||||
this.walletdb.on('confirmed', function(tx, map) {
|
||||
tx = tx.toJSON();
|
||||
map.all.forEach(function(id) {
|
||||
self.server.io.to(id).emit('confirmed', tx);
|
||||
});
|
||||
self.server.io.to('!all').emit('confirmed', tx, map);
|
||||
});
|
||||
|
||||
this.walletdb.on('updated', function(tx, map) {
|
||||
tx = tx.toJSON();
|
||||
map.all.forEach(function(id) {
|
||||
self.server.io.to(id).emit('updated', tx);
|
||||
});
|
||||
self.server.io.to('!all').emit('updated', tx, map);
|
||||
});
|
||||
|
||||
this.walletdb.on('balance', function(balance, id) {
|
||||
balance = utils.btc(balance);
|
||||
self.server.io.to(id).emit('balance', balance);
|
||||
self.server.io.to('!all').emit('balance', balance, id);
|
||||
});
|
||||
|
||||
this.walletdb.on('balances', function(balances) {
|
||||
Object.keys(balances).forEach(function(id) {
|
||||
balances[id] = utils.btc(balances[id]);
|
||||
});
|
||||
self.server.io.to('!all').emit('balances', balances);
|
||||
});
|
||||
};
|
||||
|
||||
NodeServer.prototype.use = function use(path, callback) {
|
||||
return this.server.use(path, callback);
|
||||
};
|
||||
|
||||
NodeServer.prototype.get = function get(path, callback) {
|
||||
return this.server.get(path, callback);
|
||||
};
|
||||
|
||||
NodeServer.prototype.post = function post(path, callback) {
|
||||
return this.server.post(path, callback);
|
||||
};
|
||||
|
||||
NodeServer.prototype.put = function put(path, callback) {
|
||||
return this.server.put(path, callback);
|
||||
};
|
||||
|
||||
NodeServer.prototype.del = function del(path, callback) {
|
||||
return this.server.del(path, callback);
|
||||
};
|
||||
|
||||
NodeServer.prototype.listen = function listen(port, host, callback) {
|
||||
return this.server.listen(port, host, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose
|
||||
*/
|
||||
|
||||
module.exports = NodeServer;
|
||||
@ -75,16 +75,13 @@ Fullnode.prototype._init = function _init() {
|
||||
});
|
||||
|
||||
// WalletDB needs access to the network type.
|
||||
this.walletdb = new bcoin.walletdb(this, {
|
||||
type: this.options.walletdb
|
||||
});
|
||||
this.walletdb = new bcoin.walletdb(this);
|
||||
|
||||
// HTTP needs access to the mempool
|
||||
// and blockdb.
|
||||
this.http = new bcoin.http(this, {
|
||||
key: this.options.httpKey,
|
||||
cert: this.options.httpCert,
|
||||
webhook: this.options.webhook
|
||||
this.http = new bcoin.http.server(this, {
|
||||
key: this.options.sslKey,
|
||||
cert: this.options.sslCert
|
||||
});
|
||||
|
||||
// Bind to errors
|
||||
@ -100,6 +97,10 @@ Fullnode.prototype._init = function _init() {
|
||||
self.emit('error', err);
|
||||
});
|
||||
|
||||
this.http.on('error', function(err) {
|
||||
self.emit('error', err);
|
||||
});
|
||||
|
||||
this.walletdb.on('error', function(err) {
|
||||
self.emit('error', err);
|
||||
});
|
||||
|
||||
@ -1106,7 +1106,7 @@ TX.prototype.toExtended = function toExtended(coins) {
|
||||
return;
|
||||
}
|
||||
|
||||
coin = bcoin.protocol.framer.coin(input.output, true);
|
||||
coin = bcoin.protocol.framer.coin(input.output);
|
||||
off += utils.writeIntv(buf, coin.length, off);
|
||||
off += utils.copy(coin, buf, off);
|
||||
});
|
||||
@ -1166,7 +1166,11 @@ TX._fromExtended = function _fromExtended(buf, coins) {
|
||||
off += chunkSize;
|
||||
if (coin.length === 0)
|
||||
continue;
|
||||
tx.inputs[i].output = bcoin.protocol.parser.parseCoin(coin, true);
|
||||
coin = bcoin.protocol.parser.parseCoin(coin);
|
||||
coin.hash = tx.inputs[i].prevout.hash;
|
||||
coin.index = tx.inputs[i].prevout.index;
|
||||
coin.spent = false;
|
||||
tx.inputs[i].output = coin;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1048,7 +1048,7 @@ TXPool.prototype.getHeightHashes = function getHeightHashes(height, callback) {
|
||||
return this.getHeightRangeHashes({ start: height, end: height }, callback);
|
||||
};
|
||||
|
||||
TXPool.prototype.getTimeRangeHashes = function getTimeRangeHashes(address, options, callback) {
|
||||
TXPool.prototype.getRangeHashes = function getRangeHashes(address, options, callback) {
|
||||
var prefix = this.prefix + '/';
|
||||
var self = this;
|
||||
var txs = [];
|
||||
@ -1097,11 +1097,11 @@ TXPool.prototype.getTimeRangeHashes = function getTimeRangeHashes(address, optio
|
||||
})();
|
||||
};
|
||||
|
||||
TXPool.prototype.getTimeRange = function getLast(address, options, callback) {
|
||||
TXPool.prototype.getRange = function getLast(address, options, callback) {
|
||||
var self = this;
|
||||
var txs = [];
|
||||
|
||||
return this.getTimeRangeHashes(address, options, function(err, hashes) {
|
||||
return this.getRangeHashes(address, options, function(err, hashes) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
@ -1127,7 +1127,7 @@ TXPool.prototype.getTimeRange = function getLast(address, options, callback) {
|
||||
};
|
||||
|
||||
TXPool.prototype.getLast = function getLast(address, limit, callback) {
|
||||
return this.getTimeRange(address, {
|
||||
return this.getRange(address, {
|
||||
start: 0,
|
||||
end: 0xffffffff,
|
||||
reverse: true,
|
||||
|
||||
@ -134,6 +134,10 @@ Wallet.prototype._init = function _init() {
|
||||
|
||||
this.provider.setID(this.id);
|
||||
|
||||
this.provider.on('error', function(err) {
|
||||
utils.debug('Wallet Error: %s', err.message);
|
||||
});
|
||||
|
||||
this.provider.on('tx', function(tx) {
|
||||
self.emit('tx', tx);
|
||||
});
|
||||
|
||||
@ -161,13 +161,14 @@ WalletDB.prototype._init = function _init() {
|
||||
|
||||
balances[id] = balance;
|
||||
|
||||
self.emit('balance', balance, id);
|
||||
self.emit(id + ' balance', balance);
|
||||
});
|
||||
}, function(err) {
|
||||
if (err)
|
||||
self.emit('error', err);
|
||||
|
||||
self.emit('balances', balances);
|
||||
self.emit('balances', balances, map);
|
||||
});
|
||||
|
||||
// Only sync for confirmed txs.
|
||||
@ -551,10 +552,10 @@ WalletDB.prototype.getLast = function getLast(id, limit, callback) {
|
||||
return this.tx.getLast(id, limit, callback);
|
||||
};
|
||||
|
||||
WalletDB.prototype.getTimeRange = function getTimeRange(id, options, callback) {
|
||||
WalletDB.prototype.getRange = function getRange(id, options, callback) {
|
||||
var self = this;
|
||||
id = id.id || id;
|
||||
return this.tx.getTimeRange(id, options, callback);
|
||||
return this.tx.getRange(id, options, callback);
|
||||
};
|
||||
|
||||
WalletDB.prototype.fillTX = function fillTX(tx, callback) {
|
||||
@ -689,8 +690,8 @@ Provider.prototype.getLast = function getLast(limit, callback) {
|
||||
return this.db.getLast(this.id, limit, callback);
|
||||
};
|
||||
|
||||
Provider.prototype.getTimeRange = function getTimeRange(options, callback) {
|
||||
return this.db.getTimeRange(this.id, options, callback);
|
||||
Provider.prototype.getRange = function getRange(options, callback) {
|
||||
return this.db.getRange(this.id, options, callback);
|
||||
};
|
||||
|
||||
Provider.prototype.getTX = function getTX(hash, callback) {
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
"scripts": {
|
||||
"test": "rm -rf ~/.bcoin-test && BCOIN_PREFIX=~/.bcoin-test mocha --reporter spec test/*-test.js"
|
||||
},
|
||||
"repository": "git://github.com/indutny/bcoin.git",
|
||||
"repository": "git://github.com/bcoin-org/bcoin.git",
|
||||
"keywords": [
|
||||
"bitcoin",
|
||||
"blockchain",
|
||||
@ -35,7 +35,7 @@
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"secp256k1": "3.0.0",
|
||||
"request": "2.67.0"
|
||||
"socket.io": "1.45.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"hash.js": "1.0.3",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user