From e7e6e4e09c4d79ce61a6f03c97f332068c34e603 Mon Sep 17 00:00:00 2001 From: zz Date: Tue, 2 Jun 2026 01:48:32 +0800 Subject: [PATCH 1/4] feat(vm): optimize the check for create2 --- .../src/main/java/org/tron/core/vm/program/Program.java | 3 +++ actuator/src/main/java/org/tron/core/vm/utils/MUtil.java | 6 ++++++ common/src/main/java/org/tron/core/config/Parameter.java | 5 +++-- 3 files changed, 12 insertions(+), 2 deletions(-) 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 80d972041dc..31789547013 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 @@ -1621,6 +1621,9 @@ public void createContract2(DataWord value, DataWord memStart, DataWord memSize, stackPushZero(); return; } + if (getCallDeep() == MAX_DEPTH) { + MUtil.checkCPUTimeForCreate2(); + } if (VMConfig.allowTvmIstanbul()) { senderAddress = getContextAddress(); } else { diff --git a/actuator/src/main/java/org/tron/core/vm/utils/MUtil.java b/actuator/src/main/java/org/tron/core/vm/utils/MUtil.java index c94f28b3a2f..e3e67129dad 100644 --- a/actuator/src/main/java/org/tron/core/vm/utils/MUtil.java +++ b/actuator/src/main/java/org/tron/core/vm/utils/MUtil.java @@ -64,4 +64,10 @@ public static void checkCPUTime() { throw new OutOfTimeException("CPU timeout for 0x0a executing"); } } + + public static void checkCPUTimeForCreate2() { + if (ForkController.instance().pass(Parameter.ForkBlockVersionEnum.VERSION_4_8_1_1)) { + throw new OutOfTimeException("CPU timeout for create2 executing"); + } + } } 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 8ec27ed3eb5..9dbe062cd47 100644 --- a/common/src/main/java/org/tron/core/config/Parameter.java +++ b/common/src/main/java/org/tron/core/config/Parameter.java @@ -28,7 +28,8 @@ public enum ForkBlockVersionEnum { VERSION_4_7_7(31, 1596780000000L, 80), VERSION_4_8_0(32, 1596780000000L, 80), VERSION_4_8_0_1(33, 1596780000000L, 70), - VERSION_4_8_1(34, 1596780000000L, 80); + VERSION_4_8_1(34, 1596780000000L, 80), + VERSION_4_8_1_1(35, 1596780000000L, 70); // if add a version, modify BLOCK_VERSION simultaneously @Getter @@ -77,7 +78,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 = 34; + public static final int BLOCK_VERSION = 35; 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; From 5be262d14d2b8aafcd66865a24b651b9b7fa9a51 Mon Sep 17 00:00:00 2001 From: zz Date: Tue, 2 Jun 2026 17:29:58 +0800 Subject: [PATCH 2/4] feat(vm): optimize the check for ModExp --- .../main/java/org/tron/core/vm/PrecompiledContracts.java | 7 ++++++- actuator/src/main/java/org/tron/core/vm/utils/MUtil.java | 6 ++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java b/actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java index 654a76db33b..cc11a58717f 100644 --- a/actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java +++ b/actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java @@ -622,6 +622,8 @@ public static class ModExp extends PrecompiledContract { private static final int ARGS_OFFSET = 32 * 3; // addresses length part + private static final int UPPER_BOUND = 1024; + @Override public long getEnergyForData(byte[] data) { @@ -633,7 +635,6 @@ public long getEnergyForData(byte[] data) { int expLen = parseLen(data, 1); int modLen = parseLen(data, 2); - byte[] expHighBytes = parseBytes(data, addSafely(ARGS_OFFSET, baseLen), min(expLen, 32, VMConfig.disableJavaLangMath())); @@ -660,6 +661,10 @@ public Pair execute(byte[] data) { int expLen = parseLen(data, 1); int modLen = parseLen(data, 2); + if (baseLen == 0 && modLen == 0 && expLen > UPPER_BOUND) { + MUtil.checkCPUTimeForModExp(); + } + BigInteger base = parseArg(data, ARGS_OFFSET, baseLen); BigInteger exp = parseArg(data, addSafely(ARGS_OFFSET, baseLen), expLen); BigInteger mod = parseArg(data, addSafely(addSafely(ARGS_OFFSET, baseLen), expLen), modLen); diff --git a/actuator/src/main/java/org/tron/core/vm/utils/MUtil.java b/actuator/src/main/java/org/tron/core/vm/utils/MUtil.java index e3e67129dad..e07360e6863 100644 --- a/actuator/src/main/java/org/tron/core/vm/utils/MUtil.java +++ b/actuator/src/main/java/org/tron/core/vm/utils/MUtil.java @@ -70,4 +70,10 @@ public static void checkCPUTimeForCreate2() { throw new OutOfTimeException("CPU timeout for create2 executing"); } } + + public static void checkCPUTimeForModExp() { + if (ForkController.instance().pass(Parameter.ForkBlockVersionEnum.VERSION_4_8_1_1)) { + throw new OutOfTimeException("CPU timeout for modExp executing"); + } + } } From 460d243f13c07490c685bdd7c95f11b053f76e44 Mon Sep 17 00:00:00 2001 From: zz Date: Tue, 2 Jun 2026 19:20:49 +0800 Subject: [PATCH 3/4] test(vm): add tests for create2/modExp checks --- .../runtime/vm/Create2ModExpForkTest.java | 177 ++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 framework/src/test/java/org/tron/common/runtime/vm/Create2ModExpForkTest.java diff --git a/framework/src/test/java/org/tron/common/runtime/vm/Create2ModExpForkTest.java b/framework/src/test/java/org/tron/common/runtime/vm/Create2ModExpForkTest.java new file mode 100644 index 00000000000..bef91eaef37 --- /dev/null +++ b/framework/src/test/java/org/tron/common/runtime/vm/Create2ModExpForkTest.java @@ -0,0 +1,177 @@ +package org.tron.common.runtime.vm; + +import java.util.Arrays; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.Pair; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.tron.common.BaseTest; +import org.tron.common.parameter.CommonParameter; +import org.tron.common.runtime.InternalTransaction; +import org.tron.common.utils.ForkController; +import org.tron.core.Constant; +import org.tron.core.config.Parameter.ForkBlockVersionEnum; +import org.tron.core.config.args.Args; +import org.tron.core.exception.ContractValidateException; +import org.tron.core.store.StoreFactory; +import org.tron.core.vm.PrecompiledContracts; +import org.tron.core.vm.PrecompiledContracts.PrecompiledContract; +import org.tron.core.vm.config.ConfigLoader; +import org.tron.core.vm.config.VMConfig; +import org.tron.core.vm.program.Program; +import org.tron.core.vm.program.Program.OutOfTimeException; +import org.tron.core.vm.program.invoke.ProgramInvokeMockImpl; +import org.tron.core.vm.utils.MUtil; +import org.tron.protos.Protocol; + + +@Slf4j +public class Create2ModExpForkTest extends BaseTest { + + // mirrors the private Program.MAX_DEPTH + private static final int MAX_CALL_DEPTH = 64; + + // mirrors PrecompiledContracts.ModExp.UPPER_BOUND + private static final int MOD_EXP_UPPER_BOUND = 1024; + + // ModExp precompile address (0x05) + private static final DataWord MOD_EXP_ADDR = new DataWord( + "0000000000000000000000000000000000000000000000000000000000000005"); + + @BeforeClass + public static void init() { + Args.setParam(new String[] {"--output-directory", dbPath(), "--debug"}, Constant.TEST_CONF); + CommonParameter.getInstance().setDebug(true); + } + + @AfterClass + public static void destroy() { + ConfigLoader.disable = false; + VMConfig.initVmHardFork(false); + VMConfig.initAllowTvmCompatibleEvm(0); + Args.clearParam(); + } + + @Before + public void setUp() { + ForkController.instance().init(chainBaseManager); + deactivateFork(ForkBlockVersionEnum.VERSION_4_8_1_1); + } + + @Test + public void checkCPUTimeForCreate2_isGatedByFork() { + MUtil.checkCPUTimeForCreate2(); + + activateFork(ForkBlockVersionEnum.VERSION_4_8_1_1); + + OutOfTimeException ex = + Assert.assertThrows(OutOfTimeException.class, MUtil::checkCPUTimeForCreate2); + Assert.assertEquals("CPU timeout for create2 executing", ex.getMessage()); + } + + @Test + public void checkCPUTimeForModExp_isGatedByFork() { + MUtil.checkCPUTimeForModExp(); + + activateFork(ForkBlockVersionEnum.VERSION_4_8_1_1); + + OutOfTimeException ex = + Assert.assertThrows(OutOfTimeException.class, MUtil::checkCPUTimeForModExp); + Assert.assertEquals("CPU timeout for modExp executing", ex.getMessage()); + } + + @Test + public void modExp_degenerateInput_throwsOnlyAfterFork() { + PrecompiledContract modExp = PrecompiledContracts.getContractForAddress(MOD_EXP_ADDR); + byte[] data = buildModExpInput(MOD_EXP_UPPER_BOUND + 1); + + Pair out = modExp.execute(data); + Assert.assertTrue(out.getLeft()); + + activateFork(ForkBlockVersionEnum.VERSION_4_8_1_1); + + OutOfTimeException ex = + Assert.assertThrows(OutOfTimeException.class, () -> modExp.execute(data)); + Assert.assertEquals("CPU timeout for modExp executing", ex.getMessage()); + } + + @Test + public void modExp_atUpperBound_doesNotThrowAfterFork() { + activateFork(ForkBlockVersionEnum.VERSION_4_8_1_1); + + PrecompiledContract modExp = PrecompiledContracts.getContractForAddress(MOD_EXP_ADDR); + Pair out = modExp.execute(buildModExpInput(MOD_EXP_UPPER_BOUND)); + Assert.assertTrue(out.getLeft()); + } + + @Test + public void createContract2_atMaxDepth_legacyPath_throwsAfterFork() + throws ContractValidateException { + VMConfig.initAllowTvmCompatibleEvm(0); + activateFork(ForkBlockVersionEnum.VERSION_4_8_1_1); + + Program program = buildProgramAtMaxDepth(); + OutOfTimeException ex = Assert.assertThrows(OutOfTimeException.class, + () -> program.createContract2( + DataWord.ZERO(), DataWord.ZERO(), DataWord.ZERO(), DataWord.ZERO())); + Assert.assertEquals("CPU timeout for create2 executing", ex.getMessage()); + } + + @Test + public void createContract2_atMaxDepth_compatibleEvmOn_doesNotThrow() + throws ContractValidateException { + VMConfig.initAllowTvmCompatibleEvm(1); + activateFork(ForkBlockVersionEnum.VERSION_4_8_1_1); + + Program program = buildProgramAtMaxDepth(); + program.createContract2(DataWord.ZERO(), DataWord.ZERO(), DataWord.ZERO(), DataWord.ZERO()); + Assert.assertEquals(DataWord.ZERO(), program.getStack().pop()); + } + + // ---- helpers --------------------------------------------------------------------------------- + + private Program buildProgramAtMaxDepth() throws ContractValidateException { + StoreFactory.init(); + StoreFactory storeFactory = StoreFactory.getInstance(); + storeFactory.setChainBaseManager(chainBaseManager); + byte[] ops = new byte[] {0}; + ProgramInvokeMockImpl invoke = new ProgramInvokeMockImpl(storeFactory, ops, ops) { + @Override + public int getCallDeep() { + return MAX_CALL_DEPTH; + } + }; + Program program = new Program(ops, ops, invoke, + new InternalTransaction(Protocol.Transaction.getDefaultInstance(), + InternalTransaction.TrxType.TRX_UNKNOWN_TYPE)); + program.setRootTransactionId(new byte[32]); + return program; + } + + private byte[] buildModExpInput(int expLen) { + byte[] data = new byte[96]; + byte[] expLenWord = new DataWord(expLen).getData(); + System.arraycopy(expLenWord, 0, data, 32, 32); + return data; + } + + private void activateFork(ForkBlockVersionEnum forkVersion) { + byte[] stats = new byte[27]; + Arrays.fill(stats, (byte) 1); + chainBaseManager.getDynamicPropertiesStore().statsByVersion(forkVersion.getValue(), stats); + long maintenanceTimeInterval = + chainBaseManager.getDynamicPropertiesStore().getMaintenanceTimeInterval(); + long hardForkTime = ((forkVersion.getHardForkTime() - 1) / maintenanceTimeInterval + 1) + * maintenanceTimeInterval; + chainBaseManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(hardForkTime + 1); + } + + private void deactivateFork(ForkBlockVersionEnum forkVersion) { + chainBaseManager.getDynamicPropertiesStore() + .statsByVersion(forkVersion.getValue(), new byte[27]); + chainBaseManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(0L); + } +} From a17f9a306d8013703f8b37cab53f5ea406f98a09 Mon Sep 17 00:00:00 2001 From: zz Date: Tue, 2 Jun 2026 19:43:02 +0800 Subject: [PATCH 4/4] feat(version): update version to 4.8.1.1 --- framework/src/main/java/org/tron/program/Version.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/main/java/org/tron/program/Version.java b/framework/src/main/java/org/tron/program/Version.java index de3f91f0a5c..2a8f53b5ef2 100644 --- a/framework/src/main/java/org/tron/program/Version.java +++ b/framework/src/main/java/org/tron/program/Version.java @@ -4,7 +4,7 @@ public class Version { public static final String VERSION_NAME = "GreatVoyage-v4.8.0.1-1-g44a4bc8263"; public static final String VERSION_CODE = "18636"; - private static final String VERSION = "4.8.1"; + private static final String VERSION = "4.8.1.1"; public static String getVersion() { return VERSION;