Skip to content

Commit

Permalink
Merge pull request #227 from pshenmic/feat/identity-balance
Browse files Browse the repository at this point in the history
Fetch Identity balance from DAPI GRPC
  • Loading branch information
pshenmic authored Sep 3, 2024
2 parents ca847a5 + f4224e0 commit 9ed566b
Show file tree
Hide file tree
Showing 10 changed files with 84 additions and 19 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@ env:
IMAGE_NAME: ${{ github.repository }}

jobs:
pull_request_lint:
pull_request_lint:
runs-on: ubuntu-latest

steps:
steps:
- name: "Validate label"
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') ||
contains(github.event.pull_request.labels.*.name, 'indexer')) == false &&
(github.event_name == 'pull_request')
(github.event_name == 'pull_request')
run: exit 1

test_data_contract:
needs: pull_request_lint
runs-on: ubuntu-latest
Expand Down
5 changes: 4 additions & 1 deletion packages/api/.env
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ DASHCORE_HOST=127.0.0.1
DASHCORE_PORT=19998
DASHCORE_USER=username
DASHCORE_PASS=password
EPOCH_CHANGE_TIME=3600000
EPOCH_CHANGE_TIME=3600000
DAPI_HOST=127.0.0.1
DAPI_PORT=1443
DAPI_PROTOCOL=http
18 changes: 14 additions & 4 deletions packages/api/src/controllers/IdentitiesController.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
const IdentitiesDAO = require('../dao/IdentitiesDAO')

