Skip to content

Commit a8b62a2

Browse files
authored
Merge pull request #1401 from tronprotocol/distinguish__timeout
Distinguish timeout
2 parents d169877 + 9bf3d89 commit a8b62a2

27 files changed

+515
-276
lines changed

src/main/java/org/tron/common/runtime/Runtime.java

Lines changed: 62 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
package org.tron.common.runtime;
22

3-
import static com.google.common.primitives.Longs.max;
4-
import static com.google.common.primitives.Longs.min;
3+
import static java.lang.Math.max;
4+
import static java.lang.Math.min;
55
import static org.apache.commons.lang3.ArrayUtils.isEmpty;
66
import static org.tron.common.runtime.utils.MUtil.convertToTronAddress;
77
import static org.tron.common.runtime.utils.MUtil.transfer;
88
import static org.tron.common.runtime.vm.VMUtils.saveProgramTraceFile;
99
import static org.tron.common.runtime.vm.VMUtils.zipAndEncode;
10-
import static org.tron.common.runtime.vm.program.InternalTransaction.ExecutorType.ET_CONSTANT_TYPE;
1110
import static org.tron.common.runtime.vm.program.InternalTransaction.ExecutorType.ET_NORMAL_TYPE;
1211
import static org.tron.common.runtime.vm.program.InternalTransaction.ExecutorType.ET_PRE_TYPE;
1312
import static org.tron.common.runtime.vm.program.InternalTransaction.ExecutorType.ET_UNKNOWN_TYPE;
@@ -33,7 +32,6 @@
3332
import org.tron.common.runtime.vm.program.InternalTransaction.ExecutorType;
3433
import org.tron.common.runtime.vm.program.Program;
3534
import org.tron.common.runtime.vm.program.Program.JVMStackOverFlowException;
36-
import org.tron.common.runtime.vm.program.Program.OutOfResourceException;
3735
import org.tron.common.runtime.vm.program.ProgramPrecompile;
3836
import org.tron.common.runtime.vm.program.ProgramResult;
3937
import org.tron.common.runtime.vm.program.invoke.ProgramInvoke;
@@ -45,15 +43,16 @@
4543
import org.tron.core.actuator.Actuator;
4644
import org.tron.core.actuator.ActuatorFactory;
4745
import org.tron.core.capsule.AccountCapsule;
46+
import org.tron.core.capsule.BlockCapsule;
4847
import org.tron.core.capsule.ContractCapsule;
4948
import org.tron.core.capsule.TransactionCapsule;
5049
import org.tron.core.config.Parameter.ChainConstant;
50+
import org.tron.core.config.args.Args;
5151
import org.tron.core.db.EnergyProcessor;
5252
import org.tron.core.db.StorageMarket;
5353
import org.tron.core.db.TransactionTrace;
5454
import org.tron.core.exception.ContractExeException;
5555
import org.tron.core.exception.ContractValidateException;
56-
import org.tron.core.exception.OutOfSlotTimeException;
5756
import org.tron.protos.Contract;
5857
import org.tron.protos.Contract.CreateSmartContract;
5958
import org.tron.protos.Contract.TriggerSmartContract;
@@ -63,6 +62,7 @@
6362
import org.tron.protos.Protocol.SmartContract.ABI;
6463
import org.tron.protos.Protocol.Transaction;
6564
import org.tron.protos.Protocol.Transaction.Contract.ContractType;
65+
import org.tron.protos.Protocol.Transaction.Result.contractResult;
6666

