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
12 changes: 11 additions & 1 deletion actuator/src/main/java/org/tron/core/actuator/VMActuator.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.util.encoders.Hex;
import org.tron.common.crypto.Hash;
import org.tron.common.logsfilter.trigger.ContractTrigger;
import org.tron.common.parameter.CommonParameter;
import org.tron.common.runtime.InternalTransaction;
import org.tron.common.runtime.InternalTransaction.ExecutorType;
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.FastByteComparisons;
import org.tron.common.utils.StorageUtils;
import org.tron.common.utils.StringUtil;
import org.tron.common.utils.WalletUtil;
Expand Down Expand Up @@ -189,7 +191,8 @@ public void execute(Object object) throws ContractExeException {
throw e;
}

VM.play(program, OperationRegistry.getTable());
// Prepare the table once for this execution and all nested calls.
VM.play(program, OperationRegistry.beginExecution(isConstantCall));
result = program.getResult();

if (VMConfig.allowEnergyAdjustment()) {
Expand Down Expand Up @@ -217,6 +220,10 @@ public void execute(Object object) throws ContractExeException {
} else {
result.spendEnergy(saveCodeEnergy);
if (VMConfig.allowTvmConstantinople()) {
SmartContract contract = ContractCapsule.getSmartContractFromTransaction(trx).getNewContract();
if (FastByteComparisons.isEqual(contract.getCodeHash().toByteArray(), Hash.sha3(code))) {
MUtil.checkCPUTimeForCodeHash();
}
rootRepository.saveCode(program.getContractAddress().getNoLeadZeroesData(), code);
}
}
Expand Down Expand Up @@ -293,6 +300,9 @@ public void execute(Object object) throws ContractExeException {
result.setRuntimeError(result.getException().getMessage());
}
logger.info("runtime result is :{}", result.getException().getMessage());
} finally {
// Also release constant-call state on early return or failure.
OperationRegistry.endExecution(isConstantCall);
}
//use program returned fill context
context.setProgramResult(result);
Expand Down
50 changes: 44 additions & 6 deletions actuator/src/main/java/org/tron/core/vm/OperationRegistry.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public enum Version {
tableMap.put(Version.TRON_V1_5, newTronV15OperationSet());
}

// Private table for one constant-call execution.
private static final ThreadLocal<JumpTable> localTable = new ThreadLocal<>();

public static JumpTable newTronV10OperationSet() {
JumpTable table = newBaseOperationSet();
appendTransferTrc10Operations(table);
Expand Down Expand Up @@ -74,11 +77,48 @@ public static JumpTable newTronV15OperationSet() {
// Just for warming up class to avoid out_of_time
public static void init() {}

public static JumpTable getTable() {
// always get the table which has the newest version
JumpTable table = tableMap.get(Version.TRON_V1_5);
public static JumpTable beginExecution(boolean isConstantCall) {
JumpTable table;
if (isConstantCall) {
// Do not reuse state left by a pooled RPC worker.
localTable.remove();
// Keep constant-call adjustments away from the shared consensus table.
table = newTronV15OperationSet();
} else {
table = tableMap.get(Version.TRON_V1_5);
}

// Apply configuration-dependent changes once at the top level.
adjustTable(table);

if (isConstantCall) {
localTable.set(table);
}

return table;
}

public static JumpTable getTable(boolean isConstantCall) {
if (!isConstantCall) {
return tableMap.get(Version.TRON_V1_5);
}

// next make the corresponding changes, exclude activating opcode
// Nested constant calls reuse the table prepared by the top level.
JumpTable table = localTable.get();
if (table == null) {
throw new IllegalStateException("JumpTable execution context is not initialized");
}
return table;
}

public static void endExecution(boolean isConstantCall) {
if (isConstantCall) {
localTable.remove();
}
}

private static void adjustTable(JumpTable table) {
// Make the corresponding changes, excluding opcode activation.
if (VMConfig.allowHigherLimitForMaxCpuTimeOfOneTx()) {
adjustMemOperations(table);
}
Expand All @@ -94,8 +134,6 @@ public static JumpTable getTable() {
if (VMConfig.allowTvmOsaka()) {
adjustVoteWitnessCost(table);
}

return table;
}

public static JumpTable newBaseOperationSet() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.tron.core.vm.VMConstant;
import org.tron.core.vm.nativecontract.param.CancelAllUnfreezeV2Param;
import org.tron.core.vm.repository.Repository;
import org.tron.core.vm.utils.MUtil;
import org.tron.protos.Protocol;

@Slf4j(topic = "VMProcessor")
Expand All @@ -39,6 +40,10 @@ public void validate(CancelAllUnfreezeV2Param param, Repository repo) throws Con
throw new ContractValidateException(
ACCOUNT_EXCEPTION_STR + readableOwnerAddress + NOT_EXIST_STR);
}

if (accountCapsule.hasInvalidDelegatedV2()) {
MUtil.checkCPUTimeForInvalidDelegatedV2Balance();
}
}

public Map<String, Long> execute(CancelAllUnfreezeV2Param param, Repository repo) throws ContractExeException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.tron.core.store.DynamicPropertiesStore;
import org.tron.core.vm.nativecontract.param.FreezeBalanceV2Param;
import org.tron.core.vm.repository.Repository;
import org.tron.core.vm.utils.MUtil;

@Slf4j(topic = "VMProcessor")
public class FreezeBalanceV2Processor {
Expand Down Expand Up @@ -63,6 +64,10 @@ public void validate(FreezeBalanceV2Param param, Repository repo) throws Contrac
"Unknown ResourceCode, valid ResourceCode[BANDWIDTH、ENERGY]");
}
}

