From 602d248b6e8ef8d60e5c0f05254d23cfa33ed31b Mon Sep 17 00:00:00 2001 From: Cletitia Date: Thu, 19 Aug 2021 15:37:30 +0800 Subject: [PATCH 1/2] feat(core): Add the function to deploy contracts with constructor parameters --- .../tron/trident/core/contract/Contract.java | 72 ++++++++++++++----- .../core/contract/ContractConstructor.java | 64 +++++++++++++++++ .../core/contract/ContractFunction.java | 20 +++++- .../exceptions/ContractCreateException.java | 8 +++ .../core/exceptions/IllegalException.java | 2 +- 5 files changed, 146 insertions(+), 20 deletions(-) create mode 100644 trident-java/core/src/main/java/org/tron/trident/core/contract/ContractConstructor.java create mode 100644 trident-java/core/src/main/java/org/tron/trident/core/exceptions/ContractCreateException.java diff --git a/trident-java/core/src/main/java/org/tron/trident/core/contract/Contract.java b/trident-java/core/src/main/java/org/tron/trident/core/contract/Contract.java index 1bdfe41..1656faf 100644 --- a/trident-java/core/src/main/java/org/tron/trident/core/contract/Contract.java +++ b/trident-java/core/src/main/java/org/tron/trident/core/contract/Contract.java @@ -3,6 +3,8 @@ import com.google.protobuf.ByteString; import com.google.protobuf.util.JsonFormat; +import org.tron.trident.abi.datatypes.Type; +import org.tron.trident.core.exceptions.ContractCreateException; import org.tron.trident.core.transaction.TransactionBuilder; import org.tron.trident.core.ApiWrapper; import org.tron.trident.proto.Common.SmartContract; @@ -12,6 +14,7 @@ import org.tron.trident.proto.Contract.CreateSmartContract; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -46,6 +49,8 @@ public class Contract { //Current transaction owner's address, to call or trigger contract" protected ByteString ownerAddr = ByteString.EMPTY; protected List functions = new ArrayList(); + //the constructor is loaded automatically from the abi, if has + protected ContractConstructor constructor = null; public Contract(Contract cntr, String ownerAddr, ApiWrapper wrapper) { this.originAddr = cntr.getOriginAddr(); @@ -194,6 +199,10 @@ public void setFunctions(List functions) { this.functions = functions; } + public ContractConstructor getConstructor() { + return constructor; + } + public static class Builder { protected ApiWrapper wrapper; protected ByteString originAddr = ByteString.EMPTY; @@ -299,6 +308,25 @@ protected void abiToFunctions() { } builder.setOutputType((String)collectParams(params, 't').get(0)); } + + switch (funcAbi.getStateMutabilityValue()) { + case 0: + builder.setStateMutability("unknownmutabilitytype"); + break; + case 1: + builder.setStateMutability("pure"); + break; + case 2: + builder.setStateMutability("view"); + break; + case 3: + builder.setStateMutability("nonpayable"); + break; + case 4: + builder.setStateMutability("payable"); + break; + } + functions.add(builder.build()); } } @@ -342,41 +370,53 @@ public SmartContract toProto() { public TransactionBuilder deploy() throws Exception { //No deposit when creating contract - return deploy(0, 0); + return deploy(Collections.emptyList()); } /** - * create a CreateSmartContract object to get ready for deployment - * @param callTokenValue deposit amount while deploying - * @param tokenId token id + * create a CreateSmartContract object to get ready for deployment. + * please note if any deposit is made during deployment(@see callValue), + * the constructor of this contract must be payable + * * @return TransactionBuilder object for signing and broadcasting - * @throws RuntimeException if deployment duplicating / owner and origin address don't match + * @throws Exception if deployment duplicating / owner and origin address don't match + * @throws ContractCreateException if passes parameters but no constructor exists */ - public TransactionBuilder deploy(long callTokenValue, long tokenId) throws Exception { + public TransactionBuilder deploy(List buildParams) throws Exception { //throws if deployed if (!this.cntrAddr.isEmpty()) { - throw new RuntimeException("This contract has already been deployed."); + throw new ContractCreateException("This contract has already been deployed."); } //throws if origin address does not match owner address if (!this.originAddr.equals(this.ownerAddr)) { - throw new RuntimeException("Origin address and owner address mismatch."); + throw new ContractCreateException("Origin address and owner address mismatch."); + } + loadConstructor(); + //throws if the contract does not have a constructor + if (null == this.constructor && !buildParams.isEmpty()) { + throw new ContractCreateException("The contract does not have a constructor."); } + this.constructor.encodeParameter(buildParams); + setBytecode(getBytecode().concat(this.constructor.getBytecode())); //create CreateSmartContract.Builder createSmartContractBuilder = CreateSmartContract.newBuilder(); createSmartContractBuilder.setOwnerAddress(ownerAddr); createSmartContractBuilder.setNewContract(toProto()); - //if any deposit - if (tokenId != 0) { - createSmartContractBuilder.setTokenId(tokenId); - createSmartContractBuilder.setCallTokenValue(callTokenValue); - } else { - createSmartContractBuilder.setTokenId(0); - createSmartContractBuilder.setCallTokenValue(0); - } return new TransactionBuilder(wrapper.blockingStub.deployContract(createSmartContractBuilder.build()).getTransaction()); } + /** + * load the constructor from ABI + */ + protected void loadConstructor() { + for (Entry e: abi.getEntrysList()) { + if (e.getName().equals("")) { + this.constructor = new ContractConstructor(e); + } + } + } + /** * load abi from json format string * @param abiString abi string in json format diff --git a/trident-java/core/src/main/java/org/tron/trident/core/contract/ContractConstructor.java b/trident-java/core/src/main/java/org/tron/trident/core/contract/ContractConstructor.java new file mode 100644 index 0000000..a28eee7 --- /dev/null +++ b/trident-java/core/src/main/java/org/tron/trident/core/contract/ContractConstructor.java @@ -0,0 +1,64 @@ +package org.tron.trident.core.contract; + +import org.bouncycastle.util.encoders.Hex; + +import com.google.protobuf.ByteString; +import org.tron.trident.abi.datatypes.Type; +import org.tron.trident.abi.TypeEncoder; +import org.tron.trident.core.exceptions.ContractCreateException; +import org.tron.trident.proto.Common.SmartContract.ABI; +import org.tron.trident.proto.Common.SmartContract.ABI.Entry; +import org.tron.trident.proto.Common.SmartContract.ABI.Entry.Param; + +import java.lang.StringBuilder; +import java.util.ArrayList; +import java.util.List; + +public class ContractConstructor { + + private Entry rawConstructor; + + private List paramTypes; + + private boolean payable; + + private ByteString bytecode = null; + + public ContractConstructor(Entry raw) { + this.rawConstructor = raw; + this.paramTypes = new ArrayList(); + + for (Param p : raw.getInputsList()) { + paramTypes.add(p.getType()); + } + + this.payable = raw.getPayable(); + } + + public Entry getRawConstructor() { + return this.rawConstructor; + } + + public List getParamTypes() { + return this.paramTypes; + } + + public boolean getPayable() { + return this.payable; + } + + public ByteString getBytecode() { + return this.bytecode; + } + + public void encodeParameter(List params) throws ContractCreateException { + if (params.size() != paramTypes.size()) { + throw new ContractCreateException("Parameter amount doesn't match."); + } + StringBuilder builder = new StringBuilder(); + for (Type p : params) { + builder.append(TypeEncoder.encode(p)); + } + this.bytecode = ByteString.copyFrom(Hex.decode(builder.toString())); + } +} diff --git a/trident-java/core/src/main/java/org/tron/trident/core/contract/ContractFunction.java b/trident-java/core/src/main/java/org/tron/trident/core/contract/ContractFunction.java index 344e0ed..38bfd6a 100644 --- a/trident-java/core/src/main/java/org/tron/trident/core/contract/ContractFunction.java +++ b/trident-java/core/src/main/java/org/tron/trident/core/contract/ContractFunction.java @@ -32,6 +32,7 @@ public class ContractFunction { private long callValue = 0; private long callTokenValue = 0; private int callTokenId = 0; + private String stateMutability; public ContractFunction(Builder builder) { this.name = builder.name; @@ -45,6 +46,7 @@ public ContractFunction(Builder builder) { this.callValue = builder.callValue; this.callTokenValue = builder.callTokenValue; this.callTokenId = builder.callTokenId; + this.stateMutability = builder.stateMutability; } public String getName() { @@ -135,6 +137,14 @@ public void setCallTokenId(int callTokenId) { this.callTokenId = callTokenId; } + public String getStateMutability() { + return stateMutability; + } + + public void setStateMutability(String stateMutability) { + this.stateMutability = stateMutability; + } + public static class Builder { private String name; private Entry abi; @@ -147,6 +157,7 @@ public static class Builder { private long callValue = 0; private long callTokenValue = 0; private int callTokenId = 0; + private String stateMutability; public Builder setName(String name) { this.name = name; @@ -202,6 +213,11 @@ public Builder setCallTokenId(int callTokenId) { this.callTokenId = callTokenId; return this; } + + public Builder setStateMutability(String stateMutability) { + this.stateMutability = stateMutability; + return this; + } public ContractFunction build() { return new ContractFunction(this); @@ -219,9 +235,7 @@ public String toString() { ret.delete(ret.length() - 2, ret.length() - 1); } ret.append(")"); - if (abi.getStateMutabilityValue() == 2) { - ret.append(" view"); - } + ret.append(" " + stateMutability); ret.append(" returns ("); ret.append(outputType); ret.append(" " + output); diff --git a/trident-java/core/src/main/java/org/tron/trident/core/exceptions/ContractCreateException.java b/trident-java/core/src/main/java/org/tron/trident/core/exceptions/ContractCreateException.java new file mode 100644 index 0000000..04f0bc4 --- /dev/null +++ b/trident-java/core/src/main/java/org/tron/trident/core/exceptions/ContractCreateException.java @@ -0,0 +1,8 @@ +package org.tron.trident.core.exceptions; + +public class ContractCreateException extends Exception { + + public ContractCreateException(String message) { + super(message); + } +} diff --git a/trident-java/core/src/main/java/org/tron/trident/core/exceptions/IllegalException.java b/trident-java/core/src/main/java/org/tron/trident/core/exceptions/IllegalException.java index d77b615..7c61ae1 100644 --- a/trident-java/core/src/main/java/org/tron/trident/core/exceptions/IllegalException.java +++ b/trident-java/core/src/main/java/org/tron/trident/core/exceptions/IllegalException.java @@ -1,6 +1,6 @@ package org.tron.trident.core.exceptions; -public class IllegalException extends Exception { +public class IllegalException extends Exception { public IllegalException(){ super("Query failed. Please check the parameters."); } From ba91830405e50d4318a8a82eff943ba9791106b2 Mon Sep 17 00:00:00 2001 From: Cletitia Date: Thu, 19 Aug 2021 15:39:57 +0800 Subject: [PATCH 2/2] update: version 0.3.0 --- trident-java/README.md | 19 +++++++++++-------- trident-java/build.gradle | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/trident-java/README.md b/trident-java/README.md index 242e82e..619bab9 100644 --- a/trident-java/README.md +++ b/trident-java/README.md @@ -4,9 +4,9 @@ Trident-Java is a lightweight SDK that includes libraries for working with TRON Trident-Java makes it easy to build TRON applications with java. -Trident-Java document: https://developers.tron.network/docs/trident-java +[Trident-Java document](https://developers.tron.network/docs/trident-java) -Due to safety concerns, trident-java will no longer upload packaged files to maven. Please clone the code from GitHub and do the packaging. +Due to safety concerns, trident-java will no longer upload packaged files to maven. Please clone the code from GitHub and do the packaging. Trident-java is compiled with java version 1.8.0_231 and gradle 5.6.4. @@ -51,19 +51,22 @@ dependencies { org.tron.trident abi - 0.2.0 - pom + 0.3.0 + system + your path org.tron.trident utils - 0.2.0 - pom + 0.3.0 + system + your path org.tron.trident core - 0.2.0 - pom + 0.3.0 + system + your path ``` diff --git a/trident-java/build.gradle b/trident-java/build.gradle index 35317d6..a68acc4 100644 --- a/trident-java/build.gradle +++ b/trident-java/build.gradle @@ -8,7 +8,7 @@ ext { } allprojects { - version '0.2.1' + version '0.3.0' group = 'org.tron.trident' repositories {