6767
@Slf4j(topic = "Runtime")
6868
public class Runtime {
@@ -71,7 +71,7 @@ public class Runtime {
7171
private SystemProperties config = SystemProperties.getInstance();
7272

7373
private Transaction trx;
74-
private Block block = null;
74+
private BlockCapsule blockCap = null;
7575
private Deposit deposit;
7676
private ProgramInvokeFactory programInvokeFactory = null;
7777
private String runtimeError;
@@ -93,18 +93,18 @@ public class Runtime {
9393

9494

9595
/**
96-
* For block's trx run
96+
* For blockCap's trx run
9797
*/
98-
public Runtime(TransactionTrace trace, Block block, Deposit deosit,
98+
public Runtime(TransactionTrace trace, BlockCapsule block, Deposit deosit,
9999
ProgramInvokeFactory programInvokeFactory) {
100100
this.trace = trace;
101101
this.trx = trace.getTrx().getInstance();
102102

103103
if (Objects.nonNull(block)) {
104-
this.block = block;
104+
this.blockCap = block;
105105
this.executorType = ET_NORMAL_TYPE;
106106
} else {
107-
this.block = Block.newBuilder().build();
107+
this.blockCap = new BlockCapsule(Block.newBuilder().build());
108108
this.executorType = ET_PRE_TYPE;
109109
}
110110
this.deposit = deosit;
@@ -127,15 +127,15 @@ public Runtime(TransactionTrace trace, Block block, Deposit deosit,
127127

128128

129129
/**
130-
* For constant trx with latest block.
130+
* For constant trx with latest blockCap.
131131
*/
132-
public Runtime(Transaction tx, Block block, DepositImpl deposit,
132+
public Runtime(Transaction tx, BlockCapsule block, DepositImpl deposit,
133133
ProgramInvokeFactory programInvokeFactory) {
134134
this.trx = tx;
135135
this.deposit = deposit;
136136
this.programInvokeFactory = programInvokeFactory;
137137
this.executorType = ET_PRE_TYPE;
138-
this.block = block;
138+
this.blockCap = block;
139139
this.energyProcessor = new EnergyProcessor(deposit.getDbManager());
140140
this.storageMarket = new StorageMarket(deposit.getDbManager());
141141
Transaction.Contract.ContractType contractType = tx.getRawData().getContract(0).getType();
@@ -166,10 +166,11 @@ public void precompiled() throws ContractValidateException, ContractExeException
166166

167167
public BigInteger getBlockCPULeftInUs() {
168168

169-
// insure block is not null
169+
// insure blockCap is not null
170170
BigInteger curBlockHaveElapsedCPUInUs =
171171
BigInteger.valueOf(
172-
1000 * (DateTime.now().getMillis() - block.getBlockHeader().getRawData()
172+
1000 * (DateTime.now().getMillis() - blockCap.getInstance().getBlockHeader()
173+
.getRawData()
173174
.getTimestamp())); // us
174175
BigInteger curBlockCPULimitInUs = BigInteger.valueOf((long)
175176
(1000 * ChainConstant.BLOCK_PRODUCED_INTERVAL * 0.5
@@ -180,28 +181,6 @@ public BigInteger getBlockCPULeftInUs() {
180181

181182
}
182183

183-
public boolean curCPULimitReachedBlockCPULimit() {
184-
185-
if (executorType == ET_NORMAL_TYPE) {
186-
BigInteger blockCPULeftInUs = getBlockCPULeftInUs();
187-
BigInteger oneTxCPULimitInUs = BigInteger
188-
.valueOf(Constant.MAX_CPU_TIME_OF_ONE_TX);
189-
190-
// TODO get from account
191-
BigInteger increasedStorageLimit = BigInteger.valueOf(10000000);
192-
193-
boolean cumulativeCPUReached =
194-
oneTxCPULimitInUs.compareTo(blockCPULeftInUs) > 0;
195-
196-
if (cumulativeCPUReached) {
197-
logger.error("cumulative CPU Reached");
198-
return true;
199-
}
200-
}
201-
202-
return false;
203-
}
204-
205184
public void execute() throws ContractValidateException, ContractExeException {
206185
switch (trxType) {
207186
case TRX_PRECOMPILED_TYPE:
@@ -285,6 +264,32 @@ private long getEnergyLimit(AccountCapsule creator, AccountCapsule caller,
285264
}
286265
}
287266

267+
private double getThisTxCPULimitInUsRatio() {
268+
269+
double thisTxCPULimitInUsRatio;
270+
271+
if (ET_NORMAL_TYPE == executorType) {
272+
// self witness 2
273+
if (this.blockCap != null && blockCap.generatedByMyself &&
274+
this.blockCap.getInstance().getBlockHeader().getWitnessSignature().isEmpty()) {
275+
thisTxCPULimitInUsRatio = 1.0;
276+
} else
277+
// self witness 3, other witness 3, fullnode 2
278+
{
279+
if (trx.getRet(0).getContractRet() == contractResult.OUT_OF_TIME) {
280+
thisTxCPULimitInUsRatio = Args.getInstance().getMinTimeRatio();
281+
} else {
282+
thisTxCPULimitInUsRatio = Args.getInstance().getMaxTimeRatio();
283+
}
284+
}
285+
} else {
286+
// self witness 1, other witness 1, fullnode 1
287+
thisTxCPULimitInUsRatio = 1.0;
288+
}
289+
290+
return thisTxCPULimitInUsRatio;
291+
}
292+
288293
/*
289294
**/
290295
private void create()
@@ -328,12 +333,10 @@ private void create()
328333
// thisTxENERGYLimitInUs = Constant.ENERGY_LIMIT_IN_ONE_TX_OF_SMART_CONTRACT;
329334
// }
330335

331-
long thisTxCPULimitInUs;
332-
if (ET_NORMAL_TYPE == executorType) {
333-
thisTxCPULimitInUs = Constant.MAX_CPU_TIME_OF_ONE_TX_WHEN_VERIFY_BLOCK;
334-
} else {
335-
thisTxCPULimitInUs = Constant.MAX_CPU_TIME_OF_ONE_TX;
336-
}
336+
337+
338+
long thisTxCPULimitInUs =
339+
(long) (Constant.MAX_CPU_TIME_OF_ONE_TX * getThisTxCPULimitInUsRatio());
337340
long vmStartInUs = System.nanoTime() / 1000;
338341
long vmShouldEndInUs = vmStartInUs + thisTxCPULimitInUs;
339342

@@ -344,9 +347,9 @@ private void create()
344347

345348
ProgramInvoke programInvoke = programInvokeFactory
346349
.createProgramInvoke(TRX_CONTRACT_CREATION_TYPE, executorType, trx,
347-
block, deposit, vmStartInUs, vmShouldEndInUs, energyLimit);
350+
blockCap.getInstance(), deposit, vmStartInUs, vmShouldEndInUs, energyLimit);
348351
this.vm = new VM(config);
349-
this.program = new Program(ops, programInvoke, internalTransaction, config);
352+
this.program = new Program(ops, programInvoke, internalTransaction, config, this.blockCap);
350353
Program.setRootTransactionId(new TransactionCapsule(trx).getTransactionId().getBytes());
351354
Program.resetNonce();
352355
Program.setRootCallConstant(isCallConstant());
@@ -400,15 +403,11 @@ private void call()
400403
this.deposit.getContract(contractAddress).getInstance()
401404
.getOriginAddress().toByteArray());
402405

403-
long thisTxENERGYLimitInUs;
404-
if (ET_NORMAL_TYPE == executorType) {
405-
thisTxENERGYLimitInUs = Constant.MAX_CPU_TIME_OF_ONE_TX_WHEN_VERIFY_BLOCK;
406-
} else {
407-
thisTxENERGYLimitInUs = Constant.MAX_CPU_TIME_OF_ONE_TX;
408-
}
406+
long thisTxCPULimitInUs =
407+
(long) (Constant.MAX_CPU_TIME_OF_ONE_TX * getThisTxCPULimitInUsRatio());
409408

410409
long vmStartInUs = System.nanoTime() / 1000;
411-
long vmShouldEndInUs = vmStartInUs + thisTxENERGYLimitInUs;
410+
long vmShouldEndInUs = vmStartInUs + thisTxCPULimitInUs;
412411

413412
long feeLimit = trx.getRawData().getFeeLimit();
414413
long energyLimit;
@@ -425,10 +424,11 @@ private void call()
425424

426425
ProgramInvoke programInvoke = programInvokeFactory
427426
.createProgramInvoke(TRX_CONTRACT_CALL_TYPE, executorType, trx,
428-
block, deposit, vmStartInUs, vmShouldEndInUs, energyLimit);
427+
blockCap.getInstance(), deposit, vmStartInUs, vmShouldEndInUs, energyLimit);
429428
this.vm = new VM(config);
430429
InternalTransaction internalTransaction = new InternalTransaction(trx);
431-
this.program = new Program(null, code, programInvoke, internalTransaction, config);
430+
this.program = new Program(null, code, programInvoke, internalTransaction, config,
431+
this.blockCap);
432432
Program.setRootTransactionId(new TransactionCapsule(trx).getTransactionId().getBytes());
433433
Program.resetNonce();
434434
Program.setRootCallConstant(isCallConstant());
@@ -443,8 +443,7 @@ private void call()
443443

444444
}
445445

446-
public void go() throws OutOfSlotTimeException {
447-
446+
public void go() {
448447
try {
449448
if (vm != null) {
450449
vm.play(program);
@@ -478,15 +477,13 @@ public void go() throws OutOfSlotTimeException {
478477
} else {
479478
deposit.commit();
480479
}
481-
} catch (OutOfResourceException e) {
482-
logger.error("runtime error is :{}", e.getMessage());
483-
throw new OutOfSlotTimeException(e.getMessage());
484-
} catch (JVMStackOverFlowException e){
480+
} catch (JVMStackOverFlowException e) {
485481
result.setException(e);
486482
runtimeError = result.getException().getMessage();
487483
logger.error("runtime error is :{}", result.getException().getMessage());
488-
} catch(Throwable e) {
484+
} catch (Throwable e) {
489485
if (Objects.isNull(result.getException())) {
486+
logger.error(e.getMessage(), e);
490487
result.setException(new RuntimeException("Unknown Throwable"));
491488
}
492489
if (StringUtils.isEmpty(runtimeError)) {
@@ -506,7 +503,8 @@ private long getEnergyFee(long callerEnergyUsage, long callerEnergyFrozen,
506503
.divide(BigInteger.valueOf(callerEnergyTotal)).longValue();
507504
}
508505

509-
public boolean isCallConstant() {
506+
public boolean isCallConstant() throws ContractValidateException {
507+
510508
TriggerSmartContract triggerContractFromTransaction = ContractCapsule
511509
.getTriggerContractFromTransaction(trx);
512510
if (TRX_CONTRACT_CALL_TYPE.equals(trxType)) {
@@ -520,7 +518,8 @@ public boolean isCallConstant() {
520518
return false;
521519
}
522520

523-
private boolean isCallConstant(byte[] address) {
521+
private boolean isCallConstant(byte[] address) throws ContractValidateException {
522+
524523
if (TRX_CONTRACT_CALL_TYPE.equals(trxType)) {
525524
ABI abi = deposit.getContract(address).getInstance().getAbi();
526525
if (Wallet.isConstant(abi, ContractCapsule.getTriggerContractFromTransaction(trx))) {

src/main/java/org/tron/common/runtime/vm/program/Program.java

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ public class Program {
8989
//Max size for stack checks
9090
private static final int MAX_STACKSIZE = 1024;
9191

92+
private BlockCapsule blockCap;
93+
9294
public static byte[] getRootTransactionId() {
9395
return rootTransactionId.clone();
9496
}
@@ -154,20 +156,20 @@ public Program(byte[] ops, ProgramInvoke programInvoke) {
154156
}
155157

156158
public Program(byte[] ops, ProgramInvoke programInvoke, InternalTransaction transaction) {
157-
this(ops, programInvoke, transaction, SystemProperties.getInstance());
159+
this(ops, programInvoke, transaction, SystemProperties.getInstance(), null);
158160
}
159161

160162
public Program(byte[] ops, ProgramInvoke programInvoke, InternalTransaction transaction,
161-
SystemProperties config) {
162-
this(null, ops, programInvoke, transaction, config);
163+
SystemProperties config, BlockCapsule blockCap) {
164+
this(null, ops, programInvoke, transaction, config, blockCap);
163165
}
164166

165167
public Program(byte[] codeHash, byte[] ops, ProgramInvoke programInvoke,
166-
InternalTransaction transaction, SystemProperties config) {
168+
InternalTransaction transaction, SystemProperties config, BlockCapsule blockCap) {
167169
this.config = config;
168170
this.invoke = programInvoke;
169171
this.transaction = transaction;
170-
172+
this.blockCap = blockCap;
171173
//this.codeHash = codeHash;
172174
this.ops = nullToEmpty(ops);
173175

@@ -529,7 +531,7 @@ this, new DataWord(newAddress), getOwnerAddress(), value,
529531
.toHexString(newAddress)));
530532
} else if (isNotEmpty(programCode)) {
531533
VM vm = new VM(config);
532-
Program program = new Program(programCode, programInvoke, internalTx, config);
534+
Program program = new Program(programCode, programInvoke, internalTx, config, this.blockCap);
533535
vm.play(program);
534536
result = program.getResult();
535537
getTrace().merge(program.getTrace());
@@ -682,7 +684,8 @@ this, new DataWord(contextAddress),
682684
byTestingSuite(), vmStartInUs, getVmShouldEndInUs(), msg.getEnergy().longValueSafe());
683685

684686
VM vm = new VM(config);
685-
Program program = new Program(null, programCode, programInvoke, internalTx, config);
687+
Program program = new Program(null, programCode, programInvoke, internalTx, config,
688+
this.blockCap);
686689
vm.play(program);
687690
result = program.getResult();
688691

@@ -766,12 +769,18 @@ public void spendEnergy(long energyValue, String opName) {
766769
}
767770

768771
public void checkCPUTimeLimit(String opName) {
769-
if (!Args.getInstance().isDebug()) {
770-
long vmNowInUs = System.nanoTime() / 1000;
771-
if (vmNowInUs > getVmShouldEndInUs()) {
772-
throw Exception.notEnoughTime(opName);
773-
}
772+
// if (this.blockCap != null && this.blockCap.generatedByMyself &&
773+
// !this.blockCap.getInstance().getBlockHeader().getWitnessSignature().isEmpty()) {
774+
// return;
775+
// }
776+
if (Args.getInstance().isDebug()) {
777+
return;
778+
}
779+
long vmNowInUs = System.nanoTime() / 1000;
780+
if (vmNowInUs > getVmShouldEndInUs()) {
781+
throw Exception.notEnoughTime(opName);
774782
}
783+
775784
}
776785

777786
public void spendAllEnergy() {

src/main/java/org/tron/core/Constant.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,7 @@ public class Constant {
4848

4949
// config for smart contract
5050
public static final long MEM_LIMIT_IN_ONE_TX_OF_SMART_CONTRACT = 32 * 1024 * 1024L; // 32MB
51-
public static final long MAX_CPU_TIME_OF_ONE_TX_WHEN_VERIFY_BLOCK = 500000; // 500 ms = 500000 us
52-
public static final long MAX_CPU_TIME_OF_ONE_TX = 100000; // 100 ms = 100000 us
51+
public static final long MAX_CPU_TIME_OF_ONE_TX = 50000; // 50 ms = 50000 us
5352
public static final long STORAGE_LIMIT_IN_ONE_TX_OF_SMART_CONTRACT = 32 * 1024 * 1024L; // 32MB
5453
public static final long SUN_PER_ENERGY = 100; // 1 us = 100 DROP = 100 * 10^-6 TRX
5554
public static final long MAX_ENERGY_IN_TX = 3000000; // ref: 1 us = 1 energy

0 commit comments

Comments
 (0)