diff --git a/actuator/src/main/java/org/tron/core/actuator/AssetIssueActuator.java b/actuator/src/main/java/org/tron/core/actuator/AssetIssueActuator.java index 331b45f106a..618a9fb191e 100644 --- a/actuator/src/main/java/org/tron/core/actuator/AssetIssueActuator.java +++ b/actuator/src/main/java/org/tron/core/actuator/AssetIssueActuator.java @@ -24,10 +24,12 @@ import java.util.List; import java.util.Objects; import lombok.extern.slf4j.Slf4j; +import org.tron.common.math.StrictMathWrapper; import org.tron.common.utils.DecodeUtil; import org.tron.core.capsule.AccountCapsule; import org.tron.core.capsule.AssetIssueCapsule; import org.tron.core.capsule.TransactionResultCapsule; +import org.tron.core.config.Parameter.ForkBlockVersionEnum; import org.tron.core.exception.BalanceInsufficientException; import org.tron.core.exception.ContractExeException; import org.tron.core.exception.ContractValidateException; @@ -263,6 +265,16 @@ public boolean validate() throws ContractValidateException { "frozenDuration must be less than " + maxFrozenSupplyTime + " days " + "and more than " + minFrozenSupplyTime + " days"); } + // make sure FrozenSupply.expireTime not overflow + if (chainBaseManager.getForkController().pass(ForkBlockVersionEnum.VERSION_4_8_1)) { + long frozenPeriod = next.getFrozenDays() * FROZEN_PERIOD; + try { + StrictMathWrapper.addExact(assetIssueContract.getStartTime(), frozenPeriod); + } catch (ArithmeticException e) { + throw new ContractValidateException( + "Start time and frozen days would cause expire time overflow"); + } + } remainSupply -= next.getFrozenAmount(); } 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 84dc58c48d2..0583962f266 100644 --- a/common/src/main/java/org/tron/common/parameter/CommonParameter.java +++ b/common/src/main/java/org/tron/common/parameter/CommonParameter.java @@ -67,7 +67,7 @@ public class CommonParameter { public boolean debug = false; @Getter @Setter - @Parameter(names = {"--min-time-ratio"}, description = "Maximum CPU tolerance when executing " + @Parameter(names = {"--min-time-ratio"}, description = "Minimum CPU tolerance when executing " + "timeout transactions while synchronizing blocks. (default: 0.0)") public double minTimeRatio = 0.0; @Getter diff --git a/framework/src/test/java/org/tron/core/actuator/AssetIssueActuatorTest.java b/framework/src/test/java/org/tron/core/actuator/AssetIssueActuatorTest.java index 77c24c28797..7daf139dc0f 100755 --- a/framework/src/test/java/org/tron/core/actuator/AssetIssueActuatorTest.java +++ b/framework/src/test/java/org/tron/core/actuator/AssetIssueActuatorTest.java @@ -1,6 +1,7 @@ package org.tron.core.actuator; import static org.junit.Assert.fail; +import static org.tron.core.config.Parameter.ChainConstant.FROZEN_PERIOD; import com.google.protobuf.Any; import com.google.protobuf.ByteString; @@ -15,12 +16,14 @@ import org.junit.Test; import org.tron.common.BaseTest; import org.tron.common.utils.ByteArray; +import org.tron.common.utils.ForkController; import org.tron.core.Constant; import org.tron.core.Wallet; import org.tron.core.capsule.AccountCapsule; import org.tron.core.capsule.AssetIssueCapsule; import org.tron.core.capsule.TransactionResultCapsule; import org.tron.core.config.Parameter.ForkBlockVersionConsts; +import org.tron.core.config.Parameter.ForkBlockVersionEnum; import org.tron.core.config.args.Args; import org.tron.core.exception.ContractExeException; import org.tron.core.exception.ContractValidateException; @@ -1868,6 +1871,53 @@ public void SameTokenNameCloseInvalidAccount() { } + @Test + public void issueStartTimeTooBig() { + long maintenanceTimeInterval = dbManager.getDynamicPropertiesStore() + .getMaintenanceTimeInterval(); + long hardForkTime = + ((ForkBlockVersionEnum.VERSION_4_0_1.getHardForkTime() - 1) / maintenanceTimeInterval + 1) + * maintenanceTimeInterval; + dbManager.getDynamicPropertiesStore() + .saveLatestBlockHeaderTimestamp(hardForkTime + 1); + + // add more check after 4.8.1 + byte[] stats = new byte[27]; + Arrays.fill(stats, (byte) 1); + dbManager.getDynamicPropertiesStore() + .statsByVersion(ForkBlockVersionEnum.VERSION_4_8_1.getValue(), stats); + boolean flag = ForkController.instance().pass(ForkBlockVersionEnum.VERSION_4_8_1); + Assert.assertTrue(flag); + + TransactionResultCapsule ret = new TransactionResultCapsule(); + + // Start time is too big. If it's to large, the account.frozen_supply.expireTime will overflow + FrozenSupply frozenSupply = FrozenSupply.newBuilder().setFrozenDays(20).setFrozenAmount(100) + .build(); + long startTime = Long.MAX_VALUE - frozenSupply.getFrozenDays() * FROZEN_PERIOD + 1; + Any any = Any.pack( + AssetIssueContract.newBuilder() + .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS))) + .setName(ByteString.copyFromUtf8(NAME)).setTotalSupply(TOTAL_SUPPLY).setTrxNum(TRX_NUM) + .setNum(NUM) + .setStartTime(startTime) + .setEndTime(startTime + 24 * 3600 * 1000) + .setDescription(ByteString.copyFromUtf8(DESCRIPTION)) + .setUrl(ByteString.copyFromUtf8(URL)) + .setPrecision(3) + .addFrozenSupply(frozenSupply) + .build()); + AssetIssueActuator actuator = new AssetIssueActuator(); + actuator.setChainBaseManager(dbManager.getChainBaseManager()).setAny(any); + + AccountCapsule owner = dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS)); + owner.setBalance(10_000_000_000L); + dbManager.getAccountStore().put(owner.createDbKey(), owner); + + processAndCheckInvalid(actuator, ret, + "Start time and frozen days would cause expire time overflow", + "Start time and frozen days would cause expire time overflow"); + } @Test public void commonErrorCheck() { diff --git a/protocol/src/main/protos/core/Tron.proto b/protocol/src/main/protos/core/Tron.proto index f75faeeac33..2b104b86d34 100644 --- a/protocol/src/main/protos/core/Tron.proto +++ b/protocol/src/main/protos/core/Tron.proto @@ -132,7 +132,7 @@ message ChainParameters { message Account { /* frozen balance */ message Frozen { - int64 frozen_balance = 1; // the frozen trx balance + int64 frozen_balance = 1; // the frozen trx or asset balance int64 expire_time = 2; // the expire time } // account nick name diff --git a/protocol/src/main/protos/core/contract/asset_issue_contract.proto b/protocol/src/main/protos/core/contract/asset_issue_contract.proto index eb86b170219..9e8ff463d52 100644 --- a/protocol/src/main/protos/core/contract/asset_issue_contract.proto +++ b/protocol/src/main/protos/core/contract/asset_issue_contract.proto @@ -10,7 +10,7 @@ message AssetIssueContract { string id = 41; message FrozenSupply { - int64 frozen_amount = 1; + int64 frozen_amount = 1; // asset amount int64 frozen_days = 2; } bytes owner_address = 1; @@ -18,7 +18,7 @@ message AssetIssueContract { bytes abbr = 3; int64 total_supply = 4; repeated FrozenSupply frozen_supply = 5; - int32 trx_num = 6; + int32 trx_num = 6; // The fields trx_num and num define the exchange rate: num tokens can be purchased with trx_num TRX. This avoids using decimals. int32 precision = 7; int32 num = 8; int64 start_time = 9;