Skip to content

Commit f44a1ac

Browse files
authored
Merge pull request #3 from cardanoapi/fix/drep-vote
Fix/drep vote
2 parents 964d032 + 231bc79 commit f44a1ac

File tree

6 files changed

+149
-43
lines changed

6 files changed

+149
-43
lines changed

docker-restart.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
sudo docker stop dbsync-api-container # Stop the existing container
2+
sudo docker rm dbsync-api-container # Remove the stopped container
3+
sudo docker build -t dbsync-api . # Build the latest image
4+
sudo docker run -p 8081:8081 -d --name dbsync-api-container --env-file .env dbsync-api # Start a new container
5+
sudo docker logs dbsync-api-container

src/controllers/blockchain.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Request, Response, Router } from 'express'
22
import { handlerWrapper } from '../errors/AppError'
3-
import { fetchEpochDuration, fetchEpochParams } from '../repository/blockchain'
3+
import { fetchCommitteeGovState, fetchEpochDuration, fetchEpochParams } from '../repository/blockchain'
44

55
const router = Router()
66

@@ -16,7 +16,13 @@ const getEpochParams = async (req: Request, res: Response): Promise<any> => {
1616
return res.status(200).json(result)
1717
}
1818

19+
const getCommitteeGovState = async(req:Request, res:Response):Promise<any> => {
20+
const result = await fetchCommitteeGovState()
21+
return res.status(200).json(result)
22+
}
23+
1924
router.get('/epoch', handlerWrapper(getEpochDuration))
2025
router.get('/epoch/params', handlerWrapper(getEpochParams))
26+
router.get('/gov-state/committee', handlerWrapper(getCommitteeGovState))
2127

2228
export default router

src/helpers/validator.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,20 @@ export function validateVoter(voterType: string) {
143143
throw new AppError('Voter is neither drep or cc or spo: ' + voterType)
144144
}
145145
}
146+
147+
export function toCamelCase(str: string):string {
148+
return str.replace(/_([a-z])/g, (match, letter) => letter.toUpperCase())
149+
}
150+
151+
export function convertKeysToCamelCase(obj:any):any {
152+
if (Array.isArray(obj)) {
153+
return obj.map(convertKeysToCamelCase)
154+
} else if (obj !== null && typeof obj === 'object') {
155+
return Object.keys(obj).reduce((acc:any, key:any) => {
156+
const camelCaseKey:any = toCamelCase(key)
157+
acc[camelCaseKey] = convertKeysToCamelCase(obj[key])
158+
return acc
159+
}, {})
160+
}
161+
return obj
162+
}

src/repository/blockchain.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Prisma } from '@prisma/client'
22
import { prisma } from '../config/db'
3+
import { convertKeysToCamelCase } from '../helpers/validator'
34

