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

Validators info expansion #273

Merged
merged 59 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
e22a12e
initial commit
owl352 Sep 27, 2024
4c02323
`package.json` fix
owl352 Sep 27, 2024
c24ac51
added value on error
owl352 Oct 3, 2024
25689ee
lint
owl352 Oct 3, 2024
5141dbf
initial commit
owl352 Oct 3, 2024
9e0e27b
Revert "lint"
owl352 Oct 3, 2024
75f06c5
Revert "added value on error"
owl352 Oct 3, 2024
97f7f50
Revert "initial commit"
owl352 Oct 3, 2024
93d186f
lint
owl352 Oct 3, 2024
b6259d6
initial commi
owl352 Oct 5, 2024
0b45f33
fix
owl352 Oct 5, 2024
f6445d3
`README.md` update
owl352 Oct 5, 2024
b114f43
package.json update. Added rewards, balance and current epoch fields
owl352 Oct 9, 2024
337e15b
package.json update. Added rewards, balance and current epoch fields
owl352 Oct 9, 2024
4cb0a95
README.md update
owl352 Oct 9, 2024
438f4e9
lint
owl352 Oct 9, 2024
60bb532
bs58 removed
owl352 Oct 10, 2024
8986449
package.json fix
owl352 Oct 10, 2024
efde58e
Merge branch 'master' into feat/validators-info
owl352 Oct 10, 2024
977732f
lint
owl352 Oct 10, 2024
3739161
Merge remote-tracking branch 'origin/feat/validators-info' into feat/…
owl352 Oct 10, 2024
d92d0b8
Merge branch 'master' into feat/validators-info
owl352 Oct 11, 2024
dae5d92
Merge branch 'master' into feat/validators-info
owl352 Oct 11, 2024
1771487
Withdrawl field for by protx
owl352 Oct 11, 2024
ce8313f
names fix, structure fix
owl352 Oct 11, 2024
fa9d392
masternode vote decoding
owl352 Oct 12, 2024
0f36996
masternode vote decoding
owl352 Oct 12, 2024
ba26714
names fix
owl352 Oct 12, 2024
d107f20
epoch fix
owl352 Oct 12, 2024
d51980b
epochs test fix
owl352 Oct 12, 2024
457d27a
decode output in base64
owl352 Oct 12, 2024
4d713c8
fixes
owl352 Oct 12, 2024
4287831
lint
owl352 Oct 12, 2024
eafcaee
Merge branch 'master' into feat/validators-info
owl352 Oct 14, 2024
4eea8b0
last withdrawal time
owl352 Oct 14, 2024
a90515e
`README.md` fix
owl352 Oct 14, 2024
091d0db
withdrawals update
owl352 Oct 14, 2024
7ed8dc2
`README.md` update
owl352 Oct 14, 2024
3faf9cc
`README.md` update and tcp_connection_timeout fixes
owl352 Oct 14, 2024
6d9984c
EPOCHS update
owl352 Oct 15, 2024
bfaf068
`README.md` update
owl352 Oct 15, 2024
4e0172e
Merge branch 'feat/dpp&dapi-fix' into feat/validators-info
owl352 Oct 18, 2024
109a5b8
Merge branch 'master' into feat/validators-info
owl352 Oct 18, 2024
b315393
fixes
owl352 Oct 18, 2024
fa86fb4
fixes
owl352 Oct 18, 2024
82a76e0
lint
owl352 Oct 18, 2024
1302687
host fix
owl352 Oct 18, 2024
424be3c
test fixes, readme.md update
owl352 Oct 18, 2024
ef47baa
fixes, README.md update
owl352 Oct 18, 2024
f2e877d
validators tests fix
owl352 Oct 18, 2024
b61eebf
identities tests fix
owl352 Oct 18, 2024
b4817f0
fix
owl352 Oct 18, 2024
5c27a33
added reject
owl352 Oct 18, 2024
21a6e12
last epoch endpoint removed
owl352 Oct 18, 2024
590730e
connection fix
owl352 Oct 18, 2024
c60c60a
tiny fix
owl352 Oct 18, 2024
d98f279
tiny fix
owl352 Oct 18, 2024
42740d5
tiny fix
owl352 Oct 18, 2024
1831467
tiny fix
owl352 Oct 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/api/.env
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ DASHCORE_USER=username
DASHCORE_PASS=password
EPOCH_CHANGE_TIME=3600000
DAPI_URL=127.0.0.1:1443:self-signed
TCP_CONNECT_TIMEOUT=400
88 changes: 68 additions & 20 deletions packages/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Reference:
* [Transactions By Identity](#transactions-by-identity)
* [Transfers by Identity](#transfers-by-identity)
* [Transactions history](#transactions-history)
* [Rate](#rates)
* [Rate](#rate)

### Status
Returns basic stats and epoch info
Expand Down Expand Up @@ -266,7 +266,21 @@ GET /validators
pubKeyOperator: "b928fa4e127214ccb2b5de1660b5e371d2f3c9845077bc3900fc6aabe82ddd2e61530be3765cea15752e30fc761ab730"
}
},
identity: "8tsWRSwsTM5AXv4ViCF9gu39kzjbtfFDM6rCyL2RcFzd"
identifier: "8tsWRSwsTM5AXv4ViCF9gu39kzjbtfFDM6rCyL2RcFzd",
identityBalance: 0,
epochInfo: {
number: 1982,
firstBlockHeight: 31976,
firstCoreBlockHeight: 1118131,
startTime: 1728488466559,
feeMultiplier: 1,
endTime: 1728492066559
},
totalReward: 0,
epochReward: 0,
withdrawalsCount: null,
lastWithdrawal: null,
lastWithdrawalTime: null,
}, ...
],
pagination: {
Expand Down Expand Up @@ -304,25 +318,56 @@ GET /validator/F60A6BF9EC0794BB0CFD1E0F2217933F4B33EDE6FE810692BC275CA18148AEF0
operatorReward: 0,
confirmations: 214424,
state: {
version: 2,
service: "35.164.23.245:19999",
registeredHeight: 850334,
lastPaidHeight: 1064721,
consecutivePayments: 0,
PoSePenalty: 0,
PoSeRevivedHeight: 1027671,
PoSeBanHeight: -1,
revocationReason: 0,
ownerAddress: "yWrbg8HNwkogZfqKe1VW8czS9KiqdjvJtE",
votingAddress: "yWrbg8HNwkogZfqKe1VW8czS9KiqdjvJtE",
platformNodeID: "b5f25f8f70cf8d05c2d2970bdf186c994431d84e",
platformP2PPort: 36656,
platformHTTPPort: 1443,
payoutAddress: "yeRZBWYfeNE4yVUHV4ZLs83Ppn9aMRH57A",
pubKeyOperator: "b928fa4e127214ccb2b5de1660b5e371d2f3c9845077bc3900fc6aabe82ddd2e61530be3765cea15752e30fc761ab730"
version: 2,
service: "35.164.23.245:19999",
registeredHeight: 850334,
lastPaidHeight: 1064721,
consecutivePayments: 0,
PoSePenalty: 0,
PoSeRevivedHeight: 1027671,
PoSeBanHeight: -1,
revocationReason: 0,
ownerAddress: "yWrbg8HNwkogZfqKe1VW8czS9KiqdjvJtE",
votingAddress: "yWrbg8HNwkogZfqKe1VW8czS9KiqdjvJtE",
platformNodeID: "b5f25f8f70cf8d05c2d2970bdf186c994431d84e",
platformP2PPort: 36656,
platformHTTPPort: 1443,
payoutAddress: "yeRZBWYfeNE4yVUHV4ZLs83Ppn9aMRH57A",
pubKeyOperator: "b928fa4e127214ccb2b5de1660b5e371d2f3c9845077bc3900fc6aabe82ddd2e61530be3765cea15752e30fc761ab730",
endpoints: {
coreP2PPortStatus: {
host: '52.33.28.41',
port: 19999,
status: 'ERROR'
},
platformP2PPortStatus: {
host: '52.33.28.41',
port: 36656,
status: 'ERROR'
},
platformGrpcPortStatus: {
host: '52.33.28.41',
port: 1443,
status: 'ERROR'
}
}
}
},
"identity: "8tsWRSwsTM5AXv4ViCF9gu39kzjbtfFDM6rCyL2RcFzd"
identifier: "8tsWRSwsTM5AXv4ViCF9gu39kzjbtfFDM6rCyL2RcFzd",
identityBalance: 0,
epochInfo: {
number: 1982,
firstBlockHeight: 31976,
firstCoreBlockHeight: 1118131,
startTime: 1728488466559,
feeMultiplier: 1,
endTime: 1728492066559
},
totalReward: 0,
epochReward: 0,
withdrawalsCount: 1,
lastWithdrawal: "01FE1F00379C66C6E3BFD81A088E57E17613EC36E4FF812458535A8ABCB84047",
lastWithdrawalTime: "2024-10-12T03:15:19.257Z"
}
```
---
Expand Down Expand Up @@ -729,7 +774,7 @@ Response codes:
Return all transfers made by the given identity
* `limit` cannot be more then 100
```
GET /identities/GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec/transfers?page=1&limit=10&order=asc
GET /identities/GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec/transfers?page=1&limit=10&order=asc&type=1

