diff --git a/README.md b/README.md index 476d8efa..97d78ff7 100644 --- a/README.md +++ b/README.md @@ -1791,14 +1791,95 @@ Transaction broadcasted successfully ``` ### Output routes -####GET '/v1/transactions/:txHash([A-Fa-f0-9]{64})/outputs' -####GET '/v1/transactions/:txHash([A-Fa-f0-9]{64})/outputs/:index([0-9]+)' +####GET '/v1/transactions/2ceea8fb53873ae3f61fb332bf844e5a35630a1a4885a212f84f63f39c638b5e/outputs' +``` +[ + { + "satoshis": 47203800, + "script": "OP_DUP OP_HASH160 20 0x7c8fe8004e1dfdf0826f357de9ff93db25a8239d OP_EQUALVERIFY OP_CHECKSIG" + }, + { + "satoshis": 9490000, + "script": "OP_DUP OP_HASH160 20 0xbf158227da5604c112bdf5af744f30bb7e85c7bf OP_EQUALVERIFY OP_CHECKSIG" + } +] +``` + +####GET '/v1/transactions/2ceea8fb53873ae3f61fb332bf844e5a35630a1a4885a212f84f63f39c638b5e/outputs/1' +``` +{ + "satoshis": 9490000, + "script": "OP_DUP OP_HASH160 20 0xbf158227da5604c112bdf5af744f30bb7e85c7bf OP_EQUALVERIFY OP_CHECKSIG" +} +``` ### Address routes -####GET '/v1/addresses/:address' -####GET '/v1/addresses/:address/transactions' -####GET '/v1/addresses/:addresses/utxos' +####GET '/v1/addresses/msWN7CbKLWh88P1Vr8pQa7DmZNSiy9xfkj' +``` +{ + "address": "mtBHBTKTZv74cytccymVq3weidcoy4o1UY", + "transactions": [ + "88c844570a227fe89d82e4e20d41576b95df8aa790a799bf7114dbed83b788b0", + "d1cd5072cf4f6bff12e46a1e7949e58b544abed969313d65263141b9c94221cd" + ], + "confirmed": { + "balance": 0, + "sent": 4900642709, + "received": 4900642709 + }, + "unconfirmed": { + "balance": 0, + "sent": 4900642709, + "received": 4900642709 + } +} +``` +####GET '/v1/addresses/:addresses/utxos' +``` +[ + { + "satoshis": 967008, + "script": "OP_DUP OP_HASH160 20 0x0b4322ac01719030a710b60b0a3397c074cf9edf OP_EQUALVERIFY OP_CHECKSIG", + "heightConfirmed": 410, + "address": "mgYW9pHcxjUSvqHwaJF48uFbrDfFoPAcjx", + "txId": "0c233e2730cb94dc85e32546060c2361d348921961ab957ae66acadf88a578f1", + "outputIndex": "1" + }, + { + "satoshis": 568367, + "script": "OP_DUP OP_HASH160 20 0x0b4322ac01719030a710b60b0a3397c074cf9edf OP_EQUALVERIFY OP_CHECKSIG", + "heightConfirmed": 417, + "address": "mgYW9pHcxjUSvqHwaJF48uFbrDfFoPAcjx", + "txId": "0ca394ce3c2feecb2957b3aa5ecdc964f706e0b4ceec96bfc1ace526a80c67d1", + "outputIndex": "1" + }, + { + "satoshis": 977315, + "script": "OP_DUP OP_HASH160 20 0x0b4322ac01719030a710b60b0a3397c074cf9edf OP_EQUALVERIFY OP_CHECKSIG", + "heightConfirmed": 421, + "address": "mgYW9pHcxjUSvqHwaJF48uFbrDfFoPAcjx", + "txId": "96bdd67bd1b80f70acc7cca454c5ca80cfc8ba621e0e93756c406977102b586a", + "outputIndex": "1" + }, + { + "satoshis": 496223, + "script": "OP_DUP OP_HASH160 20 0x0b4322ac01719030a710b60b0a3397c074cf9edf OP_EQUALVERIFY OP_CHECKSIG", + "heightConfirmed": 420, + "address": "mgYW9pHcxjUSvqHwaJF48uFbrDfFoPAcjx", + "txId": "97d561085af6041e2b570dd07d4ee8b49a2d5667776f2112fac611727f949b3b", + "outputIndex": "1" + }, + { + "satoshis": 123667, + "script": "OP_DUP OP_HASH160 20 0x0b4322ac01719030a710b60b0a3397c074cf9edf OP_EQUALVERIFY OP_CHECKSIG", + "heightConfirmed": 405, + "address": "mgYW9pHcxjUSvqHwaJF48uFbrDfFoPAcjx", + "txId": "e72f781efc41224cf37d1aa0c63fa4655a86b647233622e653b38eb3d379b1cc", + "outputIndex": "1" + } +] +``` ## License diff --git a/api/controllers/addresses.js b/api/controllers/addresses.js index ed1aefc8..8cfffbfe 100644 --- a/api/controllers/addresses.js +++ b/api/controllers/addresses.js @@ -23,7 +23,7 @@ Addresses.setNode = function(aNode) { * Finds an address' info by it's string representation */ Addresses.addressParam = function(req, res, next, address) { - if (!Address.isValid(address)) { + if (!Address.isValid(address, bitcore.Networks.defaultNetwork)) { res.status(422); res.send('/v1/addresses/ parameter must be a valid bitcoin address'); return; @@ -76,7 +76,7 @@ Addresses.utxos = function(req, res) { $.checkState(_.all(req.addresses, function(addr) { return addr instanceof Address; })); - node.getUTXOs(req.addresses) + node.addressService.getUnspent(req.addresses) .then(function(utxos) { res.send(utxos); }); diff --git a/api/controllers/transactions.js b/api/controllers/transactions.js index 31386caf..c819dc00 100644 --- a/api/controllers/transactions.js +++ b/api/controllers/transactions.js @@ -87,18 +87,6 @@ Transactions.send = function(req, res) { }; -/* - * Returns a list of transactions given certain request options - */ -Transactions.list = function(req, res) { - var opts = {}; - opts.address = req.address; - node.listTransactions(opts) - .then(function(transactions) { - res.send(transactions); - }); -}; - var buildIOHelper = function(name) { $.checkArgument(name === 'inputs' || name === 'outputs'); diff --git a/api/routes/v1.js b/api/routes/v1.js index 5faf1cb2..3449043c 100644 --- a/api/routes/v1.js +++ b/api/routes/v1.js @@ -44,7 +44,6 @@ function initRouter(node) { // Address routes router.get('/addresses/:address', Addresses.get); - router.get('/addresses/:address/transactions', Transactions.list); router.get('/addresses/:addresses/utxos', Addresses.utxos); // error routes diff --git a/lib/services/address.js b/lib/services/address.js index 76e6092e..f59e3caa 100644 --- a/lib/services/address.js +++ b/lib/services/address.js @@ -5,6 +5,7 @@ var bitcore = require('bitcore'); var TransactionService = require('./transaction'); var RPC = require('bitcoind-rpc'); var _ = bitcore.deps._; +var $ = bitcore.util.preconditions; var NULLTXHASH = bitcore.util.buffer.emptyBuffer(32).toString('hex'); var LASTTXHASH = bitcore.util.buffer.fill(bitcore.util.buffer.emptyBuffer(32), -1).toString('hex'); @@ -56,6 +57,7 @@ AddressService.processOutput = function(data) { var retrieveOutputs = function(indexFunction, processElement) { return function(address) { + $.checkArgument(address, 'address required'); var results = []; var self = this; @@ -81,11 +83,44 @@ AddressService.prototype.getAllOutputs = retrieveOutputs( AddressService.prototype.getSpent = retrieveOutputs( TransactionService.Index.getSpentOutputsForAddress, - function(element) { - return JSON.parse(element.value); + function(e) { + return AddressService.processOutput(e); } ); + +AddressService.prototype.getUnspent = function(addrs) { + + $.checkArgument(addrs, 'addresses required'); + $.checkArgument(_.isArray(addrs), 'addresses is array required'); + + var self = this; + return Promise.all(addrs.map(function(addr) { + return self.getUnspentForAddress(addr); + })) + .then(function(results) { + return _.flatten(results); + }); + + +}; +AddressService.prototype.getUnspentForAddress = function(addr) { + $.checkArgument(addr, 'address required'); + var all, spent; + var self = this; + return this.getAllOutputs(addr) + .then(function(s) { + all = s; + return self.getSpent(addr); + }) + .then(function(s) { + spent = s; + return _.filter(all, function(out) { + return !_.contains(spent, out); + }); + }); +}; + AddressService.prototype.buildAddressSummary = function(address, tip, allOutputs, spent, confirmations) { var result = {}; diff --git a/lib/services/block.js b/lib/services/block.js index d499e6c1..e828f8d7 100644 --- a/lib/services/block.js +++ b/lib/services/block.js @@ -206,8 +206,6 @@ BlockService.prototype.listBlocks = function(from, to, offset, limit) { var start = from + offset; var end = Math.min(to, start + limit); var blocks = []; - //console.log(from, to, offset, limit); - //console.log(start, end); // TODO: optimize: precompute heights and fetch all blocks in parallel? var fetchBlock = function(height) { if (height >= end) { @@ -284,37 +282,27 @@ BlockService.prototype.confirm = function(block, ops) { ops = ops || []; - //console.log(0); return Promise.try(function() { - //console.log(0.5); self._setHeader(ops, block); - //console.log(1); self._setNextBlock(ops, block.header.prevHash, block); - //console.log(3); self._setBlockHeight(ops, block); - //console.log(3); self._setBlockWork(ops, block); - //console.log(4); self._setBlockByTs(ops, block); - //console.log(4.1); self._setTip(ops, block); - //console.log(5); return Promise.all(block.transactions.map(function(transaction) { return self.transactionService._confirmTransaction(ops, block, transaction); })); }) .then(function() { - //console.log(6); return self.database.batchAsync(ops); }) .then(function() { - //console.log(7); return block; }); }; @@ -373,17 +361,14 @@ BlockService.prototype._setBlockByTs = function(ops, block) { /* var self = this; var key = Index.timestamp + block.header.time; - console.log('key', key); return Promise.try(function() { - console.log('a'); return self.database.getAsync(key); }) .then(function(result) { - console.log('b'); if (result === block.hash) { return Promise.resolve(); } else {