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
28 changes: 23 additions & 5 deletions actuator/src/main/java/org/tron/core/actuator/VMActuator.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.tron.common.runtime.InternalTransaction.TrxType;
import org.tron.common.runtime.ProgramResult;
import org.tron.common.runtime.vm.DataWord;
import org.tron.common.utils.ForkController;
import org.tron.common.utils.StorageUtils;
import org.tron.common.utils.StringUtil;
import org.tron.common.utils.WalletUtil;
Expand All @@ -33,6 +34,7 @@
import org.tron.core.capsule.BlockCapsule;
import org.tron.core.capsule.ContractCapsule;
import org.tron.core.capsule.ReceiptCapsule;
import org.tron.core.config.Parameter;
import org.tron.core.db.EnergyProcessor;
import org.tron.core.db.TransactionContext;
import org.tron.core.exception.ContractExeException;
Expand Down Expand Up @@ -217,6 +219,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 +335,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 All @@ -341,11 +347,7 @@ private void create()
throw new ContractValidateException("OwnerAddress is not equals OriginAddress");
}

byte[] contractName = newSmartContract.getName().getBytes();

if (contractName.length > VMConstant.CONTRACT_NAME_LENGTH) {
throw new ContractValidateException("contractName's length cannot be greater than 32");
}
checkContractNameLength(contract.getNewContract());

long percent = contract.getNewContract().getConsumeUserResourcePercent();
if (percent < 0 || percent > VMConstant.ONE_HUNDRED) {
Expand Down Expand Up @@ -455,6 +457,22 @@ private void create()

}

static void checkContractHashFields(SmartContract contract) {
if (!contract.getCodeHash().isEmpty() || !contract.getTrxHash().isEmpty()) {
MUtil.checkCPUTimeForContractHashFields();
}
}

static void checkContractNameLength(SmartContract contract) throws ContractValidateException {
int contractNameLength =
ForkController.instance().pass(Parameter.ForkBlockVersionEnum.VERSION_4_8_2_2)
? contract.getNameBytes().size()
: contract.getName().getBytes().length;
if (contractNameLength > VMConstant.CONTRACT_NAME_LENGTH) {
throw new ContractValidateException("contractName's length cannot be greater than 32");
}
}

/**
* **
*/
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();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
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 org.junit.Test;
import org.junit.function.ThrowingRunnable;
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.exception.ContractValidateException;
import org.tron.protos.contract.SmartContractOuterClass.SmartContract;

public class ContractNameValidationTest {

@Test
public void acceptsThirtyTwoByteNameAfterActivation() throws Throwable {
SmartContract contract = contractWithName("12345678901234567890123456789012");

runWithActivation(true, () -> VMActuator.checkContractNameLength(contract));
}

@Test
public void rejectsThirtyThreeByteNameAfterActivation() {
SmartContract contract = contractWithName("123456789012345678901234567890123");

ContractValidateException exception = assertThrows(ContractValidateException.class,
() -> runWithActivation(true, () -> VMActuator.checkContractNameLength(contract)));

assertEquals("contractName's length cannot be greater than 32", exception.getMessage());
}

@Test
public void countsMultibyteNameUsingProtobufBytesAfterActivation() {
SmartContract contract = contractWithName("合合合合合合合合合合合");
assertEquals(33, contract.getNameBytes().size());

assertThrows(ContractValidateException.class,
() -> runWithActivation(true, () -> VMActuator.checkContractNameLength(contract)));
}

@Test
public void preservesNameValidationBeforeActivation() {
SmartContract contract = contractWithName("123456789012345678901234567890123");

assertThrows(ContractValidateException.class,
() -> runWithActivation(false, () -> VMActuator.checkContractNameLength(contract)));
}

private SmartContract contractWithName(String name) {
return SmartContract.newBuilder().setName(name).build();
}

private void runWithActivation(boolean activated, ThrowingRunnable action) throws Throwable {
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