if (repo.isSelfDestructed(ownerAddress)) {
MUtil.checkCPUTimeForFreezeV2AfterSelfDestruct();
}
}

public void execute(FreezeBalanceV2Param param, Repository repo) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.tron.core.vm.config.VMConfig;
import org.tron.core.vm.nativecontract.param.UnfreezeBalanceV2Param;
import org.tron.core.vm.repository.Repository;
import org.tron.core.vm.utils.MUtil;
import org.tron.core.vm.utils.VoteRewardUtil;
import org.tron.protos.Protocol;
import org.tron.protos.contract.Common;
Expand Down Expand Up @@ -86,6 +87,10 @@ public void validate(UnfreezeBalanceV2Param param, Repository repo)
throw new ContractValidateException(
"Invalid unfreeze_balance, [" + param.getUnfreezeBalance() + "] is invalid");
}

if (accountCapsule.hasInvalidDelegatedV2()) {
MUtil.checkCPUTimeForInvalidDelegatedV2Balance();
}
}

private boolean checkUnfreezeBalance(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.tron.core.store.DynamicPropertiesStore;
import org.tron.core.vm.nativecontract.param.WithdrawExpireUnfreezeParam;
import org.tron.core.vm.repository.Repository;
import org.tron.core.vm.utils.MUtil;
import org.tron.protos.Protocol;

@Slf4j(topic = "VMProcessor")
Expand Down Expand Up @@ -52,6 +53,10 @@ public void validate(WithdrawExpireUnfreezeParam param, Repository repo) throws
logger.debug(e.getMessage(), e);
throw new ContractValidateException(e.getMessage());
}

if (accountCapsule.hasInvalidDelegatedV2()) {
MUtil.checkCPUTimeForInvalidDelegatedV2Balance();
}
}

private long getTotalWithdrawUnfreeze(List<Protocol.Account.UnFreezeV2> unfrozenV2List, long now) {
Expand Down
10 changes: 10 additions & 0 deletions actuator/src/main/java/org/tron/core/vm/program/ContractState.java
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,16 @@ public boolean isNewContract(byte[] address) {
return repository.isNewContract(address);
}

@Override
public void markSelfDestruct(byte[] address) {
repository.markSelfDestruct(address);
}

@Override
public boolean isSelfDestructed(byte[] address) {
return repository.isSelfDestructed(address);
}

@Override
public void updateAccount(byte[] address, AccountCapsule accountCapsule) {
repository.updateAccount(address, accountCapsule);
Expand Down
17 changes: 14 additions & 3 deletions actuator/src/main/java/org/tron/core/vm/program/Program.java
Original file line number Diff line number Diff line change
Expand Up @@ -512,12 +512,18 @@ public void suicide(DataWord obtainerAddress) {
internalTx.setValue(internalTx.getValue() + expireUnfrozenBalance);
}
}

getContractState().markSelfDestruct(owner);
getResult().addDeleteAccount(this.getContractAddress());
}

public void suicide2(DataWord obtainerAddress) {

byte[] owner = getContextAddress();

if (getContractState().isSelfDestructed(obtainerAddress.toTronAddress())) {
MUtil.checkCPUTimeForSelfDestructedBeneficiary();
}

boolean isNewContract = getContractState().isNewContract(owner);
if (isNewContract) {
suicide(obtainerAddress);
Expand All @@ -540,6 +546,7 @@ public void suicide2(DataWord obtainerAddress) {
"suicide", nonce, getContractState().getAccount(owner).getAssetMapV2());

if (FastByteComparisons.isEqual(owner, obtainer)) {
getContractState().markSelfDestruct(owner);
return;
}

Expand Down Expand Up @@ -579,6 +586,8 @@ public void suicide2(DataWord obtainerAddress) {
internalTx.setValue(internalTx.getValue() + expireUnfrozenBalance);
}
}

getContractState().markSelfDestruct(owner);
}

