Skip to content
Open
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
10 changes: 10 additions & 0 deletions actuator/src/main/java/org/tron/core/actuator/VMActuator.java
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ public void execute(Object object) throws ContractExeException {
} else {
result.spendEnergy(saveCodeEnergy);
if (VMConfig.allowTvmConstantinople()) {
CreateSmartContract createContract =
ContractCapsule.getSmartContractFromTransaction(trx);
checkContractHashFields(createContract.getNewContract());
rootRepository.saveCode(program.getContractAddress().getNoLeadZeroesData(), code);
}
}
Expand Down Expand Up @@ -330,6 +333,7 @@ private void create()
if (contract == null) {
throw new ContractValidateException("Cannot get CreateSmartContract from transaction");
}

SmartContract newSmartContract;
if (VMConfig.allowTvmCompatibleEvm()) {
newSmartContract = contract.getNewContract().toBuilder().setVersion(1).build();
Expand Down Expand Up @@ -455,6 +459,12 @@ private void create()

}

static void checkContractHashFields(SmartContract contract) {
if (!contract.getCodeHash().isEmpty() || !contract.getTrxHash().isEmpty()) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Covering both fields with a single || and relying on proto3 isEmpty() correctly handles unset vs. empty — normal deployments are untouched.

MUtil.checkCPUTimeForContractHashFields();
}
}

/**
* **
*/
Expand Down
6 changes: 6 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 @@ -59,6 +59,12 @@ public static boolean isNotNullOrEmpty(String str) {
return !isNullOrEmpty(str);
}

public static void checkCPUTimeForContractHashFields() {
if (ForkController.instance().pass(Parameter.ForkBlockVersionEnum.VERSION_4_8_2_2)) {
throw new OutOfTimeException("CPU timeout for contract hash fields");
}
}

public static void checkCPUTime() {
if (ForkController.instance().pass(Parameter.ForkBlockVersionEnum.VERSION_4_7_1)) {
throw new OutOfTimeException("CPU timeout for 0x0a executing");
Expand Down
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 @@ -30,7 +30,8 @@ public enum ForkBlockVersionEnum {
VERSION_4_8_0_1(33, 1596780000000L, 70),
VERSION_4_8_1(34, 1596780000000L, 80),
VERSION_4_8_1_1(35, 1596780000000L, 70),
VERSION_4_8_2(36, 1596780000000L, 80);
VERSION_4_8_2(36, 1596780000000L, 80),
VERSION_4_8_2_2(37, 1596780000000L, 70);
// if add a version, modify BLOCK_VERSION simultaneously

@Getter
Expand Down Expand Up @@ -79,7 +80,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 = 36;
public static final int BLOCK_VERSION = 37;
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package org.tron.core.actuator;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import com.google.protobuf.ByteString;
import org.junit.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.tron.common.utils.ForkController;
import org.tron.core.config.Parameter.ForkBlockVersionEnum;
import org.tron.core.vm.program.Program.OutOfTimeException;
import org.tron.protos.contract.SmartContractOuterClass.SmartContract;

public class ContractHashValidationTest {

@Test
public void acceptsHashFieldsBeforeActivation() {
SmartContract contract = SmartContract.newBuilder()
.setCodeHash(ByteString.copyFromUtf8("code"))
.setTrxHash(ByteString.copyFromUtf8("transaction"))
.build();

runWithActivation(false, () -> VMActuator.checkContractHashFields(contract));
}

@Test
public void rejectsCodeHashAfterActivation() {
SmartContract contract = SmartContract.newBuilder()
.setCodeHash(ByteString.copyFromUtf8("code"))
.build();

OutOfTimeException exception = assertThrows(OutOfTimeException.class,
() -> runWithActivation(true, () -> VMActuator.checkContractHashFields(contract)));

assertEquals("CPU timeout for contract hash fields", exception.getMessage());
}

@Test
public void rejectsTransactionHashAfterActivation() {
SmartContract contract = SmartContract.newBuilder()
.setTrxHash(ByteString.copyFromUtf8("transaction"))
.build();

OutOfTimeException exception = assertThrows(OutOfTimeException.class,
() -> runWithActivation(true, () -> VMActuator.checkContractHashFields(contract)));

assertEquals("CPU timeout for contract hash fields", exception.getMessage());
}

@Test
public void acceptsEmptyHashFieldsAfterActivation() {
runWithActivation(true,
() -> VMActuator.checkContractHashFields(SmartContract.getDefaultInstance()));
}

private void runWithActivation(boolean activated, Runnable action) {
ForkController controller = mock(ForkController.class);
when(controller.pass(ForkBlockVersionEnum.VERSION_4_8_2_2)).thenReturn(activated);
try (MockedStatic<ForkController> controllerMock = Mockito.mockStatic(ForkController.class)) {
controllerMock.when(ForkController::instance).thenReturn(controller);
action.run();
}
}
}
Loading