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 Promise.try(function() {
|
||||||
|
|
||||||
return this.rpc.getBlockHash(height);
|
return self.rpc.getBlockHash(height);
|
||||||
|
|
||||||
}).then(function(blockHash) {
|
}).then(function(blockHash) {
|
||||||
|
|
||||||
@ -210,11 +210,11 @@ BlockService.prototype._confirmBlock = function(block) {
|
|||||||
|
|
||||||
var ops = [];
|
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) {
|
if (block.header.prevHash.toString('hex') !== NULLBLOCKHASH) {
|
||||||
return self.getBlock(block.header.prevHash);
|
return self.getBlock(block.header.prevHash);
|
||||||
@ -226,11 +226,11 @@ BlockService.prototype._confirmBlock = function(block) {
|
|||||||
|
|
||||||
return self._setBlockHeight(ops, block, parent.height + 1);
|
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 Promise.all(block.transactions.map(function(transaction) {
|
||||||
return self.transactionService._confirmTransaction(ops, block, 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.database = opts.database || Promise.promisifyAll(new LevelUp(config.get('LevelUp')));
|
||||||
this.rpc = opts.rpc || Promise.promisifyAll(new RPC(config.get('RPC')));
|
this.rpc = opts.rpc || Promise.promisifyAll(new RPC(config.get('RPC')));
|
||||||
}
|
}
|
||||||
|
TransactionService.Index = Index;
|
||||||
|
|
||||||
TransactionService.transactionRPCtoBitcore = function(rpcResponse) {
|
TransactionService.transactionRPCtoBitcore = function(rpcResponse) {
|
||||||
if (rpcResponse.error) {
|
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