balance. http.

This commit is contained in:
Christopher Jeffrey 2016-03-31 16:17:10 -07:00
parent b0e6826232
commit 8346cccbcb
8 changed files with 275 additions and 103 deletions

View File

@ -13,13 +13,14 @@ var request = require('./request');
* Client
*/
function Client(uri) {
function Client(uri, passphrase) {
if (!(this instanceof Client))
return new Client(uri);
EventEmitter.call(this);
this.uri = uri;
this.passphrase = passphrase;
this.loaded = false;
this.id = null;
this._init();
@ -44,24 +45,46 @@ Client.prototype._init = function _init() {
this.socket.on('open', function() {
self.socket.on('tx', function(tx, map) {
self.emit('tx', bcoin.tx.fromJSON(tx), map);
try {
tx = bcoin.tx.fromJSON(tx);
} catch (e) {
return self.emit('error', e);
}
self.emit('tx', tx, map);
});
self.socket.on('confirmed', function(tx, map) {
self.emit('confirmed', bcoin.tx.fromJSON(tx), map);
try {
tx = bcoin.tx.fromJSON(tx);
} catch (e) {
return self.emit('error', e);
}
self.emit('confirmed', tx, map);
});
self.socket.on('updated', function(tx, map) {
self.emit('updated', bcoin.tx.fromJSON(tx), map);
try {
tx = bcoin.tx.fromJSON(tx);
} catch (e) {
return self.emit('error', e);
}
self.emit('updated', tx, map);
});
self.socket.on('balance', function(balance, id) {
self.emit('balance', utils.satoshi(balance), id);
self.emit('balance', {
confirmed: utils.satoshi(balance.confirmed),
unconfirmed: utils.satoshi(balance.unconfirmed)
}, id);
});
self.socket.on('balances', function(balances) {
Object.keys(balances).forEach(function(id) {
balances[id] = utils.satoshi(balances[id]);
self.socket.on('balances', function(json) {
var balances = {};
Object.keys(json).forEach(function(id) {
balances[id] = {
confirmed: utils.satoshi(json[id].confirmed),
unconfirmed: utils.satoshi(json[id].unconfirmed)
};
});
self.emit('balances', balances);
});
@ -98,9 +121,17 @@ Client.prototype.unlistenAll = function unlistenAll() {
this.unlistenWallet('!all');
};
Client.prototype.destroy = function destroy() {
Client.prototype.close =
Client.prototype.destroy = function destroy(callback) {
callback = utils.ensure(callback);
if (!this.socket)
return utils.nextTick(callback);
this.socket.destroy();
this.socket = null;
return utils.nextTick(callback);
};
Client.prototype._request = function _request(method, endpoint, json, callback) {
@ -111,6 +142,9 @@ Client.prototype._request = function _request(method, endpoint, json, callback)
json = null;
}
if (json)
json.passphrase = this.passphrase;
if (json && method === 'get') {
json = null;
query = json;
@ -167,9 +201,15 @@ Client.prototype.getWalletAll = function getWalletAll(id, callback) {
if (!body)
return callback(null, []);
return callback(null, body.map(function(data) {
return bcoin.tx.fromJSON(data);
}));
try {
body = body.map(function(data) {
return bcoin.tx.fromJSON(data);
});
} catch (e) {
return callback(e);
}
return callback(null, body);
});
};
@ -181,9 +221,15 @@ Client.prototype.getWalletCoins = function getWalletCoins(id, callback) {
if (!body)
return callback(null, []);
return callback(null, body.map(function(data) {
return bcoin.coin.fromJSON(data);
}));
try {
body = body.map(function(data) {
return bcoin.coin.fromJSON(data);
});
} catch (e) {
return callback(e);
}
return callback(null, body);
});
};
@ -195,9 +241,15 @@ Client.prototype.getWalletPending = function getPending(id, callback) {
if (!body)
return callback(null, []);
return callback(null, body.map(function(data) {
return bcoin.coin.fromJSON(data);
}));
try {
body = body.map(function(data) {
return bcoin.coin.fromJSON(data);
});
} catch (e) {
return callback(e);
}
return callback(null, body);
});
};
@ -209,7 +261,10 @@ Client.prototype.getWalletBalance = function getBalance(id, callback) {
if (!body)
return callback(new Error('Not found.'));
return callback(null, utils.satoshi(body.balance));
return callback(null, {
confirmed: utils.satoshi(body.balance.confirmed),
unconfirmed: utils.satoshi(body.balance.unconfirmed)
});
});
};
@ -222,9 +277,15 @@ Client.prototype.getWalletLast = function getLast(id, limit, callback) {
if (!body)
return callback(null, []);
return callback(null, body.map(function(data) {
return bcoin.tx.fromJSON(data);
}));
try {
body = body.map(function(data) {
return bcoin.tx.fromJSON(data);
});
} catch (e) {
return callback(e);
}
return callback(null, body);
});
};
@ -236,9 +297,15 @@ Client.prototype.getWalletRange = function getWalletRange(id, options, callback)
if (!body)
return callback(null, []);
return callback(null, body.map(function(data) {
return bcoin.tx.fromJSON(data);
}));
try {
body = body.map(function(data) {
return bcoin.tx.fromJSON(data);
});
} catch (e) {
return callback(e);
}
return callback(null, body);
});
};
@ -252,21 +319,36 @@ Client.prototype.getWalletTX = function getTX(id, hash, callback) {
if (!body)
return callback(null, []);
return callback(null, bcoin.tx.fromJSON(body));
try {
body = bcoin.tx.fromJSON(body);
} catch (e) {
return callback(e);
}
return callback(null, body);
});
};
Client.prototype.getWalletCoin = function getCoin(id, hash, index, callback) {
hash = utils.revHex(hash);
var path;
return this._get('/wallet/' + id + '/coin/' + hash + '/' + index, function(err, body) {
hash = utils.revHex(hash);
path = '/wallet/' + id + '/coin/' + hash + '/' + index;
return this._get(path, function(err, body) {
if (err)
return callback(err);
if (!body)
return callback(null, []);
return callback(null, bcoin.coin.fromJSON(body));
try {
body = bcoin.coin.fromJSON(body);
} catch (e) {
return callback(e);
}
return callback(null, body);
});
};
@ -293,9 +375,15 @@ Client.prototype.getCoinsByAddress = function getCoinsByAddress(address, callbac
if (!body)
return callback(null, []);
return callback(null, body.map(function(data) {
return bcoin.coin.fromJSON(data);
}));
try {
body = body.map(function(data) {
return bcoin.coin.fromJSON(data);
});
} catch (e) {
return callback(e);
}
return callback(null, body);
});
};
@ -307,9 +395,15 @@ Client.prototype.getCoin = function getCoin(hash, index, callback) {
return callback(err);
if (!body)
return callback(null, []);
return callback();
return callback(null, bcoin.coin.fromJSON(body));
try {
body = bcoin.coin.fromJSON(body);
} catch (e) {
return callback(e);
}
return callback(null, body);
});
};
@ -323,9 +417,15 @@ Client.prototype.getTXByAddress = function getTXByAddress(address, callback) {
if (!body)
return callback(null, []);
return callback(null, body.map(function(data) {
return bcoin.tx.fromJSON(data);
}));
try {
body = body.map(function(data) {
return bcoin.tx.fromJSON(data);
});
} catch (e) {
return callback(e);
}
return callback(null, body);
});
};
@ -337,9 +437,15 @@ Client.prototype.getTX = function getTX(hash, callback) {
return callback(err);
if (!body)
return callback(null, []);
return callback();
return callback(null, bcoin.tx.fromJSON(body));
try {
body = bcoin.tx.fromJSON(body);
} catch (e) {
return callback(e);
}
return callback(null, body);
});
};
@ -352,9 +458,15 @@ Client.prototype.getBlock = function getBlock(hash, callback) {
return callback(err);
if (!body)
return callback(null, []);
return callback();
return callback(null, bcoin.block.fromJSON(body));
try {
body = bcoin.block.fromJSON(body);
} catch (e) {
return callback(e);
}
return callback(null, body);
});
};
@ -370,6 +482,29 @@ Client.prototype.broadcast = function broadcast(tx, callback) {
});
};
Client.prototype.walletSend = function walletSend(id, options, callback) {
var body = {
address: options.address,
value: utils.btc(options.value)
};
callback = utils.ensure(callback);
return this._post('/wallet/' + id + '/send', body, function(err, body) {
if (err)
return callback(err);
try {
body = bcoin.tx.fromJSON(body);
} catch (e) {
return callback(e);
}
return callback(null, body);
});
};
/**
* Expose
*/