class IdentitiesController {
constructor (knex) {
constructor (knex, dapi) {
this.identitiesDAO = new IdentitiesDAO(knex)
this.dapi = dapi
}

getIdentityByIdentifier = async (request, response) => {
Expand All @@ -14,7 +15,9 @@ class IdentitiesController {
return response.status(404).send({ message: 'not found' })
}

response.send(identity)
const balance = await this.dapi.getIdentityBalance(identifier)

response.send({ ...identity, balance })
}

getIdentityByDPNS = async (request, response) => {
Expand All @@ -26,15 +29,22 @@ class IdentitiesController {
return response.status(404).send({ message: 'not found' })
}

response.send(identity)
const balance = await this.dapi.getIdentityBalance(identity.identifier)

response.send({ ...identity, balance })
}

getIdentities = async (request, response) => {
const { page = 1, limit = 10, order = 'asc', order_by: orderBy = 'block_height' } = request.query

const identities = await this.identitiesDAO.getIdentities(Number(page), Number(limit), order, orderBy)

response.send(identities)
const identitiesWithBalance = await Promise.all(identities.resultSet.map(async identity => {
const balance = await this.dapi.getIdentityBalance(identity.identifier)
return { ...identity, balance }
}))

response.send({ ...identities, resultSet: identitiesWithBalance })
}

getTransactionsByIdentity = async (request, response) => {
Expand Down
11 changes: 8 additions & 3 deletions packages/api/src/controllers/MainController.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ const API_VERSION = require('../../package.json').version
const PLATFORM_VERSION = '1' + require('../../package.json').dependencies.dash.substring(1)

class MainController {
constructor (knex) {
constructor (knex, dapi) {
this.blocksDAO = new BlocksDAO(knex)
this.dataContractsDAO = new DataContractsDAO(knex)
this.documentsDAO = new DocumentsDAO(knex)
this.transactionsDAO = new TransactionsDAO(knex)
this.identitiesDAO = new IdentitiesDAO(knex)
this.validatorsDAO = new ValidatorsDAO(knex)
this.dapi = dapi
}

getStatus = async (request, response) => {
Expand Down Expand Up @@ -109,7 +110,9 @@ class MainController {
const identity = await this.identitiesDAO.getIdentityByIdentifier(query)

if (identity) {
return response.send({ identity })
const balance = await this.dapi.getIdentityBalance(identity.identifier)

return response.send({ identity: { ...identity, balance } })
}

// search data contracts
Expand All @@ -131,7 +134,9 @@ class MainController {
const identity = await this.identitiesDAO.getIdentityByDPNS(query)

if (identity) {
return response.send({ identity })
const balance = await this.dapi.getIdentityBalance(identity.identifier)

return response.send({ identity: { ...identity, balance } })
}
}

Expand Down
6 changes: 2 additions & 4 deletions packages/api/src/dao/IdentitiesDAO.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ module.exports = class IdentitiesDAO {
'tx_hash', 'is_system', 'blocks.timestamp as timestamp', 'recipient', 'amount')
.leftJoin('state_transitions', 'state_transitions.hash', 'tx_hash')
.leftJoin('blocks', 'state_transitions.block_hash', 'blocks.hash')
.select(this.knex.raw('COALESCE((select sum(amount) from transfers where recipient = identifier), 0) - COALESCE((select sum(amount) from transfers where sender = identifier), 0) as balance'))
.select(this.knex('state_transitions').count('*').where('owner', identifier).as('total_txs'))
.select(this.knex(documentsSubQuery).count('*').where('rank', 1).as('total_documents'))
.select(this.knex(dataContractsSubQuery).count('*').where('rank', 1).as('total_data_contracts'))
Expand Down Expand Up @@ -120,7 +119,7 @@ module.exports = class IdentitiesDAO {
.as('as_data_contracts')

const rows = await this.knex.with('with_alias', filteredIdentities)
.select('total_txs', 'balance', 'identity_id', 'identifier', 'identity_owner', 'revision', 'tx_hash', 'blocks.timestamp as timestamp', 'row_number', 'is_system')
.select('total_txs', 'identity_id', 'identifier', 'identity_owner', 'revision', 'tx_hash', 'blocks.timestamp as timestamp', 'row_number', 'is_system')
.select(this.knex('with_alias').count('*').as('total_count'))
.select(this.knex(this.knex(documentsSubQuery)
.select('id', this.knex.raw('rank() over (partition by as_documents.identifier order by as_documents.id desc) rank')).as('ranked_documents'))
Expand All @@ -142,8 +141,7 @@ module.exports = class IdentitiesDAO {
owner: row.identity_owner,
total_data_contracts: parseInt(row.total_data_contracts),
total_documents: parseInt(row.total_documents),
total_txs: parseInt(row.total_txs),
balance: parseInt(row.balance)
total_txs: parseInt(row.total_txs)
})), page, limit, totalCount)
}

Expand Down
18 changes: 18 additions & 0 deletions packages/api/src/dapi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const { Identifier } = require('@dashevo/wasm-dpp')

class DAPI {
dapi
dpp

constructor (dapi, dpp) {
this.dapi = dapi
this.dpp = dpp
}

async getIdentityBalance (identifier) {
const identity = await this.dapi.platform.getIdentity(Identifier.from(identifier))
return this.dpp.identity.createFromBuffer(identity.getIdentity()).balance
}
}

module.exports = DAPI
2 changes: 1 addition & 1 deletion packages/api/src/schemas.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const schemaTypes = [
},
orderBy: {
type: ['string', 'null'],
enum: ['block_height', 'documents_count']
enum: ['block_height', 'documents_count', 'tx_count', 'balance']
},
isActive: { type: ['boolean', 'null'] }
}
Expand Down
22 changes: 20 additions & 2 deletions packages/api/src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ const DataContractsController = require('./controllers/DataContractsController')
const ValidatorsController = require('./controllers/ValidatorsController')
const { getKnex } = require('./utils')
const BlocksDAO = require('./dao/BlocksDAO')
const DAPI = require('./dapi')
const DAPIClient = require('@dashevo/dapi-client')

function errorHandler (err, req, reply) {
if (err instanceof ServiceNotAvailableError) {
Expand All @@ -37,12 +39,28 @@ function errorHandler (err, req, reply) {
let client
let knex
let fastify
let dapi

module.exports = {
start: async () => {
client = new Dash.Client()

await client.platform.initialize()

const dapiClient = new DAPIClient({
dapiAddresses: [
{
host: process.env.DAPI_HOST ?? 'localhost',
port: process.env.DAPI_PORT ?? '1443',
protocol: process.env.DAPI_PROTOCOL ?? 'http'
}
]
})

const { dpp } = client.platform

dapi = new DAPI(dapiClient, dpp)

fastify = Fastify()

await fastify.register(cors, {
Expand All @@ -59,13 +77,13 @@ module.exports = {

await knex.raw('select 1+1')

const mainController = new MainController(knex)
const mainController = new MainController(knex, dapi)
const epochController = new EpochController(knex)
const blocksController = new BlocksController(knex)
const transactionsController = new TransactionsController(client, knex)
const dataContractsController = new DataContractsController(knex)
const documentsController = new DocumentsController(knex)
const identitiesController = new IdentitiesController(knex)
const identitiesController = new IdentitiesController(knex, dapi)
const validatorsController = new ValidatorsController(knex)

Routes({
Expand Down
8 changes: 8 additions & 0 deletions packages/api/test/integration/identities.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const { getKnex } = require('../../src/utils')
const fixtures = require('../utils/fixtures')
const StateTransitionEnum = require('../../src/enums/StateTransitionEnum')
const tenderdashRpc = require('../../src/tenderdashRpc')
const DAPI = require('../../src/dapi')

describe('Identities routes', () => {
let app
Expand All @@ -26,6 +27,8 @@ describe('Identities routes', () => {
let transactions

before(async () => {
mock.method(DAPI.prototype, 'getIdentityBalance', async () => 0)

mock.method(tenderdashRpc, 'getBlockByHeight', async () => ({
block: {
header: {
Expand Down Expand Up @@ -361,6 +364,11 @@ describe('Identities routes', () => {
identities.push({ identity, block, transfer })
}

mock.method(DAPI.prototype, 'getIdentityBalance', async (identifier) => {
const { identity } = identities.find(({ identity }) => identity.identifier === identifier)
return identity.balance
})

const { body } = await client.get('/identities?order_by=balance&order=desc')
.expect(200)
.expect('Content-Type', 'application/json; charset=utf-8')
Expand Down
5 changes: 5 additions & 0 deletions packages/api/test/integration/main.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const fixtures = require('../utils/fixtures')
const StateTransitionEnum = require('../../src/enums/StateTransitionEnum')
const { getKnex } = require('../../src/utils')
const tenderdashRpc = require('../../src/tenderdashRpc')
const DAPI = require('../../src/dapi')

const genesisTime = new Date(0)
const blockDiffTime = 2 * 3600 * 1000
Expand All @@ -26,6 +27,8 @@ describe('Other routes', () => {
let documentTransaction

before(async () => {
mock.method(DAPI.prototype, 'getIdentityBalance', async () => 0)

mock.method(tenderdashRpc, 'getBlockByHeight', async () => ({
block: {
header: {
Expand Down Expand Up @@ -185,6 +188,8 @@ describe('Other routes', () => {
})

it('should search by identity', async () => {
mock.method(DAPI.prototype, 'getIdentityBalance', async () => 0)

const { body } = await client.get(`/search?query=${identityAlias.alias}`)
.expect(200)
.expect('Content-Type', 'application/json; charset=utf-8')
Expand Down

0 comments on commit 9ed566b

Please sign in to comment.