diff --git a/actuator/src/main/java/org/tron/core/actuator/ExchangeTransactionActuator.java b/actuator/src/main/java/org/tron/core/actuator/ExchangeTransactionActuator.java
index 612f673832e..6f50d61c235 100755
--- a/actuator/src/main/java/org/tron/core/actuator/ExchangeTransactionActuator.java
+++ b/actuator/src/main/java/org/tron/core/actuator/ExchangeTransactionActuator.java
@@ -66,7 +66,8 @@ public boolean execute(Object object) throws ContractExeException {
long tokenQuant = exchangeTransactionContract.getQuant();
byte[] anotherTokenID;
- long anotherTokenQuant = exchangeCapsule.transaction(tokenID, tokenQuant);
+ long anotherTokenQuant = exchangeCapsule.transaction(tokenID, tokenQuant,
+ dynamicStore.allowStrictMath());
if (Arrays.equals(tokenID, firstTokenID)) {
anotherTokenID = secondTokenID;
@@ -205,7 +206,8 @@ public boolean validate() throws ContractValidateException {
}
}
- long anotherTokenQuant = exchangeCapsule.transaction(tokenID, tokenQuant);
+ long anotherTokenQuant = exchangeCapsule.transaction(tokenID, tokenQuant,
+ dynamicStore.allowStrictMath());
if (anotherTokenQuant < tokenExpected) {
throw new ContractValidateException("token required must greater than expected");
}
diff --git a/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java b/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java
index 8f3501442f0..fb4d6f76228 100644
--- a/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java
+++ b/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java
@@ -779,6 +779,21 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore,
}
break;
}
+ case ALLOW_STRICT_MATH: {
+ if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_7_7)) {
+ throw new ContractValidateException(
+ "Bad chain parameter id [ALLOW_STRICT_MATH]");
+ }
+ if (dynamicPropertiesStore.allowStrictMath()) {
+ throw new ContractValidateException(
+ "[ALLOW_STRICT_MATH] has been valid, no need to propose again");
+ }
+ if (value != 1) {
+ throw new ContractValidateException(
+ "This value[ALLOW_STRICT_MATH] is only allowed to be 1");
+ }
+ break;
+ }
default:
break;
}
@@ -857,7 +872,8 @@ public enum ProposalType { // current value, value range
MAX_DELEGATE_LOCK_PERIOD(78), // (86400, 10512000]
ALLOW_OLD_REWARD_OPT(79), // 0, 1
ALLOW_ENERGY_ADJUSTMENT(81), // 0, 1
- MAX_CREATE_ACCOUNT_TX_SIZE(82); // [500, 10000]
+ MAX_CREATE_ACCOUNT_TX_SIZE(82), // [500, 10000]
+ ALLOW_STRICT_MATH(87); // 0, 1
private long code;
diff --git a/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java b/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java
index 63c3ff791d6..79a536f4cbf 100644
--- a/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java
+++ b/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java
@@ -40,6 +40,7 @@ public static void load(StoreFactory storeFactory) {
VMConfig.initDynamicEnergyMaxFactor(ds.getDynamicEnergyMaxFactor());
VMConfig.initAllowTvmShangHai(ds.getAllowTvmShangHai());
VMConfig.initAllowEnergyAdjustment(ds.getAllowEnergyAdjustment());
+ VMConfig.initAllowStrictMath(ds.getAllowStrictMath());
}
}
}
diff --git a/actuator/src/main/java/org/tron/core/vm/config/VMConfig.java b/actuator/src/main/java/org/tron/core/vm/config/VMConfig.java
index 3eb1f8fd4b8..90a2c6335f6 100644
--- a/actuator/src/main/java/org/tron/core/vm/config/VMConfig.java
+++ b/actuator/src/main/java/org/tron/core/vm/config/VMConfig.java
@@ -51,6 +51,8 @@ public class VMConfig {
private static boolean ALLOW_ENERGY_ADJUSTMENT = false;
+ private static boolean ALLOW_STRICT_MATH = false;
+
private VMConfig() {
}
@@ -142,6 +144,10 @@ public static void initAllowEnergyAdjustment(long allow) {
ALLOW_ENERGY_ADJUSTMENT = allow == 1;
}
+ public static void initAllowStrictMath(long allow) {
+ ALLOW_STRICT_MATH = allow == 1;
+ }
+
public static boolean getEnergyLimitHardFork() {
return CommonParameter.ENERGY_LIMIT_HARD_FORK;
}
@@ -221,4 +227,8 @@ public static boolean allowTvmShanghai() {
public static boolean allowEnergyAdjustment() {
return ALLOW_ENERGY_ADJUSTMENT;
}
+
+ public static boolean allowStrictMath() {
+ return ALLOW_STRICT_MATH;
+ }
}
diff --git a/actuator/src/main/java/org/tron/core/vm/program/Program.java b/actuator/src/main/java/org/tron/core/vm/program/Program.java
index 0b0ef5bc9ba..4273778a7d6 100644
--- a/actuator/src/main/java/org/tron/core/vm/program/Program.java
+++ b/actuator/src/main/java/org/tron/core/vm/program/Program.java
@@ -2230,7 +2230,8 @@ public long updateContextContractFactor() {
contractState.getDynamicPropertiesStore().getCurrentCycleNumber(),
VMConfig.getDynamicEnergyThreshold(),
VMConfig.getDynamicEnergyIncreaseFactor(),
- VMConfig.getDynamicEnergyMaxFactor())) {
+ VMConfig.getDynamicEnergyMaxFactor(),
+ VMConfig.allowStrictMath())) {
contractState.updateContractState(getContextAddress(), contractStateCapsule
);
}
diff --git a/chainbase/src/main/java/org/tron/common/math/Maths.java b/chainbase/src/main/java/org/tron/common/math/Maths.java
new file mode 100644
index 00000000000..a1ff6ed89a1
--- /dev/null
+++ b/chainbase/src/main/java/org/tron/common/math/Maths.java
@@ -0,0 +1,20 @@
+package org.tron.common.math;
+
+/**
+ * This class is deprecated and should not be used in new code,
+ * for cross-platform consistency, please use {@link StrictMathWrapper} instead,
+ * especially for floating-point calculations.
+ */
+@Deprecated
+public class Maths {
+
+ /**
+ * Returns the value of the first argument raised to the power of the second argument.
+ * @param a the base.
+ * @param b the exponent.
+ * @return the value {@code a}{@code b}.
+ */
+ public static double pow(double a, double b, boolean useStrictMath) {
+ return useStrictMath ? StrictMathWrapper.pow(a, b) : MathWrapper.pow(a, b);
+ }
+}
diff --git a/chainbase/src/main/java/org/tron/core/capsule/ContractStateCapsule.java b/chainbase/src/main/java/org/tron/core/capsule/ContractStateCapsule.java
index 8633534280b..8ebb86ea332 100644
--- a/chainbase/src/main/java/org/tron/core/capsule/ContractStateCapsule.java
+++ b/chainbase/src/main/java/org/tron/core/capsule/ContractStateCapsule.java
@@ -5,6 +5,7 @@
import com.google.protobuf.InvalidProtocolBufferException;
import lombok.extern.slf4j.Slf4j;
+import org.tron.common.math.Maths;
import org.tron.core.store.DynamicPropertiesStore;
import org.tron.protos.contract.SmartContractOuterClass;
import org.tron.protos.contract.SmartContractOuterClass.ContractState;
@@ -77,12 +78,13 @@ public boolean catchUpToCycle(DynamicPropertiesStore dps) {
dps.getCurrentCycleNumber(),
dps.getDynamicEnergyThreshold(),
dps.getDynamicEnergyIncreaseFactor(),
- dps.getDynamicEnergyMaxFactor()
+ dps.getDynamicEnergyMaxFactor(),
+ dps.allowStrictMath()
);
}
public boolean catchUpToCycle(
- long newCycle, long threshold, long increaseFactor, long maxFactor
+ long newCycle, long threshold, long increaseFactor, long maxFactor, boolean useStrictMath
) {
long lastCycle = getUpdateCycle();
@@ -119,9 +121,9 @@ public boolean catchUpToCycle(
}
// Calc the decrease percent (decrease factor [75% ~ 100%])
- double decreasePercent = Math.pow(
+ double decreasePercent = Maths.pow(
1 - (double) increaseFactor / DYNAMIC_ENERGY_DECREASE_DIVISION / precisionFactor,
- cycleCount
+ cycleCount, useStrictMath
);
// Decrease to this cycle
diff --git a/chainbase/src/main/java/org/tron/core/capsule/ExchangeCapsule.java b/chainbase/src/main/java/org/tron/core/capsule/ExchangeCapsule.java
index 1cf91301b43..0dec7d60820 100644
--- a/chainbase/src/main/java/org/tron/core/capsule/ExchangeCapsule.java
+++ b/chainbase/src/main/java/org/tron/core/capsule/ExchangeCapsule.java
@@ -112,9 +112,9 @@ public byte[] createDbKey() {
return calculateDbKey(getID());
}
- public long transaction(byte[] sellTokenID, long sellTokenQuant) {
+ public long transaction(byte[] sellTokenID, long sellTokenQuant, boolean useStrictMath) {
long supply = 1_000_000_000_000_000_000L;
- ExchangeProcessor processor = new ExchangeProcessor(supply);
+ ExchangeProcessor processor = new ExchangeProcessor(supply, useStrictMath);
long buyTokenQuant = 0;
long firstTokenBalance = this.exchange.getFirstTokenBalance();
diff --git a/chainbase/src/main/java/org/tron/core/capsule/ExchangeProcessor.java b/chainbase/src/main/java/org/tron/core/capsule/ExchangeProcessor.java
index e1b536b3e7a..91f5c101b58 100644
--- a/chainbase/src/main/java/org/tron/core/capsule/ExchangeProcessor.java
+++ b/chainbase/src/main/java/org/tron/core/capsule/ExchangeProcessor.java
@@ -1,14 +1,17 @@
package org.tron.core.capsule;
import lombok.extern.slf4j.Slf4j;
+import org.tron.common.math.Maths;
@Slf4j(topic = "capsule")
public class ExchangeProcessor {
private long supply;
+ private final boolean useStrictMath;
- public ExchangeProcessor(long supply) {
+ public ExchangeProcessor(long supply, boolean useStrictMath) {
this.supply = supply;
+ this.useStrictMath = useStrictMath;
}
private long exchangeToSupply(long balance, long quant) {
@@ -16,7 +19,8 @@ private long exchangeToSupply(long balance, long quant) {
long newBalance = balance + quant;
logger.debug("balance + quant: " + newBalance);
- double issuedSupply = -supply * (1.0 - Math.pow(1.0 + (double) quant / newBalance, 0.0005));
+ double issuedSupply = -supply * (1.0
+ - Maths.pow(1.0 + (double) quant / newBalance, 0.0005, this.useStrictMath));
logger.debug("issuedSupply: " + issuedSupply);
long out = (long) issuedSupply;
supply += out;
@@ -27,8 +31,8 @@ private long exchangeToSupply(long balance, long quant) {
private long exchangeFromSupply(long balance, long supplyQuant) {
supply -= supplyQuant;
- double exchangeBalance =
- balance * (Math.pow(1.0 + (double) supplyQuant / supply, 2000.0) - 1.0);
+ double exchangeBalance = balance
+ * (Maths.pow(1.0 + (double) supplyQuant / supply, 2000.0, this.useStrictMath) - 1.0);
logger.debug("exchangeBalance: " + exchangeBalance);
return (long) exchangeBalance;
diff --git a/chainbase/src/main/java/org/tron/core/db/StorageMarket.java b/chainbase/src/main/java/org/tron/core/db/StorageMarket.java
deleted file mode 100644
index 10a3b656565..00000000000
--- a/chainbase/src/main/java/org/tron/core/db/StorageMarket.java
+++ /dev/null
@@ -1,234 +0,0 @@
-package org.tron.core.db;
-
-import lombok.extern.slf4j.Slf4j;
-import org.tron.core.capsule.AccountCapsule;
-import org.tron.core.store.AccountStore;
-import org.tron.core.store.DynamicPropertiesStore;
-
-@Slf4j(topic = "DB")
-public class StorageMarket {
- private static final String LOG_MSG = "NewTotalPool: {}, newTotalReserved: {}.";
- private static final long MS_PER_YEAR = 365 * 24 * 3600 * 1000L;
- private AccountStore accountStore;
- private DynamicPropertiesStore dynamicPropertiesStore;
- private long supply = 1_000_000_000_000_000L;
-
-
- public StorageMarket(AccountStore accountStore, DynamicPropertiesStore dynamicPropertiesStore) {
- this.accountStore = accountStore;
- this.dynamicPropertiesStore = dynamicPropertiesStore;
- }
-
- private long exchangeToSupply(boolean isTRX, long quant) {
- logger.info("IsTRX: {}.", isTRX);
- long balance = isTRX ? dynamicPropertiesStore.getTotalStoragePool() :
- dynamicPropertiesStore.getTotalStorageReserved();
- logger.info("Balance: {}.", balance);
- long newBalance = balance + quant;
- logger.info("Balance + quant: {}.", balance + quant);
-
-// if (isTRX) {
-// dbManager.getDynamicPropertiesStore().saveTotalStoragePool(newBalance);
-// } else {
-// dbManager.getDynamicPropertiesStore().saveTotalStorageReserved(newBalance);
-// }
-
- double issuedSupply = -supply * (1.0 - Math.pow(1.0 + (double) quant / newBalance, 0.0005));
- logger.info("IssuedSupply: {}.", issuedSupply);
- long out = (long) issuedSupply;
- supply += out;
-
- return out;
- }
-
- private long exchangeToSupply2(boolean isTRX, long quant) {
- logger.info("IsTRX: {}.", isTRX);
- long balance = isTRX ? dynamicPropertiesStore.getTotalStoragePool() :
- dynamicPropertiesStore.getTotalStorageReserved();
- logger.info("Balance: {}.", balance);
- long newBalance = balance - quant;
- logger.info("Balance - quant: {}.", balance - quant);
-
-// if (isTRX) {
-// dbManager.getDynamicPropertiesStore().saveTotalStoragePool(newBalance);
-// } else {
-// dbManager.getDynamicPropertiesStore().saveTotalStorageReserved(newBalance);
-// }
-
- double issuedSupply = -supply * (1.0 - Math.pow(1.0 + (double) quant / newBalance, 0.0005));
- logger.info("IssuedSupply: {}.", issuedSupply);
- long out = (long) issuedSupply;
- supply += out;
-
- return out;
- }
-
- private long exchange_from_supply(boolean isTRX, long supplyQuant) {
- long balance = isTRX ? dynamicPropertiesStore.getTotalStoragePool() :
- dynamicPropertiesStore.getTotalStorageReserved();
- supply -= supplyQuant;
-
- double exchangeBalance =
- balance * (Math.pow(1.0 + (double) supplyQuant / supply, 2000.0) - 1.0);
- logger.info("ExchangeBalance: {}.", exchangeBalance);
- long out = (long) exchangeBalance;
-
- if (isTRX) {
- out = Math.round(exchangeBalance / 100000) * 100000;
- logger.info("Out: {}.", out);
- }
-
- return out;
- }
-
- public long exchange(long from, boolean isTRX) {
- long relay = exchangeToSupply(isTRX, from);
- return exchange_from_supply(!isTRX, relay);
- }
-
- public long calculateTax(long duration, long limit) {
- // todo: Support for change by the committee
- double ratePerYear = dynamicPropertiesStore.getStorageExchangeTaxRate() / 100.0;
- double millisecondPerYear = MS_PER_YEAR;
- double feeRate = duration / millisecondPerYear * ratePerYear;
- long storageTax = (long) (limit * feeRate);
- logger.info("StorageTax: {}.", storageTax);
- return storageTax;
- }
-
-
- public long tryPayTax(long duration, long limit) {
- long storageTax = calculateTax(duration, limit);
- long tax = exchange(storageTax, false);
- logger.info("Tax: {}.", tax);
-
- long newTotalTax = dynamicPropertiesStore.getTotalStorageTax() + tax;
- long newTotalPool = dynamicPropertiesStore.getTotalStoragePool() - tax;
- long newTotalReserved = dynamicPropertiesStore.getTotalStorageReserved()
- + storageTax;
- logger.info("Reserved: {}.", dynamicPropertiesStore.getTotalStorageReserved());
- boolean eq = dynamicPropertiesStore.getTotalStorageReserved()
- == 128L * 1024 * 1024 * 1024;
- logger.info("Reserved == 128GB: {}.", eq);
- logger.info("NewTotalTax: {}, newTotalPool: {}, newTotalReserved: {}.",
- newTotalTax, newTotalPool, newTotalReserved);
-
- return storageTax;
- }
-
- public long payTax(long duration, long limit) {
- long storageTax = calculateTax(duration, limit);
- long tax = exchange(storageTax, false);
- logger.info("Tax: {}.", tax);
-
- long newTotalTax = dynamicPropertiesStore.getTotalStorageTax() + tax;
- long newTotalPool = dynamicPropertiesStore.getTotalStoragePool() - tax;
- long newTotalReserved = dynamicPropertiesStore.getTotalStorageReserved()
- + storageTax;
- logger.info("Reserved: {}.", dynamicPropertiesStore.getTotalStorageReserved());
- boolean eq = dynamicPropertiesStore.getTotalStorageReserved()
- == 128L * 1024 * 1024 * 1024;
- logger.info("Reserved == 128GB: {}.", eq);
- logger.info("NewTotalTax: {}, newTotalPool: {}, newTotalReserved: {}.",
- newTotalTax, newTotalPool, newTotalReserved);
- dynamicPropertiesStore.saveTotalStorageTax(newTotalTax);
- dynamicPropertiesStore.saveTotalStoragePool(newTotalPool);
- dynamicPropertiesStore.saveTotalStorageReserved(newTotalReserved);
-
- return storageTax;
- }
-
- public long tryBuyStorageBytes(long storageBought) {
- long relay = exchangeToSupply2(false, storageBought);
- return exchange_from_supply(true, relay);
- }
-
- public long tryBuyStorage(long quant) {
- return exchange(quant, true);
- }
-
- public long trySellStorage(long bytes) {
- return exchange(bytes, false);
- }
-
- public AccountCapsule buyStorageBytes(AccountCapsule accountCapsule, long storageBought) {
- long now = dynamicPropertiesStore.getLatestBlockHeaderTimestamp();
- long currentStorageLimit = accountCapsule.getStorageLimit();
-
- long relay = exchangeToSupply2(false, storageBought);
- long quant = exchange_from_supply(true, relay);
-
- long newBalance = accountCapsule.getBalance() - quant;
- logger.info("New balance: {}.", newBalance);
-
- long newStorageLimit = currentStorageLimit + storageBought;
- logger.info("StorageBought: {}, newStorageLimit: {}.", storageBought, newStorageLimit);
-
- accountCapsule.setLatestExchangeStorageTime(now);
- accountCapsule.setStorageLimit(newStorageLimit);
- accountCapsule.setBalance(newBalance);
- accountStore.put(accountCapsule.createDbKey(), accountCapsule);
-
- long newTotalPool = dynamicPropertiesStore.getTotalStoragePool() + quant;
- long newTotalReserved = dynamicPropertiesStore.getTotalStorageReserved()
- - storageBought;
- logger.info(LOG_MSG, newTotalPool, newTotalReserved);
- dynamicPropertiesStore.saveTotalStoragePool(newTotalPool);
- dynamicPropertiesStore.saveTotalStorageReserved(newTotalReserved);
- return accountCapsule;
- }
-
-
- public void buyStorage(AccountCapsule accountCapsule, long quant) {
- long now = dynamicPropertiesStore.getLatestBlockHeaderTimestamp();
- long currentStorageLimit = accountCapsule.getStorageLimit();
-
- long newBalance = accountCapsule.getBalance() - quant;
- logger.info("New balance: {}.", newBalance);
-
- long storageBought = exchange(quant, true);
- long newStorageLimit = currentStorageLimit + storageBought;
- logger.info("StorageBought: {}, newStorageLimit: {}.", storageBought, newStorageLimit);
-
- accountCapsule.setLatestExchangeStorageTime(now);
- accountCapsule.setStorageLimit(newStorageLimit);
- accountCapsule.setBalance(newBalance);
- accountStore.put(accountCapsule.createDbKey(), accountCapsule);
-
- long newTotalPool = dynamicPropertiesStore.getTotalStoragePool() + quant;
- long newTotalReserved = dynamicPropertiesStore.getTotalStorageReserved()
- - storageBought;
- logger.info(LOG_MSG, newTotalPool, newTotalReserved);
- dynamicPropertiesStore.saveTotalStoragePool(newTotalPool);
- dynamicPropertiesStore.saveTotalStorageReserved(newTotalReserved);
-
- }
-
- public void sellStorage(AccountCapsule accountCapsule, long bytes) {
- long now = dynamicPropertiesStore.getLatestBlockHeaderTimestamp();
- long currentStorageLimit = accountCapsule.getStorageLimit();
-
- long quant = exchange(bytes, false);
- long newBalance = accountCapsule.getBalance() + quant;
-
- long newStorageLimit = currentStorageLimit - bytes;
- logger.info("Quant: {}, newStorageLimit: {}.", quant, newStorageLimit);
-
- accountCapsule.setLatestExchangeStorageTime(now);
- accountCapsule.setStorageLimit(newStorageLimit);
- accountCapsule.setBalance(newBalance);
- accountStore.put(accountCapsule.createDbKey(), accountCapsule);
-
- long newTotalPool = dynamicPropertiesStore.getTotalStoragePool() - quant;
- long newTotalReserved = dynamicPropertiesStore.getTotalStorageReserved()
- + bytes;
- logger.info(LOG_MSG, newTotalPool, newTotalReserved);
- dynamicPropertiesStore.saveTotalStoragePool(newTotalPool);
- dynamicPropertiesStore.saveTotalStorageReserved(newTotalReserved);
-
- }
-
- public long getAccountLeftStorageInByteFromBought(AccountCapsule accountCapsule) {
- return accountCapsule.getStorageLimit() - accountCapsule.getStorageUsage();
- }
-}
diff --git a/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java b/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java
index 2b50ec76af2..4af338f09bb 100644
--- a/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java
+++ b/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java
@@ -222,6 +222,7 @@ public class DynamicPropertiesStore extends TronStoreWithRevoking
private static final byte[] ALLOW_ENERGY_ADJUSTMENT = "ALLOW_ENERGY_ADJUSTMENT".getBytes();
private static final byte[] MAX_CREATE_ACCOUNT_TX_SIZE = "MAX_CREATE_ACCOUNT_TX_SIZE".getBytes();
+ private static final byte[] ALLOW_STRICT_MATH = "ALLOW_STRICT_MATH".getBytes();
@Autowired
private DynamicPropertiesStore(@Value("properties") String dbName) {
@@ -2876,6 +2877,19 @@ public long getMaxCreateAccountTxSize() {
.map(ByteArray::toLong)
.orElse(CommonParameter.getInstance().getMaxCreateAccountTxSize());
}
+ public long getAllowStrictMath() {
+ return Optional.ofNullable(getUnchecked(ALLOW_STRICT_MATH))
+ .map(BytesCapsule::getData)
+ .map(ByteArray::toLong)
+ .orElse(CommonParameter.getInstance().getAllowStrictMath());
+ }
+ public void saveAllowStrictMath(long allowStrictMath) {
+ this.put(ALLOW_STRICT_MATH, new BytesCapsule(ByteArray.fromLong(allowStrictMath)));
+ }
+
+ public boolean allowStrictMath() {
+ return getAllowStrictMath() == 1L;
+ }
private static class DynamicResourceProperties {
diff --git a/common/src/main/java/org/tron/common/math/MathWrapper.java b/common/src/main/java/org/tron/common/math/MathWrapper.java
new file mode 100644
index 00000000000..519dafb9d42
--- /dev/null
+++ b/common/src/main/java/org/tron/common/math/MathWrapper.java
@@ -0,0 +1,14 @@
+package org.tron.common.math;
+
+/**
+ * This class is deprecated and should not be used in new code,
+ * for cross-platform consistency, please use {@link StrictMathWrapper} instead,
+ * especially for floating-point calculations.
+ */
+@Deprecated
+public class MathWrapper {
+
+ public static double pow(double a, double b) {
+ return Math.pow(a, b);
+ }
+}
diff --git a/common/src/main/java/org/tron/common/math/StrictMathWrapper.java b/common/src/main/java/org/tron/common/math/StrictMathWrapper.java
new file mode 100644
index 00000000000..6285f6567c0
--- /dev/null
+++ b/common/src/main/java/org/tron/common/math/StrictMathWrapper.java
@@ -0,0 +1,8 @@
+package org.tron.common.math;
+
+public class StrictMathWrapper {
+
+ public static double pow(double a, double b) {
+ return StrictMath.pow(a, b);
+ }
+}
diff --git a/common/src/main/java/org/tron/common/parameter/CommonParameter.java b/common/src/main/java/org/tron/common/parameter/CommonParameter.java
index 62ed12d856c..1aa3befe8aa 100644
--- a/common/src/main/java/org/tron/common/parameter/CommonParameter.java
+++ b/common/src/main/java/org/tron/common/parameter/CommonParameter.java
@@ -677,6 +677,10 @@ public class CommonParameter {
@Setter
public long maxCreateAccountTxSize = 1000L;
+ @Getter
+ @Setter
+ public long allowStrictMath;
+
private static double calcMaxTimeRatio() {
//return max(2.0, min(5.0, 5 * 4.0 / max(Runtime.getRuntime().availableProcessors(), 1)));
return 5.0;
diff --git a/common/src/main/java/org/tron/core/Constant.java b/common/src/main/java/org/tron/core/Constant.java
index da3b2b1becc..96ff41b91da 100644
--- a/common/src/main/java/org/tron/core/Constant.java
+++ b/common/src/main/java/org/tron/core/Constant.java
@@ -386,4 +386,5 @@ public class Constant {
public static final String COMMITTEE_ALLOW_OLD_REWARD_OPT = "committee.allowOldRewardOpt";
public static final String COMMITTEE_ALLOW_ENERGY_ADJUSTMENT = "committee.allowEnergyAdjustment";
+ public static final String COMMITTEE_ALLOW_STRICT_MATH = "committee.allowStrictMath";
}
diff --git a/common/src/main/java/org/tron/core/config/Parameter.java b/common/src/main/java/org/tron/core/config/Parameter.java
index 027c225eb5d..247c5dd4fe2 100644
--- a/common/src/main/java/org/tron/core/config/Parameter.java
+++ b/common/src/main/java/org/tron/core/config/Parameter.java
@@ -24,7 +24,8 @@ public enum ForkBlockVersionEnum {
VERSION_4_7_1(27, 1596780000000L, 80),
VERSION_4_7_2(28, 1596780000000L, 80),
VERSION_4_7_4(29, 1596780000000L, 80),
- VERSION_4_7_5(30, 1596780000000L, 80);
+ VERSION_4_7_5(30, 1596780000000L, 80),
+ VERSION_4_7_7(31, 1596780000000L, 80);
// if add a version, modify BLOCK_VERSION simultaneously
@Getter
@@ -73,7 +74,7 @@ public class ChainConstant {
public static final int SINGLE_REPEAT = 1;
public static final int BLOCK_FILLED_SLOTS_NUMBER = 128;
public static final int MAX_FROZEN_NUMBER = 1;
- public static final int BLOCK_VERSION = 30;
+ public static final int BLOCK_VERSION = 31;
public static final long FROZEN_PERIOD = 86_400_000L;
public static final long DELEGATE_PERIOD = 3 * 86_400_000L;
public static final long TRX_PRECISION = 1000_000L;
diff --git a/framework/src/main/java/org/tron/core/Wallet.java b/framework/src/main/java/org/tron/core/Wallet.java
index 769274e8f2a..0943723f2f4 100755
--- a/framework/src/main/java/org/tron/core/Wallet.java
+++ b/framework/src/main/java/org/tron/core/Wallet.java
@@ -1343,6 +1343,11 @@ public Protocol.ChainParameters getChainParameters() {
.setValue(dbManager.getDynamicPropertiesStore().getMaxCreateAccountTxSize())
.build());
+ builder.addChainParameter(Protocol.ChainParameters.ChainParameter.newBuilder()
+ .setKey("getAllowStrictMath")
+ .setValue(dbManager.getDynamicPropertiesStore().getAllowStrictMath())
+ .build());
+
return builder.build();
}
diff --git a/framework/src/main/java/org/tron/core/config/args/Args.java b/framework/src/main/java/org/tron/core/config/args/Args.java
index 00142733f74..8853971a5f8 100644
--- a/framework/src/main/java/org/tron/core/config/args/Args.java
+++ b/framework/src/main/java/org/tron/core/config/args/Args.java
@@ -234,6 +234,7 @@ public static void clearParam() {
PARAMETER.maxUnsolidifiedBlocks = 54;
PARAMETER.allowOldRewardOpt = 0;
PARAMETER.allowEnergyAdjustment = 0;
+ PARAMETER.allowStrictMath = 0;
}
/**
@@ -1217,6 +1218,10 @@ public static void setParam(final String[] args, final String confFileName) {
config.hasPath(Constant.COMMITTEE_ALLOW_ENERGY_ADJUSTMENT) ? config
.getInt(Constant.COMMITTEE_ALLOW_ENERGY_ADJUSTMENT) : 0;
+ PARAMETER.allowStrictMath =
+ config.hasPath(Constant.COMMITTEE_ALLOW_STRICT_MATH) ? config
+ .getInt(Constant.COMMITTEE_ALLOW_STRICT_MATH) : 0;
+
logConfig();
}
diff --git a/framework/src/main/java/org/tron/core/consensus/ProposalService.java b/framework/src/main/java/org/tron/core/consensus/ProposalService.java
index d0c106a7e57..29eef1c3cb3 100644
--- a/framework/src/main/java/org/tron/core/consensus/ProposalService.java
+++ b/framework/src/main/java/org/tron/core/consensus/ProposalService.java
@@ -367,6 +367,10 @@ public static boolean process(Manager manager, ProposalCapsule proposalCapsule)
manager.getDynamicPropertiesStore().saveMaxCreateAccountTxSize(entry.getValue());
break;
}
+ case ALLOW_STRICT_MATH: {
+ manager.getDynamicPropertiesStore().saveAllowStrictMath(entry.getValue());
+ break;
+ }
default:
find = false;
break;
diff --git a/framework/src/test/java/org/tron/core/StorageMarketTest.java b/framework/src/test/java/org/tron/core/StorageMarketTest.java
deleted file mode 100644
index 8b6e90e1c67..00000000000
--- a/framework/src/test/java/org/tron/core/StorageMarketTest.java
+++ /dev/null
@@ -1,256 +0,0 @@
-package org.tron.core;
-
-import static org.tron.core.config.Parameter.ChainConstant.TRANSFER_FEE;
-
-import com.google.protobuf.Any;
-import com.google.protobuf.ByteString;
-import lombok.extern.slf4j.Slf4j;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.tron.common.BaseTest;
-import org.tron.common.utils.ByteArray;
-import org.tron.core.capsule.AccountCapsule;
-import org.tron.core.config.args.Args;
-import org.tron.core.db.StorageMarket;
-import org.tron.protos.Protocol.AccountType;
-import org.tron.protos.contract.StorageContract.BuyStorageContract;
-
-@Slf4j
-public class StorageMarketTest extends BaseTest {
-
- private static final String OWNER_ADDRESS;
- private static final long initBalance = 10_000_000_000_000_000L;
- private static StorageMarket storageMarket;
-
- static {
- Args.setParam(new String[]{"--output-directory", dbPath()}, Constant.TEST_CONF);
- OWNER_ADDRESS = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
- }
-
- /**
- * create temp Capsule test need.
- */
- @Before
- public void createAccountCapsule() {
- storageMarket = new StorageMarket(dbManager.getAccountStore(),
- dbManager.getDynamicPropertiesStore());
-
- AccountCapsule ownerCapsule =
- new AccountCapsule(
- ByteString.copyFromUtf8("owner"),
- ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)),
- AccountType.Normal,
- initBalance);
- dbManager.getAccountStore().put(ownerCapsule.getAddress().toByteArray(), ownerCapsule);
-
- dbManager.getDynamicPropertiesStore().saveTotalStorageReserved(
- 128L * 1024 * 1024 * 1024);
- dbManager.getDynamicPropertiesStore().saveTotalStoragePool(100_000_000_000000L);
- dbManager.getDynamicPropertiesStore().saveTotalStorageTax(0);
-
- dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(0);
- }
-
- private Any getContract(String ownerAddress, long quant) {
- return Any.pack(
- BuyStorageContract.newBuilder()
- .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(ownerAddress)))
- .setQuant(quant)
- .build());
- }
-
- @Test
- public void testBuyStorage() {
- long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
- long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
- Assert.assertEquals(currentPool, 100_000_000_000000L);
- Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
-
- AccountCapsule owner =
- dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
-
- long quant = 2_000_000_000_000L; // 2 million trx
- storageMarket.buyStorage(owner, quant);
-
- Assert.assertEquals(owner.getBalance(), initBalance - quant
- - TRANSFER_FEE);
- Assert.assertEquals(2694881440L, owner.getStorageLimit());
- Assert.assertEquals(currentReserved - 2694881440L,
- dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
- Assert.assertEquals(currentPool + quant,
- dbManager.getDynamicPropertiesStore().getTotalStoragePool());
-
- }
-
- @Test
- public void testBuyStorage2() {
- long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
- long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
- Assert.assertEquals(currentPool, 100_000_000_000000L);
- Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
-
- AccountCapsule owner =
- dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
-
- long quant = 1_000_000_000_000L; // 1 million trx
-
- storageMarket.buyStorage(owner, quant);
-
- Assert.assertEquals(owner.getBalance(), initBalance - quant
- - TRANSFER_FEE);
- Assert.assertEquals(1360781717L, owner.getStorageLimit());
- Assert.assertEquals(currentReserved - 1360781717L,
- dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
- Assert.assertEquals(currentPool + quant,
- dbManager.getDynamicPropertiesStore().getTotalStoragePool());
-
- storageMarket.buyStorage(owner, quant);
-
- Assert.assertEquals(owner.getBalance(), initBalance - 2 * quant
- - TRANSFER_FEE);
- Assert.assertEquals(2694881439L, owner.getStorageLimit());
- Assert.assertEquals(currentReserved - 2694881439L,
- dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
- Assert.assertEquals(currentPool + 2 * quant,
- dbManager.getDynamicPropertiesStore().getTotalStoragePool());
-
- }
-
-
- @Test
- public void testBuyStorageBytes() {
- long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
- long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
- Assert.assertEquals(currentPool, 100_000_000_000000L);
- Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
-
- AccountCapsule owner =
- dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
-
- long bytes = 2694881440L; // 2 million trx
- storageMarket.buyStorageBytes(owner, bytes);
-
- Assert.assertEquals(owner.getBalance(), initBalance - 2_000_000_000_000L
- - TRANSFER_FEE);
- Assert.assertEquals(bytes, owner.getStorageLimit());
- Assert.assertEquals(currentReserved - bytes,
- dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
- Assert.assertEquals(currentPool + 2_000_000_000_000L,
- dbManager.getDynamicPropertiesStore().getTotalStoragePool());
-
- }
-
- @Test
- public void testBuyStorageBytes2() {
- long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
- long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
- Assert.assertEquals(currentPool, 100_000_000_000000L);
- Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
-
- AccountCapsule owner =
- dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
-
- long bytes1 = 1360781717L;
-
- storageMarket.buyStorageBytes(owner, bytes1);
-
- Assert.assertEquals(owner.getBalance(), initBalance - 1_000_000_000_000L
- - TRANSFER_FEE);
- Assert.assertEquals(bytes1, owner.getStorageLimit());
- Assert.assertEquals(currentReserved - bytes1,
- dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
- Assert.assertEquals(currentPool + 1_000_000_000_000L,
- dbManager.getDynamicPropertiesStore().getTotalStoragePool());
-
- long bytes2 = 1334099723L;
- storageMarket.buyStorageBytes(owner, bytes2);
- Assert.assertEquals(owner.getBalance(), initBalance - 2 * 1_000_000_000_000L
- - TRANSFER_FEE);
- Assert.assertEquals(bytes1 + bytes2, owner.getStorageLimit());
- Assert.assertEquals(currentReserved - (bytes1 + bytes2),
- dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
- Assert.assertEquals(currentPool + 2 * 1_000_000_000_000L,
- dbManager.getDynamicPropertiesStore().getTotalStoragePool());
-
- }
-
- @Test
- public void testSellStorage() {
- long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
- long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
- Assert.assertEquals(currentPool, 100_000_000_000000L);
- Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
-
- AccountCapsule owner =
- dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
-
- long quant = 2_000_000_000_000L; // 2 million trx
- storageMarket.buyStorage(owner, quant);
-
- Assert.assertEquals(owner.getBalance(), initBalance - quant
- - TRANSFER_FEE);
- Assert.assertEquals(2694881440L, owner.getStorageLimit());
- Assert.assertEquals(currentReserved - 2694881440L,
- dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
- Assert.assertEquals(currentPool + quant,
- dbManager.getDynamicPropertiesStore().getTotalStoragePool());
-
- long bytes = 2694881440L;
- storageMarket.sellStorage(owner, bytes);
-
- Assert.assertEquals(owner.getBalance(), initBalance);
- Assert.assertEquals(0, owner.getStorageLimit());
- Assert.assertEquals(currentReserved,
- dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
- Assert.assertEquals(100_000_000_000_000L,
- dbManager.getDynamicPropertiesStore().getTotalStoragePool());
-
- }
-
- @Test
- public void testSellStorage2() {
- long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
- long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
- Assert.assertEquals(currentPool, 100_000_000_000000L);
- Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
-
- AccountCapsule owner =
- dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
-
- long quant = 2_000_000_000_000L; // 2 million trx
- storageMarket.buyStorage(owner, quant);
-
- Assert.assertEquals(owner.getBalance(), initBalance - quant
- - TRANSFER_FEE);
- Assert.assertEquals(2694881440L, owner.getStorageLimit());
- Assert.assertEquals(currentReserved - 2694881440L,
- dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
- Assert.assertEquals(currentPool + quant,
- dbManager.getDynamicPropertiesStore().getTotalStoragePool());
-
- long bytes1 = 2694881440L - 1360781717L; // 1 million trx
- long bytes2 = 1360781717L; // 1 million trx
-
- storageMarket.sellStorage(owner, bytes1);
-
- Assert.assertEquals(owner.getBalance(), initBalance - 1_000_000_000_000L);
- Assert.assertEquals(1360781717L, owner.getStorageLimit());
- Assert.assertEquals(currentReserved - 1360781717L,
- dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
- Assert.assertEquals(currentPool + 1_000_000_000_000L,
- dbManager.getDynamicPropertiesStore().getTotalStoragePool());
-
- storageMarket.sellStorage(owner, bytes2);
-
- Assert.assertEquals(owner.getBalance(), initBalance);
- Assert.assertEquals(0, owner.getStorageLimit());
- Assert.assertEquals(currentReserved,
- dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
- Assert.assertEquals(currentPool,
- dbManager.getDynamicPropertiesStore().getTotalStoragePool());
-
- }
-
-
-}
diff --git a/framework/src/test/java/org/tron/core/actuator/ExchangeTransactionActuatorTest.java b/framework/src/test/java/org/tron/core/actuator/ExchangeTransactionActuatorTest.java
index 02107427cad..bf60b1cd910 100644
--- a/framework/src/test/java/org/tron/core/actuator/ExchangeTransactionActuatorTest.java
+++ b/framework/src/test/java/org/tron/core/actuator/ExchangeTransactionActuatorTest.java
@@ -1502,6 +1502,7 @@ public void SameTokenNameOpenTokenBalanceNotEnough() {
@Test
public void SameTokenNameCloseTokenRequiredNotEnough() {
dbManager.getDynamicPropertiesStore().saveAllowSameTokenName(0);
+ final boolean useStrictMath = dbManager.getDynamicPropertiesStore().allowStrictMath();
InitExchangeBeforeSameTokenNameActive();
long exchangeId = 2;
String tokenId = "abc";
@@ -1520,7 +1521,7 @@ public void SameTokenNameCloseTokenRequiredNotEnough() {
try {
ExchangeCapsule exchangeCapsule = dbManager.getExchangeStore()
.get(ByteArray.fromLong(exchangeId));
- expected = exchangeCapsule.transaction(tokenId.getBytes(), quant);
+ expected = exchangeCapsule.transaction(tokenId.getBytes(), quant, useStrictMath);
} catch (ItemNotFoundException e) {
fail();
}
@@ -1555,6 +1556,7 @@ public void SameTokenNameCloseTokenRequiredNotEnough() {
@Test
public void SameTokenNameOpenTokenRequiredNotEnough() {
dbManager.getDynamicPropertiesStore().saveAllowSameTokenName(1);
+ final boolean useStrictMath = dbManager.getDynamicPropertiesStore().allowStrictMath();
InitExchangeSameTokenNameActive();
long exchangeId = 2;
String tokenId = "123";
@@ -1575,7 +1577,7 @@ public void SameTokenNameOpenTokenRequiredNotEnough() {
try {
ExchangeCapsule exchangeCapsuleV2 = dbManager.getExchangeV2Store()
.get(ByteArray.fromLong(exchangeId));
- expected = exchangeCapsuleV2.transaction(tokenId.getBytes(), quant);
+ expected = exchangeCapsuleV2.transaction(tokenId.getBytes(), quant, useStrictMath);
} catch (ItemNotFoundException e) {
fail();
}
diff --git a/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java b/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java
index db122f90c4f..52f8cdacc00 100644
--- a/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java
+++ b/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java
@@ -25,6 +25,7 @@
import org.tron.core.store.DynamicPropertiesStore;
import org.tron.core.utils.ProposalUtil;
import org.tron.core.utils.ProposalUtil.ProposalType;
+import org.tron.protos.Protocol;
@Slf4j(topic = "actuator")
public class ProposalUtilTest extends BaseTest {
@@ -385,6 +386,51 @@ public void validateCheck() {
e.getMessage());
}
+ try {
+ ProposalUtil.validator(dynamicPropertiesStore, forkUtils,
+ ProposalType.ALLOW_STRICT_MATH.getCode(), 2);
+ Assert.fail();
+ } catch (ContractValidateException e) {
+ Assert.assertEquals(
+ "Bad chain parameter id [ALLOW_STRICT_MATH]",
+ e.getMessage());
+ }
+ hardForkTime =
+ ((ForkBlockVersionEnum.VERSION_4_7_7.getHardForkTime() - 1) / maintenanceTimeInterval + 1)
+ * maintenanceTimeInterval;
+ forkUtils.getManager().getDynamicPropertiesStore()
+ .saveLatestBlockHeaderTimestamp(hardForkTime + 1);
+ forkUtils.getManager().getDynamicPropertiesStore()
+ .statsByVersion(ForkBlockVersionEnum.VERSION_4_7_7.getValue(), stats);
+ try {
+ ProposalUtil.validator(dynamicPropertiesStore, forkUtils,
+ ProposalType.ALLOW_STRICT_MATH.getCode(), 2);
+ Assert.fail();
+ } catch (ContractValidateException e) {
+ Assert.assertEquals(
+ "This value[ALLOW_STRICT_MATH] is only allowed to be 1",
+ e.getMessage());
+ }
+ try {
+ ProposalUtil.validator(dynamicPropertiesStore, forkUtils,
+ ProposalType.ALLOW_STRICT_MATH.getCode(), 1);
+ } catch (ContractValidateException e) {
+ Assert.fail(e.getMessage());
+ }
+ Protocol.Proposal proposal = Protocol.Proposal.newBuilder().putParameters(
+ ProposalType.ALLOW_STRICT_MATH.getCode(), 1).build();
+ ProposalCapsule proposalCapsule = new ProposalCapsule(proposal);
+ ProposalService.process(dbManager, proposalCapsule);
+ try {
+ ProposalUtil.validator(dynamicPropertiesStore, forkUtils,
+ ProposalType.ALLOW_STRICT_MATH.getCode(), 1);
+ Assert.fail();
+ } catch (ContractValidateException e) {
+ Assert.assertEquals(
+ "[ALLOW_STRICT_MATH] has been valid, no need to propose again",
+ e.getMessage());
+ }
+
testEnergyAdjustmentProposal();
forkUtils.getManager().getDynamicPropertiesStore()
diff --git a/framework/src/test/java/org/tron/core/capsule/ContractStateCapsuleTest.java b/framework/src/test/java/org/tron/core/capsule/ContractStateCapsuleTest.java
index 90f74074a9b..a0968b9b63a 100644
--- a/framework/src/test/java/org/tron/core/capsule/ContractStateCapsuleTest.java
+++ b/framework/src/test/java/org/tron/core/capsule/ContractStateCapsuleTest.java
@@ -15,12 +15,12 @@ public void testCatchUpCycle() {
.setUpdateCycle(1000L)
.build());
- Assert.assertFalse(capsule.catchUpToCycle(1000L, 2_000_000L, 2000L, 10_00L));
+ Assert.assertFalse(capsule.catchUpToCycle(1000L, 2_000_000L, 2000L, 10_00L, false));
Assert.assertEquals(1000L, capsule.getUpdateCycle());
Assert.assertEquals(1_000_000L, capsule.getEnergyUsage());
Assert.assertEquals(5000L, capsule.getEnergyFactor());
- Assert.assertTrue(capsule.catchUpToCycle(1010L, 900_000L, 1000L, 10_000L));
+ Assert.assertTrue(capsule.catchUpToCycle(1010L, 900_000L, 1000L, 10_000L, false));
Assert.assertEquals(1010L, capsule.getUpdateCycle());
Assert.assertEquals(0L, capsule.getEnergyUsage());
Assert.assertEquals(3137L, capsule.getEnergyFactor());
@@ -32,7 +32,7 @@ public void testCatchUpCycle() {
.setUpdateCycle(1000L)
.build());
- Assert.assertTrue(capsule.catchUpToCycle(1001L, 2_000_000L, 2000L, 10_000L));
+ Assert.assertTrue(capsule.catchUpToCycle(1001L, 2_000_000L, 2000L, 10_000L, false));
Assert.assertEquals(1001L, capsule.getUpdateCycle());
Assert.assertEquals(0L, capsule.getEnergyUsage());
Assert.assertEquals(4250L, capsule.getEnergyFactor());
@@ -44,7 +44,7 @@ public void testCatchUpCycle() {
.setUpdateCycle(1000L)
.build());
- Assert.assertTrue(capsule.catchUpToCycle(1001L, 1_000_000L, 2000L, 10_000L));
+ Assert.assertTrue(capsule.catchUpToCycle(1001L, 1_000_000L, 2000L, 10_000L, false));
Assert.assertEquals(1001L, capsule.getUpdateCycle());
Assert.assertEquals(0L, capsule.getEnergyUsage());
Assert.assertEquals(4250L, capsule.getEnergyFactor());
@@ -56,7 +56,7 @@ public void testCatchUpCycle() {
.setUpdateCycle(1000L)
.build());
- Assert.assertTrue(capsule.catchUpToCycle(1001L, 900_000L, 2000L, 10_000L));
+ Assert.assertTrue(capsule.catchUpToCycle(1001L, 900_000L, 2000L, 10_000L, false));
Assert.assertEquals(1001L, capsule.getUpdateCycle());
Assert.assertEquals(0L, capsule.getEnergyUsage());
Assert.assertEquals(8000L, capsule.getEnergyFactor());
@@ -68,7 +68,7 @@ public void testCatchUpCycle() {
.setUpdateCycle(1000L)
.build());
- Assert.assertTrue(capsule.catchUpToCycle(1001L, 900_000L, 5000L, 10_000L));
+ Assert.assertTrue(capsule.catchUpToCycle(1001L, 900_000L, 5000L, 10_000L, false));
Assert.assertEquals(1001L, capsule.getUpdateCycle());
Assert.assertEquals(0L, capsule.getEnergyUsage());
Assert.assertEquals(10_000L, capsule.getEnergyFactor());
@@ -80,7 +80,7 @@ public void testCatchUpCycle() {
.setUpdateCycle(1000L)
.build());
- Assert.assertTrue(capsule.catchUpToCycle(1002L, 900_000L, 5000L, 10_000L));
+ Assert.assertTrue(capsule.catchUpToCycle(1002L, 900_000L, 5000L, 10_000L, false));
Assert.assertEquals(1002L, capsule.getUpdateCycle());
Assert.assertEquals(0L, capsule.getEnergyUsage());
Assert.assertEquals(7500L, capsule.getEnergyFactor());
@@ -92,7 +92,7 @@ public void testCatchUpCycle() {
.setUpdateCycle(1000L)
.build());
- Assert.assertTrue(capsule.catchUpToCycle(1003L, 900_000L, 5000L, 10_000L));
+ Assert.assertTrue(capsule.catchUpToCycle(1003L, 900_000L, 5000L, 10_000L, false));
Assert.assertEquals(1003L, capsule.getUpdateCycle());
Assert.assertEquals(0L, capsule.getEnergyUsage());
Assert.assertEquals(5312L, capsule.getEnergyFactor());
@@ -104,7 +104,7 @@ public void testCatchUpCycle() {
.setUpdateCycle(1000L)
.build());
- Assert.assertTrue(capsule.catchUpToCycle(1004L, 900_000L, 5000L, 10_000L));
+ Assert.assertTrue(capsule.catchUpToCycle(1004L, 900_000L, 5000L, 10_000L, false));
Assert.assertEquals(1004L, capsule.getUpdateCycle());
Assert.assertEquals(0L, capsule.getEnergyUsage());
Assert.assertEquals(3398L, capsule.getEnergyFactor());
@@ -116,7 +116,7 @@ public void testCatchUpCycle() {
.setUpdateCycle(1000L)
.build());
- Assert.assertTrue(capsule.catchUpToCycle(1005L, 900_000L, 5000L, 10_000L));
+ Assert.assertTrue(capsule.catchUpToCycle(1005L, 900_000L, 5000L, 10_000L, true));
Assert.assertEquals(1005L, capsule.getUpdateCycle());
Assert.assertEquals(0L, capsule.getEnergyUsage());
Assert.assertEquals(1723L, capsule.getEnergyFactor());
@@ -128,7 +128,7 @@ public void testCatchUpCycle() {
.setUpdateCycle(1000L)
.build());
- Assert.assertTrue(capsule.catchUpToCycle(1005L, 900_000L, 5000L, 10_000L));
+ Assert.assertTrue(capsule.catchUpToCycle(1005L, 900_000L, 5000L, 10_000L, true));
Assert.assertEquals(1005L, capsule.getUpdateCycle());
Assert.assertEquals(0L, capsule.getEnergyUsage());
Assert.assertEquals(1723L, capsule.getEnergyFactor());
@@ -140,7 +140,7 @@ public void testCatchUpCycle() {
.setUpdateCycle(1000L)
.build());
- Assert.assertTrue(capsule.catchUpToCycle(1006L, 900_000L, 5000L, 10_000L));
+ Assert.assertTrue(capsule.catchUpToCycle(1006L, 900_000L, 5000L, 10_000L, true));
Assert.assertEquals(1006L, capsule.getUpdateCycle());
Assert.assertEquals(0L, capsule.getEnergyUsage());
Assert.assertEquals(258L, capsule.getEnergyFactor());
@@ -152,7 +152,7 @@ public void testCatchUpCycle() {
.setUpdateCycle(1000L)
.build());
- Assert.assertTrue(capsule.catchUpToCycle(1007L, 900_000L, 5000L, 10_000L));
+ Assert.assertTrue(capsule.catchUpToCycle(1007L, 900_000L, 5000L, 10_000L, true));
Assert.assertEquals(1007L, capsule.getUpdateCycle());
Assert.assertEquals(0L, capsule.getEnergyUsage());
Assert.assertEquals(0L, capsule.getEnergyFactor());
diff --git a/framework/src/test/java/org/tron/core/capsule/ExchangeCapsuleTest.java b/framework/src/test/java/org/tron/core/capsule/ExchangeCapsuleTest.java
index 791767a952f..5fcd259d738 100644
--- a/framework/src/test/java/org/tron/core/capsule/ExchangeCapsuleTest.java
+++ b/framework/src/test/java/org/tron/core/capsule/ExchangeCapsuleTest.java
@@ -52,8 +52,8 @@ public void testExchange() {
long sellQuant = 1_000_000L;
byte[] sellID = "abc".getBytes();
-
- long result = exchangeCapsule.transaction(sellID, sellQuant);
+ boolean useStrictMath = chainBaseManager.getDynamicPropertiesStore().allowStrictMath();
+ long result = exchangeCapsule.transaction(sellID, sellQuant, useStrictMath);
Assert.assertEquals(990_099L, result);
sellBalance += sellQuant;
Assert.assertEquals(sellBalance, exchangeCapsule.getFirstTokenBalance());
@@ -61,7 +61,7 @@ public void testExchange() {
Assert.assertEquals(buyBalance, exchangeCapsule.getSecondTokenBalance());
sellQuant = 9_000_000L;
- long result2 = exchangeCapsule.transaction(sellID, sellQuant);
+ long result2 = exchangeCapsule.transaction(sellID, sellQuant, useStrictMath);
Assert.assertEquals(9090909L, result + result2);
sellBalance += sellQuant;
Assert.assertEquals(sellBalance, exchangeCapsule.getFirstTokenBalance());
diff --git a/framework/src/test/java/org/tron/core/capsule/utils/ExchangeProcessorTest.java b/framework/src/test/java/org/tron/core/capsule/utils/ExchangeProcessorTest.java
index 3437eb0ea42..717c62b01a8 100644
--- a/framework/src/test/java/org/tron/core/capsule/utils/ExchangeProcessorTest.java
+++ b/framework/src/test/java/org/tron/core/capsule/utils/ExchangeProcessorTest.java
@@ -24,7 +24,7 @@ public class ExchangeProcessorTest extends BaseTest {
@BeforeClass
public static void init() {
long supply = 1_000_000_000_000_000_000L;
- processor = new ExchangeProcessor(supply);
+ processor = new ExchangeProcessor(supply, false);
}
@Test
@@ -135,5 +135,15 @@ public void testWithdraw() {
}
+ @Test
+ public void testStrictMath() {
+ long supply = 1_000_000_000_000_000_000L;
+ ExchangeProcessor processor = new ExchangeProcessor(supply, false);
+ long anotherTokenQuant = processor.exchange(4732214, 2202692725330L, 29218);
+ processor = new ExchangeProcessor(supply, true);
+ long result = processor.exchange(4732214, 2202692725330L, 29218);
+ Assert.assertNotEquals(anotherTokenQuant, result);
+ }
+
}