View File

@ -53,13 +53,23 @@ Provider.prototype._init = function _init() {
};
Provider.prototype.setID = function setID(id) {
assert(!this.id)
assert(!this.id, 'ID has already been set.');
this.id = id;
this.client.listenWallet(id);
};
Provider.prototype.destroy = function destroy() {
this.client.destroy();
Provider.prototype.open = function open(callback) {
this.client.open(callback);
};
Provider.prototype.close =
Provider.prototype.destroy = function destroy(callback) {
callback = utils.ensure(callback);
if (!this.client)
return utils.nextTick(callback);
this.client.destroy(callback);
this.client = null;
};

View File

@ -299,7 +299,10 @@ NodeServer.prototype._init = function _init() {
if (!balance)
return send(404);
send(200, { balance: utils.btc(balance) });
send(200, {
confirmed: utils.btc(balance.confirmed),
unconfirmed: utils.btc(balance.unconfirmed)
});
});
});
@ -464,16 +467,23 @@ NodeServer.prototype._initIO = function _initIO() {
});
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);
var json = {
confirmed: utils.btc(balance.confirmed),
unconfirmed: utils.btc(balance.unconfirmed)
};
self.server.io.to(id).emit('balance', json);
self.server.io.to('!all').emit('balance', json, id);
});
this.walletdb.on('balances', function(balances) {
var json = {};
Object.keys(balances).forEach(function(id) {
balances[id] = utils.btc(balances[id]);
json[id] = {
confirmed: utils.btc(balances[id].confirmed),
unconfirmed: utils.btc(balances[id].unconfirmed)
};
});
self.server.io.to('!all').emit('balances', balances);
self.server.io.to('!all').emit('balances', json);
});
};

