diff --git a/src/api/routes/v2-state/get_proposals/get_proposals.ts b/src/api/routes/v2-state/get_proposals/get_proposals.ts index 8265cf2a..060743b5 100644 --- a/src/api/routes/v2-state/get_proposals/get_proposals.ts +++ b/src/api/routes/v2-state/get_proposals/get_proposals.ts @@ -1,8 +1,8 @@ -import {FastifyInstance, FastifyReply, FastifyRequest} from "fastify"; -import {getTrackTotalHits, timedQuery} from "../../../helpers/functions.js"; +import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; +import { getTrackTotalHits, timedQuery } from "../../../helpers/functions.js"; +import { estypes } from '@elastic/elasticsearch'; async function getProposals(fastify: FastifyInstance, request: FastifyRequest) { - const query: any = request.query; // Pagination @@ -17,81 +17,124 @@ async function getProposals(fastify: FastifyInstance, request: FastifyRequest) { return 'invalid limit parameter'; } - let queryStruct: any = { - "bool": { - "must": [] - } + const maxDocs = fastify.manager.config.api.limits.get_proposals ?? 100; + + const response: any = { + query_time_ms: 0, + cached: false, + total: 0, + proposals: [], + last_indexed_block: 0, + last_indexed_block_time: '' }; - // Filter by accounts - if (query.account) { - const accounts = query.account.split(','); - for(const acc of accounts) { - queryStruct.bool.must.push({ - "bool": { - "should": [ - {"term": {"requested_approvals.actor": acc}}, - {"term": {"provided_approvals.actor": acc}} - ] - } - }); + let stateResult: any[]; + const startTime = Date.now(); // Inicia o cronômetro para a consulta + + // Verifica se a consulta deve ser feita no MongoDB + if (fastify.manager.config.indexer.experimental_mongodb_state && fastify.manager.conn.mongodb && query.useMongo === 'true') { + const dbName = `${fastify.manager.conn.mongodb.database_prefix}_${fastify.manager.chain}`; + const collection = fastify.mongo.client.db(dbName).collection('proposals'); + + const mongoQuery: any = {}; + if (query.account) { + const accounts = query.account.split(','); + mongoQuery.$or = [ + { "requested_approvals.actor": { $in: accounts } }, + { "provided_approvals.actor": { $in: accounts } } + ]; + } + if (query.proposer) { + mongoQuery.proposer = query.proposer; + } + if (query.proposal) { + mongoQuery.proposal_name = query.proposal; + } + if (typeof query.executed !== 'undefined') { + mongoQuery.executed = query.executed; + } + if (query.requested) { + mongoQuery["requested_approvals.actor"] = query.requested; + } + if (query.provided) { + mongoQuery["provided_approvals.actor"] = query.provided; } - } - - // Filter by proposer account - if (query.proposer) { - queryStruct.bool.must.push({"term": {"proposer": query.proposer}}); - } - - // Filter by proposal name - if (query.proposal) { - queryStruct.bool.must.push({"term": {"proposal_name": query.proposal}}); - } - // Filter by execution status - if (typeof query.executed !== 'undefined') { - queryStruct.bool.must.push({"term": {"executed": query.executed}}); - } + // Consultar MongoDB + console.log(`Consultar Mongo`) + const lastBlockResult = await fastify.mongo.client.db(dbName).collection('proposals').find().sort({ block_num: -1 }).limit(1).toArray(); + response.last_indexed_block = lastBlockResult[0]?.block_num || 0; + response.last_indexed_block_time = lastBlockResult[0]?.block_time || ''; + + response.total = await collection.countDocuments(mongoQuery); + stateResult = await collection + .find(mongoQuery) + .skip(skip || 0) + .limit(limit || 50) + .toArray(); + + } else { + // Caso não seja no MongoDB, faz a consulta no Elasticsearch + console.log(`Consultar Elastic`) + let queryStruct: any = { bool: { must: [] } }; + if (query.account) { + const accounts = query.account.split(','); + for (const acc of accounts) { + queryStruct.bool.must.push({ + bool: { + should: [ + { term: { "requested_approvals.actor": acc } }, + { term: { "provided_approvals.actor": acc } } + ] + } + }); + } + } + if (query.proposer) { + queryStruct.bool.must.push({ term: { proposer: query.proposer } }); + } + if (query.proposal) { + queryStruct.bool.must.push({ term: { proposal_name: query.proposal } }); + } + if (typeof query.executed !== 'undefined') { + queryStruct.bool.must.push({ term: { executed: query.executed } }); + } + if (query.requested) { + queryStruct.bool.must.push({ term: { "requested_approvals.actor": query.requested } }); + } + if (query.provided) { + queryStruct.bool.must.push({ term: { "provided_approvals.actor": query.provided } }); + } - // Filter by requested actors - if (query.requested) { - queryStruct.bool.must.push({"term": {"requested_approvals.actor": query.requested}}); - } + if (queryStruct.bool.must.length === 0) { + queryStruct = { match_all: {} }; + } - // Filter by provided actors - if (query.provided) { - queryStruct.bool.must.push({"term": {"provided_approvals.actor": query.provided}}); + // Consultar Elasticsearch + const esResult = await fastify.elastic.search({ + index: `${fastify.manager.chain}-table-proposals-*`, + from: skip || 0, + size: (limit > maxDocs ? maxDocs : limit) || 10, + track_total_hits: getTrackTotalHits(request.query), + query: queryStruct, + sort: [{ block_num: "desc" }] + }); + + stateResult = esResult.hits.hits.map((hit: any) => hit._source); + response.total = (esResult.hits.total as estypes.SearchTotalHits).value; + + // Pegando o último bloco indexado + response.last_indexed_block = esResult.hits.hits.length > 0 ? esResult.hits.hits[0]._source.block_num : 0; + response.last_indexed_block_time = esResult.hits.hits.length > 0 ? esResult.hits.hits[0]._source.block_time : ''; } - // If no filter switch to full match - if (queryStruct.bool.must.length === 0) { - queryStruct = { - "match_all": {} - }; + // Formatar resposta com os dados obtidos + for (const proposal of stateResult) { + response.proposals.push(proposal); } - const maxDocs = fastify.manager.config.api.limits.get_proposals ?? 100; - const results = await fastify.elastic.search({ - "index": fastify.manager.chain + '-table-proposals-*', - "from": skip || 0, - "size": (limit > maxDocs ? maxDocs : limit) || 10, - "track_total_hits": getTrackTotalHits(request.query), - "query": queryStruct, - "sort": [{"block_num": "desc"}] - }); - - const response: any = { - query_time: null, - cached: false, - total: results.hits.total, - proposals: [] - }; - - const hits = results.hits.hits; - for (const hit of hits) { - const prop = hit._source; - response.proposals.push(prop); - } + // Calculando o tempo de consulta + response.query_time_ms = Date.now() - startTime; return response; } @@ -99,5 +142,5 @@ async function getProposals(fastify: FastifyInstance, request: FastifyRequest) { export function getProposalsHandler(fastify: FastifyInstance, route: string) { return async (request: FastifyRequest, reply: FastifyReply) => { reply.send(await timedQuery(getProposals, fastify, request, route)); - } + }; } diff --git a/src/api/routes/v2-state/get_proposals/index.ts b/src/api/routes/v2-state/get_proposals/index.ts index 9ba1c9b8..7b9cd1e5 100644 --- a/src/api/routes/v2-state/get_proposals/index.ts +++ b/src/api/routes/v2-state/get_proposals/index.ts @@ -1,6 +1,6 @@ import {FastifyInstance} from "fastify"; import {getProposalsHandler} from "./get_proposals.js"; -import {addApiRoute, getRouteName} from "../../../helpers/functions.js"; +import {addApiRoute, extendResponseSchema, getRouteName} from "../../../helpers/functions.js"; export default function (fastify: FastifyInstance, opts: any, next) { const schema = { @@ -49,8 +49,96 @@ export default function (fastify: FastifyInstance, opts: any, next) { minimum: 1 } } - } + }, + response: extendResponseSchema({ + total: { + type: "object", + properties: { + value: {type: "number"}, + relation: {type: "string"} + } + }, + proposals: { + type: "array", + items: { + type: "object", + properties: { + proposal_name: { type: "string" }, + block_num: { type: "number" }, + proposer: { type: "string" }, + executed: { type: "boolean" }, + primary_key: { type: "string" }, + trx: { + type: "object", + properties: { + expiration: { type: "string" }, + ref_block_num: { type: "number" }, + ref_block_prefix: { type: "number" }, + max_net_usage_words: { type: "number" }, + max_cpu_usage_ms: { type: "number" }, + delay_sec: { type: "number" }, + context_free_actions: { type: "array", items: { type: "object" } }, + actions: { + type: "array", + items: { + type: "object", + properties: { + account: { type: "string" }, + name: { type: "string" }, + authorization: { + type: "array", + items: { + type: "object", + properties: { + actor: { type: "string" }, + permission: { type: "string" } + } + } + }, + data: { + type: "object", + properties: { + from: { type: "string" }, + to: { type: "string" }, + quantity: { type: "string" }, + memo: { type: "string" } + } + } + } + } + }, + transaction_extensions: { type: "array", items: { type: "object" } } + } + }, + requested_approvals: { + type: "array", + items: { + type: "object", + properties: { + actor: { type: "string" }, + permission: { type: "string" }, + time: { type: "string" } + } + } + }, + provided_approvals: { + type: "array", + items: { + type: "object", + properties: { + actor: { type: "string" }, + permission: { type: "string" }, + time: { type: "string" } + } + } + }, + earliest_exec_time: { type: "string", nullable: true } + } + } + } + }) }; + addApiRoute( fastify, 'GET', diff --git a/src/api/routes/v2-state/get_voters/get_voters.ts b/src/api/routes/v2-state/get_voters/get_voters.ts index e758e8e7..192a33e8 100644 --- a/src/api/routes/v2-state/get_voters/get_voters.ts +++ b/src/api/routes/v2-state/get_voters/get_voters.ts @@ -6,7 +6,6 @@ import { estypes } from "@elastic/elasticsearch"; import { IVoter } from "../../../../interfaces/table-voter.js"; async function getVoters(fastify: FastifyInstance, request: FastifyRequest) { - console.log(`Entrei no getVoters`); const query: any = request.query; const { skip, limit } = getSkipLimit(request.query); const maxDocs = fastify.manager.config.api.limits.get_voters ?? 100; @@ -38,7 +37,6 @@ async function getVoters(fastify: FastifyInstance, request: FastifyRequest) { .limit(limit || 50) .toArray(); - console.log(`State Result mongo:`); } else { let queryStruct: any = { bool: { must: [] } }; if (query.producer) { @@ -61,7 +59,6 @@ async function getVoters(fastify: FastifyInstance, request: FastifyRequest) { sort: [{ last_vote_weight: "desc" }] }); stateResult = esResult.hits.hits.map((hit: any) => hit._source); - console.log(`State Result elastic:`); response.voter_count = (esResult.hits.total as estypes.SearchTotalHits).value; }