diff --git a/.travis.yml b/.travis.yml index 9c7a5f95..a65b5654 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ +dist: trusty + language: java jdk: diff --git a/CHANGELOG.md b/CHANGELOG.md index 232b035d..3b1212d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ All notable changes to this project will be documented in this file. +# [v0.24.1](https://github.com/cryptape/cita-sdk-java/compare/v0.24.0...v0.24.1) (2019-08-16) + +### Feature + +* add a constructor parameter to contract deploy method +* fix some issues + # [v0.24.0](https://github.com/cryptape/cita-sdk-java/compare/v0.23.0...v0.24.0) (2019-05-30) ### Feature diff --git a/README.md b/README.md index a358b2e0..200ecc56 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ For detailed documentation, see [documentation](docs/index.md). ### Prerequisites Java 8 -Gradle 4.3 +Gradle 5.0 ### Install Install from repositories: @@ -29,12 +29,12 @@ maven com.cryptape.cita core - 0.24.0 + 0.24.1 ``` Gradle ``` -compile 'com.cryptape.cita:core:0.24.0' +compile 'com.cryptape.cita:core:0.24.1' ``` Install manually @@ -52,7 +52,7 @@ gradle shadowJar ### CITA Test net Use CITA test net (recommended): -http://121.196.200.225:1337 is provided as a test net. +https://node.cryptape.com is provided as a test net. Or build your own CITA net: Please find more information in [CITA](https://github.com/cryptape/cita). @@ -124,7 +124,7 @@ Example generate Java class from `Token.sol`, `Token.bin` and `Token.abi` under ```shell java -jar console/build/libs/console-0.17-all.jar solidity generate tests/src/main/resources/Token.bin tests/src/main/resources/Token.abi -o tests/src/main/java/ -p com.cryptape.cita.tests ``` -`Token.java` will be created from commands above and class `Token` can be used with CitaTransactionManager to deploy and call smart contract `Token`. Please be attention that [CitaTransactionManager](https://github.com/cryptape/cita-sdk-java/blob/master/core/src/main/java/com/cryptape/cita/tx/CitaTransactionManager.java) is supposed to be used as TransactionManager for transaction creation in CITA network. +`Token.java` will be created from commands above and class `Token` can be used with TransactionManager to deploy and call smart contract `Token`. Please be attention that [TransactionManager](https://github.com/cryptape/cita-sdk-java/blob/master/core/src/main/java/com/cryptape/cita/tx/TransactionManager.java) is supposed to be used as TransactionManager for transaction creation in CITA network. Please check [TokenCodegenExample.java](https://github.com/cryptape/cita-sdk-java/blob/master/tests/src/main/java/com/cryptape/cita/tests/TokenCodegenExample.java) for a complete example. ### Working with smart contract with cita-sdk-java Account (Test) @@ -162,7 +162,7 @@ cita-sdk-java 是对以太坊 Web3j 进行改写,适配 CITA 的一个 Java ### 预装组件 Java 8 -Gradle 4.3 +Gradle 5.0 ### 安装 通过远程仓库安装: @@ -170,12 +170,12 @@ Gradle 4.3 com.cryptape.cita core - 0.24.0 + 0.24.1 ``` Gradle ``` -compile 'com.cryptape.cita:core:0.24.0' +compile 'com.cryptape.cita:core:0.24.1' ``` 手动安装 @@ -192,7 +192,7 @@ gradle shadowJar ### CITA 测试网络 使用 CITA 测试网络(推荐): -http://121.196.200.225:1337 +https://node.cryptape.com 或者可以部署你自己的 CITA: 如果需要了解怎么部署 CITA 网络,请查阅[CITA](https://github.com/cryptape/cita)。 @@ -262,7 +262,7 @@ $ java -jar console-0.17-all.jar solidity generate [--javaTypes|--solidityTypes] ``` java -jar console/build/libs/console-0.17-all.jar solidity generate tests/src/main/resources/Token.bin tests/src/main/resources/Token.abi -o tests/src/main/java/ -p com.cryptape.cita.tests ``` -`Token.java` 会通过以上命令生成, `Token` 可以与 `CitaTransactionManager` 一起使用来和 Token 合约交互。请注意在 CITA 中应该使用 [CitaTransactionManager](https://github.com/cryptape/cita-sdk-java/blob/master/core/src/main/java/com/cryptape/cita/tx/CitaTransactionManager.java) 而不是 TransactionManager。 +`Token.java` 会通过以上命令生成, `Token` 可以与 `TransactionManager` 一起使用来和 Token 合约交互。请注意在 CITA 中应该使用 [TransactionManager](https://github.com/cryptape/cita-sdk-java/blob/master/core/src/main/java/com/cryptape/cita/tx/TransactionManager.java) 而不是 TransactionManager。 请在 [TokenCodegenExample.java](https://github.com/cryptape/cita-sdk-java/blob/master/tests/src/main/java/com/cryptape/cita/tests/TokenCodegenExample.java) 查看完整代码. ### 通过 CITAj 中的 Account 与智能合约交互(测试阶段) diff --git a/build.gradle b/build.gradle index 5d16728f..1b246717 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,11 @@ buildscript { dependencies { classpath 'io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.5.3' - classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.2' + /* + * the version need adapt to gradle version + * refer to https://github.com/fzdy1914/Inventory-Manager/commit/6e0df8af1ddf9261082389c4e1bb2fb728c2ae66 + */ + classpath 'com.github.jengelman.gradle.plugins:shadow:5.0.0' } } @@ -45,7 +49,7 @@ allprojects { targetCompatibility = 1.8 group 'com.cryptape.cita' - version '0.24.0' + version '0.24.1' apply plugin: 'java' apply plugin: 'jacoco' @@ -141,7 +145,7 @@ configure(subprojects.findAll { it.name != 'integration-tests' }) { publications { mavenJava(MavenPublication) { groupId 'com.cryptape.cita' - version '0.24.0' + version '0.24.1' from components.java artifact sourcesJar { diff --git a/codegen/src/main/java/com/cryptape/cita/codegen/SolidityFunctionWrapper.java b/codegen/src/main/java/com/cryptape/cita/codegen/SolidityFunctionWrapper.java index 6273e962..76d4dee6 100644 --- a/codegen/src/main/java/com/cryptape/cita/codegen/SolidityFunctionWrapper.java +++ b/codegen/src/main/java/com/cryptape/cita/codegen/SolidityFunctionWrapper.java @@ -57,6 +57,7 @@ public class SolidityFunctionWrapper extends Generator { private static final String BINARY = "BINARY"; + private static final String ABI = "ABI"; private static final String CITAJ = "citaj"; private static final String CREDENTIALS = "credentials"; private static final String TRANSACTION_MANAGER = "transactionManager"; @@ -105,7 +106,7 @@ void generateJavaFiles( throws IOException, ClassNotFoundException { String className = Strings.capitaliseFirstLetter(contractName); - TypeSpec.Builder classBuilder = createClassBuilder(className, bin); + TypeSpec.Builder classBuilder = createClassBuilder(className, bin, convertToAbiString(abi)); classBuilder.addMethod( buildConstructorAdaptToCita(TransactionManager.class, TRANSACTION_MANAGER)); @@ -170,7 +171,7 @@ private void addAddressesSupport(TypeSpec.Builder classBuilder, Map buildFunctionDefinitions( String className, TypeSpec.Builder classBuilder, @@ -1075,6 +1084,11 @@ private List loadContractDefinition(String abi) throws IOExceptio return Arrays.asList(abiDefinition); } + private String convertToAbiString(List abi) throws IOException { + ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(); + return objectMapper.writeValueAsString(abi); + } + private static class NamedTypeName { private final TypeName typeName; private final String name; diff --git a/console/build.gradle b/console/build.gradle index 68555ddc..ded31abf 100644 --- a/console/build.gradle +++ b/console/build.gradle @@ -1,4 +1,4 @@ -//apply plugin: 'com.github.johnrengelman.shadow' +apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'application' description 'cita-sdk-java command line tools' @@ -9,8 +9,13 @@ dependencies { testCompile project(path: ':crypto', configuration: 'archives'), project(path: ':core', configuration: 'archives'), project(path: ':codegen', configuration: 'archives') - testCompile files(project(':crypto').sourceSets.test.output.classesDir) - testCompile files(project(':codegen').sourceSets.test.output.classesDir) + /* + * The classesDir property was deprecated in gradle 4.x, and removed in gradle 5.x + * refer to https://stackoverflow.com/questions/54707148/gradle-could-not-get-unknown-property-classesdir-for-main-classes + * refer to https://docs.gradle.org/5.0/release-notes.html + */ + testCompile files(project(':crypto').sourceSets.test.output.classesDirs) + testCompile files(project(':codegen').sourceSets.test.output.classesDirs) } // Build command line library release with target distShadowZip diff --git a/core/build.gradle b/core/build.gradle index 8c5991ff..2f261b53 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -15,7 +15,7 @@ dependencies { "com.google.code.gson:gson:$gsonVersion" testCompile project(path: ':crypto', configuration: 'archives'), "nl.jqno.equalsverifier:equalsverifier:$equalsverifierVersion" - testCompile files(project(':crypto').sourceSets.test.output.classesDir) + testCompile files(project(':crypto').sourceSets.test.output.classesDirs) } task createProperties(dependsOn: processResources) doLast { diff --git a/core/src/main/java/com/cryptape/cita/protocol/account/Account.java b/core/src/main/java/com/cryptape/cita/protocol/account/Account.java index de3592ab..0447a923 100644 --- a/core/src/main/java/com/cryptape/cita/protocol/account/Account.java +++ b/core/src/main/java/com/cryptape/cita/protocol/account/Account.java @@ -1,5 +1,6 @@ package com.cryptape.cita.protocol.account; +import com.cryptape.cita.utils.Numeric; import java.io.File; import java.io.IOException; import java.math.BigInteger; @@ -49,14 +50,40 @@ public RawTransactionManager getTransactionManager() { /// TODO: get contract address from receipt after deploy, then return contract name public AppSendTransaction deploy( - File contractFile, String nonce, long quota, - int version, BigInteger chainId, String value) - throws IOException, InterruptedException, CompiledContract.ContractCompileError { + File contractFile, String nonce, long quota, + int version, BigInteger chainId, String value) + throws IOException, InterruptedException, CompiledContract.ContractCompileError { CompiledContract contract = new CompiledContract(contractFile); String contractBin = contract.getBin(); return this.transactionManager - .sendTransaction("", contractBin, quota, nonce, getValidUntilBlock(), - version, chainId, value); + .sendTransaction("", contractBin, quota, nonce, getValidUntilBlock(), + version, chainId, value); + } + + /** + * + * @param contractFile + * @param constructorCode add by timmyz, fulfill the construction contract situations + * @param nonce + * @param quota + * @param version + * @param chainId + * @param value + * @return + * @throws IOException + * @throws InterruptedException + * @throws CompiledContract.ContractCompileError + */ + public AppSendTransaction deploy( + File contractFile, String constructorCode, String nonce, long quota, + int version, BigInteger chainId, String value) + throws IOException, InterruptedException, CompiledContract.ContractCompileError { + CompiledContract contract = new CompiledContract(contractFile); + String contractBin = contract.getBin(); + String data = constructorCode != null ? contractBin + Numeric.cleanHexPrefix(constructorCode) : contractBin; + return this.transactionManager + .sendTransaction("", data, quota, nonce, getValidUntilBlock(), + version, chainId, value); } public Flowable deployAsync( diff --git a/core/src/main/java/com/cryptape/cita/protocol/core/methods/request/Transaction.java b/core/src/main/java/com/cryptape/cita/protocol/core/methods/request/Transaction.java index 2c412424..e384fb44 100644 --- a/core/src/main/java/com/cryptape/cita/protocol/core/methods/request/Transaction.java +++ b/core/src/main/java/com/cryptape/cita/protocol/core/methods/request/Transaction.java @@ -24,6 +24,7 @@ import com.cryptape.cita.utils.Numeric; import com.cryptape.cita.utils.Strings; +import static com.cryptape.cita.utils.Numeric.encodeQuantity; import static org.abstractj.kalium.encoders.Encoder.HEX; import static com.cryptape.cita.utils.Numeric.cleanHexPrefix; import static com.cryptape.cita.utils.Numeric.prependHexPrefix; @@ -239,7 +240,7 @@ private static String processValue(String value) { } else { BigInteger valueBigInt = value.matches("0[xX][0-9a-fA-F]+") ? Numeric.toBigInt(value) : new BigInteger(value); if (Transaction.MAX_VALUE.compareTo(valueBigInt) > 0) { - return valueBigInt.toString(16); + return encodeQuantity(valueBigInt); } else { System.out.println("Value you input is out of bound"); throw new IllegalArgumentException( diff --git a/core/src/main/java/com/cryptape/cita/tx/Contract.java b/core/src/main/java/com/cryptape/cita/tx/Contract.java index 749b53f2..194fab3f 100644 --- a/core/src/main/java/com/cryptape/cita/tx/Contract.java +++ b/core/src/main/java/com/cryptape/cita/tx/Contract.java @@ -39,6 +39,8 @@ public abstract class Contract extends ManagedTransaction { // https://www.reddit.com/r/ethereum/comments/5g8ia6/attention_miners_we_recommend_raising_gas_limit/ + private static final String ABI_ADDRESS = "ffffffffffffffffffffffffffffffffff010001"; + protected final String contractBinary; protected String contractAddress; protected String nonce; @@ -221,6 +223,37 @@ TransactionReceipt executeTransaction( contractAddress, data, quota, nonce, validUntilBlock, version, chainId, value); } + TransactionReceipt uploadAbi( + String abi, long quota, String nonce, long validUntilBlock, + int version , BigInteger chainId, String value) + throws TransactionException, IOException { + String data = hex_remove_0x(contractAddress) + hex_remove_0x(bytesToHexStr(abi.getBytes())); + return send( + ABI_ADDRESS, data, quota, nonce, validUntilBlock, + version, chainId, value); + } + + private String hex_remove_0x(String hex) { + if (hex.contains("0x")) { + return hex.substring(2); + } + return hex; + } + + private String bytesToHexStr(byte[] byteArr) { + if (null == byteArr || byteArr.length < 1) { + return ""; + } + StringBuilder sb = new StringBuilder(); + for (byte t : byteArr) { + if ((t & 0xF0) == 0) { + sb.append("0"); + } + sb.append(Integer.toHexString(t & 0xFF)); + } + return sb.toString(); + } + protected RemoteCall executeRemoteCallSingleValueReturn(Function function) { return new RemoteCall<>( () -> executeCallSingleValueReturn(function)); @@ -256,6 +289,15 @@ protected RemoteCall executeRemoteCallTransaction( quota, nonce, validUntilBlock, version, chainId, value)); } + protected RemoteCall executeUploadAbi( + String abi, long quota, String nonce, + long validUntilBlock, int version, + BigInteger chainId, String value) { + return new RemoteCall<>( + () -> executeTransaction( + abi, quota, nonce, validUntilBlock, version, chainId, value)); + } + private static T create( T contract, String binary, String encodedConstructor, @@ -277,40 +319,100 @@ private static T create( return contract; } + private static T create( + T contract, String binary, String encodedConstructor, + long quota, String nonce, long validUntilBlock, + int version, BigInteger chainId, String value, String abi) + throws IOException, TransactionException { + TransactionReceipt transactionReceipt = + contract.executeTransaction( + binary + encodedConstructor, quota, nonce, + validUntilBlock, version, chainId, value); + + String contractAddress = transactionReceipt.getContractAddress(); + if (contractAddress == null) { + throw new RuntimeException("Empty contract address returned"); + } + contract.setContractAddress(contractAddress); + contract.setTransactionReceipt(transactionReceipt); + + if(abi != null && abi.length() > 0) { + contract.uploadAbi(abi, quota, nonce, + validUntilBlock + 88, version, chainId, value); + } + + return contract; + } + protected static T deploy( - Class type, - CITAj citaj, TransactionManager transactionManager, - long quota, String nonce, long validUntilBlock, - int version, String binary, BigInteger chainId, - String value, String encodedConstructor) - throws IOException, TransactionException { + Class type, + CITAj citaj, TransactionManager transactionManager, + long quota, String nonce, long validUntilBlock, + int version, String binary, BigInteger chainId, + String value, String encodedConstructor) + throws IOException, TransactionException { + + try { + Constructor constructor = type.getDeclaredConstructor( + String.class, + CITAj.class, TransactionManager.class); + constructor.setAccessible(true); + + // we want to use null here to ensure that "to" parameter on message is not populated + // Unfortunately, we need empty string(not null) that represent create contract + T contract = constructor.newInstance( + "", citaj, transactionManager); + return create(contract, binary, encodedConstructor, quota, nonce, + validUntilBlock, version, chainId, value); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + protected static T deploy( + Class type, + CITAj citaj, TransactionManager transactionManager, + long quota, String nonce, long validUntilBlock, + int version, String binary, BigInteger chainId, + String value, String encodedConstructor, String abi) + throws IOException, TransactionException { try { Constructor constructor = type.getDeclaredConstructor( - String.class, - CITAj.class, TransactionManager.class); + String.class, + CITAj.class, TransactionManager.class); constructor.setAccessible(true); // we want to use null here to ensure that "to" parameter on message is not populated // Unfortunately, we need empty string(not null) that represent create contract T contract = constructor.newInstance( - "", citaj, transactionManager); + "", citaj, transactionManager); return create(contract, binary, encodedConstructor, quota, nonce, - validUntilBlock, version, chainId, value); + validUntilBlock, version, chainId, value, abi); } catch (Exception e) { throw new RuntimeException(e); } } protected static RemoteCall deployRemoteCall( - Class type, CITAj citaj, TransactionManager transactionManager, - long quota, String nonce, long validUntilBlock, - int version, BigInteger chainId, String value, - String binary, String encodedConstructor) { + Class type, CITAj citaj, TransactionManager transactionManager, + long quota, String nonce, long validUntilBlock, + int version, BigInteger chainId, String value, + String binary, String encodedConstructor) { + return new RemoteCall<>(() -> deploy( + type, citaj, transactionManager, quota, nonce, validUntilBlock, + version, binary, chainId, value, encodedConstructor)); + } + + protected static RemoteCall deployRemoteCall( + Class type, CITAj citaj, TransactionManager transactionManager, + long quota, String nonce, long validUntilBlock, + int version, BigInteger chainId, String value, + String binary, String encodedConstructor, String abi) { return new RemoteCall<>(() -> deploy( - type, citaj, transactionManager, quota, nonce, validUntilBlock, - version, binary, chainId, value, encodedConstructor)); + type, citaj, transactionManager, quota, nonce, validUntilBlock, + version, binary, chainId, value, encodedConstructor, abi)); } public static EventValues staticExtractEventParameters( diff --git a/core/src/main/java/com/cryptape/cita/utils/TransactionUtil.java b/core/src/main/java/com/cryptape/cita/utils/TransactionUtil.java index 4cd7a4cf..b291a5f3 100644 --- a/core/src/main/java/com/cryptape/cita/utils/TransactionUtil.java +++ b/core/src/main/java/com/cryptape/cita/utils/TransactionUtil.java @@ -1,5 +1,7 @@ package com.cryptape.cita.utils; +import static com.cryptape.cita.utils.Numeric.prependHexPrefix; + import java.math.BigInteger; import java.security.SignatureException; @@ -104,7 +106,7 @@ public static boolean verifySignature(String addr, String content) long quota = blockChainTx.getQuota(); long validUntilBlock = blockChainTx.getValidUntilBlock(); String data = bytesToHexString(blockChainTx.getData()); - String value = bytesToHexString(blockChainTx.getValue()); + String value = prependHexPrefix(bytesToHexString(blockChainTx.getValue())); // the value-param of Transaction class need add format tag String to = null; BigInteger chainId = null; diff --git a/crypto/src/main/java/com/cryptape/cita/crypto/sm2/SM2Keys.java b/crypto/src/main/java/com/cryptape/cita/crypto/sm2/SM2Keys.java index c5f4b708..345041f4 100644 --- a/crypto/src/main/java/com/cryptape/cita/crypto/sm2/SM2Keys.java +++ b/crypto/src/main/java/com/cryptape/cita/crypto/sm2/SM2Keys.java @@ -17,7 +17,19 @@ public class SM2Keys { private static final int PUBLIC_KEY_LENGTH_IN_HEX = PUBLIC_KEY_SIZE << 1; public static String getAddress(ECPoint key) { - String publicKey = key.getRawXCoord().toString() + key.getRawYCoord().toString(); + String pubXStr = key.getRawXCoord().toString(); + String pubYStr = key.getRawYCoord().toString(); + if (pubXStr.length() < PUBLIC_KEY_SIZE) { + pubXStr = Strings.zeros( + PUBLIC_KEY_SIZE - pubXStr.length()) + + pubXStr; + } + if (pubYStr.length() < PUBLIC_KEY_SIZE) { + pubYStr = Strings.zeros( + PUBLIC_KEY_SIZE - pubYStr.length()) + + pubYStr; + } + String publicKey = pubXStr + pubYStr; return getAddress(publicKey); } diff --git a/docs/transaction.md b/docs/transaction.md index 1a8dc29b..3e47fc0d 100644 --- a/docs/transaction.md +++ b/docs/transaction.md @@ -179,7 +179,7 @@ AppSendTransaction **示例** ``` -CitaTransactionManager transactionManager = new CitaTransactionManager(service, credentials); +TransactionManager transactionManager = new TransactionManager(service, credentials); String to = "{address to which the contract is sent}"; String contractBin = "{contract bin or function call bin}"; BigInteger quota = 99999; @@ -188,7 +188,7 @@ long valid_until_block = service.appBlockNumber().send().getBlockNumber() + 88; BigInteger version = BigInteger.valueOf(0); int chainId = 1; String value = "0"; -AppSendTransaction appSendTransaction = citaTransactionManager.sendTransaction(to, contractBin, quota, nonce, valid_until_block, version, chainId, value); +AppSendTransaction appSendTransaction = transactionManager.sendTransaction(to, contractBin, quota, nonce, valid_until_block, version, chainId, value); ``` ### sendTransactionAsync diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 590f0e81..7a14979b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.0-all.zip diff --git a/tests/src/main/java/com/cryptape/cita/tests/DecodeTxExample.java b/tests/src/main/java/com/cryptape/cita/tests/DecodeTxExample.java index 9f575af5..95958024 100644 --- a/tests/src/main/java/com/cryptape/cita/tests/DecodeTxExample.java +++ b/tests/src/main/java/com/cryptape/cita/tests/DecodeTxExample.java @@ -1,5 +1,7 @@ package com.cryptape.cita.tests; +import static com.cryptape.cita.utils.Numeric.decodeQuantity; + import java.io.IOException; import java.math.BigInteger; import java.util.concurrent.TimeUnit; @@ -40,9 +42,10 @@ private static String createSampleTransaction() throws IOException { String nonce = TestUtil.getNonce(); String data = ConvertStrByte.stringToHexString("some message"); long validUtilBlock = TestUtil.getValidUtilBlock(service).longValue(); + String value = decodeQuantity("0xa9b").toString(); // test value should be all-round, contains at least one a-f Transaction transferTx = new Transaction( - payeeAddr, nonce, quotaToDeploy, validUtilBlock, version, chainId, "1", data); + payeeAddr, nonce, quotaToDeploy, validUtilBlock, version, chainId, value , data); String rawTx = transferTx.sign(privateKey, cryptoTx, false); return service.appSendRawTransaction(rawTx).send().getSendTransactionResult().getHash();