Skip to content

Commit

Permalink
chore: refactor dependencies from validation and calculation packages
Browse files Browse the repository at this point in the history
  • Loading branch information
fabianbormann committed Feb 23, 2024
1 parent 2f73fa8 commit fdf116f
Show file tree
Hide file tree
Showing 47 changed files with 213 additions and 189 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.cardanofoundation.rewards.calculation;

import org.cardanofoundation.rewards.calculation.entity.*;
import org.cardanofoundation.rewards.validation.entity.jpa.projection.LatestStakeAccountUpdate;
import org.cardanofoundation.rewards.calculation.domain.*;
import org.cardanofoundation.rewards.calculation.enums.AccountUpdateAction;

import java.math.BigDecimal;
Expand Down Expand Up @@ -127,14 +126,15 @@ public static PoolRewardCalculationResult calculatePoolRewardInEpoch(String pool
int totalBlocksInEpoch, ProtocolParameters protocolParameters,
BigInteger adaInCirculation, BigInteger activeStakeInEpoch, BigInteger stakePoolRewardsPot,
BigInteger totalActiveStakeOfOwners, List<String> poolOwnerStakeAddresses,
List<LatestStakeAccountUpdate> accountUpdates, BigInteger poolOperatorRewardOutlier) {
List<AccountUpdate> accountUpdates, boolean ignoreLeaderReward) {
// Step 1: Get Pool information of current epoch
// Example: https://api.koios.rest/api/v0/pool_history?_pool_bech32=pool1z5uqdk7dzdxaae5633fqfcu2eqzy3a3rgtuvy087fdld7yws0xt&_epoch_no=210
PoolRewardCalculationResult poolRewardCalculationResult = PoolRewardCalculationResult.builder()
.epoch(poolHistoryCurrentEpoch.getEpoch())
.poolId(poolId)
.poolReward(BigInteger.ZERO)
.distributedPoolReward(BigInteger.ZERO)
.unspendableEarnedRewards(BigInteger.ZERO)
.build();

BigInteger poolStake = poolHistoryCurrentEpoch.getActiveStake();
Expand Down Expand Up @@ -190,44 +190,59 @@ public static PoolRewardCalculationResult calculatePoolRewardInEpoch(String pool
BigInteger poolOperatorReward = PoolRewardsCalculation.calculateLeaderReward(poolReward, poolMargin, poolFixedCost,
divide(totalActiveStakeOfOwners, adaInCirculation), relativePoolStake);

Map<String, AccountUpdate> latestAccountUpdates = new HashMap<>();
for (LatestStakeAccountUpdate accountUpdate : accountUpdates) {
if (latestAccountUpdates.keySet().stream().noneMatch(stakeAddress -> stakeAddress.equals(accountUpdate.getStakeAddress()))) {
latestAccountUpdates.put(accountUpdate.getStakeAddress(),
AccountUpdate.builder()
.stakeAddress(accountUpdate.getStakeAddress())
.action(AccountUpdateAction.fromString(accountUpdate.getLatestUpdateType()))
.build());
List<String> memberWithDeregisteredStakeAddresses = accountUpdates.stream()
.filter(accountUpdate -> accountUpdate.getAction().equals(AccountUpdateAction.DEREGISTRATION))
.map(AccountUpdate::getStakeAddress).toList();
List<String> memberWithUpdates = accountUpdates.stream().map(AccountUpdate::getStakeAddress).toList();

BigInteger unspendableEarnedRewards = BigInteger.ZERO;

if (!memberWithUpdates.contains(poolRewardCalculationResult.getRewardAddress()) || memberWithDeregisteredStakeAddresses.contains(poolRewardCalculationResult.getRewardAddress())) {
System.out.println("Pool " + poolId + " has been deregistered. Operator would have received " + poolOperatorReward + " but will not receive any rewards.");
AccountUpdate latestStakeAccountUpdate = accountUpdates.stream().filter(accountUpdate -> accountUpdate.getStakeAddress().equals(poolRewardCalculationResult.getRewardAddress())).findFirst().orElse(null);

if (latestStakeAccountUpdate != null &&
latestStakeAccountUpdate.getEpoch() == poolHistoryCurrentEpoch.getEpoch() + 1 &&
latestStakeAccountUpdate.getEpochSlot() > 212500) {
System.out.println("[unregRU]: " + poolRewardCalculationResult.getRewardAddress() + " has been deregistered. Operator would have received " + poolOperatorReward + " but will not receive any rewards.");
unspendableEarnedRewards = poolOperatorReward;
}
poolOperatorReward = BigInteger.ZERO;
}

if (accountUpdates.size() > 0 &&
(latestAccountUpdates.get(poolRewardCalculationResult.getRewardAddress()) == null ||
latestAccountUpdates.get(poolRewardCalculationResult.getRewardAddress()).getAction().equals(AccountUpdateAction.DEREGISTRATION))) {
System.out.println("Pool " + poolId + " has been deregistered. Operator would have received " + poolOperatorReward + " but will not receive any rewards.");
if (ignoreLeaderReward) {
poolOperatorReward = BigInteger.ZERO;
System.out.println("[reward address of multiple pools] Pool " + poolId + " has been ignored. Operator would have received " + poolOperatorReward + " but will not receive any rewards.");
}

poolOperatorReward = poolOperatorReward.add(poolOperatorRewardOutlier);
poolRewardCalculationResult.setOperatorReward(poolOperatorReward);
poolRewardCalculationResult.setDistributedPoolReward(poolOperatorReward);
// Step 11: Calculate pool member reward
List<Reward> memberRewards = new ArrayList<>();
for (Delegator delegator : poolHistoryCurrentEpoch.getDelegators()) {
if (accountUpdates.size() > 0 &&
(latestAccountUpdates.get(delegator.getStakeAddress()) == null ||
latestAccountUpdates.get(delegator.getStakeAddress()).getAction().equals(AccountUpdateAction.DEREGISTRATION))) {
System.out.println("Delegator " + delegator.getStakeAddress() + " has been deregistered. Delegator would have received " + poolOperatorReward + " but will not receive any rewards.");
continue;
}

if (delegator.getStakeAddress().equals(poolHistoryCurrentEpoch.getRewardAddress()) ||
poolOwnerStakeAddresses.contains(delegator.getStakeAddress())) {
continue;
}

BigInteger memberReward = PoolRewardsCalculation.calculateMemberReward(poolReward, poolMargin,
poolFixedCost, divide(delegator.getActiveStake(), adaInCirculation), relativePoolStake);

if (!memberWithUpdates.contains(delegator.getStakeAddress()) || memberWithDeregisteredStakeAddresses.contains(delegator.getStakeAddress())) {
System.out.println("Delegator " + delegator.getStakeAddress() + " has been deregistered. Delegator would have received " + memberReward + " but will not receive any rewards.");

AccountUpdate latestStakeAccountUpdate = accountUpdates.stream().filter(accountUpdate -> accountUpdate.getStakeAddress().equals(delegator.getStakeAddress())).findFirst().orElse(null);

if (latestStakeAccountUpdate != null &&
latestStakeAccountUpdate.getEpoch() == poolHistoryCurrentEpoch.getEpoch() + 1 &&
latestStakeAccountUpdate.getEpochSlot() > 212500) {
System.out.println("[unregRU]: " + delegator.getStakeAddress() + " has been deregistered. Operator would have received " + memberReward + " but will not receive any rewards.");
unspendableEarnedRewards = unspendableEarnedRewards.add(memberReward);
}

memberReward = BigInteger.ZERO;
}

memberRewards.add(Reward.builder()
.amount(memberReward)
.stakeAddress(delegator.getStakeAddress())
Expand All @@ -237,26 +252,7 @@ public static PoolRewardCalculationResult calculatePoolRewardInEpoch(String pool
add(poolRewardCalculationResult.getDistributedPoolReward(), memberReward));
}
poolRewardCalculationResult.setMemberRewards(memberRewards);
poolRewardCalculationResult.setUnspendableEarnedRewards(unspendableEarnedRewards);
return poolRewardCalculationResult;
}

public static BigInteger getEarnedRewardsForDeregisteredStakeAccount(PoolRewardCalculationResult poolRewardCalculationResult, List<String> stakeAddresses) {
BigInteger unspendableEarnedRewards = BigInteger.ZERO;
String poolRewardAddress = poolRewardCalculationResult.getRewardAddress();

if (poolRewardCalculationResult.getOperatorReward() != null && stakeAddresses.contains(poolRewardAddress)) {
unspendableEarnedRewards = unspendableEarnedRewards.add(poolRewardCalculationResult.getOperatorReward());
}

if (poolRewardCalculationResult.getMemberRewards() == null) {
return unspendableEarnedRewards;
}

for (Reward memberReward : poolRewardCalculationResult.getMemberRewards()) {
if (stakeAddresses.contains(memberReward.getStakeAddress())) {
unspendableEarnedRewards = unspendableEarnedRewards.add(memberReward.getAmount());
}
}
return unspendableEarnedRewards;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.cardanofoundation.rewards.calculation.entity;
package org.cardanofoundation.rewards.calculation.domain;

import lombok.*;
import org.cardanofoundation.rewards.calculation.enums.AccountUpdateAction;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.cardanofoundation.rewards.calculation.entity;
package org.cardanofoundation.rewards.calculation.domain;

import lombok.*;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.cardanofoundation.rewards.calculation.entity;
package org.cardanofoundation.rewards.calculation.domain;

import lombok.*;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.cardanofoundation.rewards.calculation.entity;
package org.cardanofoundation.rewards.calculation.domain;

import lombok.*;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.cardanofoundation.rewards.calculation.entity;
package org.cardanofoundation.rewards.calculation.domain;


import lombok.Builder;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.cardanofoundation.rewards.calculation.entity;
package org.cardanofoundation.rewards.calculation.domain;

import lombok.*;
import org.cardanofoundation.rewards.calculation.enums.MirPot;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.cardanofoundation.rewards.calculation.entity;
package org.cardanofoundation.rewards.calculation.domain;

import lombok.*;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.cardanofoundation.rewards.calculation.entity;
package org.cardanofoundation.rewards.calculation.domain;

import lombok.*;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.cardanofoundation.rewards.calculation.entity;
package org.cardanofoundation.rewards.calculation.domain;

import lombok.*;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.cardanofoundation.rewards.calculation.entity;
package org.cardanofoundation.rewards.calculation.domain;

import lombok.*;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.cardanofoundation.rewards.calculation.entity;
package org.cardanofoundation.rewards.calculation.domain;

import lombok.Builder;
import lombok.Getter;
Expand Down Expand Up @@ -26,4 +26,5 @@ public class PoolRewardCalculationResult {
Double poolMargin;
BigInteger poolCost;
List<String> poolOwnerStakeAddresses;
BigInteger unspendableEarnedRewards;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.cardanofoundation.rewards.calculation.entity;
package org.cardanofoundation.rewards.calculation.domain;

import lombok.*;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.cardanofoundation.rewards.calculation.entity;
package org.cardanofoundation.rewards.calculation.domain;

import lombok.*;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.cardanofoundation.rewards.calculation.entity;
package org.cardanofoundation.rewards.calculation.domain;

import lombok.*;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.cardanofoundation.rewards.calculation.entity;
package org.cardanofoundation.rewards.calculation.domain;

import lombok.*;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.cardanofoundation.rewards.validation;

import org.cardanofoundation.rewards.validation.data.provider.DataProvider;
import org.cardanofoundation.rewards.calculation.entity.AdaPots;
import org.cardanofoundation.rewards.calculation.entity.PoolDeregistration;
import org.cardanofoundation.rewards.calculation.domain.AdaPots;
import org.cardanofoundation.rewards.calculation.domain.PoolDeregistration;

import java.math.BigInteger;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.cardanofoundation.rewards.validation;

import org.cardanofoundation.rewards.calculation.PoolRewardsCalculation;
import org.cardanofoundation.rewards.calculation.entity.*;
import org.cardanofoundation.rewards.calculation.domain.*;
import org.cardanofoundation.rewards.validation.data.provider.DataProvider;
import org.cardanofoundation.rewards.validation.entity.jpa.projection.LatestStakeAccountUpdate;
import org.cardanofoundation.rewards.validation.entity.jpa.projection.TotalPoolRewards;
Expand Down Expand Up @@ -90,14 +90,7 @@ public static EpochCalculationResult calculateEpochPots(int epoch, DataProvider
int processedPools = 0;
long start = System.currentTimeMillis();
List<PoolHistory> poolHistories = dataProvider.getHistoryOfAllPoolsInEpoch(epoch - 2);
List<String> stakeAddresses = new ArrayList<>(poolHistories.stream()
.map(history -> history.getDelegators().stream()
.map(Delegator::getStakeAddress).toList())
.flatMap(Collection::stream).toList());
stakeAddresses.addAll(poolHistories.stream().map(PoolHistory::getRewardAddress).toList());

List<LatestStakeAccountUpdate> accountUpdates = dataProvider.getLatestStakeAccountUpdates(epoch - 1, stakeAddresses);
List<String> deregistrationInEpoch = dataProvider.getStakeAddressDeregistrationsInEpoch(epoch - 1);
List<AccountUpdate> accountUpdates = dataProvider.getLatestStakeAccountUpdates(epoch - 1);

// Member and total rewards are used in the validation part only
List<Reward> memberRewardsInEpoch = dataProvider.getMemberRewardsInEpoch(epoch - 2);
Expand All @@ -106,34 +99,31 @@ public static EpochCalculationResult calculateEpochPots(int epoch, DataProvider
long end = System.currentTimeMillis();
System.out.println("Pool and account data fetched in " + (end - start) + "ms");
BigInteger unspendableEarnedRewards = BigInteger.ZERO;

List<String> sharedPoolRewardAddressesWithoutReward = dataProvider.findSharedPoolRewardAddressWithoutReward(epoch - 2);

for (String poolId : poolIds) {
start = System.currentTimeMillis();
System.out.println("[" + processedPools + "/" + poolIds.size() + "] Processing pool: " + poolId);
PoolHistory poolHistory = poolHistories.stream().filter(history -> history.getPoolId().equals(poolId)).findFirst().orElse(null);
PoolRewardCalculationResult poolRewardCalculationResult = PoolRewardComputation.computePoolRewardInEpoch(poolId, epoch - 2, protocolParameters, epochInfo, stakePoolRewardsPot, adaInCirculation, poolHistory, accountUpdates);
PoolRewardCalculationResult poolRewardCalculationResult = PoolRewardComputation.computePoolRewardInEpoch(poolId, epoch - 2, protocolParameters, epochInfo, stakePoolRewardsPot, adaInCirculation, poolHistory, accountUpdates, sharedPoolRewardAddressesWithoutReward);

if (!PoolRewardComputation.poolRewardIsValid(poolRewardCalculationResult, memberRewardsInEpoch, totalPoolRewards)) {
System.out.println("Pool reward is invalid. Please check the details for pool " + poolId);
}

PoolRewardCalculationResults.add(poolRewardCalculationResult);
totalDistributedRewards = add(totalDistributedRewards, poolRewardCalculationResult.getDistributedPoolReward());

unspendableEarnedRewards = unspendableEarnedRewards.add(PoolRewardsCalculation.getEarnedRewardsForDeregisteredStakeAccount(poolRewardCalculationResult, deregistrationInEpoch));

unspendableEarnedRewards = unspendableEarnedRewards.add(poolRewardCalculationResult.getUnspendableEarnedRewards());
processedPools++;
end = System.currentTimeMillis();
System.out.println("Pool processed in " + (end - start) + "ms");
}

System.out.println("Unspendable rewards: " + lovelaceToAda(unspendableEarnedRewards.longValue()) + " ADA");

BigInteger calculatedReserve = subtract(reserveInPreviousEpoch, subtract(rewardPot, totalFeesForCurrentEpoch));
BigInteger undistributedRewards = subtract(stakePoolRewardsPot, totalDistributedRewards);
calculatedReserve = add(calculatedReserve, undistributedRewards);
long epochCalculationEnd = System.currentTimeMillis();
System.out.println("Epoch calculation took " +
Math.round((epochCalculationEnd - epochCalculationStart) / 1000.0) + " seconds in total.");
calculatedReserve = subtract(calculatedReserve, unspendableEarnedRewards);

System.out.println("Unspendable earned rewards: " + lovelaceToAda(unspendableEarnedRewards.intValue()) + " ADA");
treasuryForCurrentEpoch = add(treasuryForCurrentEpoch, unspendableEarnedRewards);

epochCalculationResult.setTotalDistributedRewards(totalDistributedRewards);
epochCalculationResult.setTotalRewardsPot(rewardPot);
Expand All @@ -144,6 +134,10 @@ public static EpochCalculationResult calculateEpochPots(int epoch, DataProvider
epochCalculationResult.setTotalAdaInCirculation(adaInCirculation);
epochCalculationResult.setTotalUndistributedRewards(undistributedRewards);

long epochCalculationEnd = System.currentTimeMillis();
System.out.println("Epoch calculation took " +
Math.round((epochCalculationEnd - epochCalculationStart) / 1000.0) + " seconds in total.");

return epochCalculationResult;
}
}
Loading

0 comments on commit fdf116f

Please sign in to comment.