45
export async function fetchEpochDuration(limit: number) {
56
const result = (await prisma.$queryRaw`
@@ -46,3 +47,59 @@ export async function fetchEpochParams(epoch_no?: number) {
4647
LIMIT 1;`) as Record<string, any>[]
4748
return result[0].epoch_param
4849
}
50+
51+
export async function fetchCommitteeGovState() {
52+
const result = (await prisma.$queryRaw`
53+
WITH PreviosActionId AS
54+
(
55+
SELECT
56+
CASE
57+
WHEN ENCODE(tx.hash, 'hex') = '' OR gap.index IS NULL THEN NULL
58+
ELSE ENCODE(tx.hash, 'hex') || '#' || gap.index::TEXT
59+
END AS hash_index
60+
FROM gov_action_proposal gap
61+
JOIN tx ON tx.id = gap.tx_id
62+
JOIN block b ON b.id = tx.block_id
63+
WHERE gap.id = (
64+
SELECT gap.prev_gov_action_proposal
65+
FROM gov_action_proposal gap
66+
WHERE gap.type = 'NewCommittee'
67+
ORDER BY gap.id DESC
68+
LIMIT 1
69+
)
70+
),
71+
RatifiedCommitteeGovAction AS (
72+
SELECT gap.id
73+
FROM gov_action_proposal gap
74+
WHERE gap.type = 'NewCommittee'
75+
AND ratified_epoch IS NOT NULL
76+
ORDER BY gap.id DESC
77+
LIMIT 1
78+
),
79+
Committee AS (
80+
SELECT json_build_object(
81+
'prev_gov_action_id', (SELECT hash_index FROM PreviosActionId),
82+
'quorum_numerator', c.quorum_numerator,
83+
'quorum_denominator', c.quorum_denominator,
84+
'committee_hashes', jsonb_agg(
85+
DISTINCT jsonb_build_object(
86+
'hash', encode(ch.raw, 'hex'),
87+
'has_script', ch.has_script,
88+
'expiration_epoch', cm.expiration_epoch
89+
)
90+
)
91+
) AS committee_data
92+
FROM committee c
93+
JOIN committee_member cm ON cm.committee_id = c.id
94+
JOIN committee_hash ch ON cm.committee_hash_id = ch.id
95+
LEFT JOIN RatifiedCommitteeGovAction rc
96+
ON rc.id = c.gov_action_proposal_id
97+
WHERE c.gov_action_proposal_id IS NULL
98+
GROUP BY c.quorum_numerator, c.quorum_denominator
99+
)
100+
SELECT * FROM committee
101+
`) as Record<string, any>[]
102+
const rawResult = result[0].committee_data
103+
104+
return convertKeysToCamelCase(rawResult)
105+
}

src/repository/drep.ts

Lines changed: 52 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -318,57 +318,67 @@ export const fetchDrepVoteDetails = async (dRepId: string, isScript?: boolean) =
318318
}
319319

