Skip to content

Commit

Permalink
feat: caculated active stake of DRep and Pool by utxo balance
Browse files Browse the repository at this point in the history
  • Loading branch information
Sotatek-ThinhVu committed May 9, 2024
1 parent bbe6af9 commit f6e817f
Show file tree
Hide file tree
Showing 12 changed files with 291 additions and 67 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.cardanofoundation.explorer.api.projection;

import java.math.BigInteger;

public interface DRepInfoProjection {
String getDrepHash();

BigInteger getActiveVoteStake();
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public interface GovActionDetailsProjection {

Long getBlockTime();

Long getSlot();

Integer getEpoch();

GovActionStatus getStatus();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.cardanofoundation.explorer.api.projection;

import java.math.BigInteger;

public interface PoolOverviewProjection {
String getPoolHash();

Long getCreatedAt();

Long getPoolId();

BigInteger getBalance();
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import org.cardanofoundation.explorer.api.model.response.drep.projection.DRepStatusCountProjection;
import org.cardanofoundation.explorer.api.projection.DRepRangeProjection;
import org.cardanofoundation.explorer.api.projection.DRepInfoProjection;
import org.cardanofoundation.explorer.common.entity.enumeration.DRepStatus;
import org.cardanofoundation.explorer.common.entity.explorer.DRepInfo;

Expand All @@ -29,6 +30,15 @@ public interface DrepInfoRepository extends JpaRepository<DRepInfo, Long> {
@Query("SELECT SUM(dri.delegators) from DRepInfo dri")
Long getDelegateCount();

@Query(
value =
"""
SELECT dri.drepHash as drepHash, dri.activeVoteStake as activeVoteStake
FROM DRepInfo dri
WHERE dri.createdAt >= :blockTime and dri.status != 'RETIRED'
""")
List<DRepInfoProjection> findDRepByCreatedAt(@Param("blockTime") Long blockTime);

@Query(
value =
" select dri from DRepInfo dri"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import org.cardanofoundation.explorer.api.projection.VotingCCProjection;
import org.cardanofoundation.explorer.common.entity.compositeKey.CommitteeRegistrationId;
import org.cardanofoundation.explorer.common.entity.enumeration.VoterType;
import org.cardanofoundation.explorer.common.entity.ledgersync.CommitteeRegistration;

public interface CommitteeRegistrationRepository
Expand All @@ -24,10 +25,12 @@ public interface CommitteeRegistrationRepository
"""
select lvp.voterHash as voterHash, lvp.txHash as txHash, lvp.index as index, lvp.vote as vote from CommitteeRegistration cr
left join LatestVotingProcedure lvp on lvp.govActionTxHash = :txHash
and lvp.govActionIndex = :index and lvp.voterType = 'CONSTITUTIONAL_COMMITTEE_HOT_KEY_HASH' and lvp.voterHash = cr.hotKey
and lvp.govActionIndex = :index and lvp.voterType = :voterType and lvp.voterHash = cr.hotKey
where not exists ( select 1 from CommitteeRegistration cr2 where cr2.coldKey = cr.coldKey and cr2.blockTime > cr.blockTime)
and not exists (select 1 from CommitteeDeRegistration cd where cd.coldKey = cr.coldKey and cd.blockTime > cr.blockTime)
""")
List<VotingCCProjection> findByTxHashAndIndex(
@Param("txHash") String txHash, @Param("index") Integer index);
@Param("txHash") String txHash,
@Param("index") Integer index,
@Param("voterType") List<VoterType> voterType);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.cardanofoundation.explorer.api.model.response.pool.projection.PoolDetailDelegatorProjection;
import org.cardanofoundation.explorer.api.projection.DelegationProjection;
import org.cardanofoundation.explorer.api.projection.PoolDelegationSummaryProjection;
import org.cardanofoundation.explorer.api.projection.PoolOverviewProjection;
import org.cardanofoundation.explorer.api.projection.StakeDelegationProjection;
import org.cardanofoundation.explorer.common.entity.ledgersync.*;

Expand Down Expand Up @@ -175,4 +176,14 @@ List<StakeDelegationProjection> findPoolDataByAddressIn(
+ " AND (po.id IS NULL OR po.id = (SELECT max(po2.id) FROM PoolOfflineData po2 WHERE po2.pool.id = poolHash.id))"
+ " WHERE delegation.txId IN :txIds")
List<DelegationProjection> findDelegationByTxIdIn(@Param("txIds") List<Long> txIds);

@Query(
value =
"""
select sum(sa.balance) as balance, d.poolHash.hashRaw as poolHash from Delegation d
join StakeAddress sa on sa.id = d.stakeAddressId
where d.poolHash.id in :poolIds
group by d.poolHash.hashRaw
""")
List<PoolOverviewProjection> getBalanceByPoolIdIn(@Param("poolIds") List<Long> poolIds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Page<GovernanceActionProjection> getAllByFilter(
@Query(
value =
"select gap.txHash as txHash, gap.index as index, gap.anchorHash as anchorHash, gap.anchorUrl as anchorUrl,"
+ " gap.type as type, gap.details as details, gap.epoch as epoch, gap.blockTime as blockTime, gapi.status as status, gapi.votingPower as votingPower"
+ " gap.type as type, gap.details as details, gap.epoch as epoch, gap.blockTime as blockTime,gap.slot as slot, gapi.status as status, gapi.votingPower as votingPower"
+ " from GovActionProposal gap"
+ " join GovActionProposalInfo gapi on gapi.txHash = gap.txHash and gapi.index = gap.index"
+ " where gap.txHash = :txHash and gap.index = :index")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.springframework.stereotype.Repository;

import org.cardanofoundation.explorer.api.projection.CountVoteOnGovActionProjection;
import org.cardanofoundation.explorer.api.projection.LatestVotingProcedureProjection;
import org.cardanofoundation.explorer.common.entity.compositeKey.LatestVotingProcedureId;
import org.cardanofoundation.explorer.common.entity.enumeration.VoterType;
import org.cardanofoundation.explorer.common.entity.ledgersync.LatestVotingProcedure;
Expand All @@ -27,6 +28,21 @@ List<CountVoteOnGovActionProjection> getLatestVotingProcedureByGovActionTxHashAn
@Param("govActionIndex") Integer govActionIndex,
@Param("voterType") VoterType voterType);

@Query(
value =
"""
select lvp.voterHash as voterHash, lvp.vote as vote from LatestVotingProcedure lvp
where lvp.govActionTxHash = :govActionTxHash
and lvp.govActionIndex = :govActionIndex
and lvp.voterType in :voterType
and lvp.voterHash in :voterHashList
""")
List<LatestVotingProcedureProjection> findByGovActionTxHashAndGovActionIndex(
@Param("govActionTxHash") String govActionTxHash,
@Param("govActionIndex") Integer govActionIndex,
@Param("voterHashList") List<String> voterHashList,
@Param("voterType") List<VoterType> voterType);

@Query(
value =
"select count(*) from LatestVotingProcedure lvp"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.cardanofoundation.explorer.api.model.response.pool.projection.PoolInfoProjection;
import org.cardanofoundation.explorer.api.model.response.pool.projection.PoolListProjection;
import org.cardanofoundation.explorer.api.model.response.pool.projection.PoolRegistrationProjection;
import org.cardanofoundation.explorer.api.projection.PoolOverviewProjection;
import org.cardanofoundation.explorer.api.projection.PoolRangeProjection;
import org.cardanofoundation.explorer.common.entity.ledgersync.PoolHash;

Expand Down Expand Up @@ -192,6 +193,16 @@ Page<PoolRegistrationProjection> getPoolRegistrationByPool(
+ " where ph.hashRaw =:poolHash")
Long getSlotNoWhenFirstDelegationByPoolHash(@Param("poolHash") String poolHash);

@Query(
value =
"""
select min(d.slotNo) as createdAt, ph.hashRaw as poolHash, ph.id as poolId from PoolHash ph
join Delegation d on d.poolHash.id = ph.id
group by ph.hashRaw, ph.id
order by ph.id desc
""")
List<PoolOverviewProjection> getSlotCreatedAtGroupByPoolHash();

@Query(value = "select ph.hashRaw from PoolHash ph where ph.view = :view")
Optional<String> getHashRawByView(@Param("view") String view);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,17 @@
import org.cardanofoundation.explorer.api.model.response.governanceAction.GovernanceActionResponse;
import org.cardanofoundation.explorer.api.model.response.governanceAction.HistoryVote;
import org.cardanofoundation.explorer.api.model.response.governanceAction.VotingChartResponse;
import org.cardanofoundation.explorer.api.projection.DRepInfoProjection;
import org.cardanofoundation.explorer.api.projection.GovActionDetailsProjection;
import org.cardanofoundation.explorer.api.projection.GovernanceActionProjection;
import org.cardanofoundation.explorer.api.projection.LatestVotingProcedureProjection;
import org.cardanofoundation.explorer.api.projection.PoolOverviewProjection;
import org.cardanofoundation.explorer.api.projection.VotingCCProjection;
import org.cardanofoundation.explorer.api.projection.VotingProcedureProjection;
import org.cardanofoundation.explorer.api.repository.explorer.DrepInfoRepository;
import org.cardanofoundation.explorer.api.repository.ledgersync.CommitteeRegistrationRepository;
import org.cardanofoundation.explorer.api.repository.ledgersync.DRepRegistrationRepository;
import org.cardanofoundation.explorer.api.repository.ledgersync.DelegationRepository;
import org.cardanofoundation.explorer.api.repository.ledgersync.EpochParamRepository;
import org.cardanofoundation.explorer.api.repository.ledgersync.EpochRepository;
import org.cardanofoundation.explorer.api.repository.ledgersync.GovernanceActionRepository;
Expand Down Expand Up @@ -81,6 +85,7 @@ public class GovernanceActionServiceImpl implements GovernanceActionService {
private final EpochParamRepository epochParamRepository;
private final LatestVotingProcedureRepository latestVotingProcedureRepository;
private final CommitteeRegistrationRepository committeeRegistrationRepository;
private final DelegationRepository delegationRepository;

private final EpochMapper epochMapper;
private final EpochRepository epochRepository;
Expand Down Expand Up @@ -294,7 +299,8 @@ public VotingChartResponse getVotingChartByGovActionTxHashAndIndex(
Integer committeeTotalCount =
committeeRegistrationRepository.countByExpiredEpochNo(expiredEpoch);
CommitteeState committeeState =
committeeTotalCount >= epochParam.getCommitteeMinSize().intValue()
epochParam.getCommitteeMinSize() == null
|| committeeTotalCount >= epochParam.getCommitteeMinSize().intValue()
? CommitteeState.NORMAL
: CommitteeState.NO_CONFIDENCE;

Expand Down Expand Up @@ -342,6 +348,61 @@ private void getVotingChartResponseForPool(
default:
votingChartResponse.setThreshold(null);
}
List<PoolOverviewProjection> createdAtList =
poolHashRepository.getSlotCreatedAtGroupByPoolHash();
List<PoolOverviewProjection> poolCanVoteList =
createdAtList.stream()
.filter(e -> e.getCreatedAt() <= govActionDetailsProjection.getSlot())
.toList();
Map<String, Long> poolHashByPoolIdMap =
poolCanVoteList.stream()
.collect(
Collectors.toMap(
PoolOverviewProjection::getPoolHash, PoolOverviewProjection::getPoolId));
List<Long> poolIds = poolHashByPoolIdMap.values().stream().toList();
List<PoolOverviewProjection> poolOverviewProjections =
delegationRepository.getBalanceByPoolIdIn(poolIds);
Map<String, BigInteger> activeVoteStakeByPoolMap =
poolOverviewProjections.stream()
.collect(
Collectors.toMap(
PoolOverviewProjection::getPoolHash, PoolOverviewProjection::getBalance));
BigInteger totalActiveVoteStake =
poolOverviewProjections.stream()
.map(PoolOverviewProjection::getBalance)
.filter(Objects::nonNull)
.reduce(BigInteger::add)
.orElse(BigInteger.ZERO);
List<LatestVotingProcedureProjection> latestVotingProcedureProjections =
latestVotingProcedureRepository.findByGovActionTxHashAndGovActionIndex(
govActionDetailsProjection.getTxHash(),
govActionDetailsProjection.getIndex(),
poolHashByPoolIdMap.keySet().stream().toList(),
List.of(VoterType.STAKING_POOL_KEY_HASH));

Map<Vote, List<LatestVotingProcedureProjection>> voteCount =
latestVotingProcedureProjections.stream()
.collect(Collectors.groupingBy(LatestVotingProcedureProjection::getVote));

Map<Vote, BigInteger> voteStake =
voteCount.entrySet().stream()
.collect(
Collectors.toMap(
Map.Entry::getKey,
entry ->
entry.getValue().stream()
.map( // get active vote stake of Pool
latestVotingProcedureProjection ->
activeVoteStakeByPoolMap.getOrDefault(
latestVotingProcedureProjection.getVoterHash(),
BigInteger.ZERO))
.filter(Objects::nonNull)
.reduce(BigInteger::add)
.orElse(BigInteger.ZERO)));
votingChartResponse.setActiveVoteStake(totalActiveVoteStake);
votingChartResponse.setTotalYesVoteStake(voteStake.getOrDefault(Vote.YES, BigInteger.ZERO));
votingChartResponse.setTotalNoVoteStake(voteStake.getOrDefault(Vote.NO, BigInteger.ZERO));
votingChartResponse.setAbstainVoteStake(voteStake.getOrDefault(Vote.ABSTAIN, BigInteger.ZERO));
}
// TODO: Active vote stake of DRep type is not available.
private void getVotingChartResponseForDRep(
Expand Down Expand Up @@ -374,6 +435,55 @@ private void getVotingChartResponseForDRep(
default:
votingChartResponse.setThreshold(null);
}

List<DRepInfoProjection> dRepInfoProjections =
drepInfoRepository.findDRepByCreatedAt(govActionDetailsProjection.getBlockTime());
Map<String, BigInteger> activeVoteStakeByDRepMap =
dRepInfoProjections.stream()
.collect(
Collectors.toMap(
DRepInfoProjection::getDrepHash, DRepInfoProjection::getActiveVoteStake));
BigInteger totalActiveVoteStake =
dRepInfoProjections.stream()
.map(DRepInfoProjection::getActiveVoteStake)
.filter(Objects::nonNull)
.reduce(BigInteger::add)
.orElse(BigInteger.ZERO);

List<String> dRepHashes =
dRepInfoProjections.stream().map(DRepInfoProjection::getDrepHash).toList();

List<LatestVotingProcedureProjection> latestVotingProcedureProjections =
latestVotingProcedureRepository.findByGovActionTxHashAndGovActionIndex(
govActionDetailsProjection.getTxHash(),
govActionDetailsProjection.getIndex(),
dRepHashes,
List.of(VoterType.DREP_KEY_HASH, VoterType.DREP_SCRIPT_HASH));

Map<Vote, List<LatestVotingProcedureProjection>> voteCount =
latestVotingProcedureProjections.stream()
.collect(Collectors.groupingBy(LatestVotingProcedureProjection::getVote));

Map<Vote, BigInteger> voteStake =
voteCount.entrySet().stream()
.collect(
Collectors.toMap(
Map.Entry::getKey,
entry ->
entry.getValue().stream()
.map( // get active vote stake of DRep
latestVotingProcedureProjection ->
activeVoteStakeByDRepMap.getOrDefault(
latestVotingProcedureProjection.getVoterHash(),
BigInteger.ZERO))
.filter(Objects::nonNull)
.reduce(BigInteger::add)
.orElse(BigInteger.ZERO)));

votingChartResponse.setActiveVoteStake(totalActiveVoteStake);
votingChartResponse.setTotalYesVoteStake(voteStake.getOrDefault(Vote.YES, BigInteger.ZERO));
votingChartResponse.setTotalNoVoteStake(voteStake.getOrDefault(Vote.NO, BigInteger.ZERO));
votingChartResponse.setAbstainVoteStake(voteStake.getOrDefault(Vote.ABSTAIN, BigInteger.ZERO));
}

// TODO: Threshold for CC type is not available. It must be null for now.
Expand All @@ -385,7 +495,11 @@ private void getVotingChartResponseForCCType(
votingChartResponse.setThreshold(null);
List<VotingCCProjection> votingCCProjections =
committeeRegistrationRepository.findByTxHashAndIndex(
govActionDetailsProjection.getTxHash(), govActionDetailsProjection.getIndex());
govActionDetailsProjection.getTxHash(),
govActionDetailsProjection.getIndex(),
List.of(
VoterType.CONSTITUTIONAL_COMMITTEE_HOT_SCRIPT_HASH,
VoterType.CONSTITUTIONAL_COMMITTEE_HOT_KEY_HASH));
List<VotingCCProjection> votingCCProjectionsFiltered =
votingCCProjections.stream()
.filter(votingCCProjection -> Objects.nonNull(votingCCProjection.getVote()))
Expand Down

0 comments on commit f6e817f

Please sign in to comment.