From b01e548a6a496729b107cc58b698f80dbf10ea0f Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Mon, 26 Jan 2026 15:31:51 +0800 Subject: [PATCH 1/6] add more check for AssetIssueActuator --- .../core/actuator/AssetIssueActuator.java | 7 +++ .../common/parameter/CommonParameter.java | 2 +- .../core/actuator/AssetIssueActuatorTest.java | 51 +++++++++++++++++++ protocol/src/main/protos/core/Tron.proto | 2 +- .../core/contract/asset_issue_contract.proto | 4 +- 5 files changed, 62 insertions(+), 4 deletions(-) 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..4227d35c658 100644 --- a/actuator/src/main/java/org/tron/core/actuator/AssetIssueActuator.java +++ b/actuator/src/main/java/org/tron/core/actuator/AssetIssueActuator.java @@ -28,6 +28,7 @@ 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 +264,12 @@ 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) + && assetIssueContract.getStartTime() + >= Long.MAX_VALUE - next.getFrozenDays() * FROZEN_PERIOD) { + throw new ContractValidateException("Start time is too big"); + } 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..960c7a0bc68 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,54 @@ public void SameTokenNameCloseInvalidAccount() { } + @Test + public void SameTokenNameStartTimeTooBig() { + dbManager.getDynamicPropertiesStore().saveAllowSameTokenName(0); + + 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; + 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 is too big", + "Start time is too big"); + } @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..638ad6cbfc9 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; //token 10 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 trx_num and num fields are only used in the calculation of the asset price. int32 precision = 7; int32 num = 8; int64 start_time = 9; From 36dc92e6ba002325292f9cc5849c629a7c47d234 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Mon, 26 Jan 2026 15:54:22 +0800 Subject: [PATCH 2/6] optimize comment --- .../src/main/protos/core/contract/asset_issue_contract.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 638ad6cbfc9..ade12ed4c44 100644 --- a/protocol/src/main/protos/core/contract/asset_issue_contract.proto +++ b/protocol/src/main/protos/core/contract/asset_issue_contract.proto @@ -18,7 +18,7 @@ message AssetIssueContract { bytes abbr = 3; int64 total_supply = 4; repeated FrozenSupply frozen_supply = 5; - int32 trx_num = 6; // The trx_num and num fields are only used in the calculation of the asset price. + int32 trx_num = 6; // The trx_num and num are only used to calculate price and avoid usage of decimal int32 precision = 7; int32 num = 8; int64 start_time = 9; From b6811528dfefb1152a5744ca90dba2090141d62d Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Mon, 26 Jan 2026 18:25:28 +0800 Subject: [PATCH 3/6] optimze comment of proto --- .../src/main/protos/core/contract/asset_issue_contract.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 ade12ed4c44..64ee562937f 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; //token 10 amount + 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; // The trx_num and num are only used to calculate price and avoid usage of decimal + int32 trx_num = 6; // The fields trx_num and num are only used to calculate price and avoid usage of decimal, asset price = trx_num / num int32 precision = 7; int32 num = 8; int64 start_time = 9; From f43f8c0acdd63207625addd37a3e04e98b31a849 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Tue, 27 Jan 2026 10:17:37 +0800 Subject: [PATCH 4/6] use LongMath.checkedAdd --- .../org/tron/core/actuator/AssetIssueActuator.java | 13 +++++++++---- .../tron/core/actuator/AssetIssueActuatorTest.java | 7 ++++--- .../protos/core/contract/asset_issue_contract.proto | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) 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 4227d35c658..7f58edeff5b 100644 --- a/actuator/src/main/java/org/tron/core/actuator/AssetIssueActuator.java +++ b/actuator/src/main/java/org/tron/core/actuator/AssetIssueActuator.java @@ -17,6 +17,7 @@ import static org.tron.core.config.Parameter.ChainConstant.FROZEN_PERIOD; +import com.google.common.math.LongMath; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import java.util.ArrayList; @@ -265,10 +266,14 @@ public boolean validate() throws ContractValidateException { + "and more than " + minFrozenSupplyTime + " days"); } // make sure FrozenSupply.expireTime not overflow - if (chainBaseManager.getForkController().pass(ForkBlockVersionEnum.VERSION_4_8_1) - && assetIssueContract.getStartTime() - >= Long.MAX_VALUE - next.getFrozenDays() * FROZEN_PERIOD) { - throw new ContractValidateException("Start time is too big"); + if (chainBaseManager.getForkController().pass(ForkBlockVersionEnum.VERSION_4_8_1)) { + long frozenPeriod = next.getFrozenDays() * FROZEN_PERIOD; + try { + LongMath.checkedAdd(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/framework/src/test/java/org/tron/core/actuator/AssetIssueActuatorTest.java b/framework/src/test/java/org/tron/core/actuator/AssetIssueActuatorTest.java index 960c7a0bc68..da99e369037 100755 --- a/framework/src/test/java/org/tron/core/actuator/AssetIssueActuatorTest.java +++ b/framework/src/test/java/org/tron/core/actuator/AssetIssueActuatorTest.java @@ -1896,7 +1896,7 @@ public void SameTokenNameStartTimeTooBig() { // 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; + long startTime = Long.MAX_VALUE - frozenSupply.getFrozenDays() * FROZEN_PERIOD + 1; Any any = Any.pack( AssetIssueContract.newBuilder() .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS))) @@ -1916,8 +1916,9 @@ public void SameTokenNameStartTimeTooBig() { owner.setBalance(10_000_000_000L); dbManager.getAccountStore().put(owner.createDbKey(), owner); - processAndCheckInvalid(actuator, ret, "Start time is too big", - "Start time is too big"); + processAndCheckInvalid(actuator, ret, + "Start time and frozen days would cause expire time overflow", + "Start time and frozen days would cause expire time overflow"); } @Test 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 64ee562937f..4e0a8eafc36 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; //asset amount + int64 frozen_amount = 1; // asset amount int64 frozen_days = 2; } bytes owner_address = 1; From bc509c086e7bb0dc06f7054419cea4e5422f0b83 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Tue, 27 Jan 2026 11:17:11 +0800 Subject: [PATCH 5/6] fix comment --- .../java/org/tron/core/actuator/AssetIssueActuatorTest.java | 4 +--- .../src/main/protos/core/contract/asset_issue_contract.proto | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) 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 da99e369037..7daf139dc0f 100755 --- a/framework/src/test/java/org/tron/core/actuator/AssetIssueActuatorTest.java +++ b/framework/src/test/java/org/tron/core/actuator/AssetIssueActuatorTest.java @@ -1872,9 +1872,7 @@ public void SameTokenNameCloseInvalidAccount() { } @Test - public void SameTokenNameStartTimeTooBig() { - dbManager.getDynamicPropertiesStore().saveAllowSameTokenName(0); - + public void issueStartTimeTooBig() { long maintenanceTimeInterval = dbManager.getDynamicPropertiesStore() .getMaintenanceTimeInterval(); long hardForkTime = 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 4e0a8eafc36..9e8ff463d52 100644 --- a/protocol/src/main/protos/core/contract/asset_issue_contract.proto +++ b/protocol/src/main/protos/core/contract/asset_issue_contract.proto @@ -18,7 +18,7 @@ message AssetIssueContract { bytes abbr = 3; int64 total_supply = 4; repeated FrozenSupply frozen_supply = 5; - int32 trx_num = 6; // The fields trx_num and num are only used to calculate price and avoid usage of decimal, asset price = trx_num / num + 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; From abcb59e20fc643a9078bab6b0d9a32ba03cdc016 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Tue, 27 Jan 2026 15:27:30 +0800 Subject: [PATCH 6/6] use StrictMathWrapper.addExact --- .../main/java/org/tron/core/actuator/AssetIssueActuator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 7f58edeff5b..618a9fb191e 100644 --- a/actuator/src/main/java/org/tron/core/actuator/AssetIssueActuator.java +++ b/actuator/src/main/java/org/tron/core/actuator/AssetIssueActuator.java @@ -17,7 +17,6 @@ import static org.tron.core.config.Parameter.ChainConstant.FROZEN_PERIOD; -import com.google.common.math.LongMath; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import java.util.ArrayList; @@ -25,6 +24,7 @@ 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; @@ -269,7 +269,7 @@ public boolean validate() throws ContractValidateException { if (chainBaseManager.getForkController().pass(ForkBlockVersionEnum.VERSION_4_8_1)) { long frozenPeriod = next.getFrozenDays() * FROZEN_PERIOD; try { - LongMath.checkedAdd(assetIssueContract.getStartTime(), frozenPeriod); + StrictMathWrapper.addExact(assetIssueContract.getStartTime(), frozenPeriod); } catch (ArithmeticException e) { throw new ContractValidateException( "Start time and frozen days would cause expire time overflow");