{
pagination: {
Expand All @@ -743,6 +788,9 @@ GET /identities/GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec/transfers?page=1&li
sender: "GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec",
recipient: "GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec",
timestamp: "2024-03-18T10:13:54.150Z",
txHash: "445E6F081DEE877867816AD3EF492E2C0BD1DDCCDC9C793B23DDDAF8AEA23118",
type: 6,
blockHash: "73171E0A8DCC10C6DA501E1C70A9C1E0BD6F1F8F834C2A1E787AF19B1F361D5E"
}, ...
]
}
Expand Down
1 change: 1 addition & 0 deletions packages/api/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ let genesisTime

module.exports = {
EPOCH_CHANGE_TIME: Number(process.env.EPOCH_CHANGE_TIME),
TCP_CONNECT_TIMEOUT: Number(process.env.TCP_CONNECT_TIMEOUT),
get genesisTime () {
if (!genesisTime || isNaN(genesisTime)) {
return TenderdashRPC.getBlockByHeight(1).then((blockInfo) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/controllers/EpochController.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class EpochController {
const { index } = request.params

try {
const [currentEpoch, nextEpoch] = await this.dapi.getEpochsInfo(2, index, true)
const [currentEpoch, nextEpoch] = await this.dapi.getEpochsInfo(2, index ?? undefined, index ? true : undefined)

const epoch = Epoch.fromObject({ ...currentEpoch, nextEpoch })

Expand Down
20 changes: 18 additions & 2 deletions packages/api/src/controllers/IdentitiesController.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const IdentitiesDAO = require('../dao/IdentitiesDAO')
const { IDENTITY_CREDIT_WITHDRAWAL } = require('../enums/StateTransitionEnum')

class IdentitiesController {
constructor (knex, dapi) {
Expand Down Expand Up @@ -76,12 +77,27 @@ class IdentitiesController {

getTransfersByIdentity = async (request, response) => {
const { identifier } = request.params
const { page = 1, limit = 10, order = 'asc' } = request.query
const { page = 1, limit = 10, order = 'asc', type = undefined } = request.query

const transfers = await this.identitiesDAO.getTransfersByIdentity(identifier, Number(page ?? 1), Number(limit ?? 10), order)
const transfers = await this.identitiesDAO.getTransfersByIdentity(identifier, Number(page ?? 1), Number(limit ?? 10), order, type)

response.send(transfers)
}

getWithdrawalsByIdentity = async (request, response) => {
const { identifier } = request.params
const { page = 1, limit = 10, order = 'asc' } = request.query

const withdrawals = await this.identitiesDAO.getTransfersByIdentity(
identifier,
Number(page ?? 1),
Number(limit ?? 10),
order ?? 'asc',
IDENTITY_CREDIT_WITHDRAWAL
)

response.send(withdrawals)
}
}

module.exports = IdentitiesController
99 changes: 81 additions & 18 deletions packages/api/src/controllers/ValidatorsController.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,26 @@ const TenderdashRPC = require('../tenderdashRpc')
const Validator = require('../models/Validator')
const DashCoreRPC = require('../dashcoreRpc')
const ProTxInfo = require('../models/ProTxInfo')
const { checkTcpConnect } = require('../utils')
const Epoch = require('../models/Epoch')
const { base58 } = require('@scure/base')

class ValidatorsController {
constructor (knex) {
constructor (knex, dapi) {
this.validatorsDAO = new ValidatorsDAO(knex)
this.dapi = dapi
}

getValidatorByProTxHash = async (request, response) => {
const { hash } = request.params

const validator = await this.validatorsDAO.getValidatorByProTxHash(hash)
const [currentEpoch] = await this.dapi.getEpochsInfo(1)
const epochInfo = Epoch.fromObject(currentEpoch)

const identifier = base58.encode(Buffer.from(hash, 'hex'))
const identityBalance = await this.dapi.getIdentityBalance(identifier)

const validator = await this.validatorsDAO.getValidatorByProTxHash(hash, identifier, epochInfo)

if (!validator) {
return response.status(404).send({ message: 'not found' })
Expand All @@ -24,13 +34,49 @@ class ValidatorsController {

const isActive = validators.some(validator => validator.pro_tx_hash === hash)

const [host] = proTxInfo?.state.service ? proTxInfo?.state.service.match(/^\d+\.\d+\.\d+\.\d+/) : [null]
const [servicePort] = proTxInfo?.state.service ? proTxInfo?.state.service.match(/\d+$/) : [null]

const [coreStatus, platformStatus, grpcStatus] = (await Promise.allSettled([
checkTcpConnect(servicePort, host),
checkTcpConnect(proTxInfo?.state.platformP2PPort, host),
checkTcpConnect(proTxInfo?.state.platformHTTPPort, host)
])).map((e) => e?.reason.code ? e?.reason.code : e.message)

const endpoints = {
coreP2PPortStatus: {
host,
port: Number(servicePort),
status: coreStatus
},
platformP2PPortStatus: {
host,
port: Number(proTxInfo?.state.platformP2PPort),
status: platformStatus
},
platformGrpcPortStatus: {
host,
port: Number(proTxInfo?.state.platformHTTPPort ?? 0),
status: grpcStatus
}
}

response.send(
new Validator(
validator.proTxHash,
isActive,
validator.proposedBlocksAmount,
validator.lastProposedBlockHeader,
ProTxInfo.fromObject(proTxInfo)
Validator.fromObject(
{
...validator,
isActive,
proTxInfo: ProTxInfo.fromObject({
...proTxInfo,
state: {
...proTxInfo.state,
endpoints
}
}),
identifier,
identityBalance,
epochInfo
}
)
)
}
Expand All @@ -40,29 +86,46 @@ class ValidatorsController {

const activeValidators = await TenderdashRPC.getValidators()

const [currentEpoch] = await this.dapi.getEpochsInfo(1)
const epochInfo = Epoch.fromObject(currentEpoch)

const validators = await this.validatorsDAO.getValidators(
Number(page ?? 1),
Number(limit ?? 10),
order,
isActive,
activeValidators
activeValidators,
epochInfo
)

const validatorsWithInfo = await Promise.all(
validators.resultSet.map(async (validator) =>
({ ...validator, proTxInfo: await DashCoreRPC.getProTxInfo(validator.proTxHash) })))

const resultSet = await Promise.all(
validatorsWithInfo.map(
async (validator) => {
const identifier = validator.proTxHash ? base58.encode(Buffer.from(validator.proTxHash, 'hex')) : null
const identityBalance = identifier ? await this.dapi.getIdentityBalance(identifier) : null

return Validator.fromObject(
{
...validator,
isActive: activeValidators.some(activeValidator =>
activeValidator.pro_tx_hash === validator.proTxHash),
proTxInfo: ProTxInfo.fromObject(validator.proTxInfo),
identifier,
identityBalance,
epochInfo
}
)
}
)
)

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

Expand Down
31 changes: 23 additions & 8 deletions packages/api/src/dao/IdentitiesDAO.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,21 +266,36 @@ module.exports = class IdentitiesDAO {
return new PaginatedResultSet(rows.map(row => Transaction.fromRow(row)), page, limit, totalCount)
}

getTransfersByIdentity = async (identifier, page, limit, order) => {
getTransfersByIdentity = async (identifier, page, limit, order, type) => {
const fromRank = (page - 1) * limit + 1
const toRank = fromRank + limit - 1

const subquery = this.knex('transfers')
.select('transfers.id as id', 'transfers.amount as amount', 'transfers.sender as sender', 'transfers.recipient as recipient', 'transfers.state_transition_hash as tx_hash')
.select(this.knex.raw(`rank() over (order by id ${order}) rank`))
.where('transfers.sender', '=', identifier)
.orWhere('transfers.recipient', '=', identifier)
.select(
'transfers.id as id', 'transfers.amount as amount',
'transfers.sender as sender', 'transfers.recipient as recipient',
'transfers.state_transition_hash as tx_hash',
'state_transitions.block_hash as block_hash',
'state_transitions.type as type'

)
.select(this.knex.raw(`rank() over (order by transfers.id ${order}) rank`))
.whereRaw(`(transfers.sender = '${identifier}' OR transfers.recipient = '${identifier}') ${
typeof type === 'number'
? `AND state_transitions.type = ${type}`
: ''
}`)
.leftJoin('state_transitions', 'state_transitions.hash', 'transfers.state_transition_hash')

const rows = await this.knex.with('with_alias', subquery)
.select('with_alias.id', 'amount', 'sender', 'recipient', 'rank', 'tx_hash', 'blocks.timestamp as timestamp')
.select(
'rank', 'amount', 'block_hash', 'type',
'sender', 'recipient', 'with_alias.id',
'tx_hash', 'blocks.timestamp as timestamp',
'block_hash'
)
.select(this.knex('with_alias').count('*').as('total_count'))
.leftJoin('state_transitions', 'state_transitions.hash', 'tx_hash')
.leftJoin('blocks', 'blocks.hash', 'state_transitions.block_hash')
.leftJoin('blocks', 'blocks.hash', 'with_alias.block_hash')
.from('with_alias')
.whereBetween('rank', [fromRank, toRank])
.orderBy('with_alias.id', order)
Expand Down
Loading
Loading