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); + } + }