320320
const result = (await prisma.$queryRaw`
321-
WITH DrepVoteDetails
322-
as (SELECT DISTINCT
323-
ON (gp.id, voting_procedure.drep_voter) concat(encode(gov_action_tx.hash, 'hex'), '#', gp.index) as govActionId,
324-
gov_action_metadata.title as title,
325-
voting_procedure.vote::text as voteType,
326-
voting_anchor.url as voteAnchorUrl,
327-
encode(voting_anchor.data_hash, 'hex') as voteAnchorHash,
328-
block.epoch_no as epochNo,
329-
block.time as time,
330-
encode(vote_tx.hash, 'hex') as voteTxHash,
331-
gp.type as govActionType
321+
WITH TimeOrderedDrepVoteDetails AS (
322+
SELECT DISTINCT
323+
ON (vote_tx.id, gp.id, voting_procedure.drep_voter)
324+
concat(encode(gov_action_tx.hash, 'hex'), '#', gp.index) AS govActionId,
325+
gov_action_metadata.title AS title,
326+
voting_procedure.vote::text AS voteType,
327+
voting_anchor.url AS voteAnchorUrl,
328+
encode(voting_anchor.data_hash, 'hex') AS voteAnchorHash,
329+
block.epoch_no AS epochNo,
330+
block.time AS time,
331+
encode(vote_tx.hash, 'hex') AS voteTxHash,
332+
gp.type AS govActionType
332333
FROM voting_procedure
333334
JOIN gov_action_proposal AS gp
334-
ON gp.id = voting_procedure.gov_action_proposal_id
335+
ON gp.id = voting_procedure.gov_action_proposal_id
335336
JOIN drep_hash
336-
ON drep_hash.id = voting_procedure.drep_voter
337+
ON drep_hash.id = voting_procedure.drep_voter
337338
LEFT JOIN voting_anchor
338-
ON voting_anchor.id = voting_procedure.voting_anchor_id
339+
ON voting_anchor.id = voting_procedure.voting_anchor_id
339340
JOIN tx AS gov_action_tx
340-
ON gov_action_tx.id = gp.tx_id
341+
ON gov_action_tx.id = gp.tx_id
341342
JOIN tx AS vote_tx
342-
ON vote_tx.id = voting_procedure.tx_id
343+
ON vote_tx.id = voting_procedure.tx_id
343344
JOIN block
344-
ON block.id = vote_tx.block_id
345+
ON block.id = vote_tx.block_id
345346
LEFT JOIN off_chain_vote_data
346-
ON off_chain_vote_data.voting_anchor_id = gp.voting_anchor_id
347+
ON off_chain_vote_data.voting_anchor_id = gp.voting_anchor_id
347348
LEFT JOIN off_chain_vote_gov_action_data AS gov_action_metadata
348-
ON gov_action_metadata.off_chain_vote_data_id = off_chain_vote_data.id
349-
WHERE drep_hash.raw = decode(${dRepId}
350-
, 'hex')
351-
AND (drep_hash.has_script = ${scriptPart[0]}
352-
OR drep_hash.has_script= ${scriptPart[1]})
353-
ORDER BY gp.id, voting_procedure.drep_voter, block.time, voting_procedure.id DESC),
354-
TimeOrderedDrepVoteDetails as (
355-
select *
356-
from DrepVoteDetails
357-
order by DrepVoteDetails.time desc)
358-
SELECT json_agg(
359-
json_build_object(
360-
'govActionId', TimeOrderedDrepVoteDetails.govActionId,
361-
'title', TimeOrderedDrepVoteDetails.title,
362-
'voteType', TimeOrderedDrepVoteDetails.voteType,
363-
'voteAnchorUrl', TimeOrderedDrepVoteDetails.voteAnchorUrl,
364-
'voteAnchorHash', TimeOrderedDrepVoteDetails.voteAnchorHash,
365-
'epochNo', TimeOrderedDrepVoteDetails.epochNo,
366-
'time', TimeOrderedDrepVoteDetails.time,
367-
'voteTxHash', TimeOrderedDrepVoteDetails.voteTxHash,
368-
'govActionType', TimeOrderedDrepVoteDetails.govActionType
369-
)
370-
) AS votes
371-
from TimeOrderedDrepVoteDetails
349+
ON gov_action_metadata.off_chain_vote_data_id = off_chain_vote_data.id
350+
WHERE drep_hash.raw = decode(${dRepId}, 'hex')
351+
AND (drep_hash.has_script = ${scriptPart[0]} OR drep_hash.has_script = ${scriptPart[1]})
352+
ORDER BY vote_tx.id DESC, gp.id, voting_procedure.drep_voter, block.time, voting_procedure.id DESC
353+
),
354+
GroupedVoteDetails AS (
355+
SELECT DISTINCT ON (govActionId)
356+
govActionId,
357+
title,
358+
voteType,
359+
voteAnchorUrl,
360+
voteAnchorHash,
361+
epochNo,
362+
time,
363+
voteTxHash,
364+
govActionType
365+
FROM TimeOrderedDrepVoteDetails
366+
ORDER BY govActionId, voteTxHash DESC
367+
)
368+
SELECT json_agg(
369+
json_build_object(
370+
'govActionId', GroupedVoteDetails.govActionId,
371+
'title', GroupedVoteDetails.title,
372+
'voteType', GroupedVoteDetails.voteType,
373+
'voteAnchorUrl', GroupedVoteDetails.voteAnchorUrl,
374+
'voteAnchorHash', GroupedVoteDetails.voteAnchorHash,
375+
'epochNo', GroupedVoteDetails.epochNo,
376+
'time', GroupedVoteDetails.time,
377+
'voteTxHash', GroupedVoteDetails.voteTxHash,
378+
'govActionType', GroupedVoteDetails.govActionType
379+
)
380+
) AS votes
381+
from GroupedVoteDetails
372382
`) as Record<any, any>[]
373383
return result[0].votes
374384
}

swagger.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,17 @@ paths:
655655
description: Invalid address provided
656656
'500':
657657
description: Internal server error
658+
/api/blockchain/gov-state/committee:
659+
get:
660+
summary: Get Committee Gov-State
661+
description: Get details regarding committee members, quorum, their expiration and previous gov action id
662+
tags:
663+
- Blockchain
664+
responses:
665+
'200':
666+
description: gov state
667+
'500':
668+
description: Internal server error
658669
/api/drep:
659670
get:
660671
summary: Fetch DRep list

0 commit comments

Comments
 (0)