Skip to content

feat(math): migrate all operations from java.lang.Math to java.lang.strictMath #6182

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions .github/workflows/math-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
name: Check Math Usage

on:
push:
branches: [ 'master', 'release_**' ]
pull_request:
branches: [ 'develop', 'release_**' ]
workflow_dispatch:

jobs:
check-math:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Check for java.lang.Math usage
id: check-math
shell: bash
run: |
echo "Checking for java.lang.Math usage..."

touch math_usage.txt

while IFS= read -r file; do
filename=$(basename "$file")
if [[ "$filename" == "StrictMathWrapper.java" || "$filename" == "MathWrapper.java" ]]; then
continue
fi

perl -0777 -ne '
s/"([^"\\]|\\.)*"//g;
s/'\''([^'\''\\]|\\.)*'\''//g;
s!/\*([^*]|\*[^/])*\*/!!g;
s!//[^\n]*!!g;
$hasMath = 0;
$hasMath = 1 if /^[\s]*import[\s]+java\.lang\.Math\b/m;
$hasMath = 1 if /\bjava\s*\.\s*lang\s*\.\s*Math\s*\./;
$hasMath = 1 if /(?<![\w\.])(?<!Strict)Math\s*\./;
print "$ARGV\n" if $hasMath;
' "$file" >> math_usage.txt
done < <(find . -type f -name "*.java")

sort -u math_usage.txt -o math_usage.txt

if [ -s math_usage.txt ]; then
echo "❌ Error: Forbidden Math usage found in the following files:"
cat math_usage.txt
echo "math_found=true" >> $GITHUB_OUTPUT
echo "Please use org.tron.common.math.StrictMathWrapper instead of direct Math usage."
else
echo "✅ No forbidden Math usage found"
echo "math_found=false" >> $GITHUB_OUTPUT
fi

- name: Upload findings
if: steps.check-math.outputs.math_found == 'true'
uses: actions/upload-artifact@v4
with:
name: math-usage-report
path: math_usage.txt

- name: Create comment
if: github.event_name == 'pull_request' && steps.check-math.outputs.math_found == 'true'
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const findings = fs.readFileSync('math_usage.txt', 'utf8');
const body = `### ❌ Math Usage Detection Results

Found forbidden usage of \`java.lang.Math\` in the following files:

\`\`\`
${findings}
\`\`\`

**Please review if this usage is intended.**
> [!CAUTION]
> Note: You should use \`org.tron.common.math.StrictMathWrapper\`.
> If you need to use \`java.lang.Math\`, please provide a justification.
`;

await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: body
});

- name: Fail if Math usage found
if: steps.check-math.outputs.math_found == 'true'
run: exit 1
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

import com.google.protobuf.Any;
import com.google.protobuf.GeneratedMessageV3;
import org.tron.common.math.Maths;
import org.tron.common.utils.Commons;
import org.tron.common.utils.ForkController;
import org.tron.core.ChainBaseManager;
import org.tron.core.capsule.AccountCapsule;
import org.tron.core.capsule.TransactionCapsule;
import org.tron.core.exception.BalanceInsufficientException;
import org.tron.core.store.AccountStore;
import org.tron.protos.Protocol.Transaction.Contract;
import org.tron.protos.Protocol.Transaction.Contract.ContractType;

Expand Down Expand Up @@ -63,4 +68,61 @@ public AbstractActuator setForkUtils(ForkController forkController) {
return this;
}

public long addExact(long x, long y) {
return Maths.addExact(x, y, chainBaseManager.getDynamicPropertiesStore().allowStrictMath2());
}

public long addExact(int x, int y) {
return Maths.addExact(x, y, chainBaseManager.getDynamicPropertiesStore().allowStrictMath2());
}

public long floorDiv(long x, long y) {
return Maths.floorDiv(x, y, chainBaseManager.getDynamicPropertiesStore().allowStrictMath2());
}

public long floorDiv(long x, int y) {
return this.floorDiv(x, (long) y);
}

public long multiplyExact(long x, long y) {
return Maths.multiplyExact(x, y,
chainBaseManager.getDynamicPropertiesStore().allowStrictMath2());
}

public long multiplyExact(long x, int y) {
return this.multiplyExact(x, (long) y);
}

public int multiplyExact(int x, int y) {
return Maths.multiplyExact(x, y,
chainBaseManager.getDynamicPropertiesStore().allowStrictMath2());
}

public long subtractExact(long x, long y) {
return Maths.subtractExact(x, y,
chainBaseManager.getDynamicPropertiesStore().allowStrictMath2());
}

public int min(int a, int b) {
return Maths.min(a, b, chainBaseManager.getDynamicPropertiesStore().allowStrictMath2());
}

public long min(long a, long b) {
return Maths.min(a, b, chainBaseManager.getDynamicPropertiesStore().allowStrictMath2());
}

public void adjustBalance(AccountStore accountStore, byte[] accountAddress, long amount)
throws BalanceInsufficientException {
AccountCapsule account = accountStore.getUnchecked(accountAddress);
this.adjustBalance(accountStore, account, amount);
}

