@@ -3238,53 +3238,7 @@ public Transaction callConstantContract(TransactionCapsule trxCap,
32383238 }
32393239 }
32403240 try {
3241- Block headBlock ;
3242- List <BlockCapsule > blockCapsuleList = chainBaseManager .getBlockStore ()
3243- .getBlockByLatestNum (1 );
3244- if (CollectionUtils .isEmpty (blockCapsuleList )) {
3245- throw new HeaderNotFound ("latest block not found" );
3246- } else {
3247- headBlock = blockCapsuleList .get (0 ).getInstance ();
3248- }
3249-
3250- BlockCapsule headBlockCapsule = new BlockCapsule (headBlock );
3251- TransactionContext context = new TransactionContext (headBlockCapsule , trxCap ,
3252- StoreFactory .getInstance (), true , false );
3253- VMActuator vmActuator = new VMActuator (true );
3254-
3255- vmActuator .validate (context );
3256- vmActuator .execute (context );
3257-
3258- ProgramResult result = context .getProgramResult ();
3259- if (!isEstimating && result .getException () != null
3260- || result .getException () instanceof Program .OutOfTimeException ) {
3261- RuntimeException e = result .getException ();
3262- logger .warn ("Constant call failed for reason: {}" , e .getMessage ());
3263- throw e ;
3264- }
3265-
3266- TransactionResultCapsule ret = new TransactionResultCapsule ();
3267- builder .setEnergyUsed (result .getEnergyUsed ());
3268- builder .setEnergyPenalty (result .getEnergyPenaltyTotal ());
3269- builder .addConstantResult (ByteString .copyFrom (result .getHReturn ()));
3270- result .getLogInfoList ().forEach (logInfo ->
3271- builder .addLogs (LogInfo .buildLog (logInfo )));
3272- result .getInternalTransactions ().forEach (it ->
3273- builder .addInternalTransactions (buildInternalTransaction (it )));
3274- ret .setStatus (0 , code .SUCESS );
3275- if (StringUtils .isNoneEmpty (result .getRuntimeError ())) {
3276- ret .setStatus (0 , code .FAILED );
3277- retBuilder
3278- .setMessage (ByteString .copyFromUtf8 (result .getRuntimeError ()))
3279- .build ();
3280- }
3281- if (result .isRevert ()) {
3282- ret .setStatus (0 , code .FAILED );
3283- retBuilder .setMessage (ByteString .copyFromUtf8 ("REVERT opcode executed" ))
3284- .build ();
3285- }
3286- trxCap .setResult (ret );
3287- return trxCap .getInstance ();
3241+ return executeConstantContract (trxCap , builder , retBuilder , isEstimating );
32883242 } finally {
32893243 if (acquiredHere ) {
32903244 // remove() before release(): clears the slot from this worker's
@@ -3296,6 +3250,66 @@ public Transaction callConstantContract(TransactionCapsule trxCap,
32963250 }
32973251 }
32983252
3253+ /**
3254+ * Runs the actual TVM execution for a constant call. Split out from
3255+ * {@link #callConstantContract} so the public method stays focused on the
3256+ * concurrency-cap wrapper (acquire / try-finally / release) and the VM
3257+ * execution body has no concurrency concerns to read past. Callers must
3258+ * already hold the permit (or have determined that the cap is not engaged);
3259+ * this method does no throttling of its own.
3260+ */
3261+ private Transaction executeConstantContract (TransactionCapsule trxCap ,
3262+ Builder builder , Return .Builder retBuilder , boolean isEstimating )
3263+ throws ContractValidateException , ContractExeException , HeaderNotFound , VMIllegalException {
3264+ Block headBlock ;
3265+ List <BlockCapsule > blockCapsuleList = chainBaseManager .getBlockStore ()
3266+ .getBlockByLatestNum (1 );
3267+ if (CollectionUtils .isEmpty (blockCapsuleList )) {
3268+ throw new HeaderNotFound ("latest block not found" );
3269+ } else {
3270+ headBlock = blockCapsuleList .get (0 ).getInstance ();
3271+ }
3272+
3273+ BlockCapsule headBlockCapsule = new BlockCapsule (headBlock );
3274+ TransactionContext context = new TransactionContext (headBlockCapsule , trxCap ,
3275+ StoreFactory .getInstance (), true , false );
3276+ VMActuator vmActuator = new VMActuator (true );
3277+
3278+ vmActuator .validate (context );
3279+ vmActuator .execute (context );
3280+
3281+ ProgramResult result = context .getProgramResult ();
3282+ if (!isEstimating && result .getException () != null
3283+ || result .getException () instanceof Program .OutOfTimeException ) {
3284+ RuntimeException e = result .getException ();
3285+ logger .warn ("Constant call failed for reason: {}" , e .getMessage ());
3286+ throw e ;
3287+ }
3288+
3289+ TransactionResultCapsule ret = new TransactionResultCapsule ();
3290+ builder .setEnergyUsed (result .getEnergyUsed ());
3291+ builder .setEnergyPenalty (result .getEnergyPenaltyTotal ());
3292+ builder .addConstantResult (ByteString .copyFrom (result .getHReturn ()));
3293+ result .getLogInfoList ().forEach (logInfo ->
3294+ builder .addLogs (LogInfo .buildLog (logInfo )));
3295+ result .getInternalTransactions ().forEach (it ->
3296+ builder .addInternalTransactions (buildInternalTransaction (it )));
3297+ ret .setStatus (0 , code .SUCESS );
3298+ if (StringUtils .isNoneEmpty (result .getRuntimeError ())) {
3299+ ret .setStatus (0 , code .FAILED );
3300+ retBuilder
3301+ .setMessage (ByteString .copyFromUtf8 (result .getRuntimeError ()))
3302+ .build ();
3303+ }
3304+ if (result .isRevert ()) {
3305+ ret .setStatus (0 , code .FAILED );
3306+ retBuilder .setMessage (ByteString .copyFromUtf8 ("REVERT opcode executed" ))
3307+ .build ();
3308+ }
3309+ trxCap .setResult (ret );
3310+ return trxCap .getInstance ();
3311+ }
3312+
32993313 public SmartContract getContract (GrpcAPI .BytesMessage bytesMessage ) {
33003314 byte [] address = bytesMessage .getValue ().toByteArray ();
33013315 AccountCapsule accountCapsule = chainBaseManager .getAccountStore ().get (address );
0 commit comments