diff --git a/.github/workflows/build-from-main.yml b/.github/workflows/build-from-main.yml index de0c3ea44..6a71f6947 100644 --- a/.github/workflows/build-from-main.yml +++ b/.github/workflows/build-from-main.yml @@ -14,7 +14,7 @@ permissions: jobs: check-build: - if: contains(fromJson('["main", "staging"]'), github.ref_name) + if: contains(fromJson('["main", "staging", "develop"]'), github.ref_name) environment: ${{ matrix.network }} strategy: fail-fast: false @@ -146,7 +146,27 @@ jobs: dockerfile: ./govtool/metadata-validation/Dockerfile image: ghcr.io/${{ github.repository }}-metadata-validation qovery_container_name: govtool-metadata-validation - + - branch: develop + network: dev-govtool + workdir: ./govtool/backend + name: govtool-backend + dockerfile: ./govtool/backend/Dockerfile.qovery + image: ghcr.io/${{ github.repository }}-backend + qovery_container_name: govtool-backend + - branch: develop + network: dev-govtool + workdir: ./govtool/frontend + name: govtool-frontend + dockerfile: ./govtool/frontend/Dockerfile.qovery + image: ghcr.io/${{ github.repository }}-frontend + qovery_container_name: govtool-frontend + - branch: develop + network: dev-govtool + workdir: ./govtool/metadata-validation + name: govtool-metadata-validation + dockerfile: ./govtool/metadata-validation/Dockerfile + image: ghcr.io/${{ github.repository }}-metadata-validation + qovery_container_name: govtool-metadata-validation runs-on: ubuntu-latest steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index 34361b48a..0ce80483c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,12 +12,17 @@ changes. ### Added +- Add support for preprod in matomo analytics [Issue 3173](https://github.com/IntersectMBO/govtool/issues/3173) + ### Fixed - hotfix for ada handle and payment address validation order [Issue 3155](https://github.com/IntersectMBO/govtool/issues/3155) +- fix proposal list performance by pre-filtering active proposals [Issue 3190](https://github.com/IntersectMBO/govtool/issues/3190) ### Changed +- Exclude network total stake and info from network metrics [Issue 3189](https://github.com/IntersectMBO/govtool/issues/3189) + ### Removed ## [v2.0.15](https://github.com/IntersectMBO/govtool/releases/tag/v2.0.15) 2025-03-11 diff --git a/govtool/backend/README.md b/govtool/backend/README.md index 566293184..cc5a9a285 100644 --- a/govtool/backend/README.md +++ b/govtool/backend/README.md @@ -6,9 +6,9 @@ This is a backend application of GovTool project. In order to run `backend` your host machine will need access to the `cardano-db-sync` postgres database. To have this database running locally you'll need: -- `cardano-node` -- `cardano-db-sync` -- PostgreSQL database +- [cardano-node](https://github.com/IntersectMBO/cardano-node) +- [cardano-db-sync](https://github.com/IntersectMBO/cardano-db-sync) +- [PostgreSQL database](https://www.postgresql.org/download/) (psql needs to be installed on your machine in order to compile the project) You will need your `cardano-node` and `cardano-db-sync` to be compatible with Sancho testnet. Until these features will be merged to the master branch the new Sancho compatible versions are available as releases on [github](https://github.com/IntersectMBO/cardano-db-sync/releases). You will also need a correct `cardano-node` version. The release notes for `cardano-db-sync` usualy specify that. @@ -30,44 +30,44 @@ Due to problems with openapi3 package it's hard to build this project with plain 2. Get [direnv](https://direnv.net/). -3. Set GHC version to 9.10.1: +3. Set GHC version to 9.2.8: ```sh - ghcup install ghc 9.10.1 + ghcup install ghc 9.2.8 - ghcup set ghc 9.10.1 + ghcup set ghc 9.2.8 ``` 4. Install cabal - ```sh - ghcup install cabal - ghcup set cabal - ``` + ```sh + ghcup install cabal + ghcup set cabal + ``` 5. Enter `govtool/backend` directory: ```sh - cd govtool/backend + cd govtool/backend ``` 6. Allow direnv to setup your environment: ```sh - direnv allow + direnv allow ``` 7. Update cabal & build project ```sh - cabal update - cabal build all + cabal update + cabal build all ``` 8. Create a config file. You can use `example-config.json` as a template. 9. Run project - `sh - cabal run vva-be -- --config start-app - ` + ```sh + cabal run vva-be -- --config start-app + ``` > [!WARNING] > In the context of our ongoing project enhancements, it is assumed that the executable previously known as 'vva-be' should be now officially renamed to 'govtool-backend'. This change is necessary for aligning with the updated branding and functional scope of the application and it has to be implemented in the near future as a chore and refactoring ticket. Make sure that the documentation matches the actual name of the executable. diff --git a/govtool/backend/app/Main.hs b/govtool/backend/app/Main.hs index 6311288f0..66514e170 100644 --- a/govtool/backend/app/Main.hs +++ b/govtool/backend/app/Main.hs @@ -122,6 +122,8 @@ startApp vvaConfig sentryService = do dRepVotingPowerCache <- newCache dRepListCache <- newCache networkMetricsCache <- newCache + networkInfoCache <- newCache + networkTotalStakeCache <- newCache return $ CacheEnv { proposalListCache , getProposalCache @@ -133,6 +135,8 @@ startApp vvaConfig sentryService = do , dRepVotingPowerCache , dRepListCache , networkMetricsCache + , networkInfoCache + , networkTotalStakeCache } let connectionString = encodeUtf8 (dbSyncConnectionString $ getter vvaConfig) @@ -144,6 +148,7 @@ startApp vvaConfig sentryService = do exceptionHandler :: VVAConfig -> SentryService -> Maybe Request -> SomeException -> IO () exceptionHandler vvaConfig sentryService mRequest exception = do + print exception let isNotTimeoutThread x = case fromException x of Just TimeoutThread -> False _ -> True diff --git a/govtool/backend/sql/get-network-info.sql b/govtool/backend/sql/get-network-info.sql new file mode 100644 index 000000000..86953993e --- /dev/null +++ b/govtool/backend/sql/get-network-info.sql @@ -0,0 +1,6 @@ +SELECT + (SELECT MAX(no) FROM epoch) AS current_epoch, + (SELECT MAX(block_no) FROM block) AS current_block, + network_name +FROM + meta; \ No newline at end of file diff --git a/govtool/backend/sql/get-network-metrics.sql b/govtool/backend/sql/get-network-metrics.sql index 21efd2a91..4aa9c8cbb 100644 --- a/govtool/backend/sql/get-network-metrics.sql +++ b/govtool/backend/sql/get-network-metrics.sql @@ -110,23 +110,6 @@ TotalActiveCIP119CompliantDReps AS ( AND lve.epoch_no >= (SELECT epoch_no FROM ActiveDRepBoundaryEpoch) ))) ), -TotalStakeControlledByActiveDReps AS ( - SELECT - COALESCE(SUM(dd.amount), 0)::bigint AS total - FROM - drep_hash dh - LEFT JOIN DRepDistr dd ON dd.hash_id = dh.id AND dd.rn = 1 - LEFT JOIN RankedDRepRegistration rd ON dd.hash_id = rd.drep_hash_id AND rd.rn = 1 - LEFT JOIN LatestVoteEpoch lve ON lve.drep_id = dh.id - CROSS JOIN DRepActivity - WHERE - dd.epoch_no = (SELECT no FROM CurrentEpoch) - AND COALESCE(rd.deposit, 0) >= 0 - AND ((DRepActivity.epoch_no - GREATEST(COALESCE(lve.epoch_no, 0), COALESCE(rd.epoch_no, 0))) <= DRepActivity.drep_activity) -), -CurrentBlock AS ( - SELECT MAX(block_no) AS block_no FROM block -), UniqueDelegators AS ( SELECT COUNT(DISTINCT addr_id) AS count FROM delegation_vote ), @@ -139,9 +122,6 @@ TotalGovActionProposals AS ( TotalDRepVotes AS ( SELECT COUNT(*) AS count FROM voting_procedure WHERE voter_role = 'DRep' ), -TotalStakeControlledBySPOs AS ( - SELECT SUM(ps.stake)::bigint AS total FROM pool_stat ps WHERE ps.epoch_no = (SELECT no FROM CurrentEpoch) -), LatestExistingVotingAnchor AS ( SELECT subquery.drep_registration_id, @@ -192,18 +172,6 @@ TotalRegisteredDirectVoters AS ( LEFT JOIN HasNonDeregisterVotingAnchor hndva ON hndva.drep_hash_id = rdr.drep_hash_id WHERE rdr.rn = 1 AND COALESCE(rdr.deposit, 0) >= 0 AND (leva.url IS NULL OR hndva.value = true) ), -AlwaysAbstainVotingPower AS ( - SELECT COALESCE((SELECT amount FROM drep_hash - LEFT JOIN drep_distr ON drep_hash.id = drep_distr.hash_id - WHERE drep_hash.view = 'drep_always_abstain' - ORDER BY epoch_no DESC LIMIT 1), 0) AS amount -), -AlwaysNoConfidenceVotingPower AS ( - SELECT COALESCE((SELECT amount FROM drep_hash - LEFT JOIN drep_distr ON drep_hash.id = drep_distr.hash_id - WHERE drep_hash.view = 'drep_always_no_confidence' - ORDER BY epoch_no DESC LIMIT 1), 0) AS amount -), TotalDRepDistr AS ( SELECT SUM(COALESCE(amount, 0))::bigint total_drep_distr FROM drep_distr where epoch_no = (SELECT no from CurrentEpoch) ), @@ -223,42 +191,28 @@ CommitteeThreshold AS ( OR (c.gov_action_proposal_id IS NULL) ) SELECT - CurrentEpoch.no AS epoch_no, - CurrentBlock.block_no, UniqueDelegators.count AS unique_delegators, TotalDelegations.count AS total_delegations, TotalGovActionProposals.count AS total_gov_action_proposals, TotalDRepVotes.count AS total_drep_votes, TotalRegisteredDReps.unique_registrations AS total_registered_dreps, TotalDRepDistr.total_drep_distr, - COALESCE(TotalStakeControlledByActiveDReps.total, 0) + COALESCE(AlwaysNoConfidenceVotingPower.amount, 0) AS total_stake_controlled_by_active_dreps, - COALESCE(TotalStakeControlledBySPOs.total, 0) AS total_stake_controlled_by_spos, TotalActiveDReps.unique_active_drep_registrations AS total_active_dreps, TotalInactiveDReps.total_inactive_dreps AS total_inactive_dreps, TotalActiveCIP119CompliantDReps.unique_active_cip119_compliant_drep_registrations AS total_active_cip119_compliant_dreps, TotalRegisteredDirectVoters.unique_direct_voters AS total_registered_direct_voters, - AlwaysAbstainVotingPower.amount AS always_abstain_voting_power, - AlwaysNoConfidenceVotingPower.amount AS always_no_confidence_voting_power, - meta.network_name, NoOfCommitteeMembers.total no_of_committee_members, CommitteeThreshold.quorum_numerator, CommitteeThreshold.quorum_denominator -FROM CurrentEpoch -CROSS JOIN CurrentBlock -CROSS JOIN UniqueDelegators +FROM UniqueDelegators CROSS JOIN TotalDRepDistr CROSS JOIN TotalDelegations CROSS JOIN TotalGovActionProposals CROSS JOIN TotalDRepVotes CROSS JOIN TotalRegisteredDReps -CROSS JOIN TotalStakeControlledByActiveDReps -CROSS JOIN TotalStakeControlledBySPOs CROSS JOIN TotalActiveDReps CROSS JOIN TotalInactiveDReps CROSS JOIN TotalActiveCIP119CompliantDReps CROSS JOIN TotalRegisteredDirectVoters -CROSS JOIN AlwaysAbstainVotingPower -CROSS JOIN AlwaysNoConfidenceVotingPower CROSS JOIN NoOfCommitteeMembers CROSS JOIN CommitteeThreshold -CROSS JOIN meta; diff --git a/govtool/backend/sql/get-network-total-stake.sql b/govtool/backend/sql/get-network-total-stake.sql new file mode 100644 index 000000000..9399df5c3 --- /dev/null +++ b/govtool/backend/sql/get-network-total-stake.sql @@ -0,0 +1,93 @@ +WITH DRepActivity AS ( + SELECT + drep_activity AS drep_activity, + epoch_no AS epoch_no + FROM + epoch_param + WHERE + epoch_no IS NOT NULL + ORDER BY + epoch_no DESC + LIMIT 1 +), +LatestVotingProcedure AS ( + SELECT + vp.*, + ROW_NUMBER() OVER (PARTITION BY drep_voter ORDER BY tx_id DESC) AS rn + FROM + voting_procedure vp +), +DRepDistr AS ( + SELECT + drep_distr.*, + ROW_NUMBER() OVER (PARTITION BY drep_hash.id ORDER BY drep_distr.epoch_no DESC) AS rn + FROM + drep_distr + JOIN drep_hash ON drep_hash.id = drep_distr.hash_id +), +CurrentEpoch AS ( + SELECT MAX(no) AS no FROM epoch +), +LatestVoteEpoch AS ( + SELECT + block.epoch_no, + lvp.drep_voter AS drep_id + FROM + LatestVotingProcedure lvp + JOIN tx ON tx.id = lvp.tx_id + JOIN block ON block.id = tx.block_id + WHERE + lvp.rn = 1 +), +RankedDRepRegistration AS ( + SELECT + dr.id, + dr.drep_hash_id, + dr.deposit, + dr.voting_anchor_id, + ROW_NUMBER() OVER (PARTITION BY dr.drep_hash_id ORDER BY dr.tx_id DESC) AS rn, + encode(tx.hash, 'hex') AS tx_hash, + block.epoch_no + FROM + drep_registration dr + JOIN tx ON tx.id = dr.tx_id + JOIN block ON block.id = tx.block_id +), +TotalStakeControlledByActiveDReps AS ( + SELECT + COALESCE(SUM(dd.amount), 0)::bigint AS total + FROM + drep_hash dh + LEFT JOIN DRepDistr dd ON dd.hash_id = dh.id AND dd.rn = 1 + LEFT JOIN RankedDRepRegistration rd ON dd.hash_id = rd.drep_hash_id AND rd.rn = 1 + LEFT JOIN LatestVoteEpoch lve ON lve.drep_id = dh.id + CROSS JOIN DRepActivity + WHERE + dd.epoch_no = (SELECT no FROM CurrentEpoch) + AND COALESCE(rd.deposit, 0) >= 0 + AND ((DRepActivity.epoch_no - GREATEST(COALESCE(lve.epoch_no, 0), COALESCE(rd.epoch_no, 0))) <= DRepActivity.drep_activity) +), +TotalStakeControlledBySPOs AS ( + SELECT SUM(ps.stake)::bigint AS total FROM pool_stat ps WHERE ps.epoch_no = (SELECT no FROM CurrentEpoch) +), +AlwaysAbstainVotingPower AS ( + SELECT COALESCE((SELECT amount FROM drep_hash + LEFT JOIN drep_distr ON drep_hash.id = drep_distr.hash_id + WHERE drep_hash.view = 'drep_always_abstain' + ORDER BY epoch_no DESC LIMIT 1), 0) AS amount +), +AlwaysNoConfidenceVotingPower AS ( + SELECT COALESCE((SELECT amount FROM drep_hash + LEFT JOIN drep_distr ON drep_hash.id = drep_distr.hash_id + WHERE drep_hash.view = 'drep_always_no_confidence' + ORDER BY epoch_no DESC LIMIT 1), 0) AS amount +) +SELECT + COALESCE(TotalStakeControlledByActiveDReps.total, 0) + COALESCE(AlwaysNoConfidenceVotingPower.amount, 0) AS total_stake_controlled_by_active_dreps, + COALESCE(TotalStakeControlledBySPOs.total, 0) AS total_stake_controlled_by_spos, + AlwaysAbstainVotingPower.amount AS always_abstain_voting_power, + AlwaysNoConfidenceVotingPower.amount AS always_no_confidence_voting_power +FROM TotalStakeControlledByActiveDReps +LEFT JOIN TotalStakeControlledBySPOs ON TRUE +LEFT JOIN AlwaysAbstainVotingPower ON TRUE +LEFT JOIN AlwaysNoConfidenceVotingPower ON TRUE \ No newline at end of file diff --git a/govtool/backend/sql/list-proposals.sql b/govtool/backend/sql/list-proposals.sql index 0165128fe..8ccbfd3d1 100644 --- a/govtool/backend/sql/list-proposals.sql +++ b/govtool/backend/sql/list-proposals.sql @@ -1,9 +1,19 @@ -WITH LatestDrepDistr AS ( - SELECT - *, - ROW_NUMBER() OVER (PARTITION BY hash_id ORDER BY epoch_no DESC) AS rn +WITH ActiveProposals AS ( + SELECT id + FROM gov_action_proposal + WHERE expiration > (SELECT MAX(no) FROM epoch) + AND ratified_epoch IS NULL + AND enacted_epoch IS NULL + AND expired_epoch IS NULL + AND dropped_epoch IS NULL +), +LatestDrepDistr AS ( + SELECT DISTINCT ON (hash_id) + * FROM drep_distr + ORDER BY + hash_id, epoch_no DESC ), LatestEpoch AS ( SELECT @@ -46,6 +56,7 @@ ParsedDescription AS ( gov_action_proposal WHERE gov_action_proposal.type = 'NewCommittee' + AND gov_action_proposal.id IN (SELECT id FROM ActiveProposals) ), MembersToBeRemoved AS ( SELECT @@ -96,19 +107,28 @@ EnrichedCurrentMembers AS ( pcm.id ), RankedPoolVotes AS ( - SELECT - *, - ROW_NUMBER() OVER (PARTITION BY vp.pool_voter ORDER BY vp.tx_id DESC) AS rn + SELECT DISTINCT ON (vp.pool_voter, vp.gov_action_proposal_id) + vp.gov_action_proposal_id, + vp.pool_voter, + vp.vote FROM voting_procedure vp + WHERE + vp.pool_voter IS NOT NULL + AND vp.gov_action_proposal_id IN (SELECT id FROM ActiveProposals) + ORDER BY + vp.pool_voter, + vp.gov_action_proposal_id, + vp.tx_id DESC, + vp.id DESC ), PoolVotes AS ( SELECT rpv.gov_action_proposal_id, ps.epoch_no, - COUNT(DISTINCT CASE WHEN vote = 'Yes' THEN rpv.pool_voter ELSE 0 END) AS total_unique_votes, - COUNT(DISTINCT CASE WHEN vote = 'No' THEN rpv.pool_voter ELSE 0 END) AS total_unique_votes, - COUNT(DISTINCT CASE WHEN vote = 'Abstain' THEN rpv.pool_voter ELSE 0 END) AS total_unique_votes, + COUNT(DISTINCT CASE WHEN vote = 'Yes' THEN rpv.pool_voter ELSE 0 END) AS total_yes_votes, + COUNT(DISTINCT CASE WHEN vote = 'No' THEN rpv.pool_voter ELSE 0 END) AS total_no_votes, + COUNT(DISTINCT CASE WHEN vote = 'Abstain' THEN rpv.pool_voter ELSE 0 END) AS total_abstain_votes, SUM(CASE WHEN rpv.vote = 'Yes' THEN ps.voting_power ELSE 0 END) AS poolYesVotes, SUM(CASE WHEN rpv.vote = 'No' THEN ps.voting_power ELSE 0 END) AS poolNoVotes, SUM(CASE WHEN rpv.vote = 'Abstain' THEN ps.voting_power ELSE 0 END) AS poolAbstainVotes @@ -118,48 +138,58 @@ PoolVotes AS ( pool_stat ps ON rpv.pool_voter = ps.pool_hash_id WHERE - rpv.rn = 1 AND ps.epoch_no = (SELECT MAX(no) FROM epoch) + ps.epoch_no = (SELECT MAX(no) FROM epoch) GROUP BY rpv.gov_action_proposal_id, ps.epoch_no ), RankedDRepVotes AS ( SELECT DISTINCT ON (vp.drep_voter, vp.gov_action_proposal_id) - * + vp.gov_action_proposal_id, + vp.drep_voter, + vp.vote FROM voting_procedure vp + WHERE + vp.drep_voter IS NOT NULL + AND vp.gov_action_proposal_id IN (SELECT id FROM ActiveProposals) ORDER BY - vp.drep_voter, - vp.gov_action_proposal_id, - vp.tx_id DESC + vp.drep_voter, + vp.gov_action_proposal_id, + vp.tx_id DESC, + vp.id DESC ), RankedDRepRegistration AS ( SELECT DISTINCT ON (dr.drep_hash_id) - * + dr.* FROM drep_registration dr ORDER BY dr.drep_hash_id, - dr.tx_id DESC + dr.tx_id DESC, + dr.id DESC ), CommitteeVotes AS ( SELECT - gov_action_proposal_id, - - SUM(CASE WHEN vote = 'Yes' THEN 1 ELSE 0 END) AS ccYesVotes, - SUM(CASE WHEN vote = 'No' THEN 1 ELSE 0 END) AS ccNoVotes, - SUM(CASE WHEN vote = 'Abstain' THEN 1 ELSE 0 END) AS ccAbstainVotes - FROM - voting_procedure AS vp - WHERE - vp.committee_voter IS NOT NULL - AND (vp.tx_id, vp.committee_voter, vp.gov_action_proposal_id) IN ( - SELECT MAX(tx_id), committee_voter, gov_action_proposal_id - FROM voting_procedure - WHERE committee_voter IS NOT NULL - GROUP BY committee_voter, gov_action_proposal_id - ) + vp.gov_action_proposal_id, + SUM(CASE WHEN vp.vote = 'Yes' THEN 1 ELSE 0 END) AS ccYesVotes, + SUM(CASE WHEN vp.vote = 'No' THEN 1 ELSE 0 END) AS ccNoVotes, + SUM(CASE WHEN vp.vote = 'Abstain' THEN 1 ELSE 0 END) AS ccAbstainVotes + FROM ( + SELECT DISTINCT ON (committee_voter, gov_action_proposal_id) + gov_action_proposal_id, + committee_voter, + vote + FROM voting_procedure + WHERE committee_voter IS NOT NULL + AND gov_action_proposal_id IN (SELECT id FROM ActiveProposals) + ORDER BY + committee_voter, + gov_action_proposal_id, + tx_id DESC, + id DESC + ) vp GROUP BY - gov_action_proposal_id + vp.gov_action_proposal_id ) SELECT gov_action_proposal.id, @@ -228,7 +258,7 @@ SELECT NULL END , '{}'::JSON) AS description, - CASE + CASE WHEN meta.network_name::text = 'mainnet' OR meta.network_name::text = 'preprod' THEN latest_epoch.start_time + (gov_action_proposal.expiration - latest_epoch.no)::bigint * INTERVAL '5 days' ELSE @@ -266,9 +296,9 @@ SELECT drep_voting_power.no_confidence END) no_votes, COALESCE(SUM(ldd_drep.amount) FILTER (WHERE rdv.vote::text = 'Abstain'), 0) abstain_votes, - COALESCE(ps.poolYesVotes, 0) pool_yes_votes, - COALESCE(ps.poolNoVotes, 0) pool_no_votes, - COALESCE(ps.poolAbstainVotes, 0) pool_abstain_votes, + COALESCE(ps.poolYesVotes, 0) pool_yes_votes, + COALESCE(ps.poolNoVotes, 0) pool_no_votes, + COALESCE(ps.poolAbstainVotes, 0) pool_abstain_votes, COALESCE(cv.ccYesVotes, 0) cc_yes_votes, COALESCE(cv.ccNoVotes, 0) cc_no_votes, COALESCE(cv.ccAbstainVotes, 0) cc_abstain_votes, @@ -276,6 +306,7 @@ SELECT encode(prev_gov_action_tx.hash, 'hex') as prev_gov_action_tx_hash FROM gov_action_proposal + JOIN ActiveProposals ON gov_action_proposal.id = ActiveProposals.id CROSS JOIN LatestEpoch AS latest_epoch CROSS JOIN DRepVotingPower AS drep_voting_power CROSS JOIN meta @@ -286,14 +317,14 @@ FROM LEFT JOIN off_chain_vote_gov_action_data ON off_chain_vote_gov_action_data.off_chain_vote_data_id = off_chain_vote_data.id LEFT JOIN param_proposal AS proposal_params ON gov_action_proposal.param_proposal = proposal_params.id LEFT JOIN cost_model AS cost_model ON proposal_params.cost_model_id = cost_model.id - LEFT JOIN PoolVotes ps ON gov_action_proposal.id = ps.gov_action_proposal_id + LEFT JOIN PoolVotes ps ON gov_action_proposal.id = ps.gov_action_proposal_id LEFT JOIN CommitteeVotes cv ON gov_action_proposal.id = cv.gov_action_proposal_id LEFT JOIN RankedDRepVotes rdv ON rdv.gov_action_proposal_id = gov_action_proposal.id LEFT JOIN RankedDRepRegistration rdr ON rdr.drep_hash_id = rdv.drep_voter AND COALESCE(rdr.deposit, 0) >= 0 - LEFT JOIN LatestDrepDistr ldd_drep ON ldd_drep.hash_id = rdr.drep_hash_id + LEFT JOIN LatestDrepDistr ldd_drep ON ldd_drep.hash_id = rdr.drep_hash_id AND ldd_drep.epoch_no = latest_epoch.no LEFT JOIN gov_action_proposal AS prev_gov_action ON gov_action_proposal.prev_gov_action_proposal = prev_gov_action.id - LEFT JOIN tx AS prev_gov_action_tx ON prev_gov_action.tx_id = prev_gov_action_tx.id + LEFT JOIN tx AS prev_gov_action_tx ON prev_gov_action.tx_id = prev_gov_action_tx.id WHERE (COALESCE(?, '') = '' OR off_chain_vote_gov_action_data.title ILIKE ? OR @@ -301,15 +332,6 @@ WHERE off_chain_vote_gov_action_data.motivation ILIKE ? OR off_chain_vote_gov_action_data.rationale ILIKE ? OR concat(encode(creator_tx.hash, 'hex'), '#', gov_action_proposal.index) ILIKE ?) -AND gov_action_proposal.expiration >( - SELECT - Max(NO) - FROM - epoch) -AND gov_action_proposal.ratified_epoch IS NULL -AND gov_action_proposal.enacted_epoch IS NULL -AND gov_action_proposal.expired_epoch IS NULL -AND gov_action_proposal.dropped_epoch IS NULL GROUP BY gov_action_proposal.id, creator_tx.hash, @@ -323,14 +345,14 @@ GROUP BY cv.ccAbstainVotes, proposal_params, ps.poolYesVotes, - ps.poolNoVotes, - ps.poolAbstainVotes, - meta.network_name, - voting_anchor.url, - voting_anchor.data_hash, + ps.poolNoVotes, + ps.poolAbstainVotes, + meta.network_name, + voting_anchor.url, + voting_anchor.data_hash, prev_gov_action.index, prev_gov_action_tx.hash, off_chain_vote_gov_action_data.title, off_chain_vote_gov_action_data.abstract, off_chain_vote_gov_action_data.motivation, - off_chain_vote_gov_action_data.rationale \ No newline at end of file + off_chain_vote_gov_action_data.rationale; \ No newline at end of file diff --git a/govtool/backend/src/VVA/API.hs b/govtool/backend/src/VVA/API.hs index 0e553cfaf..5bfbd304d 100644 --- a/govtool/backend/src/VVA/API.hs +++ b/govtool/backend/src/VVA/API.hs @@ -79,6 +79,9 @@ type VVAApi = :<|> "transaction" :> "status" :> Capture "transactionId" HexText :> Get '[JSON] GetTransactionStatusResponse :<|> "throw500" :> Get '[JSON] () :<|> "network" :> "metrics" :> Get '[JSON] GetNetworkMetricsResponse + :<|> "network" :> "info" :> Get '[JSON] GetNetworkInfoResponse + :<|> "network" :> "total-stake" :> Get '[JSON] GetNetworkTotalStakeResponse + server :: App m => ServerT VVAApi m server = drepList :<|> getVotingPower @@ -92,7 +95,8 @@ server = drepList :<|> getTransactionStatus :<|> throw500 :<|> getNetworkMetrics - + :<|> getNetworkInfo + :<|> getNetworkTotalStake mapDRepType :: Types.DRepType -> DRepType mapDRepType Types.DRep = NormalDRep @@ -428,29 +432,43 @@ getTransactionStatus (unHexText -> transactionId) = do throw500 :: App m => m () throw500 = throwError $ CriticalError "intentional system break for testing purposes" +getNetworkInfo :: App m => m GetNetworkInfoResponse +getNetworkInfo = do + CacheEnv {networkInfoCache} <- asks vvaCache + Types.NetworkInfo {..} <- Network.networkInfo + return $ GetNetworkInfoResponse + { getNetworkInfoResponseCurrentTime = networkInfoCurrentTime + , getNetworkInfoResponseEpochNo = networkInfoEpochNo + , getNetworkInfoResponseBlockNo = networkInfoBlockNo + , getNetworkInfoResponseNetworkName = networkInfoNetworkName + } + +getNetworkTotalStake :: App m => m GetNetworkTotalStakeResponse +getNetworkTotalStake = do + CacheEnv {networkTotalStakeCache} <- asks vvaCache + Types.NetworkTotalStake {..} <- Network.networkTotalStake + return $ GetNetworkTotalStakeResponse + { getNetworkTotalStakeResponseTotalStakeControlledByDReps = networkTotalStakeControlledByDReps + , getNetworkTotalStakeResponseTotalStakeControlledBySPOs = networkTotalStakeControlledBySPOs + , getNetworkTotalStakeResponseAlwaysAbstainVotingPower = networkTotalAlwaysAbstainVotingPower + , getNetworkTotalStakeResponseAlwaysNoConfidenceVotingPower = networkTotalAlwaysNoConfidenceVotingPower + } + getNetworkMetrics :: App m => m GetNetworkMetricsResponse getNetworkMetrics = do CacheEnv {networkMetricsCache} <- asks vvaCache Types.NetworkMetrics {..} <- Network.networkMetrics return $ GetNetworkMetricsResponse - { getNetworkMetricsResponseCurrentTime = networkMetricsCurrentTime - , getNetworkMetricsResponseCurrentEpoch = networkMetricsCurrentEpoch - , getNetworkMetricsResponseCurrentBlock = networkMetricsCurrentBlock - , getNetworkMetricsResponseUniqueDelegators = networkMetricsUniqueDelegators + { getNetworkMetricsResponseUniqueDelegators = networkMetricsUniqueDelegators , getNetworkMetricsResponseTotalDelegations = networkMetricsTotalDelegations , getNetworkMetricsResponseTotalGovernanceActions = networkMetricsTotalGovernanceActions , getNetworkMetricsResponseTotalDRepVotes = networkMetricsTotalDRepVotes , getNetworkMetricsResponseTotalRegisteredDReps = networkMetricsTotalRegisteredDReps , getNetworkMetricsResponseTotalDRepDistr = networkMetricsTotalDRepDistr - , getNetworkMetricsResponseTotalStakeControlledByDReps = networkMetricsTotalStakeControlledByDReps - , getNetworkMetricsResponseTotalStakeControlledBySPOs = networkMetricsTotalStakeControlledBySPOs , getNetworkMetricsResponseTotalActiveDReps = networkMetricsTotalActiveDReps , getNetworkMetricsResponseTotalInactiveDReps = networkMetricsTotalInactiveDReps , getNetworkMetricsResponseTotalActiveCIP119CompliantDReps = networkMetricsTotalActiveCIP119CompliantDReps , getNetworkMetricsResponseTotalRegisteredDirectVoters = networkMetricsTotalRegisteredDirectVoters - , getNetworkMetricsResponseAlwaysAbstainVotingPower = networkMetricsAlwaysAbstainVotingPower - , getNetworkMetricsResponseAlwaysNoConfidenceVotingPower = networkMetricsAlwaysNoConfidenceVotingPower - , getNetworkMetricsResponseNetworkName = networkMetricsNetworkName , getNetworkMetricsResponseNoOfCommitteeMembers = networkMetricsNoOfCommitteeMembers , getNetworkMetricsResponseQuorumNumerator = networkMetricsQuorumNumerator , getNetworkMetricsResponseQuorumDenominator = networkMetricsQuorumDenominator diff --git a/govtool/backend/src/VVA/API/Types.hs b/govtool/backend/src/VVA/API/Types.hs index 461ca5dfe..ec95925e9 100644 --- a/govtool/backend/src/VVA/API/Types.hs +++ b/govtool/backend/src/VVA/API/Types.hs @@ -874,26 +874,66 @@ instance ToSchema DelegationResponse where & example ?~ toJSON exampleDelegationResponse +data GetNetworkInfoResponse + = GetNetworkInfoResponse + { getNetworkInfoResponseCurrentTime :: UTCTime + , getNetworkInfoResponseEpochNo :: Integer + , getNetworkInfoResponseBlockNo :: Integer + , getNetworkInfoResponseNetworkName :: Text + } + +deriveJSON (jsonOptions "getNetworkInfoResponse") ''GetNetworkInfoResponse + +exampleGetNetworkInfoResponse :: Text +exampleGetNetworkInfoResponse = + "{\"currentTime\": \"1970-01-01T00:00:00Z\"," + <> "\"currentEpoch\": 0," + <> "\"currentBlock\": 0," + <> "\"networkName\": \"Mainnet\"}" + +instance ToSchema GetNetworkInfoResponse where + declareNamedSchema _ = pure $ NamedSchema (Just "GetNetworkInfoResponse") $ mempty + & type_ ?~ OpenApiObject + & description ?~ "GetNetworkInfoResponse" + & example + ?~ toJSON exampleGetNetworkInfoResponse + +data GetNetworkTotalStakeResponse + = GetNetworkTotalStakeResponse + { getNetworkTotalStakeResponseTotalStakeControlledByDReps :: Integer + , getNetworkTotalStakeResponseTotalStakeControlledBySPOs :: Integer + , getNetworkTotalStakeResponseAlwaysAbstainVotingPower :: Integer + , getNetworkTotalStakeResponseAlwaysNoConfidenceVotingPower :: Integer + } + +deriveJSON (jsonOptions "getNetworkTotalStakeResponse") ''GetNetworkTotalStakeResponse + +exampleGetNetworkTotalStakeResponse :: Text +exampleGetNetworkTotalStakeResponse = + "{\"totalStakeControlledByDReps\": 0," + <> "\"totalStakeControlledBySPOs\": 0," + <> "\"alwaysAbstainVotingPower\": 0," + <> "\"alwaysNoConfidenceVotingPower\": 0}" + +instance ToSchema GetNetworkTotalStakeResponse where + declareNamedSchema _ = pure $ NamedSchema (Just "GetNetworkTotalStakeResponse") $ mempty + & type_ ?~ OpenApiObject + & description ?~ "GetNetworkTotalStakeResponse" + & example + ?~ toJSON exampleGetNetworkTotalStakeResponse + data GetNetworkMetricsResponse = GetNetworkMetricsResponse - { getNetworkMetricsResponseCurrentTime :: UTCTime - , getNetworkMetricsResponseCurrentEpoch :: Integer - , getNetworkMetricsResponseCurrentBlock :: Integer - , getNetworkMetricsResponseUniqueDelegators :: Integer + { getNetworkMetricsResponseUniqueDelegators :: Integer , getNetworkMetricsResponseTotalDelegations :: Integer , getNetworkMetricsResponseTotalGovernanceActions :: Integer , getNetworkMetricsResponseTotalDRepVotes :: Integer , getNetworkMetricsResponseTotalRegisteredDReps :: Integer , getNetworkMetricsResponseTotalDRepDistr :: Integer - , getNetworkMetricsResponseTotalStakeControlledByDReps :: Integer - , getNetworkMetricsResponseTotalStakeControlledBySPOs :: Integer , getNetworkMetricsResponseTotalActiveDReps :: Integer , getNetworkMetricsResponseTotalInactiveDReps :: Integer , getNetworkMetricsResponseTotalActiveCIP119CompliantDReps :: Integer , getNetworkMetricsResponseTotalRegisteredDirectVoters :: Integer - , getNetworkMetricsResponseAlwaysAbstainVotingPower :: Integer - , getNetworkMetricsResponseAlwaysNoConfidenceVotingPower :: Integer - , getNetworkMetricsResponseNetworkName :: Text , getNetworkMetricsResponseNoOfCommitteeMembers :: Integer , getNetworkMetricsResponseQuorumNumerator :: Integer , getNetworkMetricsResponseQuorumDenominator :: Integer @@ -912,14 +952,10 @@ exampleGetNetworkMetricsResponse = <> "\"totalDRepVotes\": 0," <> "\"totalRegisteredDReps\": 0," <> "\"totalDRepDistr\": 0," - <> "\"totalStakeControlledByDReps\": 0," - <> "\"totalStakeControlledBySPOs\": 0," <> "\"totalActiveDReps\": 0," <> "\"totalInactiveDReps\": 0," <> "\"totalActiveCIP119CompliantDReps\": 0," <> "\"totalRegisteredDirectVoters\": 0," - <> "\"alwaysAbstainVotingPower\": 0," - <> "\"alwaysNoConfidenceVotingPower\": 0," <> "\"networkName\": \"Mainnet\"," <> "\"noOfCommitteeMembers\": 7," <> "\"quorumNumerator\": 2," diff --git a/govtool/backend/src/VVA/Network.hs b/govtool/backend/src/VVA/Network.hs index 550c354c2..797d47ac3 100644 --- a/govtool/backend/src/VVA/Network.hs +++ b/govtool/backend/src/VVA/Network.hs @@ -25,6 +25,46 @@ import VVA.Types sqlFrom :: ByteString -> SQL.Query sqlFrom bs = fromString $ unpack $ Text.decodeUtf8 bs +networkInfoSql :: SQL.Query +networkInfoSql = sqlFrom $(embedFile "sql/get-network-info.sql") + +networkInfo :: + (Has ConnectionPool r, Has VVAConfig r, MonadReader r m, MonadIO m, MonadError AppError m) => + m NetworkInfo +networkInfo = withPool $ \conn -> do + result <- liftIO $ SQL.query_ conn networkInfoSql + current_time <- liftIO getCurrentTime + case result of + [( network_epoch + , network_block_no + , network_name + )] -> return $ NetworkInfo + current_time + network_epoch + network_block_no + network_name + _ -> throwError $ CriticalError "Could not query the network info. This should never happen." + +networkTotalStakeSql :: SQL.Query +networkTotalStakeSql = sqlFrom $(embedFile "sql/get-network-total-stake.sql") + +networkTotalStake :: + (Has ConnectionPool r, Has VVAConfig r, MonadReader r m, MonadIO m, MonadError AppError m) => + m NetworkTotalStake +networkTotalStake = withPool $ \conn -> do + result <- liftIO $ SQL.query_ conn networkTotalStakeSql + case result of + [( total_stake_controlled_by_dreps + , total_stake_controlled_by_spos + , always_abstain_voting_power + , always_no_confidence_voting_power + )] -> return $ NetworkTotalStake + total_stake_controlled_by_dreps + total_stake_controlled_by_spos + always_abstain_voting_power + always_no_confidence_voting_power + _ -> throwError $ CriticalError "Could not query the network total stake. This should never happen." + networkMetricsSql :: SQL.Query networkMetricsSql = sqlFrom $(embedFile "sql/get-network-metrics.sql") @@ -33,47 +73,31 @@ networkMetrics :: m NetworkMetrics networkMetrics = withPool $ \conn -> do result <- liftIO $ SQL.query_ conn networkMetricsSql - current_time <- liftIO getCurrentTime case result of - [( epoch_no - , block_no - , unique_delegators + [( unique_delegators , total_delegations , total_gov_action_proposals , total_drep_votes , total_registered_dreps , total_drep_distr - , total_stake_controlled_by_dreps - , total_stake_controlled_by_spos , total_active_dreps , total_inactive_dreps , total_active_cip119_compliant_dreps , total_registered_direct_voters - , always_abstain_voting_power - , always_no_confidence_voting_power - , network_name , no_of_committee_members , quorum_numerator , quorum_denominator )] -> return $ NetworkMetrics - current_time - epoch_no - block_no unique_delegators total_delegations total_gov_action_proposals total_drep_votes total_registered_dreps total_drep_distr - total_stake_controlled_by_dreps - total_stake_controlled_by_spos total_active_dreps total_inactive_dreps total_active_cip119_compliant_dreps total_registered_direct_voters - always_abstain_voting_power - always_no_confidence_voting_power - network_name no_of_committee_members quorum_numerator quorum_denominator diff --git a/govtool/backend/src/VVA/Types.hs b/govtool/backend/src/VVA/Types.hs index 0e69988d6..5d1f3ca5f 100644 --- a/govtool/backend/src/VVA/Types.hs +++ b/govtool/backend/src/VVA/Types.hs @@ -203,38 +203,48 @@ instance ToJSON TransactionStatus where data CacheEnv = CacheEnv - { proposalListCache :: Cache.Cache () [Proposal] - , getProposalCache :: Cache.Cache (Text, Integer) Proposal - , currentEpochCache :: Cache.Cache () (Maybe Value) - , adaHolderVotingPowerCache :: Cache.Cache Text Integer - , adaHolderGetCurrentDelegationCache :: Cache.Cache Text (Maybe Delegation) - , dRepGetVotesCache :: Cache.Cache Text ([Vote], [Proposal]) - , dRepInfoCache :: Cache.Cache Text DRepInfo - , dRepVotingPowerCache :: Cache.Cache Text Integer - , dRepListCache :: Cache.Cache Text [DRepRegistration] - , networkMetricsCache :: Cache.Cache () NetworkMetrics + { proposalListCache :: Cache.Cache () [Proposal] + , getProposalCache :: Cache.Cache (Text, Integer) Proposal + , currentEpochCache :: Cache.Cache () (Maybe Value) + , adaHolderVotingPowerCache :: Cache.Cache Text Integer + , adaHolderGetCurrentDelegationCache :: Cache.Cache Text (Maybe Delegation) + , dRepGetVotesCache :: Cache.Cache Text ([Vote], [Proposal]) + , dRepInfoCache :: Cache.Cache Text DRepInfo + , dRepVotingPowerCache :: Cache.Cache Text Integer + , dRepListCache :: Cache.Cache Text [DRepRegistration] + , networkMetricsCache :: Cache.Cache () NetworkMetrics + , networkInfoCache :: Cache.Cache () NetworkInfo + , networkTotalStakeCache :: Cache.Cache () NetworkTotalStake + } + +data NetworkInfo + = NetworkInfo + { networkInfoCurrentTime :: UTCTime + , networkInfoEpochNo :: Integer + , networkInfoBlockNo :: Integer + , networkInfoNetworkName :: Text + } + +data NetworkTotalStake + = NetworkTotalStake + { networkTotalStakeControlledByDReps :: Integer + , networkTotalStakeControlledBySPOs :: Integer + , networkTotalAlwaysAbstainVotingPower :: Integer + , networkTotalAlwaysNoConfidenceVotingPower :: Integer } data NetworkMetrics = NetworkMetrics - { networkMetricsCurrentTime :: UTCTime - , networkMetricsCurrentEpoch :: Integer - , networkMetricsCurrentBlock :: Integer - , networkMetricsUniqueDelegators :: Integer + { networkMetricsUniqueDelegators :: Integer , networkMetricsTotalDelegations :: Integer , networkMetricsTotalGovernanceActions :: Integer , networkMetricsTotalDRepVotes :: Integer , networkMetricsTotalRegisteredDReps :: Integer , networkMetricsTotalDRepDistr :: Integer - , networkMetricsTotalStakeControlledByDReps :: Integer - , networkMetricsTotalStakeControlledBySPOs :: Integer , networkMetricsTotalActiveDReps :: Integer , networkMetricsTotalInactiveDReps :: Integer , networkMetricsTotalActiveCIP119CompliantDReps :: Integer , networkMetricsTotalRegisteredDirectVoters :: Integer - , networkMetricsAlwaysAbstainVotingPower :: Integer - , networkMetricsAlwaysNoConfidenceVotingPower :: Integer - , networkMetricsNetworkName :: Text , networkMetricsNoOfCommitteeMembers :: Integer , networkMetricsQuorumNumerator :: Integer , networkMetricsQuorumDenominator :: Integer diff --git a/govtool/backend/vva-be.cabal b/govtool/backend/vva-be.cabal index a3e807dc6..3ad2bd4e5 100644 --- a/govtool/backend/vva-be.cabal +++ b/govtool/backend/vva-be.cabal @@ -32,6 +32,8 @@ extra-source-files: sql/get-transaction-status.sql sql/get-stake-key-voting-power.sql sql/get-network-metrics.sql + sql/get-network-info.sql + sql/get-network-total-stake.sql executable vva-be main-is: Main.hs diff --git a/govtool/frontend/index.html b/govtool/frontend/index.html index 16173bfe2..9294c61a0 100644 --- a/govtool/frontend/index.html +++ b/govtool/frontend/index.html @@ -24,19 +24,29 @@