/**
* judge balance.
*/
public void adjustBalance(AccountStore accountStore, AccountCapsule account, long amount)
throws BalanceInsufficientException {
Commons.adjustBalance(accountStore, account, amount,
chainBaseManager.getDynamicPropertiesStore().allowStrictMath2());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.tron.common.utils.Commons;
import org.tron.common.utils.DecodeUtil;
import org.tron.core.capsule.AccountCapsule;
import org.tron.core.capsule.TransactionResultCapsule;
Expand Down Expand Up @@ -52,11 +51,11 @@ public boolean execute(Object object) throws ContractExeException {
accountPermissionUpdateContract.getActivesList());
accountStore.put(ownerAddress, account);

Commons.adjustBalance(accountStore, ownerAddress, -fee);
adjustBalance(accountStore, ownerAddress, -fee);
if (chainBaseManager.getDynamicPropertiesStore().supportBlackHoleOptimization()) {
chainBaseManager.getDynamicPropertiesStore().burnTrx(fee);
} else {
Commons.adjustBalance(accountStore, accountStore.getBlackhole(), fee);
adjustBalance(accountStore, accountStore.getBlackhole(), fee);
}

result.setStatus(fee, code.SUCESS);
Expand Down Expand Up @@ -111,7 +110,7 @@ private boolean checkPermission(Permission permission) throws ContractValidateEx
throw new ContractValidateException("key's weight should be greater than 0");
}
try {
weightSum = Math.addExact(weightSum, key.getWeight());
weightSum = addExact(weightSum, key.getWeight());
} catch (ArithmeticException e) {
throw new ContractValidateException(e.getMessage());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import java.util.List;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import org.tron.common.utils.Commons;
import org.tron.common.utils.DecodeUtil;
import org.tron.core.capsule.AccountCapsule;
import org.tron.core.capsule.AssetIssueCapsule;
Expand Down Expand Up @@ -84,11 +83,11 @@ public boolean execute(Object result) throws ContractExeException {
.put(assetIssueCapsuleV2.createDbV2Key(), assetIssueCapsuleV2);
}

Commons.adjustBalance(accountStore, ownerAddress, -fee);
adjustBalance(accountStore, ownerAddress, -fee);
if (dynamicStore.supportBlackHoleOptimization()) {
dynamicStore.burnTrx(fee);
} else {
Commons.adjustBalance(accountStore, accountStore.getBlackhole(), fee);//send to blackhole
adjustBalance(accountStore, accountStore.getBlackhole(), fee);//send to blackhole
}
AccountCapsule accountCapsule = accountStore.get(ownerAddress);
List<FrozenSupply> frozenSupplyList = assetIssueContract.getFrozenSupplyList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import com.google.protobuf.InvalidProtocolBufferException;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import org.tron.common.utils.Commons;
import org.tron.common.utils.DecodeUtil;
import org.tron.common.utils.StringUtil;
import org.tron.core.capsule.AccountCapsule;
Expand Down Expand Up @@ -48,13 +47,12 @@ public boolean execute(Object result)
accountStore
.put(accountCreateContract.getAccountAddress().toByteArray(), accountCapsule);

Commons
.adjustBalance(accountStore, accountCreateContract.getOwnerAddress().toByteArray(), -fee);
adjustBalance(accountStore, accountCreateContract.getOwnerAddress().toByteArray(), -fee);
// Add to blackhole address
if (dynamicStore.supportBlackHoleOptimization()) {
dynamicStore.burnTrx(fee);
} else {
Commons.adjustBalance(accountStore, accountStore.getBlackhole(), fee);
adjustBalance(accountStore, accountStore.getBlackhole(), fee);
}
ret.setStatus(fee, code.SUCESS);
} catch (BalanceInsufficientException | InvalidProtocolBufferException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@ public boolean validate() throws ContractValidateException {
}
long netUsage = (long) (accountNetUsage * TRX_PRECISION * ((double)
(dynamicStore.getTotalNetWeight()) / dynamicStore.getTotalNetLimit()));
long v2NetUsage = getV2NetUsage(ownerCapsule, netUsage);
long v2NetUsage = getV2NetUsage(ownerCapsule, netUsage,
dynamicStore.allowStrictMath2());
if (ownerCapsule.getFrozenV2BalanceForBandwidth() - v2NetUsage < delegateBalance) {
throw new ContractValidateException(
"delegateBalance must be less than or equal to available FreezeBandwidthV2 balance");
Expand All @@ -175,7 +176,8 @@ public boolean validate() throws ContractValidateException {

long energyUsage = (long) (ownerCapsule.getEnergyUsage() * TRX_PRECISION * ((double)
(dynamicStore.getTotalEnergyWeight()) / dynamicStore.getTotalEnergyCurrentLimit()));
long v2EnergyUsage = getV2EnergyUsage(ownerCapsule, energyUsage);
long v2EnergyUsage = getV2EnergyUsage(ownerCapsule, energyUsage,
dynamicStore.allowStrictMath2());
if (ownerCapsule.getFrozenV2BalanceForEnergy() - v2EnergyUsage < delegateBalance) {
throw new ContractValidateException(
"delegateBalance must be less than or equal to available FreezeEnergyV2 balance");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import java.util.Arrays;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import org.tron.common.utils.Commons;
import org.tron.common.utils.DecodeUtil;
import org.tron.common.utils.StringUtil;
import org.tron.core.capsule.AccountCapsule;
Expand Down Expand Up @@ -121,7 +120,7 @@ public boolean execute(Object object) throws ContractExeException {
if (dynamicStore.supportBlackHoleOptimization()) {
dynamicStore.burnTrx(fee);
} else {
Commons.adjustBalance(accountStore, accountStore.getBlackhole(), fee);
adjustBalance(accountStore, accountStore.getBlackhole(), fee);
}
ret.setExchangeId(id);
ret.setStatus(fee, code.SUCESS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,14 @@ public boolean execute(Object object) throws ContractExeException {

if (Arrays.equals(tokenID, firstTokenID)) {
anotherTokenID = secondTokenID;
anotherTokenQuant = Math
.floorDiv(Math.multiplyExact(secondTokenBalance, tokenQuant), firstTokenBalance);
anotherTokenQuant = floorDiv(multiplyExact(
secondTokenBalance, tokenQuant), firstTokenBalance);
exchangeCapsule.setBalance(firstTokenBalance + tokenQuant,
secondTokenBalance + anotherTokenQuant);
} else {
anotherTokenID = firstTokenID;
anotherTokenQuant = Math
.floorDiv(Math.multiplyExact(firstTokenBalance, tokenQuant), secondTokenBalance);
anotherTokenQuant = floorDiv(multiplyExact(
firstTokenBalance, tokenQuant), secondTokenBalance);
exchangeCapsule.setBalance(firstTokenBalance + anotherTokenQuant,
secondTokenBalance + tokenQuant);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,12 @@ public boolean execute(Object object) throws ContractExeException {
BigInteger bigTokenQuant = new BigInteger(String.valueOf(tokenQuant));
if (Arrays.equals(tokenID, firstTokenID)) {
anotherTokenID = secondTokenID;
// anotherTokenQuant = Math
// .floorDiv(Math.multiplyExact(secondTokenBalance, tokenQuant), firstTokenBalance);
anotherTokenQuant = bigSecondTokenBalance.multiply(bigTokenQuant)
.divide(bigFirstTokenBalance).longValueExact();
exchangeCapsule.setBalance(firstTokenBalance - tokenQuant,
secondTokenBalance - anotherTokenQuant);
} else {
anotherTokenID = firstTokenID;
// anotherTokenQuant = Math
// .floorDiv(Math.multiplyExact(firstTokenBalance, tokenQuant), secondTokenBalance);
anotherTokenQuant = bigFirstTokenBalance.multiply(bigTokenQuant)
.divide(bigSecondTokenBalance).longValueExact();
exchangeCapsule.setBalance(firstTokenBalance - anotherTokenQuant,
Expand Down Expand Up @@ -210,8 +206,6 @@ public boolean validate() throws ContractValidateException {
BigDecimal bigSecondTokenBalance = new BigDecimal(String.valueOf(secondTokenBalance));
BigDecimal bigTokenQuant = new BigDecimal(String.valueOf(tokenQuant));
if (Arrays.equals(tokenID, firstTokenID)) {
// anotherTokenQuant = Math
// .floorDiv(Math.multiplyExact(secondTokenBalance, tokenQuant), firstTokenBalance);
anotherTokenQuant = bigSecondTokenBalance.multiply(bigTokenQuant)
.divideToIntegralValue(bigFirstTokenBalance).longValueExact();
if (firstTokenBalance < tokenQuant || secondTokenBalance < anotherTokenQuant) {
Expand All @@ -230,8 +224,6 @@ public boolean validate() throws ContractValidateException {
}

} else {
// anotherTokenQuant = Math
// .floorDiv(Math.multiplyExact(firstTokenBalance, tokenQuant), secondTokenBalance);
anotherTokenQuant = bigFirstTokenBalance.multiply(bigTokenQuant)
.divideToIntegralValue(bigSecondTokenBalance).longValueExact();
if (secondTokenBalance < tokenQuant || firstTokenBalance < anotherTokenQuant) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import com.google.protobuf.InvalidProtocolBufferException;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import org.tron.common.utils.Commons;
import org.tron.common.utils.DecodeUtil;
import org.tron.core.capsule.AccountCapsule;
import org.tron.core.capsule.MarketOrderCapsule;
Expand Down Expand Up @@ -100,7 +99,7 @@ public boolean execute(Object object) throws ContractExeException {
if (dynamicStore.supportBlackHoleOptimization()) {
dynamicStore.burnTrx(fee);
} else {
Commons.adjustBalance(accountStore, accountStore.getBlackhole(), fee);
adjustBalance(accountStore, accountStore.getBlackhole(), fee);
}
// 1. return balance and token
MarketUtils
Expand Down
Loading