Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement isActive validators filter #163

Merged
merged 9 commits into from
Jul 3, 2024
43 changes: 23 additions & 20 deletions packages/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,22 +177,24 @@ GET /blocks
### Validators
Return all validators with pagination info.
* `lastProposedBlockHeader` field is nullable
* `?isActive=true` boolean can be supplied in the query params to filter by isActive field
```
GET /validators

{
resultSet: [
{
"proTxHash": "F60A6BF9EC0794BB0CFD1E0F2217933F4B33EDE6FE810692BC275CA18148AEF0",
"proposedBlocksAmount": 5,
"lastProposedBlockHeader": {
"height": 5,
"timestamp": "2024-06-23T13:51:44.154Z",
"hash": "7253F441FF6AEAC847F9E03672B9386E35FC8CBCFC4A7CC67557FCA10E342904",
"l1LockedHeight": 1337,
"appVersion": 1,
"blockVersion": 13
"validator": "F60A6BF9EC0794BB0CFD1E0F2217933F4B33EDE6FE810692BC275CA18148AEF0"
proTxHash: "F60A6BF9EC0794BB0CFD1E0F2217933F4B33EDE6FE810692BC275CA18148AEF0",
isActive: true,
proposedBlocksAmount: 5,
lastProposedBlockHeader: {
height: 5,
timestamp: "2024-06-23T13:51:44.154Z",
hash: "7253F441FF6AEAC847F9E03672B9386E35FC8CBCFC4A7CC67557FCA10E342904",
l1LockedHeight: 1337,
appVersion: 1,
blockVersion: 13
validator: "F60A6BF9EC0794BB0CFD1E0F2217933F4B33EDE6FE810692BC275CA18148AEF0"
}
}, ...
],
Expand All @@ -211,16 +213,17 @@ Get validator by ProTxHash.
GET /validator/F60A6BF9EC0794BB0CFD1E0F2217933F4B33EDE6FE810692BC275CA18148AEF0

{
"proTxHash": "F60A6BF9EC0794BB0CFD1E0F2217933F4B33EDE6FE810692BC275CA18148AEF0",
"proposedBlocksAmount": 5,
"lastProposedBlockHeader": {
"height": 5,
"timestamp": "2024-06-23T13:51:44.154Z",
"hash": "7253F441FF6AEAC847F9E03672B9386E35FC8CBCFC4A7CC67557FCA10E342904",
"l1LockedHeight": 1337,
"appVersion": 1,
"blockVersion": 13,
"validator": "F60A6BF9EC0794BB0CFD1E0F2217933F4B33EDE6FE810692BC275CA18148AEF0"
proTxHash: "F60A6BF9EC0794BB0CFD1E0F2217933F4B33EDE6FE810692BC275CA18148AEF0",
isActive: true,
proposedBlocksAmount: 5,
lastProposedBlockHeader: {
height: 5,
timestamp: "2024-06-23T13:51:44.154Z",
hash: "7253F441FF6AEAC847F9E03672B9386E35FC8CBCFC4A7CC67557FCA10E342904",
l1LockedHeight: 1337,
appVersion: 1,
blockVersion: 13,
validator: "F60A6BF9EC0794BB0CFD1E0F2217933F4B33EDE6FE810692BC275CA18148AEF0"
}
}
```
Expand Down
35 changes: 31 additions & 4 deletions packages/api/src/controllers/ValidatorsController.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
const ValidatorsDAO = require('../dao/ValidatorsDAO')
const TenderdashRPC = require('../tenderdashRpc')
const Validator = require('../models/Validator')

class ValidatorsController {
constructor (knex) {
Expand All @@ -14,19 +16,44 @@ class ValidatorsController {
return response.status(404).send({ message: 'not found' })
}

response.send(validator)
const validators = await TenderdashRPC.getValidators()

const isActive = validators.some(validator => validator.proTxHash === proTxHash)

response.send(new Validator(validator.proTxHash, isActive, validator.proposedBlocksAmount, validator.lastProposedBlockHeader))
}

getValidators = async (request, response) => {
const { page = 1, limit = 10, order = 'asc' } = request.query
const { page = 1, limit = 10, order = 'asc', isActive = undefined } = request.query

if (order !== 'asc' && order !== 'desc') {
return response.status(400).send({ message: `invalid ordering value ${order}. only 'asc' or 'desc' is valid values` })
}

const validators = await this.validatorsDAO.getValidators(Number(page), Number(limit), order)
const activeValidators = await TenderdashRPC.getValidators()

if (typeof isActive !== 'undefined') {
if (isActive !== 'true' && isActive !== 'false') {
return response.status(400).send({ message: `invalid isActive value ${order}. only boolean values are accepted` })
}
}

response.send(validators)
const validators = await this.validatorsDAO.getValidators(
Number(page),
Number(limit),
order,
typeof isActive === 'undefined' ? undefined : isActive === 'true',
activeValidators
)

return response.send({
...validators,
resultSet: validators.resultSet.map(validator =>
new Validator(validator.proTxHash, activeValidators.some(activeValidator =>
activeValidator.proTxHash === validator.proTxHash),
validator.proposedBlocksAmount,
validator.lastProposedBlockHeader))
})
}
}

