22
33import static java .lang .Math .max ;
44import static java .lang .Math .min ;
5+ import static org .apache .commons .lang3 .ArrayUtils .getLength ;
56import static org .apache .commons .lang3 .ArrayUtils .isEmpty ;
67import static org .tron .common .runtime .utils .MUtil .convertToTronAddress ;
78import static org .tron .common .runtime .utils .MUtil .transfer ;
2627import org .spongycastle .util .encoders .Hex ;
2728import org .tron .common .runtime .config .SystemProperties ;
2829import org .tron .common .runtime .vm .DataWord ;
30+ import org .tron .common .runtime .vm .EnergyCost ;
2931import org .tron .common .runtime .vm .PrecompiledContracts ;
3032import org .tron .common .runtime .vm .VM ;
3133import org .tron .common .runtime .vm .program .InternalTransaction ;
@@ -95,7 +97,7 @@ public class Runtime {
9597 /**
9698 * For blockCap's trx run
9799 */
98- public Runtime (TransactionTrace trace , BlockCapsule block , Deposit deosit ,
100+ public Runtime (TransactionTrace trace , BlockCapsule block , Deposit deposit ,
99101 ProgramInvokeFactory programInvokeFactory ) {
100102 this .trace = trace ;
101103 this .trx = trace .getTrx ().getInstance ();
@@ -107,7 +109,7 @@ public Runtime(TransactionTrace trace, BlockCapsule block, Deposit deosit,
107109 this .blockCap = new BlockCapsule (Block .newBuilder ().build ());
108110 this .executorType = ET_PRE_TYPE ;
109111 }
110- this .deposit = deosit ;
112+ this .deposit = deposit ;
111113 this .programInvokeFactory = programInvokeFactory ;
112114 this .energyProcessor = new EnergyProcessor (deposit .getDbManager ());
113115 this .storageMarket = new StorageMarket (deposit .getDbManager ());
@@ -293,8 +295,9 @@ private double getThisTxCPULimitInUsRatio() {
293295 /*
294296 **/
295297 private void create ()
296- throws ContractValidateException {
298+ throws ContractValidateException {
297299 if (!deposit .getDbManager ().getDynamicPropertiesStore ().supportVM ()) {
300+ logger .error ("vm work is off, need to be opened by the committee" );
298301 throw new ContractValidateException ("vm work is off, need to be opened by the committee" );
299302 }
300303
@@ -307,11 +310,14 @@ private void create()
307310
308311 long percent = contract .getNewContract ().getConsumeUserResourcePercent ();
309312 if (percent < 0 || percent > 100 ) {
313+ logger .error ("percent must be >= 0 and <= 100" );
310314 throw new ContractValidateException ("percent must be >= 0 and <= 100" );
311315 }
312316
313317 // insure the new contract address haven't exist
314318 if (deposit .getAccount (contractAddress ) != null ) {
319+ logger .error ("Trying to create a contract with existing contract address: " + Wallet
320+ .encode58Check (contractAddress ));
315321 throw new ContractValidateException (
316322 "Trying to create a contract with existing contract address: " + Wallet
317323 .encode58Check (contractAddress ));
@@ -342,6 +348,11 @@ private void create()
342348 long vmShouldEndInUs = vmStartInUs + thisTxCPULimitInUs ;
343349
344350 long feeLimit = trx .getRawData ().getFeeLimit ();
351+ if (feeLimit < 0 ) {
352+ logger .info ("feeLimit < 0" );
353+ throw new ContractValidateException ("feeLimit must be >= 0" );
354+ }
355+
345356 long energyLimit = getEnergyLimit (creator , feeLimit , callValue );
346357 byte [] ops = newSmartContract .getBytecode ().toByteArray ();
347358 InternalTransaction internalTransaction = new InternalTransaction (trx );
@@ -351,9 +362,9 @@ private void create()
351362 blockCap .getInstance (), deposit , vmStartInUs , vmShouldEndInUs , energyLimit );
352363 this .vm = new VM (config );
353364 this .program = new Program (ops , programInvoke , internalTransaction , config , this .blockCap );
354- Program .setRootTransactionId (new TransactionCapsule (trx ).getTransactionId ().getBytes ());
355- Program .resetNonce ();
356- Program .setRootCallConstant (isCallConstant ());
365+ this . program .setRootTransactionId (new TransactionCapsule (trx ).getTransactionId ().getBytes ());
366+ this . program .resetNonce ();
367+ this . program .setRootCallConstant (isCallConstant ());
357368 } catch (Exception e ) {
358369 logger .error (e .getMessage ());
359370 throw new ContractValidateException (e .getMessage ());
@@ -381,9 +392,10 @@ private void create()
381392 */
382393
383394 private void call ()
384- throws ContractValidateException {
395+ throws ContractValidateException {
385396
386397 if (!deposit .getDbManager ().getDynamicPropertiesStore ().supportVM ()) {
398+ logger .error ("vm work is off, need to be opened by the committee" );
387399 throw new ContractValidateException ("VM work is off, need to be opened by the committee" );
388400 }
389401
@@ -413,6 +425,10 @@ private void call()
413425 long vmShouldEndInUs = vmStartInUs + thisTxCPULimitInUs ;
414426
415427 long feeLimit = trx .getRawData ().getFeeLimit ();
428+ if (feeLimit < 0 ) {
429+ logger .info ("feeLimit < 0" );
430+ throw new ContractValidateException ("feeLimit must be >= 0" );
431+ }
416432 long energyLimit ;
417433 if (isCallConstant (contractAddress )) {
418434 energyLimit = Constant .MAX_ENERGY_IN_TX ;
@@ -427,9 +443,9 @@ private void call()
427443 InternalTransaction internalTransaction = new InternalTransaction (trx );
428444 this .program = new Program (null , code , programInvoke , internalTransaction , config ,
429445 this .blockCap );
430- Program .setRootTransactionId (new TransactionCapsule (trx ).getTransactionId ().getBytes ());
431- Program .resetNonce ();
432- Program .setRootCallConstant (isCallConstant ());
446+ this . program .setRootTransactionId (new TransactionCapsule (trx ).getTransactionId ().getBytes ());
447+ this . program .resetNonce ();
448+ this . program .setRootCallConstant (isCallConstant ());
433449 }
434450
435451 program .getResult ().setContractAddress (contractAddress );
@@ -443,6 +459,17 @@ private void call()
443459
444460 public void go () {
445461 try {
462+
463+ TransactionCapsule trxCap = new TransactionCapsule (trx );
464+ if (null != trxCap .getContractRet () && contractResult .OUT_OF_TIME
465+ .equals (trxCap .getContractRet ())) {
466+ result = program .getResult ();
467+ program .spendAllEnergy ();
468+ runtimeError = "Haven Time Out" ;
469+ result .setException (Program .Exception .notEnoughTime ("Haven Time Out" ));
470+ throw Program .Exception .notEnoughTime ("Haven Time Out" );
471+ }
472+
446473 if (vm != null ) {
447474 vm .play (program );
448475
@@ -457,6 +484,21 @@ public void go() {
457484 return ;
458485 }
459486
487+ if (TRX_CONTRACT_CREATION_TYPE == trxType && !result .isRevert ()) {
488+ byte [] code = program .getResult ().getHReturn ();
489+ long saveCodeEnergy = getLength (code ) * EnergyCost .getInstance ().getCREATE_DATA ();
490+ long afterSpend = program .getEnergyLimitLeft ().longValue () - saveCodeEnergy ;
491+ if (afterSpend < 0 ) {
492+ result .setException (
493+ Program .Exception
494+ .notEnoughSpendEnergy ("No energy to save just created contract code" ,
495+ saveCodeEnergy , program .getEnergyLimitLeft ().longValue ()));
496+ } else {
497+ result .spendEnergy (saveCodeEnergy );
498+ // have saveCode in create()
499+ }
500+ }
501+
460502 if (result .getException () != null || result .isRevert ()) {
461503 result .getDeleteAccounts ().clear ();
462504 result .getLogInfoList ().clear ();
@@ -480,6 +522,7 @@ public void go() {
480522 runtimeError = result .getException ().getMessage ();
481523 logger .error ("runtime error is :{}" , result .getException ().getMessage ());
482524 } catch (Throwable e ) {
525+ program .spendAllEnergy ();
483526 if (Objects .isNull (result .getException ())) {
484527 logger .error (e .getMessage (), e );
485528 result .setException (new RuntimeException ("Unknown Throwable" ));
@@ -506,9 +549,17 @@ public boolean isCallConstant() throws ContractValidateException {
506549 TriggerSmartContract triggerContractFromTransaction = ContractCapsule
507550 .getTriggerContractFromTransaction (trx );
508551 if (TRX_CONTRACT_CALL_TYPE .equals (trxType )) {
509- ABI abi = deposit
510- .getContract (triggerContractFromTransaction .getContractAddress ().toByteArray ())
511- .getInstance ().getAbi ();
552+
553+ ContractCapsule contract = deposit
554+ .getContract (triggerContractFromTransaction .getContractAddress ().toByteArray ());
555+ if (contract == null ) {
556+ logger .error ("contract: {} is not in contract store" , Wallet
557+ .encode58Check (triggerContractFromTransaction .getContractAddress ().toByteArray ()));
558+ throw new ContractValidateException ("contract: " + Wallet
559+ .encode58Check (triggerContractFromTransaction .getContractAddress ().toByteArray ())
560+ + " is not in contract store" );
561+ }
562+ ABI abi = contract .getInstance ().getAbi ();
512563 if (Wallet .isConstant (abi , triggerContractFromTransaction )) {
513564 return true ;
514565 }
0 commit comments