Merge pull request #46 from cmgustavo/feature/get_async_transactions
Feature/get async transactions
This commit is contained in:
commit
fad7cb73aa
16
README.md
16
README.md
|
@ -103,22 +103,30 @@ $ npm install -g bower
|
|||
A REST API is provided at /api. The entry points are:
|
||||
|
||||
|
||||
### Blocks
|
||||
### Block
|
||||
```
|
||||
/api/block/[:hash]
|
||||
/api/block/00000000a967199a2fad0877433c93df785a8d8ce062e5f9b451cd1397bdbf62
|
||||
```
|
||||
### Transactions
|
||||
### Transaction
|
||||
```
|
||||
/api/tx/[:txid]
|
||||
/api/tx/525de308971eabd941b139f46c7198b5af9479325c2395db7f2fb5ae8562556c
|
||||
```
|
||||
### Addresses
|
||||
### Addresse
|
||||
```
|
||||
/api/addr/[:addr]
|
||||
/api/addr/mmvP3mTe53qxHdPqXEvdu8WdC7GfQ2vmx5
|
||||
```
|
||||
|
||||
### Transactions by Block
|
||||
```
|
||||
/api/txs/?block=HASH
|
||||
/api/txs/?block=00000000fa6cf7367e50ad14eb0ca4737131f256fc4c5841fd3c3f140140e6b6
|
||||
```
|
||||
### Transactions by Address
|
||||
```
|
||||
/api/txs/?address=ADDR
|
||||
/api/txs/?address=mmhmMNfBiZZ37g1tgg2t8DDbNoEdqKVxAL
|
||||
|
||||
## Web Socket API
|
||||
The web socket API is served using [socket.io](http://socket.io) at:
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
|
||||
var Transaction = require('../models/Transaction');
|
||||
var Block = require('../models/Block');
|
||||
var Address = require('../models/Address');
|
||||
var async = require('async');
|
||||
//, _ = require('lodash');
|
||||
|
||||
|
||||
|
@ -38,3 +41,50 @@ exports.show = function(req, res) {
|
|||
}
|
||||
};
|
||||
|
||||
var getTransaction = function(txid, cb) {
|
||||
Transaction.fromIdWithInfo(txid, function(err, tx) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return cb(err);
|
||||
}
|
||||
return cb(null, tx.info);
|
||||
});
|
||||
};
|
||||
|
||||
exports.transactions = function(req, res, next) {
|
||||
var bId = req.query.block;
|
||||
var aId = req.query.address;
|
||||
|
||||
if (bId) {
|
||||
Block.fromHashWithInfo(bId, function(err, block) {
|
||||
if (err && !block) {
|
||||
console.log(err);
|
||||
res.status(404).send('Not found');
|
||||
return next();
|
||||
}
|
||||
|
||||
async.mapSeries(block.info.tx, getTransaction,
|
||||
function(err, results) {
|
||||
res.jsonp(results);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
var a = Address.new(aId);
|
||||
|
||||
a.update(function(err) {
|
||||
if (err && !a.totalReceivedSat) {
|
||||
console.log(err);
|
||||
res.status(404).send('Invalid address');
|
||||
return next();
|
||||
}
|
||||
|
||||
async.mapSeries(a.transactions, getTransaction,
|
||||
function(err, results) {
|
||||
res.jsonp(results);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -14,11 +14,14 @@ module.exports = function(app) {
|
|||
app.get('/api/block/:blockHash', blocks.show);
|
||||
app.param('blockHash', blocks.block);
|
||||
|
||||
// Transaction routes
|
||||
var transactions = require('../app/controllers/transactions');
|
||||
app.get('/api/tx/:txid', transactions.show);
|
||||
|
||||
app.param('txid', transactions.transaction);
|
||||
|
||||
app.get('/api/txs', transactions.transactions);
|
||||
|
||||
// Address routes
|
||||
var addresses = require('../app/controllers/addresses');
|
||||
app.get('/api/addr/:addr', addresses.show);
|
||||
app.param('addr', addresses.address);
|
||||
|
|
|
@ -1,22 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('mystery.address').controller('AddressController', ['$scope', '$routeParams', '$location', 'Global', 'Address', function ($scope, $routeParams, $location, Global, Address) {
|
||||
/*
|
||||
$scope.address = '1JmTTDcksW7A6GN7JnxuXkMAXsVN9zmgm1';
|
||||
$scope.hash160 = '77ad7d08aaa9cf489ea4e468eaeb892b85f71e27';
|
||||
$scope.transactions = [
|
||||
{
|
||||
hash: '49a1d01759690476dbeec4a8efd969c09c6d4269ea2d88f4d9d4f098f021413c',
|
||||
time: 1234123445,
|
||||
amount: 0.3
|
||||
},
|
||||
{
|
||||
hash: 'cce948b422a4d485900fb82e64458720eb89f545af3f07ddf7d18660f9f881e9',
|
||||
time: 1234123445,
|
||||
amount: 0.1
|
||||
}
|
||||
];
|
||||
*/
|
||||
$scope.global = Global;
|
||||
|
||||
$scope.findOne = function() {
|
||||
|
@ -27,4 +11,5 @@ angular.module('mystery.address').controller('AddressController', ['$scope', '$r
|
|||
});
|
||||
};
|
||||
|
||||
$scope.params = $routeParams;
|
||||
}]);
|
||||
|
|
|
@ -20,4 +20,5 @@ angular.module('mystery.blocks').controller('BlocksController', ['$scope', '$rou
|
|||
});
|
||||
};
|
||||
|
||||
$scope.params = $routeParams;
|
||||
}]);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('mystery.transactions').controller('transactionsController', ['$scope', '$routeParams', '$location', 'Global', 'Transaction', function ($scope, $routeParams, $location, Global, Transaction) {
|
||||
angular.module('mystery.transactions').controller('transactionsController', ['$scope', '$routeParams', '$location', 'Global', 'Transaction', 'TransactionsByBlock', 'TransactionsByAddress', function ($scope, $routeParams, $location, Global, Transaction, TransactionsByBlock, TransactionsByAddress) {
|
||||
$scope.global = Global;
|
||||
|
||||
$scope.findOne = function() {
|
||||
|
@ -10,5 +10,23 @@ angular.module('mystery.transactions').controller('transactionsController', ['$s
|
|||
$scope.tx = tx;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.byBlock = function(bId) {
|
||||
TransactionsByBlock.query({
|
||||
block: bId
|
||||
}, function(txs) {
|
||||
$scope.txs = txs;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.byAddress = function(aId) {
|
||||
TransactionsByAddress.query({
|
||||
address: aId
|
||||
}, function(txs) {
|
||||
$scope.txs = txs;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
}]);
|
||||
|
||||
|
|
|
@ -20,3 +20,15 @@ angular.module('mystery.transactions').factory('Transaction', ['$resource', func
|
|||
});
|
||||
}]);
|
||||
|
||||
angular.module('mystery.transactions').factory('TransactionsByBlock', ['$resource', function($resource) {
|
||||
return $resource('/api/txs', {
|
||||
block: '@block'
|
||||
});
|
||||
}]);
|
||||
|
||||
angular.module('mystery.transactions').factory('TransactionsByAddress', ['$resource', function($resource) {
|
||||
return $resource('/api/txs', {
|
||||
address: '@address'
|
||||
});
|
||||
}]);
|
||||
|
||||
|
|
|
@ -5,12 +5,13 @@
|
|||
<small>Addresses are identifiers which you use to send bitcoins to another person.</small>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="col-lg-9">
|
||||
<table class="table table-striped">
|
||||
<tbody>
|
||||
<div class="row">
|
||||
<div class="col-lg-9">
|
||||
<table class="table table-striped">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Address</td>
|
||||
<td><a href="/#!/address/{{address}}">{{address.addrStr}}</a></td>
|
||||
<td><a href="/#!/address/{{address.addrStr}}">{{address.addrStr}}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total Received</td>
|
||||
|
@ -29,32 +30,35 @@
|
|||
<td>{{address.txApperances}}</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-lg-3">
|
||||
<qrcode size="200" data="{{address.addrStr}}"></qrcode>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3">
|
||||
<qrcode size="200" data="{{address.addrStr}}"></qrcode>
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<h3>
|
||||
Transactions
|
||||
<small>transactions this address relates to</small>
|
||||
</h3>
|
||||
|
||||
<div data-ng-controller="transactionsController" data-ng-init="byAddress(params.addrStr)">
|
||||
<h2>Transactions <small>Transactions contained within this block</small></h2>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Transaction Hash</th>
|
||||
<th>Datetime</th>
|
||||
<th>Transacted amount</th>
|
||||
<th>Fee</th>
|
||||
<th>Transacted Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr data-ng-repeat="transaction in address.transactions track by $index">
|
||||
<td><a href="/#!/tx/{{transaction}}">{{transaction}}</a></td>
|
||||
<td>--</td>
|
||||
<td>--</td>
|
||||
</tr>
|
||||
<tr data-ng-show="!txs.length">
|
||||
<td colspan="4" class="text-center">Loading...</td>
|
||||
</tr>
|
||||
<tr data-ng-repeat="tx in txs">
|
||||
<td><a href="/#!/tx/{{tx.txid}}">{{tx.txid}}</a></td>
|
||||
<td>{{tx.time * 1000 | date:'medium'}}</td>
|
||||
<td>{{tx.feeds}}</td>
|
||||
<td>{{tx.valueOut}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
@ -16,18 +16,6 @@
|
|||
<td>Number Of Transactions</td>
|
||||
<td>{{block.tx.length}}<td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Output Total</td>
|
||||
<td>--</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Estimated Transaction Volume</td>
|
||||
<td>--</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Transaction Fees</td>
|
||||
<td>--</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Height</td>
|
||||
<td>{{block.height}}</td>
|
||||
|
@ -36,10 +24,6 @@
|
|||
<td>Timestamp</td>
|
||||
<td>{{block.time * 1000 | date:'medium'}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Relayed By</td>
|
||||
<td>--</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Difficulty</td>
|
||||
<td>{{block.difficulty}}</td>
|
||||
|
@ -96,17 +80,28 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Transactions <small>Transactions contained within this block</small></h2>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Hash</th>
|
||||
<div data-ng-controller="transactionsController" data-ng-init="byBlock(params.blockHash)">
|
||||
<h2>Transactions <small>Transactions contained within this block</small></h2>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Transaction Hash</th>
|
||||
<th>Datetime</th>
|
||||
<th>Fee</th>
|
||||
<th>Transacted Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr data-ng-show="!txs.length">
|
||||
<td colspan="4" class="text-center">Loading...</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr data-ng-repeat="tx in block.tx track by $index">
|
||||
<td><a href="/#!/tx/{{tx}}">{{tx}}</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<tr data-ng-repeat="tx in txs">
|
||||
<td><a href="/#!/tx/{{tx.txid}}">{{tx.txid}}</a></td>
|
||||
<td>{{tx.time * 1000 | date:'medium'}}</td>
|
||||
<td>{{tx.feeds}}</td>
|
||||
<td>{{tx.valueOut}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -23,13 +23,18 @@
|
|||
<td width="45%">
|
||||
<ul class="list-unstyled" data-ng-repeat="vin in tx.vin" data-ng-show="!tx.isCoinBase">
|
||||
<li>
|
||||
<span data-ng-show="!vin.addr">No parse address</span>
|
||||
<a data-ng-show="vin.addr" href="/#!/address/{{vin.addr}}">{{vin.addr}}</a>
|
||||
<span class="pull-right badge">{{vin.value}} BTC</span>
|
||||
<span data-ng-show="!vin.addr"><a href="/#!/tx/{{vin.txid}}">Address could not be parsed, {{vin.vout}}</a></span>
|
||||
<a data-ng-show="vin.addr" href="/#!/address/{{vin.addr}}">{{vin.addr}}</a>
|
||||
<span class="pull-right badge">{{vin.value}} BTC</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div data-ng-show="tx.isCoinBase">
|
||||
No Inputs (Newly Generated isCoinBasens)
|
||||
<ul class="list-unstyled" data-ng-repeat="vinn in tx.vin">
|
||||
<li>
|
||||
No Inputs (Newly Generated isCoinBasens)
|
||||
<span class="pull-right badge">{{vinn.reward}} BTC</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
<td width="10%" style="text-align: center;"><span class="glyphicon glyphicon-chevron-right"> </span></td>
|
||||
|
@ -82,8 +87,8 @@
|
|||
<td>{{tx.time * 1000|date:'medium'}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Reward From Block</td>
|
||||
<td><a href="/#!/block/{{tx.blockhash}}">Need height to show (it links to block page)</a></td>
|
||||
<td>Block</td>
|
||||
<td><a href="/#!/block/{{tx.blockhash}}">Block</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
Loading…
Reference in New Issue