Skip to content

Commit

Permalink
Merge branch 'develop' into fix/homepage-transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
alexeyandreevsky committed Dec 2, 2024
2 parents fccc113 + ffa2cc8 commit d152852
Show file tree
Hide file tree
Showing 16 changed files with 727 additions and 46 deletions.
7 changes: 5 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
branches:
- 'master'
pull_request:
branches: [ "master" ]
branches: [ "master", "develop" ]

env:
REGISTRY: ghcr.io
Expand All @@ -18,8 +18,11 @@ jobs:
runs-on: ubuntu-latest

steps:
- name: "Validate branch"
if: ${{github.base_ref == 'master'}}
run: exit 1
- name: "Validate label"
if: |
if: |
(contains(github.event.pull_request.labels.*.name, 'backend') ||
contains(github.event.pull_request.labels.*.name, 'data contract') ||
contains(github.event.pull_request.labels.*.name, 'frontend') ||
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
branches:
- "master"
- "*.*.*"
- "develop"
types:
- completed

Expand Down Expand Up @@ -36,11 +37,11 @@ jobs:
docker rm pe-testnet-api pe-testnet-indexer || true
drop_db:
runs-on: ubuntu-latest
runs-on: ubuntu-latest

needs: stop
needs: stop

steps:
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
Expand Down
130 changes: 120 additions & 10 deletions packages/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Reference:
* [Blocks](#blocks)
* [Validators](#validators)
* [Validator by ProTxHash](#validator-by-protxhash)
* [Validator by Masternode Identifier](#validator-by-masternode-identifier)
* [Validator Blocks Statistic](#validator-stats-by-protxhash)
* [Validator Rewards Statistic](#validator-rewards-stats-by-protxhash)
* [Transaction by hash](#transaction-by-hash)
Expand Down Expand Up @@ -150,17 +151,38 @@ Get a block by hash
GET /block/DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
{
"header": {
"hash": "04D16F8EE2A892E5F9F884C11DB97CD20BAA4A9539111A9131F847B93422DB26",
"height": 37994,
"timestamp": "2024-10-20T21:35:48.669Z",
"blockVersion": 14,
"appVersion": 4,
"l1LockedHeight": 1124953,
"validator": "8917BB546318F3410D1A7901C7B846A73446311B5164B45A03F0E613F208F234"
},
"txs": [
{
header: {
hash: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
height: 1337,
timestamp: "2024-03-18T10:13:54.150Z",
blockVersion: 13,
appVersion: 1,
l1LockedHeight: 1337
},
txs: ["DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"]
"hash": "49C07BEDB5710565CFC82F678DEB4849D2CA1CCD3DFBA6FDA3F1C0F3C39D0AD9",
"index": 0,
"blockHash": "04D16F8EE2A892E5F9F884C11DB97CD20BAA4A9539111A9131F847B93422DB26",
"blockHeight": 37994,
"type": 1,
"data": "AgDuMmDTP4yp4UxhCAbUbbj9M0NSKtDkSMDXiaFYkDf05gEAAAD8TaL0Ynpk50URo4Lr7GID83h4Q7YxOfxNyBcNWF7mwQEIcHJlb3JkZXLmaMZZr2au4ecsGG3ee1t+Ch1xKgnEDVch9iK/U8UxVe4PfekoUsU6NnJAmQzOoXBkr3P+LpzyoMFt1ppC7LqAARBzYWx0ZWREb21haW5IYXNoDLF9yHanBZpOsaoAIQ7+WgMlafEFgvsSfAqiyosXA967AAABQR8wm64iVoCLY0WmrqLS13iPcikGVcuYsqpuoqIWfYRLLlqXQlyHQ5XnsfTKor5spJtUz8gvlN3//sqH+sI8y/gz",
"timestamp": "2024-10-20T21:35:48.669Z",
"gasUsed": 34509040,
"status": "SUCCESS",
"error": null,
"owner": {
"identifier": "H2pb35GtKpjLinncBYeMsXkdDYXCbsFzzVmssce6pSJ1",
"aliases": [
{
"alias": "owl352-testnet.dash",
"status": "ok"
}
]
}
}
]
}
```
---
Expand Down Expand Up @@ -302,6 +324,89 @@ Get validator by ProTxHash.
```
GET /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"
},
proTxInfo: {
type: "Evo",
collateralHash: "6ce8545e25d4f03aba1527062d9583ae01827c65b234bd979aca5954c6ae3a59",
collateralIndex: 19,
collateralAddress: "yYK3Kiq36Xmf1ButkTUYb1iCNtJfSSM4KH",
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",
}
},
identity: "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",
endpoints: {
coreP2PPortStatus: {
host: '52.33.28.41',
port: 19999,
status: 'ERROR',
message: null
},
platformP2PPortStatus: {
host: '52.33.28.41',
port: 36656,
status: 'ERROR',
message: null
},
platformGrpcPortStatus: {
host: '52.33.28.41',
port: 1443,
status: 'ERROR',
message: null
}
}
}
```
---
### Validator by Masternode Identifier
Get validator by Masternode Identity.
* `lastProposedBlockHeader` field is nullable
```
GET /validator/identity/8tsWRSwsTM5AXv4ViCF9gu39kzjbtfFDM6rCyL2RcFzd
{
proTxHash: "F60A6BF9EC0794BB0CFD1E0F2217933F4B33EDE6FE810692BC275CA18148AEF0",
isActive: true,
Expand Down Expand Up @@ -461,9 +566,14 @@ Return transaction set paged
Status can be either `SUCCESS` or `FAIL`. In case of error tx, message will appear in the `error` field as Base64 string

* `limit` cannot be more then 100
* `owner` Identity identifier
* `status` can be `SUCCESS`, `FAIL` or `ALL`
* `transaction_type` number of tx type. Can be set multiple times
* `gas_min` number of min `gas_used`
* `gas_max` number of max `gas_used`

```
GET /transactions?=1&limit=10&order=asc
GET /transactions?=1&limit=10&order=asc&owner=6q9RFbeea73tE31LGMBLFZhtBUX3wZL3TcNynqE18Zgs&transaction_type=0&transaction_type=1&status=ALL&gas_min=0&gas_max=9999999
{
pagination: {
Expand Down
4 changes: 2 additions & 2 deletions packages/api/src/controllers/BlocksController.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const BlocksDAO = require('../dao/BlocksDAO')

class BlocksController {
constructor (knex) {
this.blocksDAO = new BlocksDAO(knex)
constructor (knex, dapi) {
this.blocksDAO = new BlocksDAO(knex, dapi)
}

getBlockByHash = async (request, response) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/controllers/MainController.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const PLATFORM_VERSION = '1' + require('../../package.json').dependencies.dash.s

class MainController {
constructor (knex, dapi) {
this.blocksDAO = new BlocksDAO(knex)
this.blocksDAO = new BlocksDAO(knex, dapi)
this.dataContractsDAO = new DataContractsDAO(knex)
this.documentsDAO = new DocumentsDAO(knex)
this.transactionsDAO = new TransactionsDAO(knex, dapi)
Expand Down
24 changes: 22 additions & 2 deletions packages/api/src/controllers/TransactionsController.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,33 @@ class TransactionsController {
}

getTransactions = async (request, response) => {
const { page = 1, limit = 10, order = 'asc' } = request.query
const {
page = 1, limit = 10,
order = 'asc', owner,
status = 'ALL',
// eslint-disable-next-line camelcase
gas_min, gas_max, transaction_type
} = 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 transactions = await this.transactionsDAO.getTransactions(Number(page ?? 1), Number(limit ?? 10), order)
// eslint-disable-next-line camelcase
if (transaction_type?.length === 0 && transaction_type) {
return response.status(400).send({ message: 'invalid filters values' })
}

const transactions = await this.transactionsDAO.getTransactions(
Number(page ?? 1),
Number(limit ?? 10),
order,
transaction_type,
owner,
status,
gas_min,
gas_max
)

response.send(transactions)
}
Expand Down
8 changes: 8 additions & 0 deletions packages/api/src/controllers/ValidatorsController.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ class ValidatorsController {
)
}

getValidatorByMasternodeIdentifier = async (request, response) => {
const { identifier } = request.params

const proTxHash = Buffer.from(base58.decode(identifier)).toString('hex')

await this.getValidatorByProTxHash({ ...request, params: { hash: proTxHash } }, response)
}

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

Expand Down
48 changes: 42 additions & 6 deletions packages/api/src/dao/BlocksDAO.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
const Block = require('../models/Block')
const PaginatedResultSet = require('../models/PaginatedResultSet')
const { getAliasInfo } = require('../utils')
const { base58 } = require('@scure/base')
const Transaction = require('../models/Transaction')

module.exports = class BlockDAO {
constructor (knex) {
constructor (knex, dapi) {
this.knex = knex
this.dapi = dapi
}

getStats = async () => {
Expand Down Expand Up @@ -34,19 +38,51 @@ module.exports = class BlockDAO {
}

getBlockByHash = async (blockHash) => {
const results = await this.knex
.select('blocks.hash as hash', 'state_transitions.hash as st_hash', 'blocks.height as height', 'blocks.timestamp as timestamp', 'blocks.block_version as block_version', 'blocks.app_version as app_version', 'blocks.l1_locked_height as l1_locked_height', 'blocks.validator as validator')
.from('blocks')
const aliasesSubquery = this.knex('identity_aliases')
.select('identity_identifier', this.knex.raw('array_agg(alias) as aliases'))
.groupBy('identity_identifier')
.as('aliases')

const rows = await this.knex('blocks')
.select(
'blocks.hash as hash', 'state_transitions.hash as tx_hash',
'blocks.height as height', 'blocks.timestamp as timestamp',
'blocks.block_version as block_version', 'blocks.app_version as app_version',
'blocks.l1_locked_height as l1_locked_height', 'blocks.validator as validator',
'state_transitions.gas_used as gas_used', 'state_transitions.data as data',
'state_transitions.status as status', 'state_transitions.owner as owner',
'aliases.aliases as aliases', 'state_transitions.error as error', 'block_hash',
'state_transitions.index as index', 'state_transitions.type as type'
)
.leftJoin('state_transitions', 'state_transitions.block_hash', 'blocks.hash')
.leftJoin(aliasesSubquery, 'aliases.identity_identifier', 'state_transitions.owner')
.whereILike('blocks.hash', blockHash)
.orderBy('state_transitions.index', 'asc')

const [block] = results
const [block] = rows

if (!block) {
return null
}

const txs = results.reduce((acc, value) => value.st_hash ? [...acc, value.st_hash] : acc, [])
const txs = block.tx_hash
? await Promise.all(rows.map(async (row) => {
const aliases = await Promise.all((row.aliases ?? []).map(async alias => {
const aliasInfo = await getAliasInfo(alias, this.dapi)

const isLocked = base58.encode(
Buffer.from(aliasInfo.contestedState?.finishedVoteInfo?.wonByIdentityId ?? ''),
'base64') !== row.identifier

return {
alias,
status: (aliasInfo.contestedState !== null && isLocked) ? 'locked' : 'ok'
}
}))

return Transaction.fromRow({ ...row, aliases })
}))
: []

return Block.fromRow({ header: block, txs })
}
Expand Down
Loading

0 comments on commit d152852

Please sign in to comment.