Expand Down
47 changes: 44 additions & 3 deletions packages/api/src/dao/ValidatorsDAO.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ module.exports = class ValidatorsDAO {
.where('validators.pro_tx_hash', proTxHash)
.as('validators')

const [row] = await this.knex(validatorsSubquery)
const subquery = this.knex(validatorsSubquery)
.select(
'pro_tx_hash',
'id',
Expand All @@ -38,6 +38,20 @@ module.exports = class ValidatorsDAO {
'blocks.block_version as block_version'
)
.leftJoin('blocks', 'blocks.hash', 'proposed_block_hash')
.as('blocks')

const [row] = await this.knex(subquery)
.select(
'id',
'pro_tx_hash',
'proposed_blocks_amount',
'block_hash',
'latest_height',
'latest_timestamp',
'l1_locked_height',
'app_version',
'block_version'
)
.where('pro_tx_hash', proTxHash)

if (!row) {
Expand All @@ -47,15 +61,34 @@ module.exports = class ValidatorsDAO {
return Validator.fromRow(row)
}

getValidators = async (page, limit, order) => {
/**
* Get all active / non
*
* @param page {number}
* @param limit {number}
* @param order {string}
* @param isActive {undefined | boolean}
* @param validators {[{}]} validators (from Tenderdash RPC)
*
* @returns {Promise<PaginatedResultSet>}
*/
getValidators = async (page, limit, order, isActive, validators) => {
const fromRank = ((page - 1) * limit) + 1
const toRank = fromRank + limit - 1

const validatorsSubquery = this.knex('validators')
.select(
'validators.pro_tx_hash as pro_tx_hash',
'validators.id',
this.knex('validators').count('pro_tx_hash').as('total_count'),
this.knex('validators')
.modify(function (knex) {
if (isActive !== undefined && isActive) {
knex.whereIn('pro_tx_hash', validators.map(validator => validator.proTxHash))
} else if (isActive !== undefined && !isActive) {
knex.whereNotIn('pro_tx_hash', validators.map(validator => validator.proTxHash))
}
})
.count('pro_tx_hash').as('total_count'),
this.knex('blocks')
.count('*')
.whereRaw('blocks.validator = validators.pro_tx_hash')
Expand Down Expand Up @@ -83,6 +116,13 @@ module.exports = class ValidatorsDAO {
'blocks.app_version as app_version',
'blocks.block_version as block_version'
)
.modify(function (knex) {
if (isActive !== undefined && isActive) {
knex.whereIn('pro_tx_hash', validators.map(validator => validator.proTxHash))
} else if (isActive !== undefined && !isActive) {
knex.whereNotIn('pro_tx_hash', validators.map(validator => validator.proTxHash))
}
})
.leftJoin('blocks', 'blocks.hash', 'proposed_block_hash')
.as('blocks')

Expand All @@ -104,6 +144,7 @@ module.exports = class ValidatorsDAO {
.orderBy('id', order)

const totalCount = rows.length > 0 ? Number(rows[0].total_count) : 0

const resultSet = rows.map((row) => Validator.fromRow(row))

return new PaginatedResultSet(resultSet, page, limit, totalCount)
Expand Down
8 changes: 6 additions & 2 deletions packages/api/src/models/Validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ const BlockHeader = require('./BlockHeader')

module.exports = class Validator {
proTxHash
isActive
proposedBlocksAmount
lastProposedBlockHeader

constructor (
proTxHash,
isActive,
proposedBlocksAmount,
lastProposedBlockHeader
) {
this.proTxHash = proTxHash ?? null
this.isActive = isActive ?? null
this.proposedBlocksAmount = proposedBlocksAmount ?? null
this.lastProposedBlockHeader = lastProposedBlockHeader ?? null
}
Expand All @@ -24,10 +27,12 @@ module.exports = class Validator {
block_hash,
l1_locked_height,
app_version,
block_version
block_version,
is_active
}) {
return new Validator(
pro_tx_hash,
is_active,
Number(proposed_blocks_amount),
block_hash
? BlockHeader.fromRow({
Expand All @@ -43,4 +48,3 @@ module.exports = class Validator {
)
}
}
/* eslint-disable camelcase */
6 changes: 6 additions & 0 deletions packages/api/src/tenderdashRpc.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ class TenderdashRPC {

return genesis
}

static async getValidators () {
const { validators } = await call('validators', 'GET')

return validators
}
}

module.exports = TenderdashRPC
Loading
Loading