Skip to content

Commit b94380c

Browse files
committed
add network fees API endpoint
1 parent 4858659 commit b94380c

File tree

8 files changed

+504
-1
lines changed

8 files changed

+504
-1
lines changed

README.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ General Methods:
5252
* [Get XRP Distribution - `GET /v2/network/xrp_distribution`](#get-xrp-distribution)
5353
* [Get Top Currencies - `GET /v2/network/top_currencies`](#get-top-currencies)
5454
* [Get Top Markets - `GET /v2/network/top_markets`](#get-top-markets)
55+
* [Get Network Fees - `GET /v2/network/fees`](#get-network-fees)
5556
* [Get Topology - `GET /v2/network/topology`](#get-topology)
5657
* [Get Topology Nodes - `GET /v2/network/topology/nodes`](#get-topology-nodes)
5758
* [Get Topology Node - `GET /v2/network/topology/nodes/{:pubkey}`](#get-topology-nodes)
@@ -2209,6 +2210,91 @@ Response:
22092210

22102211

22112212

2213+
## Get Network Fees ##
2214+
[[Source]<br>](https://github.com/ripple/rippled-historical-database/blob/develop/api/routesV2/network/getFees.js "Source")
2215+
2216+
Returns network fee stats per ledger, hour, or day. The data shows the average, minimum, maximum, and total fees incurred for the given interval/ledger. _(New in [v2.2.0][])_
2217+
2218+
#### Request Format ####
2219+
2220+
<!--<div class='multicode'>-->
2221+
2222+
```
2223+
GET /v2/network/fees
2224+
```
2225+
2226+
<!--</div>-->
2227+
2228+
Optionally, you can include the following query parameters:
2229+
2230+
| Field | Value | Description |
2231+
|--------|---------|-------------|
2232+
| start | String - [Timestamp][] | Start time of query range. Defaults to the start of the most recent interval. |
2233+
| end | String - [Timestamp][] | End time of query range. Defaults to the end of the most recent interval. |
2234+
| interval | String | Aggregation interval - valid intervals are `ledger`, `hour`, or `day`. Defaults to `ledger`. |
2235+
| descending | Boolean | Reverse chronological order |
2236+
| limit | Integer | Maximum results per page. Defaults to 200. Cannot be more than 1000. |
2237+
| marker | String | [Pagination](#pagination) key from previously returned response |
2238+
| format | String | Format of returned results: `csv` or `json`. Defaults to `json`. |
2239+
2240+
[Try it! >](https://ripple.com/build/data-api-tool/#get-network-fees)
2241+
2242+
2243+
#### Response Format ####
2244+
2245+
A successful response uses the HTTP code **200 OK** and has a JSON body with the following:
2246+
2247+
| Field | Value | Description |
2248+
|--------|-------|-------------|
2249+
| result | String | The value `success` indicates that this is a successful response. |
2250+
| marker | String | (May be omitted) [Pagination](#pagination) marker. |
2251+
| count | Integer | Number of results in the `markets` field. |
2252+
| rows | Array of Fee Summary Objects | Network fee statistics for each specific interval. |
2253+
2254+
Each Fee Summary object has the following fields:
2255+
2256+
| Field | Value | Description |
2257+
|--------|-------|-------------|
2258+
| avg | Number | Average network fee |
2259+
| min | Number | Minimum network fee |
2260+
| max | Number | Maximum network fee |
2261+
| total | Number | Total XRP consumed as network fees |
2262+
| tx_count | Number | Number of transactions in this interval |
2263+
| date | String - [Timestamp][] | Interval start time or ledger close time |
2264+
| ledger_index | Integer | Ledger index (present in `ledger` interval only) |
2265+
2266+
#### Example ####
2267+
2268+
Request:
2269+
2270+
```
2271+
GET /v2/network/fees?interval=hour
2272+
```
2273+
2274+
Response:
2275+
2276+
```
2277+
{
2278+
result: "success",
2279+
marker: "hour|20130124080000",
2280+
count: 200,
2281+
rows: [
2282+
{
2283+
avg: 0.00001,
2284+
max: 0.00001,
2285+
min: 0.00001,
2286+
total: 0.00001,
2287+
tx_count: 1,
2288+
date: "2013-01-02T06:00:00Z"
2289+
},
2290+
...
2291+
]
2292+
}
2293+
```
2294+
2295+
2296+
2297+
22122298
## Get Topology ##
22132299
[[Source]<br>](https://github.com/ripple/rippled-historical-database/blob/develop/api/routesV2/network/getTopology.js "Source")
22142300

api/routesV2/accountExchanges.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ AccountExchanges = function (req, res, next) {
1717

1818
} else if (!options.end) {
1919
errorResponse({
20-
error: 'invalid start date format',
20+
error: 'invalid end date format',
2121
code: 400
2222
});
2323
return;

api/routesV2/network/getFees.js

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
'use strict';
2+
3+
var Logger = require('../../../lib/logger');
4+
var log = new Logger({scope: 'network fees'});
5+
var smoment = require('../../../lib/smoment');
6+
var utils = require('../../../lib/utils');
7+
8+
var hbase;
9+
var intervals = [
10+
'ledger',
11+
'hour',
12+
'day'
13+
];
14+
15+
var getFees = function(req, res) {
16+
var options = {
17+
interval: req.query.interval || 'ledger',
18+
start: smoment(req.query.start || '2013-01-01'),
19+
end: smoment(req.query.end),
20+
limit: req.query.limit,
21+
marker: req.query.marker,
22+
descending: (/true/i).test(req.query.descending) ? true : false,
23+
format: (req.query.format || 'json').toLowerCase()
24+
};
25+
26+
if (!options.start) {
27+
errorResponse({
28+
error: 'invalid start date format',
29+
code: 400
30+
});
31+
return;
32+
33+
} else if (!options.end) {
34+
errorResponse({
35+
error: 'invalid end date format',
36+
code: 400
37+
});
38+
return;
39+
40+
} else if (intervals.indexOf(options.interval) === -1) {
41+
errorResponse({
42+
error: 'invalid interval',
43+
code: 400
44+
});
45+
return;
46+
}
47+
48+
if (isNaN(options.limit)) {
49+
options.limit = 200;
50+
} else if (options.limit > 1000) {
51+
options.limit = 1000;
52+
}
53+
54+
log.info('interval:', options.interval);
55+
56+
hbase.getNetworkFees(options)
57+
.then(successResponse)
58+
.catch(errorResponse);
59+
60+
/**
61+
* errorResponse
62+
* return an error response
63+
* @param {Object} err
64+
*/
65+
66+
function errorResponse(err) {
67+
log.error(err.error || err);
68+
if (err.code && err.code.toString()[0] === '4') {
69+
res.status(err.code).json({
70+
result: 'error',
71+
message: err.error
72+
});
73+
} else {
74+
res.status(500).json({
75+
result: 'error',
76+
message: 'unable to retrieve fee summary(s)'
77+
});
78+
}
79+
}
80+
81+
/**
82+
* successResponse
83+
* return a successful response
84+
* @param {Object} markets
85+
* @param {Object} options
86+
*/
87+
88+
function successResponse(data) {
89+
var filename;
90+
91+
if (data.marker) {
92+
utils.addLinkHeader(req, res, data.marker);
93+
}
94+
95+
if (options.format === 'csv') {
96+
filename = 'network fees.csv';
97+
res.csv(data.rows, filename);
98+
99+
} else {
100+
res.json({
101+
result: 'success',
102+
marker: data.marker,
103+
count: data.rows.length,
104+
rows: data.rows
105+
});
106+
}
107+
}
108+
};
109+
110+
module.exports = function(db) {
111+
hbase = db;
112+
return getFees;
113+
};

api/routesV2/network/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module.exports = function(db) {
77
xrpDistribution: require('./xrpDistribution')(db),
88
topMarkets: require('./topMarkets')(db),
99
topCurrencies: require('./topCurrencies')(db),
10+
getFees: require('./getFees')(db),
1011
getNodes: require('./getNodes')(db),
1112
getLinks: require('./getLinks')(db),
1213
getTopology: require('./getTopology')(db),

api/server.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ var Server = function (options) {
6868
app.get('/v2/network/xrp_distribution', routesV2.network.xrpDistribution);
6969
app.get('/v2/network/top_markets/:date?', routesV2.network.topMarkets);
7070
app.get('/v2/network/top_currencies/:date?', routesV2.network.topCurrencies);
71+
app.get('/v2/network/fees', routesV2.network.getFees);
7172
app.get('/v2/network/topology', routesV2.network.getTopology);
7273
app.get('/v2/network/topology/nodes', routesV2.network.getNodes);
7374
app.get('/v2/network/topology/nodes/:pubkey', routesV2.network.getNodes);

lib/hbase/hbase-thrift/data.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1860,6 +1860,55 @@ HbaseClient.getTransactions = function(options, callback) {
18601860
}
18611861
};
18621862

1863+
/**
1864+
* getNetworkFees
1865+
*/
1866+
1867+
HbaseClient.getNetworkFees = function(options) {
1868+
var self = this;
1869+
var startRow = [
1870+
options.interval,
1871+
options.start.hbaseFormatStartRow()
1872+
].join('|');
1873+
1874+
var stopRow = [
1875+
options.interval,
1876+
options.end.hbaseFormatStopRow()
1877+
].join('|');
1878+
1879+
return new Promise(function(resolve, reject) {
1880+
self.getScanWithMarker(self, {
1881+
table: 'network_fees',
1882+
startRow: startRow,
1883+
stopRow: stopRow,
1884+
limit: options.limit,
1885+
marker: options.marker,
1886+
descending: options.descending
1887+
}, function(err, resp) {
1888+
if (err) {
1889+
reject(err);
1890+
} else {
1891+
resp.rows.forEach(function(r) {
1892+
if (r.ledger_index) {
1893+
r.ledger_index = Number(r.ledger_index);
1894+
}
1895+
1896+
r.avg = Number(r.avg);
1897+
r.max = Number(r.max);
1898+
r.min = Number(r.min);
1899+
r.total = Number(r.total);
1900+
r.tx_count = Number(r.tx_count);
1901+
1902+
delete r.interval;
1903+
delete r.rowkey;
1904+
});
1905+
1906+
resolve(resp);
1907+
}
1908+
});
1909+
});
1910+
}
1911+
18631912
/**
18641913
* getAccounts
18651914
*/

test/setup.importLedgers.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ var moment = require('moment');
88
var exAggregation = require('../lib/aggregation/exchanges');
99
var statsAggregation = require('../lib/aggregation/stats');
1010
var paymentsAggregation = require('../lib/aggregation/accountPayments');
11+
var feesAggregation = require('../lib/aggregation/fees');
1112

1213
var fs = require('fs');
1314
var path = __dirname + '/mock/ledgers/';
@@ -17,10 +18,12 @@ var statsConfig;
1718
var updates = [];
1819
var exchanges = [];
1920
var payments = [];
21+
var fees = [];
2022
var pairs = { };
2123
var hbase;
2224
var stats;
2325
var aggPayments;
26+
var aggFees;
2427

2528

2629
hbaseConfig.prefix = config.get('prefix');
@@ -29,6 +32,7 @@ hbaseConfig.max_sockets = 100;
2932
hbaseConfig.timeout = 60000;
3033

3134
aggPayments = new paymentsAggregation(hbaseConfig);
35+
aggFees = new feesAggregation(hbaseConfig);
3236
stats = new statsAggregation(hbaseConfig);
3337
hbase = new HBase(hbaseConfig);
3438

@@ -46,6 +50,9 @@ describe('import ledgers', function(done) {
4650
//save payments
4751
payments.push.apply(payments, parsed.payments);
4852

53+
//save fees
54+
fees.push(parsed.feeSummary);
55+
4956
//save stats
5057
addStats(parsed);
5158
updates.push({
@@ -76,6 +83,19 @@ describe('import ledgers', function(done) {
7683
});
7784
});
7885

86+
it('should aggregate network fees', function(done) {
87+
this.timeout(7000);
88+
Promise.map(fees, function(feeSummary) {
89+
return aggFees.handleFeeSummary(feeSummary);
90+
})
91+
.then(function() {
92+
done();
93+
})
94+
.catch(function(e) {
95+
assert.ifError(e);
96+
});
97+
});
98+
7999
it('should save exchanges into hbase', function(done) {
80100
this.timeout(15000);
81101
exchanges.forEach(function(ex, i) {

0 commit comments

Comments
 (0)