mirror of
https://github.com/Qortal/qortal.git
synced 2025-07-22 20:26:50 +00:00
Fix long overflow in Block.distributeBlockRewardToQoraHolders()
Sadly no native 128bit integer support in Java 11 so resorting to using BigInteger. Added/improved unit tests to cover.
This commit is contained in:
@@ -1693,6 +1693,8 @@ public class Block {
|
||||
final boolean isProcessingNotOrphaning = totalAmount >= 0;
|
||||
|
||||
long qoraPerQortReward = BlockChain.getInstance().getQoraPerQortReward();
|
||||
BigInteger qoraPerQortRewardBI = BigInteger.valueOf(qoraPerQortReward);
|
||||
|
||||
List<AccountBalanceData> qoraHolders = this.repository.getAccountRepository().getEligibleLegacyQoraHolders(isProcessingNotOrphaning ? null : this.blockData.getHeight());
|
||||
|
||||
long totalQoraHeld = 0;
|
||||
@@ -1706,10 +1708,18 @@ public class Block {
|
||||
if (totalQoraHeld <= 0)
|
||||
return sharedAmount;
|
||||
|
||||
// Could do with a faster 128bit integer library, but until then...
|
||||
BigInteger qoraHoldersAmountBI = BigInteger.valueOf(qoraHoldersAmount);
|
||||
BigInteger totalQoraHeldBI = BigInteger.valueOf(totalQoraHeld);
|
||||
|
||||
for (int h = 0; h < qoraHolders.size(); ++h) {
|
||||
AccountBalanceData qoraHolder = qoraHolders.get(h);
|
||||
BigInteger qoraHolderBalanceBI = BigInteger.valueOf(qoraHolder.getBalance());
|
||||
|
||||
// This is where a 128bit integer library could help:
|
||||
// long holderReward = (qoraHoldersAmount * qoraHolder.getBalance()) / totalQoraHeld;
|
||||
long holderReward = qoraHoldersAmountBI.multiply(qoraHolderBalanceBI).divide(totalQoraHeldBI).longValue();
|
||||
|
||||
long holderReward = (qoraHoldersAmount * qoraHolder.getBalance()) / totalQoraHeld;
|
||||
long finalHolderReward = holderReward;
|
||||
LOGGER.trace(() -> String.format("QORA holder %s has %s / %s QORA so share: %s",
|
||||
qoraHolder.getAddress(), Amounts.prettyAmount(qoraHolder.getBalance()), finalTotalQoraHeld, Amounts.prettyAmount(finalHolderReward)));
|
||||
@@ -1724,7 +1734,7 @@ public class Block {
|
||||
|
||||
// If processing, make sure we don't overpay
|
||||
if (isProcessingNotOrphaning) {
|
||||
long maxQortFromQora = qoraHolder.getBalance() / qoraPerQortReward;
|
||||
long maxQortFromQora = Amounts.scaledDivide(qoraHolderBalanceBI, qoraPerQortRewardBI);
|
||||
|
||||
if (newQortFromQoraBalance >= maxQortFromQora) {
|
||||
// Reduce final QORT-from-QORA payment to match max
|
||||
|
@@ -64,8 +64,12 @@ public abstract class Amounts {
|
||||
return roundDownScaledMultiply(BigInteger.valueOf(multiplicand), BigInteger.valueOf(multiplier));
|
||||
}
|
||||
|
||||
public static long scaledDivide(BigInteger dividend, BigInteger divisor) {
|
||||
return dividend.multiply(Amounts.MULTIPLIER_BI).divide(divisor).longValue();
|
||||
}
|
||||
|
||||
public static long scaledDivide(long dividend, long divisor) {
|
||||
return BigInteger.valueOf(dividend).multiply(Amounts.MULTIPLIER_BI).divide(BigInteger.valueOf(divisor)).longValue();
|
||||
return scaledDivide(BigInteger.valueOf(dividend), BigInteger.valueOf(divisor));
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user