View File

@ -1579,7 +1579,7 @@ TXPool.prototype.getBalance = function getBalance(address, callback) {
unconfirmed.iadd(coins[i].value);
}
return callback(null, unconfirmed, confirmed, coins);
return callback(null, { confirmed: confirmed, unconfirmed: unconfirmed });
});
};

View File

@ -168,11 +168,14 @@ Wallet.prototype.open = function open(callback) {
this.once('open', callback);
};
Wallet.prototype.destroy = function destroy() {
if (!this.provider)
return;
Wallet.prototype.close =
Wallet.prototype.destroy = function destroy(callback) {
callback = utils.ensure(callback);
this.provider.destroy();
if (!this.provider)
return utils.nextTick(callback);
this.provider.destroy(callback);
this.provider = null;
};

View File

@ -133,6 +133,9 @@ WalletDB.prototype._init = function _init() {
var balances = {};
self.emit('updated', tx, map);
map.all.forEach(function(id) {
self.emit(id + ' updated', tx);
});
utils.forEachSerial(map.output, function(id, next) {
if (self.listeners('balance').length === 0
@ -142,29 +145,32 @@ WalletDB.prototype._init = function _init() {
self.getBalance(id, function(err, balance) {
if (err)
return self.emit('error', err);
return next(err);
balances[id] = balance;
self.emit('balance', balance, id);
self.emit(id + ' balance', balance);
next();
});
}, function(err) {
if (err)
self.emit('error', err);
return self.emit('error', err);
self.emit('balances', balances, map);
});
// Only sync for confirmed txs.
if (tx.ts === 0) {
self.emit('balances', balances, map);
return;
}
// Only sync for confirmed txs.
if (tx.ts === 0)
return;
utils.forEachSerial(map.output, function(id, next) {
self.syncOutputDepth(id, tx, next);
}, function(err) {
if (err)
self.emit('error', err);
utils.forEachSerial(map.output, function(id, next) {
self.syncOutputDepth(id, tx, next);
}, function(err) {
if (err)
self.emit('error', err);
self.emit('balances', balances, map);
});
});
});
};
@ -443,8 +449,10 @@ WalletDB.prototype.create = function create(options, callback) {
}
done();
} else {
if (bcoin.protocol.network.witness)
if (bcoin.protocol.network.type === 'segnet3'
|| bcoin.protocol.network.type === 'segnet4') {
options.witness = options.witness !== false;
}
options.provider = new Provider(self);
wallet = new bcoin.wallet(options);
@ -618,7 +626,7 @@ Provider.prototype.open = function open(callback) {
Provider.prototype.setID = function setID(id) {
var self = this;
assert(!this.id);
assert(!this.id, 'ID has already been set.');
this.id = id;
@ -643,35 +651,41 @@ Provider.prototype.setID = function setID(id) {
});
};
Provider.prototype.destroy = function destroy() {
if (this.db) {
if (this._onTX) {
this.removeListener(this.id + ' tx', this._onTX);
delete this._onTX;
}
Provider.prototype.close =
Provider.prototype.destroy = function destroy(callback) {
callback = utils.ensure(callback);
if (this._onUpdated) {
this.removeListener(this.id + ' updated', this._onUpdated);
delete this._onUpdated;
}
if (!this.db)
return utils.nextTick(callback);
if (this._onConfirmed) {
this.removeListener(this.id + ' confirmed', this._onConfirmed);
delete this._onConfirmed;
}
if (this._onTX) {
this.db.removeListener(this.id + ' tx', this._onTX);
delete this._onTX;
}
if (this._onUnconfirmed) {
this.removeListener(this.id + ' unconfirmed', this._onUnconfirmed);
delete this._onUnconfirmed;
}
if (this._onUpdated) {
this.db.removeListener(this.id + ' updated', this._onUpdated);
delete this._onUpdated;
}
if (this._onBalance) {
this.removeListener(this.id + ' balance', this._onBalance);
delete this._onBalance;
}
if (this._onConfirmed) {
this.db.removeListener(this.id + ' confirmed', this._onConfirmed);
delete this._onConfirmed;
}
if (this._onUnconfirmed) {
this.db.removeListener(this.id + ' unconfirmed', this._onUnconfirmed);
delete this._onUnconfirmed;
}
if (this._onBalance) {
this.db.removeListener(this.id + ' balance', this._onBalance);
delete this._onBalance;
}
this.db = null;
return utils.nextTick(callback);
};
Provider.prototype.getAll = function getAll(callback) {

View File

@ -101,27 +101,27 @@ describe('Wallet', function() {
assert.noError(err);
node.mempool.getBalance(function(err, balance) {
assert.noError(err);
assert.equal(balance.toString(10), '0');
assert.equal(balance.unconfirmed.toString(10), '0');
node.mempool.addTX(t1, function(err) {
assert.noError(err);
node.mempool.getBalance(function(err, balance) {
assert.noError(err);
assert.equal(balance.toString(10), '60000');
assert.equal(balance.unconfirmed.toString(10), '60000');
node.mempool.addTX(t2, function(err) {
assert.noError(err);
node.mempool.getBalance(function(err, balance) {
assert.noError(err);
assert.equal(balance.toString(10), '50000');
assert.equal(balance.unconfirmed.toString(10), '50000');
node.mempool.addTX(t3, function(err) {
assert.noError(err);
node.mempool.getBalance(function(err, balance) {
assert.noError(err);
assert.equal(balance.toString(10), '22000');
assert.equal(balance.unconfirmed.toString(10), '22000');
node.mempool.addTX(f1, function(err) {
assert.noError(err);
node.mempool.getBalance(function(err, balance) {
assert.noError(err);
assert.equal(balance.toString(10), '20000');
assert.equal(balance.unconfirmed.toString(10), '20000');
node.mempool.getAll(function(err, txs) {
assert(txs.some(function(tx) {
return tx.hash('hex') === f1.hash('hex');

View File

@ -190,26 +190,26 @@ describe('Wallet', function() {
assert.noError(err);
w.getBalance(function(err, balance) {
assert.noError(err);
assert.equal(balance.toString(10), '22500');
assert.equal(balance.unconfirmed.toString(10), '22500');
wdb.addTX(t1, function(err) {
w.getBalance(function(err, balance) {
assert.noError(err);
assert.equal(balance.toString(10), '73000');
assert.equal(balance.unconfirmed.toString(10), '73000');
wdb.addTX(t2, function(err) {
assert.noError(err);
w.getBalance(function(err, balance) {
assert.noError(err);
assert.equal(balance.toString(10), '47000');
assert.equal(balance.unconfirmed.toString(10), '47000');
wdb.addTX(t3, function(err) {
assert.noError(err);
w.getBalance(function(err, balance) {
assert.noError(err);
assert.equal(balance.toString(10), '22000');
assert.equal(balance.unconfirmed.toString(10), '22000');
wdb.addTX(f1, function(err) {
assert.noError(err);
w.getBalance(function(err, balance) {
assert.noError(err);
assert.equal(balance.toString(10), '11000');
assert.equal(balance.unconfirmed.toString(10), '11000');
w.getAll(function(err, txs) {
assert(txs.some(function(tx) {
return tx.hash('hex') === f1.hash('hex');
@ -244,7 +244,7 @@ describe('Wallet', function() {
assert.noError(err);
dw.getBalance(function(err, balance) {
assert.noError(err);
assert.equal(balance.toString(10), '11000');
assert.equal(balance.unconfirmed.toString(10), '11000');
cb();
});
});