Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
poli208 committed Oct 27, 2024
1 parent 3580ee9 commit 58c0580
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 5 deletions.
21 changes: 21 additions & 0 deletions packages/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ Reference:
* [Blocks](#blocks)
* [Validators](#validators)
* [Validator by ProTxHash](#validator-by-protxhash)
* [Validator Blocks Statistic](#validator-stats-by-protxhash)
* [Validator Rewards Statistic](#validator-rewards-stats-by-protxhash)
* [Transaction by hash](#transaction-by-hash)
* [Transactions](#transactions)
* [Data Contract By Identifier](#data-contract-by-identifier)
Expand Down Expand Up @@ -375,6 +377,25 @@ GET /validator/F60A6BF9EC0794BB0CFD1E0F2217933F4B33EDE6FE810692BC275CA18148AEF0
}
```
---
### Validator rewards stats by ProTxHash
Return a series data for the reward from proposed blocks by validator chart with

* `start` lower interval threshold in ISO string ( _optional_ )
* `end` upper interval threshold in ISO string ( _optional_ )


```
GET /validator/F60A6BF9EC0794BB0CFD1E0F2217933F4B33EDE6FE810692BC275CA18148AEF0/reward/stats?start=2024-01-01T00:00:00&end=2025-01-01T00:00:00
[
{
timestamp: "2024-06-23T13:51:44.154Z",
data: {
reward: 34000000
}
},...
]
```
---
### Validator stats by ProTxHash
Return a series data for the amount of proposed blocks by validator chart with

Expand Down
48 changes: 48 additions & 0 deletions packages/api/src/controllers/ValidatorsController.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,54 @@ class ValidatorsController {

response.send(stats)
}

getValidatorRewardStatsByProTxHash = async (request, response) => {
const { hash } = request.params
const {
start = new Date().getTime() - 3600000,
end = new Date().getTime(),
timespan = null
} = request.query

if (timespan) {
const possibleValues = ['1h', '24h', '3d', '1w']

if (possibleValues.indexOf(timespan) === -1) {
return response.status(400)
.send({ message: `invalid timespan value ${timespan}. only one of '${possibleValues}' is valid` })
}
}

let timespanStart = null
let timespanEnd = null

const timespanInterval = {
'1h': { offset: 3600000, step: 'PT5M' },
'24h': { offset: 86400000, step: 'PT2H' },
'3d': { offset: 259200000, step: 'PT6H' },
'1w': { offset: 604800000, step: 'PT14H' }
}[timespan]

if (start > end) {
return response.status(400).send({ message: 'start timestamp cannot be more than end timestamp' })
}

if (timespanInterval) {
timespanStart = new Date().getTime() - timespanInterval.offset
timespanEnd = new Date().getTime()
}

const interval = timespanInterval?.step ?? calculateInterval(new Date(start), new Date(end))

const stats = await this.validatorsDAO.getValidatorRewardStatsByProTxHash(
hash,
new Date(timespanStart ?? start),
new Date(timespanEnd ?? end),
interval
)

response.send(stats)
}
}

module.exports = ValidatorsController
32 changes: 32 additions & 0 deletions packages/api/src/dao/ValidatorsDAO.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,4 +231,36 @@ module.exports = class ValidatorsDAO {
}))
.map(({ timestamp, data }) => new SeriesData(timestamp, data))
}

getValidatorRewardStatsByProTxHash = async (proTxHash, start, end, interval) => {
const startSql = `'${start.toISOString()}'::timestamptz`

const endSql = `'${end.toISOString()}'::timestamptz`

const ranges = this.knex
.from(this.knex.raw(`generate_series(${startSql}, ${endSql}, '${interval}'::interval) date_to`))
.select('date_to', this.knex.raw('LAG(date_to, 1) over (order by date_to asc) date_from'))

const rows = await this.knex.with('ranges', ranges)
.select(this.knex.raw(`COALESCE(date_from, date_to - interval '${interval}'::interval) date_from`), 'date_to')
.select(
this.knex('blocks')
.whereRaw('blocks.timestamp > date_from and blocks.timestamp <= date_to')
.whereILike('validator', proTxHash)
.sum('gas_used')
.leftJoin('state_transitions', 'state_transitions.block_hash', 'blocks.hash')
.as('gas_used')
)
.from('ranges')

return rows
.slice(1)
.map(row => ({
timestamp: row.date_from,
data: {
reward: parseInt(row.gas_used ?? 0)
}
}))
.map(({ timestamp, data }) => new SeriesData(timestamp, data))
}
}
14 changes: 14 additions & 0 deletions packages/api/src/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,20 @@ module.exports = ({
querystring: { $ref: 'timeInterval#' }
}
},
{
path: '/validator/:hash/rewards/stats',
method: 'GET',
handler: validatorsController.getValidatorRewardStatsByProTxHash,
schema: {
params: {
type: 'object',
properties: {
hash: { $ref: 'hash#' }
}
},
querystring: { $ref: 'timeInterval#' }
}
},
{
path: '/validator/:hash',
method: 'GET',
Expand Down
64 changes: 64 additions & 0 deletions packages/api/test/integration/validators.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1717,6 +1717,70 @@ describe('Validators routes', () => {
assert.deepEqual(expectedStats.reverse(), body)
})

it('should return reward stats by proTxHash with custom timespan', async () => {
validators = [
await fixtures.validator(knex),
await fixtures.validator(knex)
]
blocks = []
transactions = []

const [validator] = validators

for (let i = 0; i <= 20; i++) {
const block = await fixtures.block(knex, {
validator: validators[i % 2].pro_tx_hash,
timestamp: new Date(new Date().getTime() + (3600000 * (i % 3)) + 30000000)
})

blocks.push(block)
}

for (let i = 0; i <= 35; i++) {
const transaction = await fixtures.transaction(knex, {
block_hash: blocks[i % 20].hash,
gas_used: 1000,
type: 0,
owner: identities[0].identifier
})
transactions.push(transaction)
}

const { body } = await client.get(`/validator/${validator.pro_tx_hash}/rewards/stats?start=${new Date(new Date().getTime() + 30000000).toISOString()}&end=${new Date(new Date().getTime() + 42000000).toISOString()}`)
.expect(200)
.expect('Content-Type', 'application/json; charset=utf-8')

const [firstPeriod] = body.toReversed()
const firstTimestamp = new Date(firstPeriod.timestamp).getTime()

const expectedStats = []

for (let i = 0; i < body.length; i++) {
const nextPeriod = firstTimestamp - 3600000 * i
const prevPeriod = firstTimestamp - 3600000 * (i - 1)

const rewardedBlocksHash = blocks.filter(block =>
(block.validator === validator.pro_tx_hash &&
block.timestamp.getTime() <= prevPeriod &&
block.timestamp.getTime() >= nextPeriod
))
.map(block => block.hash)

const txs = transactions.filter(transaction => rewardedBlocksHash.includes(transaction.block_hash))

expectedStats.push(
{
timestamp: new Date(nextPeriod).toISOString(),
data: {
reward: txs.length > 0 ? txs.reduce((total, next) => total + next.gas_used, 0) : 0
}
}
)
}

assert.deepEqual(expectedStats.reverse(), body)
})

it('should return error on wrong bounds', async () => {
await client.get(`/validator/${validators[0].pro_tx_hash}/stats?start=2025-01-02T00:00:00&end=2024-01-08T00:00:00`)
.expect(400)
Expand Down
40 changes: 35 additions & 5 deletions packages/frontend/src/app/api/content.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Reference:
* [Blocks](#blocks)
* [Validators](#validators)
* [Validator by ProTxHash](#validator-by-protxhash)
* [Validator Blocks Statistic](#validator-stats-by-protxhash)
* [Validator Rewards Statistic](#validator-rewards-stats-by-protxhash)
* [Transaction by hash](#transaction-by-hash)
* [Transactions](#transactions)
* [Data Contract By Identifier](#data-contract-by-identifier)
Expand Down Expand Up @@ -342,10 +344,34 @@ GET /validator/F60A6BF9EC0794BB0CFD1E0F2217933F4B33EDE6FE810692BC275CA18148AEF0
}
```
---
### Validator rewards stats by ProTxHash
Return a series data for the reward from proposed blocks by validator chart with

* `start` lower interval threshold in ISO string ( _optional_ )
* `end` upper interval threshold in ISO string ( _optional_ )


```
GET /validator/F60A6BF9EC0794BB0CFD1E0F2217933F4B33EDE6FE810692BC275CA18148AEF0/reward/stats?start=2024-01-01T00:00:00&end=2025-01-01T00:00:00
[
{
timestamp: "2024-06-23T13:51:44.154Z",
data: {
reward: 34000000
}
},...
]
```
---
### Validator stats by ProTxHash
Return a series data for the amount of proposed blocks by validator chart with variable timespan (1h, 24h, 3d, 1w)
Return a series data for the amount of proposed blocks by validator chart with

* `start` lower interval threshold in ISO string ( _optional_ )
* `end` upper interval threshold in ISO string ( _optional_ )


```
GET /validator/F60A6BF9EC0794BB0CFD1E0F2217933F4B33EDE6FE810692BC275CA18148AEF0/stats?timespan=24h
GET /validator/F60A6BF9EC0794BB0CFD1E0F2217933F4B33EDE6FE810692BC275CA18148AEF0/stats?start=2024-01-01T00:00:00&end=2025-01-01T00:00:00
[
{
timestamp: "2024-06-23T13:51:44.154Z",
Expand Down Expand Up @@ -772,9 +798,13 @@ Response codes:
500: Internal Server Error
```
### Transactions history
Return a series data for the amount of transactions chart with variable timespan (1h, 24h, 3d, 1w)
Return a series data for the amount of transactions chart

* `start` lower interval threshold in ISO string ( _optional_ )
* `end` upper interval threshold in ISO string ( _optional_ )

```
GET /transactions/history?timespan=1h
GET /transactions/history?start=2024-01-01T00:00:00&end=2025-01-01T00:00:00
[
{
timestamp: "2024-04-22T08:45:20.911Z",
Expand All @@ -797,7 +827,7 @@ GET /transactions/history?timespan=1h
Response codes:
```
200: OK
400: Invalid input, check timespan value
400: Invalid input, check start/end values
500: Internal Server Error
```
### Rate
Expand Down

0 comments on commit 58c0580

Please sign in to comment.