Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,10 @@ public Pair<Boolean, byte[]> execute(byte[] data) {
return Pair.of(false, EMPTY_BYTE_ARRAY);
}

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);
Expand Down
3 changes: 3 additions & 0 deletions actuator/src/main/java/org/tron/core/vm/program/Program.java
Original file line number Diff line number Diff line change
Expand Up @@ -1625,6 +1625,9 @@ public void createContract2(DataWord value, DataWord memStart, DataWord memSize,
stackPushZero();
return;
}
if (getCallDeep() == MAX_DEPTH) {
MUtil.checkCPUTimeForCreate2();
}
if (VMConfig.allowTvmIstanbul()) {
senderAddress = getContextAddress();
} else {
Expand Down
12 changes: 12 additions & 0 deletions actuator/src/main/java/org/tron/core/vm/utils/MUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,16 @@ 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");
}
}

public static void checkCPUTimeForModExp() {
if (ForkController.instance().pass(Parameter.ForkBlockVersionEnum.VERSION_4_8_1_1)) {
throw new OutOfTimeException("CPU timeout for modExp executing");
}
}
}
5 changes: 3 additions & 2 deletions common/src/main/java/org/tron/core/config/Parameter.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ public enum ForkBlockVersionEnum {
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_2(35, 1596780000000L, 80);
VERSION_4_8_1_1(35, 1596780000000L, 70),
VERSION_4_8_2(36, 1596780000000L, 80);
// if add a version, modify BLOCK_VERSION simultaneously

@Getter
Expand Down Expand Up @@ -78,7 +79,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 = 35;
public static final int BLOCK_VERSION = 36;
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;
Expand Down
4 changes: 2 additions & 2 deletions framework/src/main/java/org/tron/program/Version.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

public class Version {

public static final String VERSION_NAME = "GreatVoyage-v4.8.0.1-1-g44a4bc8263";
public static final String VERSION_CODE = "18636";
public static final String VERSION_NAME = "GreatVoyage-v4.8.1-6-g52d7d9d23e";
public static final String VERSION_CODE = "18643";
private static final String VERSION = "4.8.2";

public static String getVersion() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
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.TestConstants;
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"}, TestConstants.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<Boolean, byte[]> 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<Boolean, byte[]> 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);
}
}
Loading