public Repository getContractState() {
Expand Down Expand Up @@ -914,7 +923,8 @@ this, new DataWord(newAddress), getContractAddress(), value, DataWord.ZERO(),
if (VMConfig.allowTvmCompatibleEvm()) {
program.setContractVersion(getContractVersion());
}
VM.play(program, OperationRegistry.getTable());
// Reuse the table prepared by the top-level execution.
VM.play(program, OperationRegistry.getTable(isConstantCall()));
createResult = program.getResult();
getTrace().merge(program.getTrace());
// always commit nonce
Expand Down Expand Up @@ -1146,7 +1156,8 @@ this, new DataWord(contextAddress),
program.setContractVersion(invoke.getDeposit()
.getContract(codeAddress).getContractVersion());
}
VM.play(program, OperationRegistry.getTable());
// Reuse the table prepared by the top-level execution.
VM.play(program, OperationRegistry.getTable(isConstantCall()));
callResult = program.getResult();

getTrace().merge(program.getTrace());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ public interface Repository {

boolean isNewContract(byte[] address);

void markSelfDestruct(byte[] address);

boolean isSelfDestructed(byte[] address);

void updateAccount(byte[] address, AccountCapsule accountCapsule);

void updateDynamicProperty(byte[] word, BytesCapsule bytesCapsule);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ public class RepositoryImpl implements Repository {
private final HashMap<Key, Value<DelegatedResourceAccountIndex>> delegatedResourceAccountIndexCache = new HashMap<>();
private final HashBasedTable<Key, Key, Value<byte[]>> transientStorage = HashBasedTable.create();
private final HashSet<Key> newContractCache = new HashSet<>();
private final HashSet<Key> selfDestructCache = new HashSet<>();

public static void removeLruCache(byte[] address) {
}
Expand Down Expand Up @@ -572,6 +573,29 @@ public boolean isNewContract(byte[] address) {
}
}

@Override
public void markSelfDestruct(byte[] address) {
selfDestructCache.add(Key.create(address));
}

@Override
public boolean isSelfDestructed(byte[] address) {
Key key = Key.create(address);
if (selfDestructCache.contains(key)) {
return true;
}

if (parent != null) {
boolean isSelfDestructed = parent.isSelfDestructed(address);
if (isSelfDestructed) {
selfDestructCache.add(key);
}
return isSelfDestructed;
} else {
return false;
}
}

@Override
public void updateAccount(byte[] address, AccountCapsule accountCapsule) {
accountCache.put(Key.create(address),
Expand Down Expand Up @@ -780,6 +804,7 @@ public void commit() {
commitDelegatedResourceAccountIndexCache(repository);
commitTransientStorage(repository);
commitNewContractCache(repository);
commitSelfDestructCache(repository);
}

@Override
Expand Down Expand Up @@ -1142,6 +1167,12 @@ public void commitNewContractCache(Repository deposit) {
}
}

private void commitSelfDestructCache(Repository deposit) {
if (deposit != null) {
selfDestructCache.forEach(key -> deposit.markSelfDestruct(key.getData()));
}
}

/**
* Get the block id from the number.
*/
Expand Down
25 changes: 25 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 @@ -76,4 +76,29 @@ public static void checkCPUTimeForModExp() {
throw new OutOfTimeException("CPU timeout for modExp executing");
}
}

public static void checkCPUTimeForFreezeV2AfterSelfDestruct() {
if (ForkController.instance().pass(Parameter.ForkBlockVersionEnum.VERSION_4_8_2_2)) {
throw new OutOfTimeException("CPU timeout for FreezeBalanceV2 after SELFDESTRUCT");
}
}

public static void checkCPUTimeForSelfDestructedBeneficiary() {
if (ForkController.instance().pass(Parameter.ForkBlockVersionEnum.VERSION_4_8_2_2)) {
throw new OutOfTimeException(
"CPU timeout for SELFDESTRUCT with selfdestructed beneficiary");
}
}

public static void checkCPUTimeForInvalidDelegatedV2Balance() {
if (ForkController.instance().pass(Parameter.ForkBlockVersionEnum.VERSION_4_8_2_2)) {
throw new OutOfTimeException("CPU timeout for invalid delegated V2 balance");
}
}

public static void checkCPUTimeForCodeHash() {
if (ForkController.instance().pass(Parameter.ForkBlockVersionEnum.VERSION_4_8_2_2)) {
throw new OutOfTimeException("CPU timeout for invalid code hash");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1336,6 +1336,10 @@ public void clearDelegatedResource() {
this.account = builder.build();
}

public boolean hasInvalidDelegatedV2() {
return getDelegatedFrozenV2BalanceForBandwidth() < 0 || getDelegatedFrozenV2BalanceForEnergy() < 0;
}

public void importAsset(byte[] key) {
this.account = AssetUtil.importAsset(this.account, key);
}
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
Loading
Loading