diff --git a/.ci/ci_check.sh b/.ci/ci_check.sh index 0f3c2d2e4..e70341556 100755 --- a/.ci/ci_check.sh +++ b/.ci/ci_check.sh @@ -1,6 +1,7 @@ #!/bin/bash set -e +tag="v2.7.2" LOG_INFO() { local content=${1} echo -e "\033[32m ${content}\033[0m" @@ -28,9 +29,9 @@ download_tassl() download_build_chain() { - tag=$(curl -sS "https://gitee.com/api/v5/repos/FISCO-BCOS/FISCO-BCOS/tags" | grep -oe "\"name\":\"v[2-9]*\.[0-9]*\.[0-9]*\"" | cut -d \" -f 4 | sort -V | tail -n 1) LOG_INFO "--- current tag: $tag" - curl -LO "https://github.com/FISCO-BCOS/FISCO-BCOS/releases/download/${tag}/build_chain.sh" && chmod u+x build_chain.sh +# curl -LO "https://github.com/FISCO-BCOS/FISCO-BCOS/releases/download/${tag}/build_chain.sh" && chmod u+x build_chain.sh + curl -LO "https://raw.githubusercontent.com/FISCO-BCOS/FISCO-BCOS/master-2.0/tools/build_chain.sh" && chmod u+x build_chain.sh } get_sed_cmd() @@ -75,11 +76,11 @@ build_node() { local node_type="${1}" if [ "${node_type}" == "sm" ];then - ./build_chain.sh -l 127.0.0.1:4 -g + bash -x build_chain.sh -l 127.0.0.1:4 -g sed_cmd=$(get_sed_cmd) $sed_cmd 's/sm_crypto_channel=false/sm_crypto_channel=true/g' nodes/127.0.0.1/node*/config.ini else - ./build_chain.sh -l 127.0.0.1:4 + bash -x build_chain.sh -l 127.0.0.1:4 fi ./nodes/127.0.0.1/fisco-bcos -v ./nodes/127.0.0.1/start_all.sh diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 7c601955a..b1507c8a6 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -12,7 +12,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-18.04, ubuntu-16.04, macos-latest] + os: [ubuntu-18.04, ubuntu-20.04, macos-latest] steps: - uses: actions/checkout@v2 with: diff --git a/Changelog.md b/Changelog.md index 73f130721..5f89f7dcb 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,24 @@ +## v2.8.1 +(2022-04-29) +Added: +* add decodeTransactionInput to ABICodec (FISCO-BCOS#360) + +Update: +* optimize java-sdk connection error message (java-sdk#536) + +Fix: +* fix serialize ABIDefinition with fallback failed (java-sdk#302) + +---- +添加: +* ABICodec支持decodeTransactionInput + +更新: +* 优化java-sdk初始化失败错误提示 + +修复: +* 修复ABI fallback接口序列化失败的问题 + ## v2.8.0 (2021-07-27) Added: diff --git a/build.gradle b/build.gradle index 48764a66d..ac0cdf394 100644 --- a/build.gradle +++ b/build.gradle @@ -37,7 +37,7 @@ ext { // integrationTest.mustRunAfter test allprojects { group = 'org.fisco-bcos.java-sdk' - version = '2.8.0-GMT0018' + version = '2.8.1' apply plugin: 'maven' apply plugin: 'maven-publish' apply plugin: 'idea' diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/ABICodec.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/ABICodec.java index 060f3a7d7..97e490ae4 100644 --- a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/ABICodec.java +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/ABICodec.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.fisco.bcos.sdk.abi.wrapper.ABICodecJsonWrapper; import org.fisco.bcos.sdk.abi.wrapper.ABICodecObject; @@ -303,9 +304,58 @@ public List decodeMethod(String ABI, String methodName, String output) throws ABICodecException { return decodeMethodAndGetOutputObject(ABI, methodName, output).getLeft(); } + /** + * decode the input string into json + * + * @param input the transaction input + * @return the decoded json string of the input + */ + public List decodeTransactionInputToString(String ABI, String input) + throws ABICodecException { + String inputWithPrefix = addHexPrefixToString(input); + String methodId = inputWithPrefix.substring(0, 10); + return decodeMethodByIdToString(ABI, methodId, input.substring(10), false); + } - public List decodeMethodById(String ABI, String methodId, String output) + public Pair, List> decodeTransactionInput(String ABI, String input) throws ABICodecException { + String inputWithPrefix = addHexPrefixToString(input); + String methodId = inputWithPrefix.substring(0, 10); + return decodeDataByMethodId(ABI, methodId, input.substring(10), false); + } + + public Pair, List> decodeMethodInput( + String ABI, String input, String methodName, String code) throws ABICodecException { + ContractABIDefinition contractABIDefinition = abiDefinitionFactory.loadABI(ABI); + List methods; + ABICodecObject abiCodecObject = new ABICodecObject(); + ABIObjectFactory abiObjectFactory = new ABIObjectFactory(); + if (StringUtils.equals(methodName, "constructor")) { + String lastCode = StringUtils.substring(code, code.length() - 32, code.length()); + String paramsInput = StringUtils.substringAfter(input, lastCode); + // remove methodId of input + return abiCodecObject.decodeJavaObjectAndOutputObject( + abiObjectFactory.createInputObject(contractABIDefinition.getConstructor()), + paramsInput); + } else { + methods = contractABIDefinition.getFunctions().get(methodName); + } + for (ABIDefinition abiDefinition : methods) { + ABIObject outputABIObject = abiObjectFactory.createInputObject(abiDefinition); + try { + return abiCodecObject.decodeJavaObjectAndOutputObject( + outputABIObject, input.substring(10)); + } catch (Exception e) { + logger.warn(" exception in decodeMethodInput : {}", e.getMessage()); + } + } + String errorMsg = " cannot decode in decodeMethodInput with appropriate interface ABI"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + + public Pair, List> decodeDataByMethodId( + String ABI, String methodId, String data, boolean isOutput) throws ABICodecException { ContractABIDefinition contractABIDefinition = abiDefinitionFactory.loadABI(ABI); ABIDefinition abiDefinition = contractABIDefinition.getABIDefinitionByMethodId(methodId); if (abiDefinition == null) { @@ -313,10 +363,15 @@ public List decodeMethodById(String ABI, String methodId, String output) logger.error(errorMsg); throw new ABICodecException(errorMsg); } - ABIObject outputABIObject = abiObjectFactory.createOutputObject(abiDefinition); + ABIObject outputABIObject = null; + if (isOutput) { + outputABIObject = abiObjectFactory.createOutputObject(abiDefinition); + } else { + outputABIObject = abiObjectFactory.createInputObject(abiDefinition); + } ABICodecObject abiCodecObject = new ABICodecObject(); try { - return abiCodecObject.decodeJavaObject(outputABIObject, output); + return abiCodecObject.decodeJavaObjectAndOutputObject(outputABIObject, data); } catch (Exception e) { logger.error(" exception in decodeMethodByIdToObject : {}", e.getMessage()); } @@ -326,6 +381,11 @@ public List decodeMethodById(String ABI, String methodId, String output) throw new ABICodecException(errorMsg); } + public List decodeMethodById(String ABI, String methodId, String output) + throws ABICodecException { + return decodeDataByMethodId(ABI, methodId, output, true).getLeft(); + } + public List decodeMethodByInterface(String ABI, String methodInterface, String output) throws ABICodecException { FunctionEncoder functionEncoder = new FunctionEncoder(cryptoSuite); @@ -361,6 +421,11 @@ public List decodeMethodToString(String ABI, String methodName, String o public List decodeMethodByIdToString(String ABI, String methodId, String output) throws ABICodecException { + return decodeMethodByIdToString(ABI, methodId, output, true); + } + + public List decodeMethodByIdToString( + String ABI, String methodId, String data, boolean isOutput) throws ABICodecException { ContractABIDefinition contractABIDefinition = abiDefinitionFactory.loadABI(ABI); ABIDefinition abiDefinition = contractABIDefinition.getABIDefinitionByMethodId(methodId); if (abiDefinition == null) { @@ -368,10 +433,15 @@ public List decodeMethodByIdToString(String ABI, String methodId, String logger.error(errorMsg); throw new ABICodecException(errorMsg); } - ABIObject outputABIObject = abiObjectFactory.createOutputObject(abiDefinition); + ABIObject outputABIObject = null; + if (isOutput) { + outputABIObject = abiObjectFactory.createOutputObject(abiDefinition); + } else { + outputABIObject = abiObjectFactory.createInputObject(abiDefinition); + } ABICodecJsonWrapper abiCodecJsonWrapper = new ABICodecJsonWrapper(); try { - return abiCodecJsonWrapper.decode(outputABIObject, output); + return abiCodecJsonWrapper.decode(outputABIObject, data); } catch (UnsupportedOperationException e) { logger.error(" exception in decodeMethodByIdToString : {}", e.getMessage()); } @@ -513,6 +583,13 @@ public List decodeEventByInterfaceToString( return decodeEventByTopicToString(ABI, methodId, log); } + private String addHexPrefixToString(String s) { + if (!s.startsWith("0x")) { + return "0x" + s; + } + return s; + } + private List mergeEventParamsAndTopics( ABIDefinition abiDefinition, List params, List topics) { List ret = new ArrayList<>(); diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABIDefinition.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABIDefinition.java index 4809822ac..1b6abfd3f 100644 --- a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABIDefinition.java +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABIDefinition.java @@ -1,5 +1,7 @@ package org.fisco.bcos.sdk.abi.wrapper; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -26,16 +28,38 @@ * blockchain state), view (specified to not modify the blockchain state), nonpayable (function does * not accept Ether - the default) and payable (function accepts Ether).
*/ +@JsonIgnoreProperties(ignoreUnknown = true) public class ABIDefinition { + public static final String CONSTRUCTOR_TYPE = "constructor"; + public static final String FUNCTION_TYPE = "function"; + public static final String EVENT_TYPE = "event"; + public static final String FALLBACK_TYPE = "fallback"; + public static final String RECEIVE_TYPE = "receive"; + + @JsonProperty("name") private String name; + + @JsonProperty("type") private String type; + + @JsonProperty("constant") private boolean constant; + + @JsonProperty("payable") private boolean payable; + + @JsonProperty("anonymous") private boolean anonymous; + + @JsonProperty("stateMutability") private String stateMutability; + @JsonProperty("inputs") private List inputs; + + @JsonProperty("outputs") private List outputs; + public static List CONSTANT_KEY = Arrays.asList("view"); public ABIDefinition() {} @@ -94,14 +118,19 @@ public static ABIDefinition createDefaultConstructorABIDefinition() { */ public String getMethodSignatureAsString() { StringBuilder result = new StringBuilder(); - result.append(name); + // Fix: the name field of the fallback is empty + if (name != null) { + result.append(name); + } result.append("("); - String params = - getInputs() - .stream() - .map(abi -> abi.getTypeAsString()) - .collect(Collectors.joining(",")); - result.append(params); + if (getInputs() != null) { + String params = + getInputs() + .stream() + .map(abi -> abi.getTypeAsString()) + .collect(Collectors.joining(",")); + result.append(params); + } result.append(")"); return result.toString(); } @@ -113,8 +142,11 @@ public String getMethodSignatureAsString() { * @return the method id */ public String getMethodId(CryptoSuite cryptoSuite) { - FunctionEncoder encoder = new FunctionEncoder(cryptoSuite); - return encoder.buildMethodId(getMethodSignatureAsString()); + if (getType().equals(ABIDefinition.FUNCTION_TYPE)) { + FunctionEncoder encoder = new FunctionEncoder(cryptoSuite); + return encoder.buildMethodId(getMethodSignatureAsString()); + } + return ""; } public boolean isConstant() { diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABIDefinitionFactory.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABIDefinitionFactory.java index f5738ac0f..9072b530e 100644 --- a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABIDefinitionFactory.java +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABIDefinitionFactory.java @@ -1,12 +1,12 @@ package org.fisco.bcos.sdk.abi.wrapper; +import org.fisco.bcos.sdk.abi.ABICodecException; import org.fisco.bcos.sdk.crypto.CryptoSuite; import org.fisco.bcos.sdk.utils.ObjectMapperFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ABIDefinitionFactory { - private static final Logger logger = LoggerFactory.getLogger(ABIDefinitionFactory.class); private CryptoSuite cryptoSuite; @@ -28,12 +28,27 @@ public ContractABIDefinition loadABI(String abi) { ContractABIDefinition contractABIDefinition = new ContractABIDefinition(cryptoSuite); for (ABIDefinition abiDefinition : abiDefinitions) { - if (abiDefinition.getType().equals("constructor")) { + if (abiDefinition.getType().equals(ABIDefinition.CONSTRUCTOR_TYPE)) { contractABIDefinition.setConstructor(abiDefinition); - } else if (abiDefinition.getType().equals("function")) { + } else if (abiDefinition.getType().equals(ABIDefinition.FUNCTION_TYPE)) { contractABIDefinition.addFunction(abiDefinition.getName(), abiDefinition); - } else if (abiDefinition.getType().equals("event")) { + } else if (abiDefinition.getType().equals(ABIDefinition.EVENT_TYPE)) { contractABIDefinition.addEvent(abiDefinition.getName(), abiDefinition); + } else if (abiDefinition.getType().equals(ABIDefinition.FALLBACK_TYPE)) { + if (contractABIDefinition.hasFallbackFunction()) { + throw new ABICodecException("only single fallback is allowed"); + } + contractABIDefinition.setFallbackFunction(abiDefinition); + } else if (abiDefinition.getType().equals(ABIDefinition.RECEIVE_TYPE)) { + if (contractABIDefinition.hasReceiveFunction()) { + throw new ABICodecException("only single receive is allowed"); + } + if (abiDefinition.getStateMutability().equals("payable") == false + && abiDefinition.isPayable() == false) { + throw new ABICodecException( + "the statemutability of receive can only be payable"); + } + contractABIDefinition.setReceiveFunction(abiDefinition); } else { // skip and do nothing } diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ContractABIDefinition.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ContractABIDefinition.java index a8b9fc9cb..e5244c78d 100644 --- a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ContractABIDefinition.java +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ContractABIDefinition.java @@ -18,6 +18,8 @@ public class ContractABIDefinition { private Map> events = new HashMap<>(); // method id => function private Map methodIDToFunctions = new HashMap<>(); + private ABIDefinition fallbackFunction; + private ABIDefinition receiveFunction; // event topic => topic private Map eventTopicToEvents = new HashMap<>(); private CryptoSuite cryptoSuite; @@ -107,4 +109,28 @@ public ABIDefinition getABIDefinitionByMethodId(String methodId) { public ABIDefinition getABIDefinitionByEventTopic(String topic) { return eventTopicToEvents.get(Numeric.prependHexPrefix(topic)); } + + public ABIDefinition getFallbackFunction() { + return fallbackFunction; + } + + public void setFallbackFunction(ABIDefinition fallbackFunction) { + this.fallbackFunction = fallbackFunction; + } + + public boolean hasFallbackFunction() { + return this.fallbackFunction != null; + } + + public boolean hasReceiveFunction() { + return this.receiveFunction != null; + } + + public ABIDefinition getReceiveFunction() { + return receiveFunction; + } + + public void setReceiveFunction(ABIDefinition receiveFunction) { + this.receiveFunction = receiveFunction; + } } diff --git a/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABICodecTest.java b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABICodecTest.java index 3fb9a37b0..a02fd1ba8 100644 --- a/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABICodecTest.java +++ b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABICodecTest.java @@ -1,15 +1,24 @@ package org.fisco.bcos.sdk.test.abi; +import java.io.IOException; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import org.fisco.bcos.sdk.abi.ABICodec; import org.fisco.bcos.sdk.abi.ABICodecException; import org.fisco.bcos.sdk.abi.wrapper.ABICodecObject; import org.fisco.bcos.sdk.abi.wrapper.ABIDefinition; +import org.fisco.bcos.sdk.abi.wrapper.ABIDefinitionFactory; import org.fisco.bcos.sdk.abi.wrapper.ABIObject; import org.fisco.bcos.sdk.abi.wrapper.ABIObjectFactory; import org.fisco.bcos.sdk.abi.wrapper.ContractABIDefinition; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; import org.junit.Assert; import org.junit.Test; @@ -227,9 +236,13 @@ public class ABICodecTest { + " \"payable\": false,\n" + " \"stateMutability\": \"nonpayable\",\n" + " \"type\": \"fallback\"\n" + + " },\n" + + " {\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"payable\",\n" + + " \"type\": \"receive\"\n" + " }\n" + "]"; - // int a, Info[] memory b, string memory c /* * { @@ -291,7 +304,40 @@ function test(int a, Info[] memory b, string memory c) public returns(int) { private String encodedWithMethodId = "0x00a3c75d" + encoded; @Test - public void testEncodeFromString() { + public void testEncodeFromString() throws IOException { + CryptoSuite cryptoSuite = new CryptoSuite(CryptoType.ECDSA_TYPE); + ABIDefinitionFactory abiDefinitionFactory = new ABIDefinitionFactory(cryptoSuite); + ContractABIDefinition abiDefinition = abiDefinitionFactory.loadABI(abiDesc); + // check the fallback function + Assert.assertTrue(abiDefinition.getFallbackFunction() != null); + // check the content of the fallback function + Assert.assertTrue(abiDefinition.getFallbackFunction().getStateMutability().equals( "nonpayable")); + Assert.assertTrue(abiDefinition.getFallbackFunction().isPayable() == false); + Assert.assertTrue(abiDefinition.getFallbackFunction().getType().equals("fallback")); + + // check receive functions + Assert.assertTrue(abiDefinition.getReceiveFunction() != null); + Assert.assertTrue(abiDefinition.getReceiveFunction().getType().equals("receive")); + + // check serialization and deserialization + ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(); + byte[] encodedABIDefinitions = objectMapper.writeValueAsBytes(abiDefinition.getFallbackFunction()); + // decode + ABIDefinition decodedABIDefinition = objectMapper.readValue(encodedABIDefinitions, ABIDefinition.class); + Assert.assertTrue(decodedABIDefinition.getStateMutability().equals( "nonpayable")); + Assert.assertTrue(decodedABIDefinition.isPayable() == false); + Assert.assertTrue(decodedABIDefinition.getType().equals("fallback")); + // test encode/decode for all the functions + for(String key : abiDefinition.getFunctions().keySet()) + { + List abiDefinitions = abiDefinition.getFunctions().get(key); + for(int i = 0; i < abiDefinitions.size(); i++) { + ABIDefinition functionAbiDefinition = abiDefinitions.get(i); + encodedABIDefinitions = objectMapper.writeValueAsBytes(functionAbiDefinition); + decodedABIDefinition = objectMapper.readValue(encodedABIDefinitions, ABIDefinition.class); + } + } + List args = new ArrayList(); args.add("100"); // [{"name": "Hello world!", "count": 100, "items": [{"a": 1, "b": 2, "c": 3}]}, {"name": @@ -401,9 +447,21 @@ public void testEncodeByInterface() { argsObjects.add(a); try { String s1 = abiCodec.encodeMethodByInterface("call(uint256[2],uint256[],bytes,address)", argsObjects); - String abi = "[{\"constant\":false,\"inputs\":[{\"name\":\"u1\",\"type\":\"uint256[2]\"},{\"name\":\"u2\",\"type\":\"uint256[]\"},{\"name\":\"b\",\"type\":\"bytes\"},{\"name\":\"a\",\"type\":\"address\"}],\"name\":\"call\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"u\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"a\",\"type\":\"uint256\"},{\"name\":\"s\",\"type\":\"string\"}],\"name\":\"add\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"u\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"LogAdd1\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"u\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"LogAdd2\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"u\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"a\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"s\",\"type\":\"string\"}],\"name\":\"LogAdd3\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"LogAdd4\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"LogAdd5\",\"type\":\"event\"}]"; + String abi = "[{\"inputs\":[{\"name\":\"u1\",\"type\":\"uint256[2]\"},{\"name\":\"u2\",\"type\":\"uint256[]\"},{\"name\":\"b\",\"type\":\"bytes\"},{\"name\":\"a\",\"type\":\"address\"}],\"name\":\"call\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"u\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"a\",\"type\":\"uint256\"},{\"name\":\"s\",\"type\":\"string\"}],\"name\":\"add\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"u\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"LogAdd1\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"u\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"LogAdd2\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"u\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"a\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"s\",\"type\":\"string\"}],\"name\":\"LogAdd3\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"LogAdd4\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"LogAdd5\",\"type\":\"event\"}]"; String s2 = abiCodec.encodeMethod(abi, "call", argsObjects); Assert.assertEquals(s1, s2); + // test ABIDefinition + // check constant + CryptoSuite cryptoSuite = new CryptoSuite(CryptoType.ECDSA_TYPE); + ABIDefinitionFactory abiDefinitionFactory = new ABIDefinitionFactory(cryptoSuite); + ContractABIDefinition abiDefinition = abiDefinitionFactory.loadABI(abi); + Map> functions = abiDefinition.getFunctions(); + Assert.assertTrue(functions.containsKey("call")); + List callABIDefinition = functions.get("call"); + Assert.assertEquals(1, callABIDefinition.size()); + Assert.assertTrue(callABIDefinition.get(0).isConstant()); + // check without + } catch (ABICodecException e) { Assert.fail(e.getMessage()); } diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/ChannelImp.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/ChannelImp.java index 580165c25..60f032513 100644 --- a/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/ChannelImp.java +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/ChannelImp.java @@ -89,11 +89,11 @@ public void start() { network.start(); checkConnectionsToStartPeriodTask(); running = true; - logger.debug("Start the channel success"); + logger.debug("====> Start the channel success"); } catch (NetworkException e) { network.stop(); - logger.error("init channel network error, {} ", e.getMessage()); - throw new ChannelException("init channel network error: " + e.getMessage(), e); + logger.error("====> init channel network error, {} ", e.getMessage()); + throw new ChannelException("init channel network error!\n" + e.getMessage(), e); } } @@ -115,13 +115,7 @@ private void checkConnectionsToStartPeriodTask() { connectionInfoStr += peer + ", "; } - String baseMessage = - " nodes: " - + connectionInfoStr - + "java version: " - + System.getProperty("java.version") - + " ,java vendor: " - + System.getProperty("java.vm.vendor"); + String baseMessage = " nodes: " + connectionInfoStr; if (getAvailablePeer().size() == 0) { String errorMessage = " Failed to connect to " + baseMessage; diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/config/ConfigOption.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/ConfigOption.java index 1d3123830..0869c0bf5 100644 --- a/sdk-core/src/main/java/org/fisco/bcos/sdk/config/ConfigOption.java +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/ConfigOption.java @@ -21,6 +21,7 @@ import org.fisco.bcos.sdk.config.model.AmopConfig; import org.fisco.bcos.sdk.config.model.ConfigProperty; import org.fisco.bcos.sdk.config.model.CryptoMaterialConfig; +import org.fisco.bcos.sdk.config.model.CryptoProviderConfig; import org.fisco.bcos.sdk.config.model.NetworkConfig; import org.fisco.bcos.sdk.config.model.ThreadPoolConfig; import org.fisco.bcos.sdk.model.CryptoType; @@ -37,6 +38,7 @@ public class ConfigOption { private AmopConfig amopConfig; private NetworkConfig networkConfig; private ThreadPoolConfig threadPoolConfig; + private CryptoProviderConfig cryptoProviderConfig; private ConfigProperty configProperty; public ConfigOption(ConfigProperty configProperty) throws ConfigException { @@ -54,6 +56,8 @@ public ConfigOption(ConfigProperty configProperty, int cryptoType) throws Config networkConfig = new NetworkConfig(configProperty); // load threadPoolConfig threadPoolConfig = new ThreadPoolConfig(configProperty); + // load cryptoProviderConfig + cryptoProviderConfig = new CryptoProviderConfig(configProperty); // init configProperty this.configProperty = configProperty; } @@ -101,4 +105,12 @@ public ThreadPoolConfig getThreadPoolConfig() { public void setThreadPoolConfig(ThreadPoolConfig threadPoolConfig) { this.threadPoolConfig = threadPoolConfig; } + + public CryptoProviderConfig getCryptoProviderConfig() { + return cryptoProviderConfig; + } + + public void setCryptoProviderConfig(CryptoProviderConfig cryptoProviderConfig) { + this.cryptoProviderConfig = cryptoProviderConfig; + } } diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/ConfigProperty.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/ConfigProperty.java index d584a5f78..53f33f778 100644 --- a/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/ConfigProperty.java +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/ConfigProperty.java @@ -42,6 +42,7 @@ public class ConfigProperty { public List amop; public Map account; public Map threadPool; + public Map cryptoProvider; public Map getCryptoMaterial() { return cryptoMaterial; @@ -83,6 +84,14 @@ public void setThreadPool(Map threadPool) { this.threadPool = threadPool; } + public Map getCryptoProvider() { + return cryptoProvider; + } + + public void setCryptoProvider(Map cryptoProvider) { + this.cryptoProvider = cryptoProvider; + } + public static String getValue(Map config, String key, String defaultValue) { if (config == null || config.get(key) == null) { return defaultValue; @@ -101,10 +110,6 @@ public static InputStream getConfigInputStream(String configFilePath) throws Con return inputStream; } } catch (IOException e) { - logger.warn( - "Load config from {} failed, trying to load from the classpath, e: {}", - configFilePath, - e); if (inputStream != null) { try { inputStream.close(); @@ -115,6 +120,10 @@ public static InputStream getConfigInputStream(String configFilePath) throws Con } // try to load from the class path ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + logger.info( + "Load config from {} failed, trying to load from the resourcePath {}", + configFilePath, + classLoader.getResource("").getPath()); inputStream = classLoader.getResourceAsStream(configFilePath); return inputStream; } diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/CryptoProviderConfig.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/CryptoProviderConfig.java new file mode 100644 index 000000000..896c1a082 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/CryptoProviderConfig.java @@ -0,0 +1,31 @@ +package org.fisco.bcos.sdk.config.model; + +import static org.fisco.bcos.sdk.model.CryptoProviderType.SSM; + +import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CryptoProviderConfig { + private static Logger logger = LoggerFactory.getLogger(CryptoProviderConfig.class); + private String type; + + protected CryptoProviderConfig() {} + + public CryptoProviderConfig(ConfigProperty configProperty) { + Map cryptoProvider = configProperty.getCryptoProvider(); + if (cryptoProvider != null) { + this.type = ConfigProperty.getValue(cryptoProvider, "type", SSM); + } else { + type = SSM; + } + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/network/ChannelHandler.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/ChannelHandler.java index 35842fea0..2577cc679 100644 --- a/sdk-core/src/main/java/org/fisco/bcos/sdk/network/ChannelHandler.java +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/ChannelHandler.java @@ -91,12 +91,11 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exc } } else { logger.error( - " handshake failed, host: {}, port: {}, message: {}, cause: {} ", + " handshake failed, host: {}, port: {}, reason: {}, error stack: {} ", host, port, - e.cause().getMessage(), + e.cause().getLocalizedMessage(), e.cause()); - ctx.disconnect(); ctx.close(); } diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/network/ConnectionManager.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/ConnectionManager.java index beb46d78f..af7f28404 100644 --- a/sdk-core/src/main/java/org/fisco/bcos/sdk/network/ConnectionManager.java +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/ConnectionManager.java @@ -36,6 +36,7 @@ import io.netty.handler.timeout.IdleStateHandler; import io.netty.util.concurrent.Future; import java.io.IOException; +import java.nio.channels.ClosedChannelException; import java.security.Security; import java.util.ArrayList; import java.util.List; @@ -47,9 +48,11 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import javax.net.ssl.SSLHandshakeException; import org.fisco.bcos.sdk.config.ConfigOption; import org.fisco.bcos.sdk.model.CryptoType; import org.fisco.bcos.sdk.model.RetCode; +import org.fisco.bcos.sdk.utils.SystemInformation; import org.fisco.bcos.sdk.utils.ThreadPoolService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,6 +72,7 @@ public class ConnectionManager { private Bootstrap bootstrap = new Bootstrap(); private List connChannelFuture = new ArrayList(); private ScheduledExecutorService reconnSchedule = new ScheduledThreadPoolExecutor(1); + private int cryptoType; public ConnectionManager(ConfigOption configOption, MsgHandler msgHandler) { this(configOption.getNetworkConfig().getPeers(), msgHandler); @@ -115,7 +119,7 @@ public void startConnect(ConfigOption configOption) throws NetworkException { for (int i = 0; i < connectionInfoList.size(); i++) { ConnectionInfo connInfo = connectionInfoList.get(i); ChannelFuture connectFuture = connChannelFuture.get(i); - if (checkConnectionResult(connInfo, connectFuture, errorMessageList)) { + if (checkConnectionResult(cryptoType, connInfo, connectFuture, errorMessageList)) { atLeastOneConnectSuccess = true; } } @@ -125,20 +129,20 @@ public void startConnect(ConfigOption configOption) throws NetworkException { logger.error(" all connections have failed, {} ", errorMessageList); String errorMessageString = ""; for (RetCode errorRetCode : errorMessageList) { - errorMessageString += errorRetCode.getMessage() + "\n"; + errorMessageString += "* " + errorRetCode.getMessage() + "\n"; } for (RetCode errorRetCode : errorMessageList) { if (errorRetCode.getCode() == NetworkException.SSL_HANDSHAKE_FAILED) { throw new NetworkException( - " Failed to connect to all the nodes! errorMessage: \n" - + errorMessageString, + "Failed to connect to all the nodes!\n" + errorMessageString, NetworkException.SSL_HANDSHAKE_FAILED); } } throw new NetworkException( - " Failed to connect to all the nodes! errorMessage: \n" + errorMessageString, + "Failed to connect to all the nodes!\n" + errorMessageString, NetworkException.CONNECT_FAILED); } + cryptoType = configOption.getCryptoMaterialConfig().getSslCryptoType(); logger.debug(" start connect end. "); } @@ -192,7 +196,8 @@ private void reconnect() { ChannelFuture connectFuture = bootstrap.connect(connectionInfo.getIp(), connectionInfo.getPort()); List errorMessageList = new ArrayList<>(); - if (checkConnectionResult(connectionInfo, connectFuture, errorMessageList)) { + if (checkConnectionResult( + cryptoType, connectionInfo, connectFuture, errorMessageList)) { logger.info( " reconnect to {}:{} success", connectionInfo.getIp(), @@ -350,27 +355,26 @@ protected void initChannel(SocketChannel ch) throws Exception { } private boolean checkConnectionResult( - ConnectionInfo connInfo, ChannelFuture connectFuture, List errorMessageList) { + int cryptoType, + ConnectionInfo connInfo, + ChannelFuture connectFuture, + List errorMessageList) { connectFuture.awaitUninterruptibly(); if (!connectFuture.isSuccess()) { + String errorMessage = + "connect to " + + connInfo.getIp() + + ":" + + connInfo.getPort() + + " failed! Please make sure the nodes have been started, and the network between the SDK and the nodes are connected normally."; /** connect failed. */ if (Objects.isNull(connectFuture.cause())) { - logger.error("connect to {}:{} failed. ", connInfo.getIp(), connInfo.getPort()); + logger.error("{}", errorMessage); } else { - logger.error( - "connect to {}:{} failed. {}", - connInfo.getIp(), - connInfo.getPort(), - connectFuture.cause().getMessage()); + errorMessage += "reason: " + connectFuture.cause().getLocalizedMessage() + "\n"; + logger.error("{}, cause: {}", errorMessage, connectFuture.cause().getMessage()); } - errorMessageList.add( - new RetCode( - NetworkException.CONNECT_FAILED, - "connect to " - + connInfo.getIp() - + ":" - + connInfo.getPort() - + " failed")); + errorMessageList.add(new RetCode(NetworkException.CONNECT_FAILED, errorMessage)); return false; } else { /** connect success, check ssl handshake result. */ @@ -379,7 +383,7 @@ private boolean checkConnectionResult( "! Please make sure the certificate is correctly configured and copied, ensure that the SDK and the node are in the same agency!"; if (Objects.isNull(sslhandler)) { String sslHandshakeFailedMessage = - " ssl handshake failed:/" + "ssl handshake failed:/" + connInfo.getIp() + ":" + connInfo.getPort() @@ -391,18 +395,48 @@ private boolean checkConnectionResult( return false; } - Future sshHandshakeFuture = + Future sslHandshakeFuture = sslhandler.handshakeFuture().awaitUninterruptibly(); - if (sshHandshakeFuture.isSuccess()) { - logger.trace(" ssl handshake success {}:{}", connInfo.getIp(), connInfo.getPort()); + if (sslHandshakeFuture.isSuccess()) { + logger.info(" ssl handshake success {}:{}", connInfo.getIp(), connInfo.getPort()); return true; } else { String sslHandshakeFailedMessage = - " ssl handshake failed:/" + "ssl handshake failed:/" + connInfo.getIp() + ":" + connInfo.getPort() - + checkerMessage; + + "\n"; + if (sslHandshakeFuture.cause() instanceof SSLHandshakeException) { + if (cryptoType == CryptoType.ECDSA_TYPE + && !SystemInformation.supportSecp256K1) { + sslHandshakeFailedMessage += + " reason: secp256k1 algorithm is disabled by the current jdk. Please enable secp256k1 or replace to jdk that supports secp256k1."; + } else { + SSLHandshakeException e = + (SSLHandshakeException) sslHandshakeFuture.cause(); + sslHandshakeFailedMessage += + " reason: " + + e.getLocalizedMessage() + + ". Please make sure the certificate are correctly configured and copied."; + } + } else if (sslHandshakeFuture.cause() instanceof ClosedChannelException) { + ClosedChannelException e = (ClosedChannelException) sslHandshakeFuture.cause(); + if (cryptoType == CryptoType.ECDSA_TYPE) { + sslHandshakeFailedMessage += + " reason: The node closes the connection. Maybe connect to the sm node with ecdsa context or the node and the SDK are not belong to the same agency."; + } else { + sslHandshakeFailedMessage += + " reason: The node closes the connection. Maybe connect to the ecdsa node with sm context or the node and the SDK are not belong to the same agency."; + } + } else { + sslHandshakeFailedMessage += + " reason: " + + sslHandshakeFuture.cause().getLocalizedMessage() + + " Please check if there is a netty conflict, the netty version currently supported by the sdk is:" + + SystemInformation.nettyVersion; + } + logger.error(sslHandshakeFailedMessage); errorMessageList.add( new RetCode( diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/network/NetworkImp.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/NetworkImp.java index 71756dc7c..cd94c0d24 100644 --- a/sdk-core/src/main/java/org/fisco/bcos/sdk/network/NetworkImp.java +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/NetworkImp.java @@ -110,17 +110,16 @@ private CheckCertExistenceResult checkCertExistence(boolean isSM) throws Network CheckCertExistenceResult result = new CheckCertExistenceResult(); result.setCheckPassed(true); - String errorMessage = ""; - errorMessage = errorMessage + "Please make sure "; + String errorMessage = "["; if (configOption.getCryptoMaterialConfig().getCaInputStream() == null) { result.setCheckPassed(false); errorMessage = - errorMessage + configOption.getCryptoMaterialConfig().getCaCertPath() + " "; + errorMessage + configOption.getCryptoMaterialConfig().getCaCertPath() + ","; } if (configOption.getCryptoMaterialConfig().getSdkCertInputStream() == null) { result.setCheckPassed(false); errorMessage = - errorMessage + configOption.getCryptoMaterialConfig().getSdkCertPath() + " "; + errorMessage + configOption.getCryptoMaterialConfig().getSdkCertPath() + ","; } if (configOption.getCryptoMaterialConfig().getSdkPrivateKeyInputStream() == null) { @@ -128,11 +127,11 @@ private CheckCertExistenceResult checkCertExistence(boolean isSM) throws Network errorMessage = errorMessage + configOption.getCryptoMaterialConfig().getSdkPrivateKeyPath() - + " "; + + ","; } if (!isSM) { - errorMessage = errorMessage + "exists!"; + errorMessage = errorMessage + "]"; result.setErrorMessage(errorMessage); return result; } @@ -141,113 +140,132 @@ private CheckCertExistenceResult checkCertExistence(boolean isSM) throws Network errorMessage = errorMessage + configOption.getCryptoMaterialConfig().getEnSSLPrivateKeyPath() - + " "; + + ","; result.setCheckPassed(false); } if (configOption.getCryptoMaterialConfig().getEnSSLCertInputStream() == null) { errorMessage = errorMessage + configOption.getCryptoMaterialConfig().getEnSSLCertPath() - + " "; + + ","; result.setCheckPassed(false); } } - errorMessage = errorMessage + "exist!"; + errorMessage = errorMessage + "]"; result.setErrorMessage(errorMessage); return result; } @Override public void start() throws NetworkException { - boolean tryEcdsaConnect = false; CheckCertExistenceResult result = null; String ecdsaCryptoInfo = configOption.getCryptoMaterialConfig().toString(); + String tipsInformation = "\n* TRACE INFORMATION:\n----------------------------\n"; try { try { + tipsInformation += "====> STEP1: try to connect nodes with ecdsa context...\n"; + logger.info("{}", tipsInformation); result = checkCertExistence(false); if (result.isCheckPassed()) { - logger.debug("start connManager with ECDSA sslContext"); + String message = + "<==== STEP1-1: Load certificates for ecdsa context success..."; + tipsInformation += message + "\n"; + logger.info("====> {}, start connManager with ECDSA sslContext", message); connManager.startConnect(configOption); connManager.startReconnectSchedule(); return; } else { - logger.warn( - "Try to connect node with ECDSA sslContext failed, the tried NON-SM certPath: " - + ecdsaCryptoInfo - + ", currentPath: " - + new File("").getAbsolutePath()); + String errorMessage = + "<==== STEP1 Result: try to connect nodes with ecdsa context failed for cert missing\n* Missed certificates: " + + result.getErrorMessage() + + "\n"; + errorMessage += "currentPath: " + new File("").getAbsolutePath() + "\n"; + tipsInformation += errorMessage + "\n"; + logger.warn(errorMessage); } } catch (NetworkException e) { - configOption.reloadConfig(CryptoType.SM_TYPE); if (e.getErrorCode() == NetworkException.CONNECT_FAILED) { - String errorMessage = e.getMessage(); - errorMessage += - "\n* If your blockchain is NON-SM,please provide the NON-SM certificates: " - + ecdsaCryptoInfo - + ".\n"; - errorMessage += - "\n* If your blockchain is SM, please provide the SM certificates: " - + configOption.getCryptoMaterialConfig().toString() - + "\n"; - throw new NetworkException( - errorMessage + "\n" + SystemInformation.getSystemInformation()); + String errorMessage = "<==== connect nodes failed, reason:\n" + e.getMessage(); + tipsInformation += errorMessage + "\n"; + logger.warn("{}", errorMessage); + throw new NetworkException(tipsInformation); } // means that all the ECDSA certificates exist - tryEcdsaConnect = true; + String errorMessage = + "<==== STEP1 Result: try to connect nodes with ecdsa context failed. reason:\n" + + e.getMessage(); + tipsInformation += errorMessage + "\n"; + logger.info("{}", errorMessage); + configOption.reloadConfig(CryptoType.SM_TYPE); connManager.stopNetty(); - logger.debug( - "start connManager with the ECDSA sslContext failed, try to use SM sslContext, error info: {}", - e.getMessage()); } - logger.debug("start connManager with SM sslContext"); + String message = "----------------------------\n"; + message += + "====> STEP2: connect nodes with ecdsa context failed, try to connect nodes with sm-context..."; + tipsInformation += message + "\n"; + logger.info("{}", message); configOption.reloadConfig(CryptoType.SM_TYPE); result = checkCertExistence(true); if (!result.isCheckPassed()) { - if (tryEcdsaConnect) { - String errorMessage = - "\n* Try init the sslContext failed.\n\n* If your blockchain channel config is NON-SM, please provide the NON-SM certificates: " - + ecdsaCryptoInfo - + ".\n"; - errorMessage += - "\n* If your blockchain channel config is SM, please provide the missing certificates: " - + result.getErrorMessage() - + "\n"; - throw new NetworkException(errorMessage); - } else { - String errorMessage = - "\n# Not providing all the certificates to connect to the node! Please provide the certificates to connect with the block-chain.\n"; - errorMessage += - "\n* If your blockchain is NON-SM, please provide the NON-SM certificates: " - + ecdsaCryptoInfo - + ". \n"; - errorMessage += - "\n* If your blockchain is SM, please provide the SM certificates: " - + configOption.getCryptoMaterialConfig().toString() - + "\n"; - throw new NetworkException(errorMessage); - } + message = + "<==== STEP2 Result: connect with sm context failed for cert missing.\n* Missed certificates: \n" + + result.getErrorMessage() + + "\n"; + message += "currentPath: " + new File("").getAbsolutePath() + "\n"; + message += "----------------------------\n"; + message += + "<====> Error: try to connect nodes with both ecdsa and sm context failed <====>\n"; + message += + "<====>\033[1;31m Please refer to github issue: " + + SystemInformation.connectionFaqIssueUrl + + " \033[0m\n"; + message += + "<====>\033[1;31m Please refer to fisco-docs: " + + SystemInformation.connectionFaqDocUrl + + " \033[0m\n"; + message += "----------------------------\n"; + + message += SystemInformation.getSystemInformation(); + tipsInformation += message + "\n"; + logger.warn("{}", message); + throw new NetworkException(tipsInformation); } try { + message = "<==== STEP2-1: Load certificates for sm context success..."; + tipsInformation += message + "\n"; + logger.info("{}", message); // create a new connectionManager to connect the node with the SM sslContext connManager = new ConnectionManager(configOption, handler); connManager.startConnect(configOption); connManager.startReconnectSchedule(); - } catch (NetworkException e) { - String errorMessage = e.getMessage(); - errorMessage += - "\n* If your blockchain channel config is NON-SM, please provide the NON-SM certificates: " - + ecdsaCryptoInfo - + ".\n"; - errorMessage += - "\n* If your blockchain channel config is SM, please provide the SM certificates: " - + configOption.getCryptoMaterialConfig().toString() + } catch (Exception e) { + message = + "<==== STEP2 Result: connect nodes with sm context failed for " + + e.getMessage() + "\n"; - throw new NetworkException( - errorMessage + "\n" + SystemInformation.getSystemInformation()); + message += "----------------------------\n"; + message += + "<====> Error: try to connect nodes with both ecdsa and sm context failed <====>\n"; + message += + "<====>\033[1;31m Please refer to github issue: " + + SystemInformation.connectionFaqIssueUrl + + " \033[0m\n"; + message += + "<====>\033[1;31m Please refer to fisco-docs: " + + SystemInformation.connectionFaqDocUrl + + " \033[0m\n"; + message += "----------------------------\n"; + + message += SystemInformation.getSystemInformation(); + tipsInformation += message; + logger.warn("{}, e: ", message, e); + throw new NetworkException(tipsInformation); } } catch (ConfigException e) { throw new NetworkException(e); + } catch (Exception e) { + throw new NetworkException(e); } } diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/SystemInformation.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/SystemInformation.java index bd7295870..b44b0bfcf 100644 --- a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/SystemInformation.java +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/SystemInformation.java @@ -19,6 +19,14 @@ import java.util.List; public class SystemInformation { + // Note: must update the version if publish new-version + private static final String sdkVersion = "2.8.1"; + public static final String connectionFaqIssueUrl = + "https://github.com/FISCO-BCOS/java-sdk/issues/536"; + public static final String connectionFaqDocUrl = + "https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/faq/connect.html"; + public static final String nettyVersion = "4.1.53.Final"; + public static class InformationProperty { private String key; private String value; @@ -47,59 +55,57 @@ public void setValue(String value) { public static final InformationProperty JAVA_VERSION = new InformationProperty("Java Version", System.getProperty("java.version")); + public static final InformationProperty JDK_DISABLED_NAMED_CURVES = + new InformationProperty( + "JDK Disabled NamedCurves", System.getProperty("jdk.disabled.namedCurves")); + public static final InformationProperty JDK_DISABLE_NATIVE_OPTION = + new InformationProperty( + "JDK DisableNative Option", System.getProperty("jdk.sunec.disableNative")); public static final InformationProperty OS_NAME = new InformationProperty("OS Name", System.getProperty("os.name")); public static final InformationProperty OS_ARCH = new InformationProperty("OS Arch", System.getProperty("os.arch")); public static final InformationProperty OS_VERSION = new InformationProperty("OS Version", System.getProperty("os.version")); - public static final InformationProperty VENDOR_NAME = - new InformationProperty("Vendor Name", System.getProperty("java.vendor")); - public static final InformationProperty VENDOR_URL = - new InformationProperty("Vendor URL", System.getProperty("java.vendor.url")); public static final InformationProperty JVM_VERSION = new InformationProperty("JVM Version", System.getProperty("java.vm.version")); - public static final InformationProperty JVM_NAME = - new InformationProperty("JVM Name", System.getProperty("java.vm.name")); - public static final InformationProperty JVM_VENDOR = - new InformationProperty("JVM Vendor", System.getProperty("java.vm.vendor")); - public static final InformationProperty JAVA_LIB_PATH = - new InformationProperty("JAVA Library Path", System.getProperty("java.library.path")); - public static final InformationProperty JDK_DISABLED_NAMED_CURVES = - new InformationProperty( - "JDK Disabled NamedCurves", System.getProperty("jdk.disabled.namedCurves")); - public static final InformationProperty JDK_DISABLE_NATIVE_OPTION = - new InformationProperty( - "JDK DisableNative Option", System.getProperty("jdk.sunec.disableNative")); - + public static final InformationProperty JAVA_VENDOR = + new InformationProperty("JVM Vendor", System.getProperty("java.vendor")); + public static final InformationProperty JAVA_VENDOR_URL = + new InformationProperty("JVM Vendor URL", System.getProperty("java.vendor.url")); private static String systemInformation; - public static List EXPECTED_CURVES = Arrays.asList("secp256k1", "secp256r1"); + public static List EXPECTED_CURVES = Arrays.asList("secp256k1"); + public static boolean supportSecp256K1 = false; static { - systemInformation = "[System Information]:\n"; + systemInformation += "--------- System Information --------- \n"; + systemInformation = "* FISCO BCOS Java SDK Version: " + sdkVersion + "\n"; + String supportedCurves = + Security.getProviders("AlgorithmParameters.EC")[0] + .getService("AlgorithmParameters", "EC") + .getAttribute("SupportedCurves"); + if (supportedCurves.contains("secp256k1")) { + supportSecp256K1 = true; + } + for (String curve : EXPECTED_CURVES) { + if (supportedCurves.contains(curve)) { + systemInformation += "* Support " + curve + " : true\n"; + } else { + systemInformation += "* Support " + curve + " : false\n"; + } + } Field[] fields = SystemInformation.class.getDeclaredFields(); for (Field field : fields) { if (field.getType().equals(InformationProperty.class)) { try { InformationProperty property = (InformationProperty) field.get(null); systemInformation += - "[" + property.getKey() + "] : " + property.getValue() + "\n"; + "* " + property.getKey() + " : " + property.getValue() + "\n"; } catch (IllegalAccessException e) { continue; } } } - String supportedCurves = - Security.getProviders("AlgorithmParameters.EC")[0] - .getService("AlgorithmParameters", "EC") - .getAttribute("SupportedCurves"); - for (String curve : EXPECTED_CURVES) { - if (supportedCurves.contains(curve)) { - systemInformation += "[Support " + curve + "] : true\n"; - } else { - systemInformation += "[Support " + curve + "] : false\n"; - } - } } public static String getSystemInformation() { diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keypair/CryptoKeyPair.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keypair/CryptoKeyPair.java index ad7ffb4c7..e8b5467d4 100644 --- a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keypair/CryptoKeyPair.java +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keypair/CryptoKeyPair.java @@ -88,7 +88,7 @@ public CryptoKeyPair(KeyPair keyPair) { */ CryptoKeyPair(final CryptoResult nativeResult) { this.hexPrivateKey = nativeResult.privateKey; - this.hexPublicKey = nativeResult.publicKey; + this.hexPublicKey = getPublicKeyNoPrefix(nativeResult.publicKey); } /** @@ -164,7 +164,7 @@ public CryptoKeyPair createKeyPair(String hexPrivateKey) { return createKeyPair(keyPair); } - protected static String getPublicKeyNoPrefix(String publicKeyStr) { + public static String getPublicKeyNoPrefix(String publicKeyStr) { String publicKeyNoPrefix = Numeric.cleanHexPrefix(publicKeyStr); if (publicKeyNoPrefix.startsWith(UNCOMPRESSED_PUBLICKEY_FLAG_STR) && publicKeyNoPrefix.length() @@ -188,7 +188,7 @@ protected static String getPublicKeyNoPrefix(String publicKeyStr) { public String getAddress() { // Note: The generated publicKey is prefixed with 04, When calculate the address, need to // remove 04 - return getAddress(this.getHexPublicKey().substring(2)); + return getAddress(getPublicKeyNoPrefix(this.hexPublicKey)); } public String getAddress(String publicKey) { diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keypair/SDFSM2KeyPair.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keypair/SDFSM2KeyPair.java index 55134f1fa..26c17b9d4 100644 --- a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keypair/SDFSM2KeyPair.java +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keypair/SDFSM2KeyPair.java @@ -52,11 +52,7 @@ protected SDFSM2KeyPair(long keyIndex, String password) { throw new KeyPairException( "get sdf sm2 internal key public key failed:" + pkResult.getSdfErrorMessage()); } - this.hexPublicKey = - Numeric.getHexKeyWithPrefix( - pkResult.getPublicKey(), - CryptoKeyPair.UNCOMPRESSED_PUBLICKEY_FLAG_STR, - CryptoKeyPair.PUBLIC_KEY_LENGTH_IN_HEX); + this.hexPublicKey = getPublicKeyNoPrefix(pkResult.getPublicKey()); this.isInternalKey = true; } diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keystore/KeyTool.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keystore/KeyTool.java index 6420d5716..9c954d14f 100644 --- a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keystore/KeyTool.java +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keystore/KeyTool.java @@ -138,7 +138,7 @@ public static String getHexedPublicKey(PublicKey publicKey) { byte[] publicKeyBytes = ((BCECPublicKey) publicKey).getQ().getEncoded(false); BigInteger publicKeyValue = new BigInteger(1, Arrays.copyOfRange(publicKeyBytes, 1, publicKeyBytes.length)); - return ("04" + Numeric.toHexStringNoPrefixZeroPadded(publicKeyValue, 128)); + return Numeric.toHexStringNoPrefixZeroPadded(publicKeyValue, 128); } /** @@ -306,7 +306,7 @@ private static Method getMethod( try { return ec5UtilClass.getDeclaredMethod(methodName, parameterTypes); } catch (NoSuchMethodException e) { - logger.warn("get method for EC5Util failed, method name: {}", methodName); + logger.debug("try to get method for EC5Util failed, method name: {}", methodName); return null; } } diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/SDFSM2Signature.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/SDFSM2Signature.java index dcf1dd582..162893abc 100644 --- a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/SDFSM2Signature.java +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/SDFSM2Signature.java @@ -38,7 +38,10 @@ public String signWithStringSignature(final String message, final CryptoKeyPair public String signMessage(String message, CryptoKeyPair keyPair) { CryptoResult hashResult = NativeInterface.sm2ComputeHashE( - Numeric.cleanHexPrefix(keyPair.getHexPublicKey()), + Numeric.getHexKeyWithPrefix( + keyPair.getHexPublicKey(), + UNCOMPRESSED_PUBLICKEY_FLAG_STR, + PUBLIC_KEY_LENGTH_IN_HEX), Numeric.cleanHexPrefix(message)); checkCryptoResult(hashResult); SDFCryptoResult signatureResult; diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/SM2Signature.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/SM2Signature.java index fcd6d93be..cc45cfebb 100644 --- a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/SM2Signature.java +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/SM2Signature.java @@ -41,7 +41,10 @@ public String signMessage(String message, CryptoKeyPair keyPair) { CryptoResult signatureResult = NativeInterface.sm2SignFast( keyPair.getHexPrivateKey(), - keyPair.getHexPublicKey(), + Numeric.getHexKeyWithPrefix( + keyPair.getHexPublicKey(), + CryptoKeyPair.UNCOMPRESSED_PUBLICKEY_FLAG_STR, + CryptoKeyPair.PUBLIC_KEY_LENGTH_IN_HEX), Numeric.cleanHexPrefix(message)); if (signatureResult.wedprErrorMessage != null && !signatureResult.wedprErrorMessage.isEmpty()) { diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/SM2SignatureResult.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/SM2SignatureResult.java index 8447f8e4b..510e069ee 100644 --- a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/SM2SignatureResult.java +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/SM2SignatureResult.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import java.util.List; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; import org.fisco.bcos.sdk.rlp.RlpString; import org.fisco.bcos.sdk.rlp.RlpType; import org.fisco.bcos.sdk.utils.Hex; @@ -24,7 +25,8 @@ public class SM2SignatureResult extends SignatureResult { public SM2SignatureResult(final String hexPublicKey, final String signatureString) { super(signatureString); - this.pub = Hex.decode(hexPublicKey.substring(2)); + // clean 04 prefix + this.pub = Hex.decode(CryptoKeyPair.getPublicKeyNoPrefix(hexPublicKey)); } public SM2SignatureResult(byte[] pub, byte[] r, byte[] s) { diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/vrf/Curve25519VRF.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/vrf/Curve25519VRF.java index 9d4b62508..06ce2c12a 100644 --- a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/vrf/Curve25519VRF.java +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/vrf/Curve25519VRF.java @@ -50,7 +50,7 @@ public String generateVRFProof(String privateKey, String vrfInput) { public boolean verify(String publicKey, String vrfInput, String vrfProof) { SdkResult result = NativeInterface.curve25519VrfVerifyUtf8(publicKey, vrfInput, vrfProof); if (result.wedprErrorMessage != null && !result.wedprErrorMessage.isEmpty()) { - throw new VRFException("verify VRF Proof failed: " + result.wedprErrorMessage); + return false; } return result.booleanResult; } @@ -87,7 +87,7 @@ public BigInteger vrfProofToRandomValue(String vrfProof) { public boolean isValidVRFPublicKey(String vrfPublicKey) { SdkResult result = NativeInterface.curve25519VrfIsValidPublicKey(vrfPublicKey); if (result.wedprErrorMessage != null && !result.wedprErrorMessage.isEmpty()) { - throw new VRFException("invalid VRF public key:" + result.wedprErrorMessage); + return false; } return result.booleanResult; } diff --git a/sdk-crypto/src/test/java/org/fisco/bcos/sdk/crypto/KeyToolTest.java b/sdk-crypto/src/test/java/org/fisco/bcos/sdk/crypto/KeyToolTest.java index 404fe67b5..617f53d62 100644 --- a/sdk-crypto/src/test/java/org/fisco/bcos/sdk/crypto/KeyToolTest.java +++ b/sdk-crypto/src/test/java/org/fisco/bcos/sdk/crypto/KeyToolTest.java @@ -34,9 +34,8 @@ public void testECDSALoadPEMFile() { CryptoType.ECDSA_TYPE, "0x0fc3c4bb89bd90299db4c62be0174c4966286c00"); // check the public key and the privateKey - // Note the 04 prefix Assert.assertEquals( - "04dbbfee4f76f5a3bc3dbc2e6127c4a1f50b7614bff4138a44a79aed3d42f67f9c7aa70570205f9b60a5888c6415b6a830012677b4415a79ccd1533fe5637861df", + "dbbfee4f76f5a3bc3dbc2e6127c4a1f50b7614bff4138a44a79aed3d42f67f9c7aa70570205f9b60a5888c6415b6a830012677b4415a79ccd1533fe5637861df", cryptoKeyPair.getHexPublicKey()); Assert.assertEquals( "bc516b2600eec3a216f457dc14cf83a01ed22d0fc2149fc911dc2ec486fe57a3", @@ -52,7 +51,7 @@ public void testSMLoadPEMFile() { CryptoType.SM_TYPE, "0x40b3558746e8f9a47a474774e8c4a9e67d4e3174"); Assert.assertEquals( - "043b72cd28244c856d3d89b67d1c5ff22e1f26835bafcd63e9a4ad3424a2a57f2b759149f46c696df08b9d9473686675fc6dade744d0c82bdc5598d759e015fd96", + "3b72cd28244c856d3d89b67d1c5ff22e1f26835bafcd63e9a4ad3424a2a57f2b759149f46c696df08b9d9473686675fc6dade744d0c82bdc5598d759e015fd96", cryptoKeyPair.getHexPublicKey()); Assert.assertEquals( "901744c34e2adffc9fd7fb12e8cba2d88a79aaf54be9b4e11660153287489f13", @@ -83,7 +82,7 @@ public void testLoadECDSAP12File() { "123456", "0x45e14c53197adbcb719d915fb93342c25600faaf"); Assert.assertEquals( - "04d7b9e00f56d3f79305359fa2d7db166021e73086bdcd2e7a28d6ed27345e1f2ddecf85db7438e8457fd474ef9c4ceb89abb7d5fa60a22f2902ec26dca52ad5e5", + "d7b9e00f56d3f79305359fa2d7db166021e73086bdcd2e7a28d6ed27345e1f2ddecf85db7438e8457fd474ef9c4ceb89abb7d5fa60a22f2902ec26dca52ad5e5", cryptoKeyPair.getHexPublicKey()); Assert.assertEquals( "c0c8b4d96aa4aefaeeafa157789d528b6010f65059dee796d8757e1171bbcd2c", @@ -100,7 +99,7 @@ public void testLoadSMP12File() { "abcd123", "0x6f68461309925093236df82b51df630a55d32377"); Assert.assertEquals( - "04a809a0176dc24432490697b6ed74995a6716a122a0fa5c73429a259cd73f14995934522288f226a049bbbb803d78f296289bee8fb4f5d7821514e731a57c9f2f", + "a809a0176dc24432490697b6ed74995a6716a122a0fa5c73429a259cd73f14995934522288f226a049bbbb803d78f296289bee8fb4f5d7821514e731a57c9f2f", cryptoKeyPair.getHexPublicKey()); Assert.assertEquals( "d0cbcdfea24e206688ce6c1a63171a24d9e1e0cf5331151ed5406e07fdb38256", diff --git a/sdk-crypto/src/test/java/org/fisco/bcos/sdk/crypto/SignatureTest.java b/sdk-crypto/src/test/java/org/fisco/bcos/sdk/crypto/SignatureTest.java index f062f0c75..fa722ea2a 100644 --- a/sdk-crypto/src/test/java/org/fisco/bcos/sdk/crypto/SignatureTest.java +++ b/sdk-crypto/src/test/java/org/fisco/bcos/sdk/crypto/SignatureTest.java @@ -54,12 +54,16 @@ public void testCryptoSuiteForECDSA() { // generate keyPair CryptoKeyPair keyPair = cryptoSuite.createKeyPair(); CryptoSuite cryptoSuite2 = new CryptoSuite(CryptoType.ECDSA_TYPE, keyPair); - Assert.assertTrue(cryptoSuite2.getCryptoKeyPair().getHexPublicKey().equals(cryptoSuite.getCryptoKeyPair().getHexPublicKey())); - Assert.assertTrue(cryptoSuite2.getCryptoKeyPair().getHexPrivateKey().equals(cryptoSuite.getCryptoKeyPair().getHexPrivateKey())); + System.out.println("cryptoSuite2.getCryptoKeyPair().getHexPublicKey(): " + cryptoSuite2.getCryptoKeyPair().getHexPublicKey()); + System.out.println("cryptoSuite.getCryptoKeyPair().getHexPublicKey(): " + cryptoSuite.getCryptoKeyPair().getHexPublicKey()); + Assert.assertEquals(cryptoSuite2.getCryptoKeyPair().getHexPublicKey(), cryptoSuite.getCryptoKeyPair().getHexPublicKey()); + Assert.assertEquals(cryptoSuite2.getCryptoKeyPair().getHexPrivateKey(), cryptoSuite.getCryptoKeyPair().getHexPrivateKey()); cryptoSuite2 = new CryptoSuite(CryptoType.ECDSA_TYPE, cryptoSuite.getCryptoKeyPair().getHexPrivateKey()); - Assert.assertTrue(cryptoSuite2.getCryptoKeyPair().getHexPublicKey().equals(cryptoSuite.getCryptoKeyPair().getHexPublicKey())); - Assert.assertTrue(cryptoSuite2.getCryptoKeyPair().getHexPrivateKey().equals(cryptoSuite.getCryptoKeyPair().getHexPrivateKey())); + System.out.println("cryptoSuite2.getCryptoKeyPair().getHexPublicKey(): " + cryptoSuite2.getCryptoKeyPair().getHexPublicKey()); + System.out.println("cryptoSuite.getCryptoKeyPair().getHexPublicKey(): " + cryptoSuite.getCryptoKeyPair().getHexPublicKey()); + Assert.assertEquals(cryptoSuite2.getCryptoKeyPair().getHexPublicKey(), cryptoSuite.getCryptoKeyPair().getHexPublicKey()); + Assert.assertEquals(cryptoSuite2.getCryptoKeyPair().getHexPrivateKey(), cryptoSuite.getCryptoKeyPair().getHexPrivateKey()); // test signature testSignature(cryptoSuite, keyPair); @@ -76,7 +80,7 @@ public void testCryptoSuiteForECDSA() { System.out.println("hexedPublicKey: " + hexedPublicKey); System.out.println("keyPair.getHexPublicKey(): " + keyPair.getHexPublicKey()); System.out.println("keyPair.getHexPrivate(): " + keyPair.getHexPrivateKey()); - Assert.assertEquals(hexedPublicKey, keyPair.getHexPublicKey().substring(2)); + Assert.assertEquals(hexedPublicKey, keyPair.getHexPublicKey()); testSignature(cryptoSuite, keyPair); String hexedPrivateKeyStr = "bcec428d5205abe0f0cc8a734083908d9eb8563e31f943d760786edf42ad67dd"; @@ -91,12 +95,12 @@ public void testCryptoSuiteForSM2() { CryptoKeyPair keyPair = cryptoSuite.createKeyPair(); CryptoSuite cryptoSuite2 = new CryptoSuite(CryptoType.SM_TYPE, keyPair); - Assert.assertTrue(cryptoSuite2.getCryptoKeyPair().getHexPublicKey().equals(cryptoSuite.getCryptoKeyPair().getHexPublicKey())); - Assert.assertTrue(cryptoSuite2.getCryptoKeyPair().getHexPrivateKey().equals(cryptoSuite.getCryptoKeyPair().getHexPrivateKey())); + Assert.assertEquals(cryptoSuite2.getCryptoKeyPair().getHexPublicKey(), cryptoSuite.getCryptoKeyPair().getHexPublicKey()); + Assert.assertEquals(cryptoSuite2.getCryptoKeyPair().getHexPrivateKey(), cryptoSuite.getCryptoKeyPair().getHexPrivateKey()); cryptoSuite2 = new CryptoSuite(CryptoType.SM_TYPE, cryptoSuite.getCryptoKeyPair().getHexPrivateKey()); - Assert.assertTrue(cryptoSuite2.getCryptoKeyPair().getHexPublicKey().equals(cryptoSuite.getCryptoKeyPair().getHexPublicKey())); - Assert.assertTrue(cryptoSuite2.getCryptoKeyPair().getHexPrivateKey().equals(cryptoSuite.getCryptoKeyPair().getHexPrivateKey())); + Assert.assertEquals(cryptoSuite2.getCryptoKeyPair().getHexPublicKey(), cryptoSuite.getCryptoKeyPair().getHexPublicKey()); + Assert.assertEquals(cryptoSuite2.getCryptoKeyPair().getHexPrivateKey(), cryptoSuite.getCryptoKeyPair().getHexPrivateKey()); // test signature testSignature(cryptoSuite, keyPair); } @@ -202,8 +206,7 @@ private void testKeyPair(CryptoKeyPair keyPair, String publicKey, String expecte Assert.assertEquals(expectedAddress, keyPair.getAddress(publicKey)); String uncompressedPublicKey = publicKey; boolean contain0x = false; - if(publicKey.startsWith("0x")) - { + if (publicKey.startsWith("0x")) { contain0x = true; uncompressedPublicKey = publicKey.substring(2); } @@ -214,32 +217,28 @@ private void testKeyPair(CryptoKeyPair keyPair, String publicKey, String expecte + uncompressedPublicKey; } String prefix = "04"; - if(contain0x) - { + if (contain0x) { prefix = "0x04"; } Assert.assertEquals(expectedAddress, keyPair.getAddress(prefix + uncompressedPublicKey)); // convert the publicKey into BigInteger - BigInteger uncompressedPublicKeyValue = new BigInteger(uncompressedPublicKey, 16); + BigInteger uncompressedPublicKeyValue = new BigInteger(uncompressedPublicKey, 16); Assert.assertEquals(expectedAddress, "0x" + Hex.toHexString(keyPair.getAddress(uncompressedPublicKeyValue))); // convert the publicKey into bytes byte[] uncompressedPublicKeyBytes = Hex.decode(Numeric.cleanHexPrefix(uncompressedPublicKey)); Assert.assertEquals(expectedAddress, "0x" + Hex.toHexString(keyPair.getAddress(uncompressedPublicKeyBytes))); - if(smCrypto) - { - Assert.assertEquals(expectedAddress, SM2KeyPair.getAddressByPublicKey(publicKey)); - Assert.assertEquals(expectedAddress, SM2KeyPair.getAddressByPublicKey(uncompressedPublicKey)); - Assert.assertEquals(expectedAddress, "0x" + Hex.toHexString(SM2KeyPair.getAddressByPublicKey(uncompressedPublicKeyValue))); - Assert.assertEquals(expectedAddress, "0x" + Hex.toHexString(SM2KeyPair.getAddressByPublicKey(uncompressedPublicKeyBytes))); - - } - else - { - Assert.assertEquals(expectedAddress, ECDSAKeyPair.getAddressByPublicKey(publicKey)); - Assert.assertEquals(expectedAddress, ECDSAKeyPair.getAddressByPublicKey(uncompressedPublicKey)); - Assert.assertEquals(expectedAddress, "0x" + Hex.toHexString(ECDSAKeyPair.getAddressByPublicKey(uncompressedPublicKeyValue))); - Assert.assertEquals(expectedAddress, "0x" + Hex.toHexString(ECDSAKeyPair.getAddressByPublicKey(uncompressedPublicKeyBytes))); + if (smCrypto) { + Assert.assertEquals(expectedAddress, SM2KeyPair.getAddressByPublicKey(publicKey)); + Assert.assertEquals(expectedAddress, SM2KeyPair.getAddressByPublicKey(uncompressedPublicKey)); + Assert.assertEquals(expectedAddress, "0x" + Hex.toHexString(SM2KeyPair.getAddressByPublicKey(uncompressedPublicKeyValue))); + Assert.assertEquals(expectedAddress, "0x" + Hex.toHexString(SM2KeyPair.getAddressByPublicKey(uncompressedPublicKeyBytes))); + + } else { + Assert.assertEquals(expectedAddress, ECDSAKeyPair.getAddressByPublicKey(publicKey)); + Assert.assertEquals(expectedAddress, ECDSAKeyPair.getAddressByPublicKey(uncompressedPublicKey)); + Assert.assertEquals(expectedAddress, "0x" + Hex.toHexString(ECDSAKeyPair.getAddressByPublicKey(uncompressedPublicKeyValue))); + Assert.assertEquals(expectedAddress, "0x" + Hex.toHexString(ECDSAKeyPair.getAddressByPublicKey(uncompressedPublicKeyBytes))); } } @@ -304,7 +303,7 @@ public void testSignature(Hash hasher, Signature signature, CryptoKeyPair keyPai signature.verify( keyPair.getHexPublicKey(), hexMessageWithPrefix, signResult.convertToString())); //verify - String hexPublicKeyWithoutPrefix = keyPair.getHexPublicKey().substring(2); + String hexPublicKeyWithoutPrefix = keyPair.getHexPublicKey(); Assert.assertTrue( signature.verify( hexPublicKeyWithoutPrefix, message, signResult.convertToString())); @@ -343,20 +342,17 @@ public void testSignature(Hash hasher, Signature signature, CryptoKeyPair keyPai try { String invalidMessage = "0xb3b9ce5a0725c1457b8c7872d05accb3887ecc09a50dc7619b53837e4d9f"; SignatureResult signResult = signature.sign(invalidMessage, keyPair); - }catch(SignatureException e) - { + } catch (SignatureException e) { System.out.println("Sign failed for " + e.getMessage()); } try { String invalidMessage = ""; - for(int i = 0; i < 64; i++) - { + for (int i = 0; i < 64; i++) { invalidMessage += "r"; } SignatureResult signResult = signature.sign(invalidMessage, keyPair); - }catch(SignatureException e) - { + } catch (SignatureException e) { System.out.println("Sign failed for " + e.getMessage()); } } @@ -510,10 +506,10 @@ public void testLoadAndStoreKeyPairWithP12(int cryptoType) throws ConfigExceptio System.out.println("P12 orgKeyPair pri: " + orgKeyPair.getHexPrivateKey()); System.out.println("P12 decodedKeyPair pr: " + decodedCryptoKeyPair.getHexPrivateKey()); - Assert.assertTrue( - orgKeyPair.getHexPrivateKey().equals(decodedCryptoKeyPair.getHexPrivateKey())); - Assert.assertTrue( - orgKeyPair.getHexPublicKey().equals(decodedCryptoKeyPair.getHexPublicKey())); + Assert.assertEquals( + orgKeyPair.getHexPrivateKey(), decodedCryptoKeyPair.getHexPrivateKey()); + Assert.assertEquals( + orgKeyPair.getHexPublicKey(), decodedCryptoKeyPair.getHexPublicKey()); // test sign and verify message with String publicP12Path = p12FilePath + ".pub"; diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/decode/TransactionDecoderInterface.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/decode/TransactionDecoderInterface.java index 8551763d1..927cf86cb 100644 --- a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/decode/TransactionDecoderInterface.java +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/decode/TransactionDecoderInterface.java @@ -69,6 +69,18 @@ public TransactionResponse decodeReceiptWithoutValues( String abi, TransactionReceipt transactionReceipt) throws TransactionException, IOException, ABICodecException; + /** + * parse the transaction information from receipt without return values, but with input values + * + * @param abi contract abi + * @param transactionReceipt transaction receipt + * @param constructorCode decode for constructor + * @return the resolved status and other transaction detail + */ + public TransactionResponse decodeReceiptWithoutOutputValues( + String abi, TransactionReceipt transactionReceipt, String constructorCode) + throws TransactionException, IOException, ABICodecException; + /** * parse the transaction events from receipt logs * diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/decode/TransactionDecoderService.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/decode/TransactionDecoderService.java index 2f3d9f368..111b277f7 100644 --- a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/decode/TransactionDecoderService.java +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/decode/TransactionDecoderService.java @@ -72,6 +72,15 @@ public TransactionResponse decodeReceiptWithValues( String abi, String functionName, TransactionReceipt transactionReceipt) throws IOException, ABICodecException, TransactionException { TransactionResponse response = decodeReceiptWithoutValues(abi, transactionReceipt); + // parse the input + if (transactionReceipt.getInput() != null) { + Pair, List> inputObject = + abiCodec.decodeTransactionInput(abi, transactionReceipt.getInput()); + String inputValues = JsonUtils.toJson(inputObject.getLeft()); + response.setInputData(inputValues); + response.setInputObject(inputObject.getLeft()); + response.setInputABIObject(inputObject.getRight()); + } // only successful tx has return values. if (transactionReceipt.getStatus().equals("0x0")) { Pair, List> returnObject = @@ -101,6 +110,24 @@ public TransactionResponse decodeReceiptWithoutValues( return response; } + @Override + public TransactionResponse decodeReceiptWithoutOutputValues( + String abi, TransactionReceipt transactionReceipt, String constructorCode) + throws TransactionException, IOException, ABICodecException { + TransactionResponse response = decodeReceiptWithoutValues(abi, transactionReceipt); + // parse the input + if (transactionReceipt.getInput() != null && transactionReceipt.isStatusOK()) { + Pair, List> inputObject = + abiCodec.decodeMethodInput( + abi, transactionReceipt.getInput(), "constructor", constructorCode); + String inputValues = JsonUtils.toJson(inputObject.getLeft()); + response.setInputData(inputValues); + response.setInputObject(inputObject.getLeft()); + response.setInputABIObject(inputObject.getRight()); + } + return response; + } + @Override public TransactionResponse decodeReceiptStatus(TransactionReceipt receipt) { TransactionResponse response = new TransactionResponse(); diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/manager/AssembleTransactionProcessor.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/manager/AssembleTransactionProcessor.java index 72b5c2972..a0fee8de3 100644 --- a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/manager/AssembleTransactionProcessor.java +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/manager/AssembleTransactionProcessor.java @@ -103,8 +103,9 @@ public TransactionReceipt deployAndGetReceipt(String data) { @Override public TransactionResponse deployAndGetResponse(String abi, String signedData) { TransactionReceipt receipt = transactionPusher.push(signedData); + String code = client.getCode(receipt.getContractAddress()).getCode(); try { - return transactionDecoder.decodeReceiptWithoutValues(abi, receipt); + return transactionDecoder.decodeReceiptWithoutOutputValues(abi, receipt, code); } catch (TransactionException | IOException | ABICodecException e) { log.error("deploy exception: {}", e.getMessage()); return new TransactionResponse( diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/dto/TransactionResponse.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/dto/TransactionResponse.java index cd6c6e0ff..fbaba1dfb 100644 --- a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/dto/TransactionResponse.java +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/dto/TransactionResponse.java @@ -37,6 +37,10 @@ public class TransactionResponse extends CommonResponse { private List returnObject; private List returnABIObject; + private String inputData; + private List inputObject; + private List inputABIObject; + public TransactionResponse() { super(); } @@ -134,4 +138,28 @@ public List getReturnABIObject() { public void setReturnABIObject(List returnABIObject) { this.returnABIObject = returnABIObject; } + + public List getInputObject() { + return inputObject; + } + + public void setInputObject(List inputObject) { + this.inputObject = inputObject; + } + + public List getInputABIObject() { + return inputABIObject; + } + + public void setInputABIObject(List inputABIObject) { + this.inputABIObject = inputABIObject; + } + + public String getInputData() { + return inputData; + } + + public void setInputData(String inputData) { + this.inputData = inputData; + } } diff --git a/src/integration-test/java/org/fisco/bcos/sdk/transaction/decoder/TransactionDecoderServiceTest.java b/src/integration-test/java/org/fisco/bcos/sdk/transaction/decoder/TransactionDecoderServiceTest.java index fb9a359b5..6f53dcdc0 100644 --- a/src/integration-test/java/org/fisco/bcos/sdk/transaction/decoder/TransactionDecoderServiceTest.java +++ b/src/integration-test/java/org/fisco/bcos/sdk/transaction/decoder/TransactionDecoderServiceTest.java @@ -65,6 +65,8 @@ public void testDecode() throws Exception { return; } String contractAddress = response.getContractAddress(); + Assert.assertEquals(2, response.getInputObject().size()); + // System.out.println(JsonUtils.toJson(response)); // increment TransactionReceipt transactionReceipt = diff --git a/src/integration-test/java/org/fisco/bcos/sdk/transaction/manager/AssembleTransactionProcessorTest.java b/src/integration-test/java/org/fisco/bcos/sdk/transaction/manager/AssembleTransactionProcessorTest.java index c16b15757..e15365d7f 100644 --- a/src/integration-test/java/org/fisco/bcos/sdk/transaction/manager/AssembleTransactionProcessorTest.java +++ b/src/integration-test/java/org/fisco/bcos/sdk/transaction/manager/AssembleTransactionProcessorTest.java @@ -101,6 +101,8 @@ public void test1HelloWorld() throws Exception { transactionProcessor.sendTransactionAndGetResponseByContractLoader( "HelloWorld", helloWorldAddrss, "set", params); Assert.assertEquals("0x0", res.getTransactionReceipt().getStatus()); + Assert.assertEquals("test", res.getInputObject().get(0)); + // System.out.println(JsonUtils.toJson(res)); // test call by contract loader CallResponse callResponse2 = @@ -293,7 +295,6 @@ public void onResponse(TransactionReceipt receipt) { abi, "getUint256", Lists.newArrayList()); - // System.out.println(JsonUtils.toJson(callResponse3)); Assert.assertEquals("Success", callResponse3.getReturnMessage()); } catch (TransactionBaseException | ABICodecException e) { System.out.println(e.getMessage()); @@ -313,6 +314,7 @@ public void test6ComplexSetValues() throws Exception { params.add("test2"); TransactionResponse response = transactionProcessor.deployByContractLoader("ComplexSol", params); + // System.out.println(JsonUtils.toJson(response)); if (!response.getTransactionReceipt().getStatus().equals("0x0")) { return; } @@ -322,14 +324,14 @@ public void test6ComplexSetValues() throws Exception { String[] o = {"0x1", "0x2", "0x3"}; List a = Arrays.asList(o); paramsSetValues.add(a); - paramsSetValues.add("set values 字符串"); + paramsSetValues.add("set values 字符"); TransactionResponse transactionResponse = transactionProcessor.sendTransactionAndGetResponse( contractAddress, abi, "setValues", paramsSetValues); // System.out.println(JsonUtils.toJson(transactionResponse)); Map>> eventsMap = transactionResponse.getEventResultMap(); Assert.assertEquals(1, eventsMap.size()); - Assert.assertEquals("set values 字符串", eventsMap.get("LogSetValues").get(0).get(2)); + Assert.assertEquals("set values 字符", eventsMap.get("LogSetValues").get(0).get(2)); } @Test @@ -401,4 +403,31 @@ public void test8ComplexSetBytesFuture() throws Exception { Assert.assertEquals("0x0", response.getTransactionReceipt().getStatus()); }); } + + @Test + public void test9ComplexIncrementInputParser() throws Exception { + AssembleTransactionProcessor transactionProcessor = + TransactionProcessorFactory.createAssembleTransactionProcessor( + client, cryptoKeyPair, abiFile, binFile); + // deploy + List params = Lists.newArrayList(); + params.add(1); + params.add("test2"); + TransactionResponse response = + transactionProcessor.deployByContractLoader("ComplexSol", params); + if (!response.getTransactionReceipt().getStatus().equals("0x0")) { + return; + } + Assert.assertEquals(2, response.getInputABIObject().size()); + Assert.assertEquals("test2", response.getInputObject().get(1)); + String contractAddress = response.getContractAddress(); + // increment v + TransactionResponse transactionResponse = + transactionProcessor.sendTransactionAndGetResponse( + contractAddress, + abi, + "incrementUint256", + Lists.newArrayList(BigInteger.valueOf(10))); + Assert.assertEquals(BigInteger.valueOf(10), transactionResponse.getInputObject().get(0)); + } } diff --git a/src/integration-test/java/org/fisco/bcos/sdk/transaction/manager/AssembleTransactionWithRemoteSignProcessorTest.java b/src/integration-test/java/org/fisco/bcos/sdk/transaction/manager/AssembleTransactionWithRemoteSignProcessorTest.java index 0f4233637..e435d0a98 100644 --- a/src/integration-test/java/org/fisco/bcos/sdk/transaction/manager/AssembleTransactionWithRemoteSignProcessorTest.java +++ b/src/integration-test/java/org/fisco/bcos/sdk/transaction/manager/AssembleTransactionWithRemoteSignProcessorTest.java @@ -48,7 +48,7 @@ public class AssembleTransactionWithRemoteSignProcessorTest { private static final String abiFile = "src/integration-test/resources/abi/"; private static final String binFile = "src/integration-test/resources/bin/"; private List params = Lists.newArrayList("test"); - // prepare sdk, read from the config file + // prepare sdk, read from the config file private BcosSDK sdk = BcosSDK.build(configFile); // set the group number 1 private Client client = sdk.getClient(Integer.valueOf(1)); diff --git a/src/integration-test/java/org/fisco/bcos/sdk/transaction/mock/RemoteSignCallbackMock.java b/src/integration-test/java/org/fisco/bcos/sdk/transaction/mock/RemoteSignCallbackMock.java index 355209640..fd6fd5000 100644 --- a/src/integration-test/java/org/fisco/bcos/sdk/transaction/mock/RemoteSignCallbackMock.java +++ b/src/integration-test/java/org/fisco/bcos/sdk/transaction/mock/RemoteSignCallbackMock.java @@ -21,7 +21,7 @@ public RemoteSignCallbackMock( } /** - * 签名结果回调的实现 + * callback of sign transaction * * @param signatureStr 签名服务回调返回的签名结果串 * @return * @@ -29,7 +29,7 @@ public RemoteSignCallbackMock( @Override public int handleSignedTransaction(SignatureResult signatureStr) { System.out.println(System.currentTimeMillis() + " SignatureResult: " + signatureStr); - // 完成了交易签名后,将其发送出去 + // after sign, send it TransactionReceipt tr = assembleTransactionWithRemoteSignProcessor.signAndPush( rawTransaction, signatureStr.convertToString());