Add address service
This commit is contained in:
parent
2139058954
commit
e70dbb4ce3
130
lib/services/address.js
Normal file
130
lib/services/address.js
Normal file
@ -0,0 +1,130 @@
|
||||
'use strict';
|
||||
|
||||
var Promise = require('bluebird');
|
||||
var bitcore = require('bitcore');
|
||||
var _ = bitcore.deps._;
|
||||
|
||||
var NULLTXHASH = bitcore.util.buffer.emptyBuffer(32).toString('hex');
|
||||
var LASTTXHASH = bitcore.util.buffer.fill(bitcore.util.buffer.emptyBuffer(32), -1).toString('hex');
|
||||
var MAXOUTPUT = 1 << 31;
|
||||
|
||||
function AddressService(opts) {
|
||||
opts = _.extend({}, opts);
|
||||
this.transactionService = opts.transactionService;
|
||||
this.blockService = opts.blockService;
|
||||
this.database = opts.database || Promise.promisifyAll(new LevelUp(config.get('LevelUp')));
|
||||
this.rpc = opts.rpc || Promise.promisifyAll(new RPC(config.get('RPC')));
|
||||
}
|
||||
|
||||
AddressService.prototype.getSummary = function(address, confirmations) {
|
||||
|
||||
var self = this;
|
||||
var tip, allOutputs, spent;
|
||||
confirmations = confirmations || 6;
|
||||
|
||||
return Promise.try(function() {
|
||||
|
||||
return self.blockService.getLatest();
|
||||
|
||||
}).then(function(latest) {
|
||||
|
||||
tip = latest;
|
||||
return self.getAllOutputs(address);
|
||||
|
||||
}).then(function(outputs) {
|
||||
|
||||
allOutputs = outputs;
|
||||
return self.getSpent(address);
|
||||
|
||||
}).then(function(spent) {
|
||||
|
||||
return self.buildAddressSummary(address, tip, allOutputs, spent);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
AddressService.prototype.getAllOutputs = function(address) {
|
||||
var results = [];
|
||||
var self = this;
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
self.db.createReadStream({
|
||||
gte: TransactionService.Index.getOutputsForAddress(address, NULLTXHASH, 0),
|
||||
lte: TransactionService.Index.getOutputsForAddress(address, LASTTXHASH, MAXOUTPUT)
|
||||
}).on('data', function(element) {
|
||||
results.push(element.value);
|
||||
}).on('close', function() {
|
||||
reject();
|
||||
}).on('end', function() {
|
||||
resolve(results);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
AddressService.prototype.getSpent = function(address) {
|
||||
var results = [];
|
||||
var self = this;
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
self.db.createReadStream({
|
||||
gte: TransactionService.Index.getSpentOutputsForAddress(address, NULLTXHASH, 0),
|
||||
lte: TransactionService.Index.getSpentOutputsForAddress(address, LASTTXHASH, MAXOUTPUT)
|
||||
}).on('data', function(element) {
|
||||
results.push(element.value);
|
||||
}).on('close', function() {
|
||||
reject();
|
||||
}).on('end', function() {
|
||||
resolve(results);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
AddressService.prototype.buildAddressSummary = function(address, tip, allOutputs, spent) {
|
||||
|
||||
var result = {};
|
||||
var transactionsAppended = {};
|
||||
|
||||
result.address = address.toString();
|
||||
result.transactions = [];
|
||||
|
||||
result.confirmed = {
|
||||
balance: 0,
|
||||
sent: 0,
|
||||
received: 0
|
||||
};
|
||||
result.unconfirmed = {
|
||||
balance: 0,
|
||||
sent: 0,
|
||||
received: 0
|
||||
};
|
||||
_.each(allOutputs, function(output) {
|
||||
var value = output.satoshis;
|
||||
result.unconfirmed.balance += value;
|
||||
result.unconfirmed.received += value;
|
||||
if (tip.height - output.heightConfirmed - 1 >= confirmations) {
|
||||
result.confirmed.balance += value;
|
||||
result.confirmed.received += value;
|
||||
}
|
||||
});
|
||||
_.each(spent, function(output) {
|
||||
var value = output.satoshis;
|
||||
if (!transactionsAppended[output.spentTx]) {
|
||||
transactionsAppended[output.spentTx] = true;
|
||||
result.transactions.push(output.spentTx);
|
||||
}
|
||||
if (!transactionsAppended[output.spendInput.prevTxId]) {
|
||||
transactionsAppended[output.spendInput.prevTxId] = true;
|
||||
result.transactions.push(output.spendInput.prevTxId);
|
||||
}
|
||||
result.unconfirmed.balance -= value;
|
||||
result.unconfirmed.sent += value;
|
||||
if (tip.height - output.heightSpent - 1 >= confirmations) {
|
||||
result.confirmed.balance -= value;
|
||||
result.confirmed.sent += value;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
module.exports = AddressService;
|
||||
@ -168,7 +168,7 @@ BlockService.prototype.getBlockByHeight = function(height) {
|
||||
|
||||
return Promise.try(function() {
|
||||
|
||||
return this.rpc.getBlockHash(height);
|
||||
return self.rpc.getBlockHash(height);
|
||||
|
||||
}).then(function(blockHash) {
|
||||
|
||||
@ -210,11 +210,11 @@ BlockService.prototype._confirmBlock = function(block) {
|
||||
|
||||
var ops = [];
|
||||
|
||||
this.writeLock().then(
|
||||
this.writeLock().then(function() {
|
||||
|
||||
self._setNextBlock.bind(self, ops, block.header.prevHash, block)
|
||||
return self._setNextBlock(ops, block.header.prevHash, block);
|
||||
|
||||
).then(function() {
|
||||
}).then(function() {
|
||||
|
||||
if (block.header.prevHash.toString('hex') !== NULLBLOCKHASH) {
|
||||
return self.getBlock(block.header.prevHash);
|
||||
@ -226,11 +226,11 @@ BlockService.prototype._confirmBlock = function(block) {
|
||||
|
||||
return self._setBlockHeight(ops, block, parent.height + 1);
|
||||
|
||||
}).then(
|
||||
}).then(function() {
|
||||
|
||||
self._setBlockByTs.bind(self, ops, block)
|
||||
return self._setBlockByTs(ops, block);
|
||||
|
||||
).then(function() {
|
||||
}).then(function() {
|
||||
|
||||
return Promise.all(block.transactions.map(function(transaction) {
|
||||
return self.transactionService._confirmTransaction(ops, block, transaction);
|
||||
|
||||
@ -80,6 +80,7 @@ function TransactionService (opts) {
|
||||
this.database = opts.database || Promise.promisifyAll(new LevelUp(config.get('LevelUp')));
|
||||
this.rpc = opts.rpc || Promise.promisifyAll(new RPC(config.get('RPC')));
|
||||
}
|
||||
TransactionService.Index = Index;
|
||||
|
||||
TransactionService.transactionRPCtoBitcore = function(rpcResponse) {
|
||||
if (rpcResponse.error) {
|
||||
|
||||
28
test/services/address.js
Normal file
28
test/services/address.js
Normal file
@ -0,0 +1,28 @@
|
||||
'use strict';
|
||||
|
||||
var sinon = require('sinon');
|
||||
var should = require('chai').should();
|
||||
var Promise = require('bluebird');
|
||||
|
||||
var bitcore = require('bitcore');
|
||||
var _ = bitcore.deps._;
|
||||
|
||||
var TransactionService = require('../../lib/services/transaction');
|
||||
|
||||
describe.only('AddressService', function() {
|
||||
|
||||
it('initializes correctly', function() {
|
||||
var database = 'mock';
|
||||
var rpc = 'mock';
|
||||
var blockService = 'mock';
|
||||
var transactionService = 'mock';
|
||||
var service = new TransactionService({
|
||||
database: database,
|
||||
transactionService: transactionService,
|
||||
blockService: blockService,
|
||||
rpc: rpc
|
||||
});
|
||||
should.exist(service);
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user