Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: optimize trigger interface #5079

Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ public void pay() throws BalanceInsufficientException {
AccountCapsule origin = accountStore.get(originAccount);
AccountCapsule caller = accountStore.get(callerAccount);
if (dynamicPropertiesStore.supportUnfreezeDelay()
&& receipt.getReceipt().getResult().equals(contractResult.SUCCESS)) {
&& getRuntimeResult().getException() == null && !getRuntimeResult().isRevert()) {

// just fo caller is not origin, we set the related field for origin account
if (origin != null && !caller.getAddress().equals(origin.getAddress())) {
Expand Down
23 changes: 17 additions & 6 deletions framework/src/main/java/org/tron/core/Wallet.java
Original file line number Diff line number Diff line change
Expand Up @@ -2842,7 +2842,7 @@ public Transaction triggerContract(TriggerSmartContract
triggerSmartContract.getData().toByteArray());

if (isConstant(abi, selector)) {
return callConstantContract(trxCap, builder, retBuilder);
return callConstantContract(trxCap, builder, retBuilder, false);
} else {
return trxCap.getInstance();
}
Expand Down Expand Up @@ -2960,13 +2960,19 @@ private Transaction cleanContextAndTriggerConstantContract(
txExtBuilder.clear();
txRetBuilder.clear();
transaction = triggerConstantContract(
triggerSmartContract, txCap, txExtBuilder, txRetBuilder);
triggerSmartContract, txCap, txExtBuilder, txRetBuilder, true);
return transaction;
}

public Transaction triggerConstantContract(TriggerSmartContract triggerSmartContract,
TransactionCapsule trxCap, Builder builder, Return.Builder retBuilder)
throws ContractValidateException, ContractExeException, HeaderNotFound, VMIllegalException {
return triggerConstantContract(triggerSmartContract, trxCap, builder, retBuilder, false);
}

public Transaction triggerConstantContract(TriggerSmartContract triggerSmartContract,
TransactionCapsule trxCap, Builder builder, Return.Builder retBuilder, boolean isEstimating)
throws ContractValidateException, ContractExeException, HeaderNotFound, VMIllegalException {

if (triggerSmartContract.getContractAddress().isEmpty()) { // deploy contract
CreateSmartContract.Builder deployBuilder = CreateSmartContract.newBuilder();
Expand All @@ -2991,11 +2997,11 @@ public Transaction triggerConstantContract(TriggerSmartContract triggerSmartCont
throw new ContractValidateException("Smart contract is not exist.");
}
}
return callConstantContract(trxCap, builder, retBuilder);
return callConstantContract(trxCap, builder, retBuilder, isEstimating);
}

public Transaction callConstantContract(TransactionCapsule trxCap,
Builder builder, Return.Builder retBuilder)
Builder builder, Return.Builder retBuilder, boolean isEstimating)
throws ContractValidateException, ContractExeException, HeaderNotFound, VMIllegalException {

if (!Args.getInstance().isSupportConstant()) {
Expand All @@ -3011,15 +3017,17 @@ public Transaction callConstantContract(TransactionCapsule trxCap,
headBlock = blockCapsuleList.get(0).getInstance();
}

TransactionContext context = new TransactionContext(new BlockCapsule(headBlock), trxCap,
BlockCapsule headBlockCapsule = new BlockCapsule(headBlock);
TransactionContext context = new TransactionContext(headBlockCapsule, trxCap,
StoreFactory.getInstance(), true, false);
VMActuator vmActuator = new VMActuator(true);

vmActuator.validate(context);
vmActuator.execute(context);

ProgramResult result = context.getProgramResult();
if (result.getException() != null) {
if (!isEstimating && result.getException() != null
|| result.getException() instanceof Program.OutOfTimeException) {
RuntimeException e = result.getException();
logger.warn("Constant call has an error {}", e.getMessage());
throw e;
Expand All @@ -3028,6 +3036,9 @@ public Transaction callConstantContract(TransactionCapsule trxCap,
TransactionResultCapsule ret = new TransactionResultCapsule();
builder.setEnergyUsed(result.getEnergyUsed());
builder.setEnergyPenalty(result.getEnergyPenaltyTotal());
builder.setBlockNumber(headBlockCapsule.getNum());
builder.setBlockHash(ByteString.copyFrom(headBlockCapsule.getBlockId().getBytes()));
builder.setEnergyPenalty(result.getEnergyPenaltyTotal());
builder.addConstantResult(ByteString.copyFrom(result.getHReturn()));
result.getLogInfoList().forEach(logInfo ->
builder.addLogs(LogInfo.buildLog(logInfo)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.google.protobuf.ByteString;
import io.netty.util.internal.StringUtil;
import java.io.IOException;
import java.security.InvalidParameterException;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
Expand All @@ -25,26 +24,12 @@
@Slf4j(topic = "API")
public class EstimateEnergyServlet extends RateLimiterServlet {

private final String functionSelector = "function_selector";

@Autowired
private Wallet wallet;

protected void doGet(HttpServletRequest request, HttpServletResponse response) {
}

protected void validateParameter(String contract) {
JSONObject jsonObject = JSONObject.parseObject(contract);
if (!jsonObject.containsKey("owner_address")
|| StringUtil.isNullOrEmpty(jsonObject.getString("owner_address"))) {
throw new InvalidParameterException("owner_address isn't set.");
}
if (!jsonObject.containsKey("contract_address")
|| StringUtil.isNullOrEmpty(jsonObject.getString("contract_address"))) {
throw new InvalidParameterException("contract_address isn't set.");
}
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException {
TriggerSmartContract.Builder build = TriggerSmartContract.newBuilder();
Expand All @@ -57,21 +42,19 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
.collect(Collectors.joining(System.lineSeparator()));
Util.checkBodySize(contract);
visible = Util.getVisiblePost(contract);
validateParameter(contract);
Util.validateParameter(contract);
JsonFormat.merge(contract, build, visible);
JSONObject jsonObject = JSONObject.parseObject(contract);

boolean isFunctionSelectorSet = jsonObject.containsKey(functionSelector)
&& !StringUtil.isNullOrEmpty(jsonObject.getString(functionSelector));
String data;
boolean isFunctionSelectorSet =
!StringUtil.isNullOrEmpty(jsonObject.getString(Util.FUNCTION_SELECTOR));
if (isFunctionSelectorSet) {
String selector = jsonObject.getString(functionSelector);
String parameter = jsonObject.getString("parameter");
data = Util.parseMethod(selector, parameter);
String selector = jsonObject.getString(Util.FUNCTION_SELECTOR);
String parameter = jsonObject.getString(Util.FUNCTION_PARAMETER);
String data = Util.parseMethod(selector, parameter);
build.setData(ByteString.copyFrom(ByteArray.fromHexString(data)));
} else {
build.setData(ByteString.copyFrom(new byte[0]));
}

TransactionCapsule trxCap = wallet.createTransactionCapsule(build.build(),
Protocol.Transaction.Contract.ContractType.TriggerSmartContract);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.google.protobuf.ByteString;
import io.netty.util.internal.StringUtil;
import java.io.IOException;
import java.security.InvalidParameterException;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
Expand All @@ -27,26 +26,12 @@
@Slf4j(topic = "API")
public class TriggerConstantContractServlet extends RateLimiterServlet {

private final String functionSelector = "function_selector";

@Autowired
private Wallet wallet;

protected void doGet(HttpServletRequest request, HttpServletResponse response) {
}

protected void validateParameter(String contract) {
JSONObject jsonObject = JSONObject.parseObject(contract);
if (!jsonObject.containsKey("owner_address")
|| StringUtil.isNullOrEmpty(jsonObject.getString("owner_address"))) {
throw new InvalidParameterException("owner_address isn't set.");
}
if (!jsonObject.containsKey("contract_address")
|| StringUtil.isNullOrEmpty(jsonObject.getString("contract_address"))) {
throw new InvalidParameterException("contract_address isn't set.");
}
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException {
TriggerSmartContract.Builder build = TriggerSmartContract.newBuilder();
Expand All @@ -58,21 +43,19 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
.collect(Collectors.joining(System.lineSeparator()));
Util.checkBodySize(contract);
visible = Util.getVisiblePost(contract);
validateParameter(contract);
Util.validateParameter(contract);
JsonFormat.merge(contract, build, visible);
JSONObject jsonObject = JSONObject.parseObject(contract);

boolean isFunctionSelectorSet = jsonObject.containsKey(functionSelector)
&& !StringUtil.isNullOrEmpty(jsonObject.getString(functionSelector));
String data;
boolean isFunctionSelectorSet =
!StringUtil.isNullOrEmpty(jsonObject.getString(Util.FUNCTION_SELECTOR));
if (isFunctionSelectorSet) {
String selector = jsonObject.getString(functionSelector);
String parameter = jsonObject.getString("parameter");
data = Util.parseMethod(selector, parameter);
String selector = jsonObject.getString(Util.FUNCTION_SELECTOR);
String parameter = jsonObject.getString(Util.FUNCTION_PARAMETER);
String data = Util.parseMethod(selector, parameter);
build.setData(ByteString.copyFrom(ByteArray.fromHexString(data)));
} else {
build.setData(ByteString.copyFrom(new byte[0]));
}

TransactionCapsule trxCap = wallet
.createTransactionCapsule(build.build(), ContractType.TriggerSmartContract);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,24 @@
@Slf4j(topic = "API")
public class TriggerSmartContractServlet extends RateLimiterServlet {

private final String functionSelector = "function_selector";

@Autowired
private Wallet wallet;

protected void doGet(HttpServletRequest request, HttpServletResponse response) {
}

protected void validateParameter(String contract) {
private void validateParameter(String contract) {
JSONObject jsonObject = JSONObject.parseObject(contract);
if (!jsonObject.containsKey("owner_address")
|| StringUtil.isNullOrEmpty(jsonObject.getString("owner_address"))) {
throw new InvalidParameterException("owner_address isn't set.");
if (StringUtil.isNullOrEmpty(jsonObject.getString(Util.OWNER_ADDRESS))) {
throw new InvalidParameterException(Util.OWNER_ADDRESS + " isn't set.");
}
if (StringUtil.isNullOrEmpty(jsonObject.getString(Util.CONTRACT_ADDRESS))) {
throw new InvalidParameterException(Util.CONTRACT_ADDRESS + " isn't set.");
}
if (!jsonObject.containsKey("contract_address")
|| StringUtil.isNullOrEmpty(jsonObject.getString("contract_address"))) {
throw new InvalidParameterException("contract_address isn't set.");
if (!StringUtil.isNullOrEmpty(jsonObject.getString(Util.FUNCTION_SELECTOR))
^ StringUtil.isNullOrEmpty(jsonObject.getString(Util.CALL_DATA))) {
throw new InvalidParameterException("Only one of "
+ Util.FUNCTION_SELECTOR + " and " + Util.CALL_DATA + " can be set.");
}
}

Expand All @@ -62,16 +63,13 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
JsonFormat.merge(contract, build, visible);
JSONObject jsonObject = JSONObject.parseObject(contract);

boolean isFunctionSelectorSet = jsonObject.containsKey(functionSelector)
&& !StringUtil.isNullOrEmpty(jsonObject.getString(functionSelector));
String data;
boolean isFunctionSelectorSet =
!StringUtil.isNullOrEmpty(jsonObject.getString(Util.FUNCTION_SELECTOR));
if (isFunctionSelectorSet) {
String selector = jsonObject.getString(functionSelector);
String parameter = jsonObject.getString("parameter");
data = Util.parseMethod(selector, parameter);
String selector = jsonObject.getString(Util.FUNCTION_SELECTOR);
String parameter = jsonObject.getString(Util.FUNCTION_PARAMETER);
String data = Util.parseMethod(selector, parameter);
build.setData(ByteString.copyFrom(ByteArray.fromHexString(data)));
} else {
build.setData(ByteString.copyFrom(new byte[0]));
}

build.setCallTokenValue(Util.getJsonLongValue(jsonObject, "call_token_value"));
Expand Down
34 changes: 33 additions & 1 deletion framework/src/main/java/org/tron/core/services/http/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ public class Util {
public static final String EXTRA_DATA = "extra_data";
public static final String PARAMETER = "parameter";

// Used for TVM http interfaces
public static final String OWNER_ADDRESS = "owner_address";
public static final String CONTRACT_ADDRESS = "contract_address";
public static final String FUNCTION_SELECTOR = "function_selector";
public static final String FUNCTION_PARAMETER = "parameter";
public static final String CALL_DATA = "data";

public static String printTransactionFee(String transactionFee) {
JSONObject jsonObject = new JSONObject();
JSONObject receipt = JSONObject.parseObject(transactionFee);
Expand Down Expand Up @@ -220,7 +227,7 @@ public static JSONObject printTransactionToJSON(Transaction transaction, boolean
.parseObject(JsonFormat.printToString(deployContract, selfType));
byte[] ownerAddress = deployContract.getOwnerAddress().toByteArray();
byte[] contractAddress = generateContractAddress(transaction, ownerAddress);
jsonTransaction.put("contract_address", ByteArray.toHexString(contractAddress));
jsonTransaction.put(CONTRACT_ADDRESS, ByteArray.toHexString(contractAddress));
break;
default:
Class clazz = TransactionFactory.getContract(contract.getType());
Expand Down Expand Up @@ -543,4 +550,29 @@ public static List<Log> convertLogAddressToTronAddress(TransactionInfo transacti
return newLogList;
}

/**
* Validate parameters for trigger constant and estimate energy
* - Rule-1: owner address must be set
* - Rule-2: either contract address is set or call data is set
* - Rule-3: only one of function selector and call data can be set
* @param contract parameters in json format
* @throws InvalidParameterException if validation is not passed, this kind of exception is thrown
*/
public static void validateParameter(String contract) throws InvalidParameterException {
JSONObject jsonObject = JSONObject.parseObject(contract);
if (StringUtils.isEmpty(jsonObject.getString(OWNER_ADDRESS))) {
throw new InvalidParameterException(OWNER_ADDRESS + " isn't set.");
}
if (StringUtils.isEmpty(jsonObject.getString(CONTRACT_ADDRESS))
&& StringUtils.isEmpty(jsonObject.getString(CALL_DATA))) {
throw new InvalidParameterException("At least one of "
+ CONTRACT_ADDRESS + " and " + CALL_DATA + " must be set.");
}
if (!StringUtils.isEmpty(jsonObject.getString(FUNCTION_SELECTOR))
^ StringUtils.isEmpty(jsonObject.getString(CALL_DATA))) {
throw new InvalidParameterException("Only one of "
+ FUNCTION_SELECTOR + " and " + CALL_DATA + " can be set.");
}
}

}
2 changes: 2 additions & 0 deletions protocol/src/main/protos/api/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,8 @@ message TransactionExtention {
repeated TransactionInfo.Log logs = 6;
repeated InternalTransaction internal_transactions = 7;
int64 energy_penalty = 8;
int64 block_number = 9;
bytes block_hash = 10;
}

message EstimateEnergyMessage {
Expand Down