diff --git a/.ci/ci_check.sh b/.ci/ci_check.sh new file mode 100755 index 000000000..b572f8632 --- /dev/null +++ b/.ci/ci_check.sh @@ -0,0 +1,128 @@ +#!/bin/bash + +set -e +LOG_INFO() { + local content=${1} + echo -e "\033[32m ${content}\033[0m" +} +check_basic() +{ +# check code format +bash gradlew verifyGoogleJavaFormat +# build +bash gradlew build --info +} + +download_tassl() +{ + mkdir -p ~/.fisco/ + if [ "$(uname)" == "Darwin" ];then + curl -LO https://github.com/FISCO-BCOS/LargeFiles/raw/master/tools/tassl_mac.tar.gz + mv tassl_mac.tar.gz ~/.fisco/tassl.tar.gz + else + curl -LO https://github.com/FISCO-BCOS/LargeFiles/raw/master/tools/tassl.tar.gz + mv tassl.tar.gz ~/.fisco/tassl.tar.gz + fi + tar -xvf ~/.fisco/tassl.tar.gz +} + +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 +} + +get_sed_cmd() +{ + local sed_cmd="sed -i" + if [ "$(uname)" == "Darwin" ];then + sed_cmd="sed -i .bkp" + fi + echo "$sed_cmd" +} + +prepare_environment() +{ + ## prepare resources for integration test + mkdir -p src/integration-test/resources/ + mkdir -p conf + cp -r nodes/127.0.0.1/sdk/* conf + cp src/test/resources/config-example.toml src/integration-test/resources/config.toml + cp src/test/resources/config-example.toml src/test/resources/config.toml + cp src/test/resources/log4j.properties src/integration-test/resources/ + cp -r src/test/resources/amop conf/amop + cp -r src/test/resources/amop src/integration-test/resources/amop + rm -rf src/integration-test/resources/abi + rm -rf src/integration-test/resources/bin + cp -r src/test/resources/ecdsa/abi src/integration-test/resources/abi + cp -r src/test/resources/ecdsa/bin src/integration-test/resources/bin + mkdir -p sdk-amop/src/test/resources + cp -r src/test/resources/ sdk-amop/src/test/resources + + sed_cmd=$(get_sed_cmd) + + local node_type="${1}" + if [ "${node_type}" == "sm" ];then + rm -rf src/integration-test/resources/abi + rm -rf src/integration-test/resources/bin + cp -r src/test/resources/gm/abi src/integration-test/resources/abi + cp -r src/test/resources/gm/bin src/integration-test/resources/bin + fi +} + +build_node() +{ + local node_type="${1}" + if [ "${node_type}" == "sm" ];then + ./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 + fi + ./nodes/127.0.0.1/fisco-bcos -v + ./nodes/127.0.0.1/start_all.sh +} + +clean_node() +{ + bash nodes/127.0.0.1/stop_all.sh + rm -rf nodes +} + + # check integration-test for non-gm node +check_standard_node() +{ + build_node + prepare_environment + ## run integration test + bash gradlew clean integrationTest --info + ## clean + clean_node +} + +check_sm_node() +{ + build_node "sm" + prepare_environment "sm" + ## run integration test + bash gradlew clean integrationTest --info + ## clean + clean_node +} +LOG_INFO "------ download_tassl---------" +download_tassl +LOG_INFO "------ check_basic---------" +./gradlew build -x test +LOG_INFO "------ download_build_chain---------" +download_build_chain +LOG_INFO "------ check_standard_node---------" +check_standard_node +LOG_INFO "------ check_sm_node---------" +check_sm_node +LOG_INFO "------ check_basic---------" +check_basic +#LOG_INFO "------ check_log---------" +#cat log/* |grep -i error +#cat log/* |grep -i warn diff --git a/.ci/ci_check_commit.sh b/.ci/ci_check_commit.sh new file mode 100644 index 000000000..2d9579de4 --- /dev/null +++ b/.ci/ci_check_commit.sh @@ -0,0 +1,75 @@ +#!/bin/bash + +set -e + +scan_code_script="cobra/cobra.py -f json -o /tmp/report.json -t " +ignore_files=(sh crt key json toml SignatureTest.java Ok.java bin abi ChannelTest.java ParallelOkDemo.java PerformanceAmop.java DagPrecompiledDemo.java KeyToolTest.java CryptoSuite.java AmopMsgHandlerTest.java TopicManager.java PrivateTopicVerifyTest.java AmopMsgBuilder.java TopicManagerTest.java AmopSubscribe.java AmopPublisher.java AmopPublisherPrivate.java AmopSubscribePrivate.java AmopPublisherFile.java AmopPublisherPrivateFile.java DemoAmopCallback.java FileToByteArrayHelper.java OkD.java TableTest.java PerformanceTable.java HelloWorld.java PerformanceRPC.java CodecTest.java ResponseTest.java ConfigTest.java) +commit_limit=6 + +LOG_ERROR() { + content=${1} + echo -e "\033[31m${content}\033[0m" +} + +LOG_INFO() { + content=${1} + echo -e "\033[32m${content}\033[0m" +} + +should_ignore() { + local file=${1} + for ignore in ${ignore_files[*]}; do + if echo "${file}" | grep "${ignore}" &>/dev/null; then + echo "ignore ${file} ${ignore}" + return 0 + fi + done + return 1 +} + +scan_code() { + # Redirect output to stderr. + exec 1>&2 + for file in $(git diff-index --name-status HEAD^ | awk '{print $2}'); do + if should_ignore "${file}"; then continue; fi + if [ ! -f "${file}" ]; then continue; fi + LOG_INFO "check file ${file}" + python ${scan_code_script} "$file" + trigger_rules=$(jq -r '.' /tmp/report.json | grep 'trigger_rules' | awk '{print $2}' | sed 's/,//g') + echo "trigger_rules is ${trigger_rules}" + rm /tmp/report.json + if [ ${trigger_rules} -ne 0 ]; then + echo "######### ERROR: Scan code failed, please adjust them before commit" + exit 1 + fi + done +} + +install_cobra() { + git clone https://github.com/WhaleShark-Team/cobra.git + pip install -r cobra/requirements.txt + cp cobra/config.template cobra/config +} + +check_commit_message() +{ + local commits=$(git rev-list --count HEAD^..HEAD) + if [ ${commit_limit} -lt ${commits} ]; then + LOG_ERROR "${commits} commits, limit is ${commit_limit}" + exit 1 + fi + local unique_commit=$(git log --format=%s HEAD^..HEAD | sort -u | wc -l) + if [ ${unique_commit} -ne ${commits} ]; then + LOG_ERROR "${commits} != ${unique_commit}, please make commit message unique!" + exit 1 + fi + local merges=$(git log --format=%s HEAD^..HEAD | grep -i merge | wc -l) + if [ ${merges} -gt 2 ]; then + LOG_ERROR "PR contain merge : ${merges}, Please rebase!" + exit 1 + fi +} + +check_commit_message +install_cobra +scan_code diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 000000000..ac1da9083 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,23 @@ +version: 2.1 +jobs: + build: + working_directory: /java-sdk + docker: + - image: centos:7 + environment: + PATH=$PATH:/usr/bin + steps: + - run: + name: Setup dependencies + command: | + yum install -y epel-release centos-release-scl which + yum install -y git openssl-devel openssl java java-devel + - checkout + - run: + name: Compile + command: | + bash gradlew build -x test -x integrationTest + - run: + name: Integration Test + command: | + bash .ci/ci_check.sh \ No newline at end of file diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 000000000..db7c9e70c --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,19 @@ +codecov: + branch: * +coverage: + ignore: + - "src/integration-test/**/*" + status: + project: + default: + target: 30% + threshold: null + if_not_found: success + patch: + default: + enabled: no + if_not_found: success + changes: + default: + enabled: no + if_not_found: success diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml new file mode 100644 index 000000000..7c601955a --- /dev/null +++ b/.github/workflows/workflow.yml @@ -0,0 +1,27 @@ +name: Java-SDK GitHub Actions +on: + pull_request: + release: + types: [published, created, edited] +env: + CCACHE_DIR: ${{ github.workspace }}/ccache + +jobs: + build: + name: build + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-18.04, ubuntu-16.04, macos-latest] + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 5 + - name: install macOS dependencies + if: runner.os == 'macOS' + run: brew install openssl@1.1 openjdk + - name: install Ubuntu dependencies + if: runner.os == 'Linux' + run: sudo apt-get update && sudo apt install -y git curl libssl-dev default-jdk build-essential + - name: run integration testing + run: /bin/bash .ci/ci_check.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..9913a5264 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +.gradle/ +.idea/ +log/ +build +java-sdk.iml + +## eclipse ## +.classpath +.project +.settings/ +bin/ +out/ +dist/ +conf/ + +## integration test files +nodes/ +src/integration-test/resources/ +build_chain.sh +account/ +conf/ +gmcert.cnf +gmsm2.param +integrationTestEnv.sh +gradle.properties +gpg.gpg diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..f0c677293 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,123 @@ +# safe list +branches: + only: + - /.*/ + - +jobs: + fast_finish: true + include: + - language: python + python: 3.6 + dist: bionic + before_cache: + cache: + before_install: + script: | + bash .ci/ci_check_commit.sh + + # ubuntu 16, openjdk 8 + - language: java + jdk: openjdk8 + os: linux + dist: xenial + sudo: required + env: + - CACHE_NAME=ubuntu16_openjdk8 + + # ubuntu 16, openjdk 11 + - language: java + jdk: openjdk11 + os: linux + dist: xenial + sudo: required + env: + - CACHE_NAME=ubuntu16_openjdk11 + + # ubuntu 18, openjdk 8 + - language: java + jdk: openjdk8 + os: linux + dist: bionic + sudo: required + env: + - CACHE_NAME=ubuntu18_openjdk8 + + # ubuntu 18, openjdk 11 + - language: java + jdk: openjdk11 + os: linux + dist: bionic + sudo: required + env: + - CACHE_NAME=ubuntu18_openjdk11 + + # ubuntu 16, openjdk 14 + - language: java + jdk: openjdk14 + os: linux + dist: xenial + sudo: required + env: + - CACHE_NAME=ubuntu16_openjdk14 + + # ubuntu 18, openjdk 14 + - language: java + jdk: openjdk14 + os: linux + dist: bionic + sudo: required + env: + - CACHE_NAME=ubuntu18_openjdk14 + + # ubuntu 18, oraclejdk 14 + - language: java + jdk: oraclejdk14 + os: linux + dist: bionic + sudo: required + env: + - CACHE_NAME=ubuntu18_oraclejdk14 + + # ubuntu 18, oraclejdk 11 + - language: java + jdk: oraclejdk11 + os: linux + dist: bionic + sudo: required + env: + - CACHE_NAME=ubuntu18_oraclejdk11 + + # ubuntu 16, oraclejdk 11 + - language: java + jdk: oraclejdk11 + os: linux + dist: xenial + sudo: required + env: + - CACHE_NAME=ubuntu16_oraclejdk11 + + # ubuntu 16, oraclejdk 14 + - language: java + jdk: oraclejdk14 + os: linux + dist: xenial + sudo: required + env: + - CACHE_NAME=ubuntu16_oraclejdk14 +addons: + apt: + packages: + - openssl + - libssl-dev +before_cache: + - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock + - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ +cache: + directories: + - $HOME/.gradle/caches/ + - $HOME/.gradle/wrapper/ +script: | + bash .ci/ci_check.sh +after_success: + - ./gradlew jacocoTestReport + - bash <(curl -s https://codecov.io/bash) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..6114ba20b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,67 @@ +English / [中文](docs/CONTRIBUTING_CN.md) + +# Contributing and Review Guidelines + +All contributions are welcome! + +## Branching + +Our branching method is [git-flow](https://jeffkreeftmeijer.com/git-flow/) + +- **master**: Latest stable branch +- **dev**: Stable branch waiting for release(merge to master) +- **feature-xxxx**: A developing branch of a new feature named xxxx +- **bugfix-xxxx**: A branch to fix the bug named xxxx + +## How to + +### Issue + +Go to [issues page](https://github.com/FISCO-BCOS/java-sdk/issues) + +### Fix bugs + +1. **Fork** this repo +2. **Create** a new branch named **bugfix-xxxx** forked from your repo's **master** branch +3. **Fix** the bug +4. **Test** the fixed code +5. Make **pull request** back to this repo's **dev** branch +6. Wait the community to review the code +7. Merged(**Bug fixed**) + +### Develop a new feature + +1. **Fork** this repo +2. **Create** a new branch named **feature-xxxx** forked from your repo's **dev** branch +3. **Coding** in feature-xxxx +4. **Pull** this repo's dev branch to your feature-xxxx constantly +5. **Test** your code +6. Make **pull request** back to this repo's dev branch +7. Wait the community to review the code +8. Merged !!!! + +## Code formatting + +The code formatting tool are described by the [google-java-format-gradle-plugin](https://github.com/sherter/google-java-format-gradle-plugin). + +Execute the task `googleJavaFormat` to format all *.java files in the project +``` +./gradlew goJF +``` +Execute the task `verifyGoogleJavaFormat` to verify that all *.java files are formatted properly +``` +./gradlew verGJF +``` + +## Continuous integration + +**Continuous integration platform** + +* travis-ci: [![Build Status](https://travis-ci.org/FISCO-BCOS/java-sdk.svg?branch=master)](https://travis-ci.org/FISCO-BCOS/java-sdk) + + +**Code quality** + +* Codacy: [![Codacy Badge](https://app.codacy.com/project/badge/Grade/d830a3be25c04b04b032870e4184482a)](https://www.codacy.com/gh/FISCO-BCOS/java-sdk/dashboard?utm_source=github.com&utm_medium=referral&utm_content=FISCO-BCOS/java-sdk&utm_campaign=Badge_Grade) + + diff --git a/Changelog.md b/Changelog.md new file mode 100644 index 000000000..cea195d53 --- /dev/null +++ b/Changelog.md @@ -0,0 +1,16 @@ +### v2.6.1-rc1 + +(2020-09-30) + +This java sdk is a code refactoring version base on web3sdk 2.6.1. It includes the following new features: + +* Support Toml config file, simplify configuration options. +* Support connecting with nodes of different groups. +* Support AMOP subscription and unsubscription at any time instead of just before start service. +* ABI module add support of encode and decode of struct type data. +* Use the common crypto tools of WeBank. +* Add a new module called group management to help applications manage nodes which java SDK connecting with. +* Use modular design, each module can use independently. For example, you can create crypto.jar file if only crypto module is needed. + +Please note that: +Java SDK supports FISCO BCOS 2.X, but not compatible with web3sdk. Mean, when tow user want to use AMOP functions to talk with each other, they should either both use java sdk, or both use web3sdk. \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 2b865e7d4..a43f08aa4 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,53 @@ -# java-sdk -Java SDK of FISCO-BCOS +![](docs/images/FISCO_BCOS_Logo.svg) + +English / [中文](docs/README_CN.md) + +# Java SDK + +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) +[![Build Status](https://travis-ci.org/FISCO-BCOS/java-sdk.svg?branch=master)](https://travis-ci.org/FISCO-BCOS/java-sdk) +[![CodeFactor](https://www.codefactor.io/repository/github/fisco-bcos/java-sdk/badge)](https://www.codefactor.io/repository/github/fisco-bcos/java-sdk) +[![GitHub All Releases](https://img.shields.io/github/downloads/FISCO-BCOS/java-sdk/total.svg)](https://github.com/FISCO-BCOS/java-sdk) + +This is the FISCO BCOS Client SDK for Java. Developers can use Java SDK to build blockchain applications with FISCO BCOS blockchain. + +## Functions +* Contract compiling. +* Interacting with FISCO BCOS JSON-RPC interface. +* constructing and sending transactions. +* Advanced Messages Onchain Protocol(AMOP) functions. +* Contract event subscription. +* Encoding and decoding data with ABI. +* Account Management. + +## New Features +This java sdk is a code refactoring version base on web3sdk (not recommend to use), it includes the following new features: + +* Support Toml config file, simplify configuration options. +* Support connecting with nodes of different groups. +* Support AMOP subscription and unsubscription at any time instead of just before start service. +* ABI module add support of encode and decode of struct type data. +* Use the common crypto tools of WeBank. +* Add a new module called group management to help applications manage nodes which java SDK connecting with. +* Use modular design, each module can use independently. For example, you can create crypto.jar file if only crypto module is needed. + +## Documentation +* [English User Handbook](https://fisco-bcos-documentation.readthedocs.io/en/latest/docs/sdk/java_sdk/index.html) +* [Chinese User Handbook](https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/sdk/java_sdk/index.html#) +* [Chinese WIKI](https://github.com/FISCO-BCOS/java-sdk/wiki) + +## Quick Start +* [English](https://fisco-bcos-documentation.readthedocs.io/en/latest/docs/sdk/java_sdk/quick_start.html) +* [Chinese](https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/sdk/java_sdk/quick_start.html) + +## Join Our Community + +The FISCO BCOS community is one of the most active open-source blockchain communities in China. It provides long-term technical support for both institutional and individual developers and users of FISCO BCOS. Thousands of technical enthusiasts from numerous industry sectors have joined this community, studying and using FISCO BCOS platform. If you are also interested, you are most welcome to join us for more support and fun. + +![](https://media.githubusercontent.com/media/FISCO-BCOS/LargeFiles/master/images/QR_image_en.png) + + +## License +![license](http://img.shields.io/badge/license-Apache%20v2-blue.svg) + +All contributions are made under the [Apache License 2.0](http://www.apache.org/licenses/). See [LICENSE](LICENSE). \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 000000000..2fe5a5d8b --- /dev/null +++ b/build.gradle @@ -0,0 +1,319 @@ +// Apply the java-library plugin to add support for Java Library +plugins { + id 'com.github.sherter.google-java-format' version '0.8' + id 'maven-publish' +} +println("Notice: current gradle version is " + gradle.gradleVersion) +// Additional attribute definition +ext { + if (!project.hasProperty("ossrhUsername")) { + ossrhUsername="xxx" + } + + if (!project.hasProperty("ossrhPassword")) { + ossrhPassword="xxx" + } + // jackson version + jacksonVersion = "2.11.0" + commonsIOVersion = "2.4" + commonsLang3Version = "3.1" + javapoetVersion = "1.7.0" + picocliVersion = "3.6.0" + nettyVersion = "4.1.50.Final" + nettySMSSLContextVersion = "1.1.0" + toml4jVersion = "0.7.2" + bcprovJDK15onVersion = "1.60" + keyMiniToolkit = "1.0.0" + + solcJVersion = "0.4.25.1" + //solcJVersion = "0.5.2.0" + //solcJVersion = "0.6.10.0" + slf4jVersion = "1.7.30" + junitVersion = "4.12" + commonsCollections4Version = "4.4" + guavaVersion = "29.0-jre" +} + +// check.dependsOn integrationTest +// integrationTest.mustRunAfter test +allprojects { + group = 'org.fisco-bcos.java-sdk' + version = '2.6.1-rc1' + apply plugin: 'maven' + apply plugin: 'maven-publish' + apply plugin: 'idea' + apply plugin: 'eclipse' + apply plugin: 'java' + apply plugin: 'jacoco' + apply plugin: 'signing' + + configurations.all { + resolutionStrategy.cacheChangingModulesFor 30, 'seconds' + } + + jacocoTestReport { + reports { + xml.enabled true + html.enabled false + } + } + sourceCompatibility = '1.8' + + // In this section you declare where to find the dependencies of your project + repositories { + maven { url "http://maven.aliyun.com/nexus/content/groups/public/" } + maven { url "https://oss.sonatype.org/content/repositories/snapshots" } + mavenCentral() + } + + dependencies { + compile ("org.slf4j:slf4j-api:${slf4jVersion}") + testCompile ("junit:junit:${junitVersion}") + } + + clean.doLast { + file("dist/apps/").deleteDir() + file("dist/conf/").deleteDir() + file("dist/lib/").deleteDir() + } +} + +subprojects { + sourceSets { + main { + java { + srcDir 'src/main/java' + } + + resources { + srcDir 'src/main/resources' + } + } + } + jar { + destinationDir file("dist/apps") + archiveName project.name + "-" + version + ".jar" + + exclude "**/*.xml" + exclude "**/*.properties" + + doLast { + copy { + from file("src/test/resources/") + into "dist/conf" + } + copy { + from configurations.runtime + into "dist/lib" + } + copy { + from file("build/libs/") + into "dist/apps" + } + } + } + + // for upload to maven + task sourcesJar(type: Jar) { + classifier = "sources" + from sourceSets.main.allSource + } + + task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = "javadoc" + from javadoc.destinationDir + } + artifacts { + archives jar + archives sourcesJar + archives javadocJar + } +} + +sourceSets { + main { + java { + srcDir "sdk-core/src/main/java" + srcDir "sdk-crypto/src/main/java" + srcDir "sdk-abi/src/main/java" + srcDir "sdk-amop/src/main/java" + srcDir "sdk-service/src/main/java" + srcDir "sdk-transaction/src/main/java" + srcDir "sdk-codegen/src/main/java" + } + + resources { + srcDir 'src/main/resources' + } + } + integrationTest { + java { + compileClasspath += main.output + test.output + runtimeClasspath += main.output + test.output + srcDir file('src/integration-test/java') + srcDir file('sdk-demo/src/main') + } + resources.srcDir file('src/integration-test/resources') + } +} +configurations { + integrationTestCompile.extendsFrom testCompile + integrationTestRuntime.extendsFrom testRuntime +} + +task integrationTest(type: Test) { + testClassesDirs = sourceSets.integrationTest.output.classesDirs + classpath = sourceSets.integrationTest.runtimeClasspath +} + +dependencies { + compile ("org.bouncycastle:bcprov-jdk15on:${bcprovJDK15onVersion}") + compile ("org.apache.commons:commons-lang3:${commonsLang3Version}") + compile ("io.netty:netty-all:${nettyVersion}") + compile ("org.fisco-bcos:netty-sm-ssl-context:${nettySMSSLContextVersion}") + compile ("com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}") + compile ("commons-io:commons-io:${commonsIOVersion}") + compile ("com.squareup:javapoet:${javapoetVersion}") + compile ("info.picocli:picocli:${picocliVersion}") + compile ("com.webank:key-mini-toolkit:${keyMiniToolkit}") + compile ("com.moandjiezana.toml:toml4j:${toml4jVersion}") + + testCompile ("org.apache.commons:commons-collections4:${commonsCollections4Version}") + testCompile ("org.fisco-bcos:solcJ:${solcJVersion}") + testCompile ("com.google.guava:guava:${guavaVersion}") +} +googleJavaFormat { + options style: 'AOSP' + source = sourceSets*.allJava + include '**/*.java' +} + +verifyGoogleJavaFormat { + source = sourceSets*.allJava + include '**/*.java' +} + +javadoc { + options.addStringOption('Xdoclint:none', '-quiet') + options.addStringOption('encoding', 'UTF-8') + options.addStringOption('charSet', 'UTF-8') +} + +task sourcesJar(type: Jar) { + from sourceSets.main.allJava + archiveClassifier = 'sources' +} + +task javadocJar(type: Jar) { + from javadoc + archiveClassifier = 'javadoc' +} + +publishing { + publications { + mavenJava(MavenPublication) { + + artifactId project.name + groupId project.group + version project.version + + from components.java + artifact sourcesJar + artifact javadocJar + pom { + name = 'fisco-bcos' + description = 'fisco-bcos java-sdk' + url = 'http://www.fisco-bcos.org' + + licenses { + license { + name = 'The Apache License, Version 2.0' + url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + developers { + developer { + id = 'zhangsan' + name = 'zhangsan' + email = 'zhangsan@example.com' + } + } + scm { + connection = 'https://github.com/FISCO-BCOS/java-sdk.git' + url = 'https://github.com/FISCO-BCOS/java-sdk.git' + } + } + } + } + repositories { + maven { + def releasesRepoURL = "https://oss.sonatype.org/service/local/staging/deploy/maven2" + def snapshotsRepoURL = "https://oss.sonatype.org/content/repositories/snapshots" + url = !version.endsWith("SNAPSHOT") ? releasesRepoURL : snapshotsRepoURL + + credentials { + username ossrhUsername + password ossrhPassword + } + } + } + + signing { + sign publishing.publications.mavenJava + } +} + +jar { + // destinationDir file('dist/apps') + // archiveName project.name + '-' + project.version + '.jar' + exclude '**/*.xml' + exclude '**/*.properties' + + manifest { + try { + def repo = grgit.open() + if (repo != null) { + def user = System.getProperty("user.name") + def date = new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") + def branch = repo.branch.getCurrent().getName() + def commit = repo.head().getAbbreviatedId(40) + + attributes(["Built-By" : user, + "Implementation-Timestamp": date, + "Git-Branch" : branch, + "Git-Commit" : commit + ]) + + logger.info(" Commit : ") + logger.info(" => user: {}", user) + logger.info(" => date: {}", date) + logger.info(" => branch: {}", branch) + logger.info(" => commit: {}", commit) + } + } catch (Exception e) { + // logger.warn(' .git not exist, cannot found commit info') + } + } from sourceSets.main.output + + doLast { + copy { + from destinationDir + into 'dist/apps' + } + copy { + from configurations.runtime + into 'dist/lib' + } + copy { + from file('src/test/resources/config-example.toml') + from file('src/test/resources/applicationContext-sample.xml') + from file('src/test/resources/log4j.properties') + into 'dist/conf' + } + copy { + from file('src/test/resources/amop/') + into 'conf/amop' + } + } +} +check.dependsOn jacocoTestReport diff --git a/docs/CONTRIBUTING_CN.md b/docs/CONTRIBUTING_CN.md new file mode 100644 index 000000000..f119c5198 --- /dev/null +++ b/docs/CONTRIBUTING_CN.md @@ -0,0 +1,67 @@ +[English](../CONTRIBUTING.md) / 中文 + +# 贡献代码 + +非常感谢能有心为FISCO-BCOS社区贡献代码! + +## 分支策略 + +项目采用[git-flow](https://jeffkreeftmeijer.com/git-flow/)的分支策略。 + +* master:最新的稳定分支 +* dev:待发布的稳定分支 +* feature-xxxx:一个正在开发xxxx特性分支 +* bugfix-xxxx:一个正在修bug xxxx的分支 + +## 贡献方法 + +### Issue + +可直接去[issues page](https://github.com/FISCO-BCOS/java-sdk/issues)提issue。 + +### 修复bug + +1. Fork本仓库到个人仓库 +2. 从个人仓库的master分支拉出一个bugfix-xxxx分支 +3. 在bugfix-xxxx上修复bug +4. 测试修复的bug +5. PR(Pull Request)到本仓库的dev分支 +6. 等待社区review这个PR +7. PR合入,bug修复完成! + +### 开发新特性 + +1. Fork本仓库到个人仓库 +2. 从个人仓库的dev分支拉出一个feature-xxxx分支 +3. 在feature-xxxx上进行特性开发 +4. 不定期的从本仓库的dev分支pull最新的改动到feature-xxxx分支 +5. 测试新特性 +6. PR(Pull Request)到本参考的dev分支 +7. 等待社区review这个PR +8. PR合入,特性开发完成! + +## 代码格式化 + +代码格式化gradle插件[google-java-format-gradle-plugin](https://github.com/sherter/google-java-format-gradle-plugin). + +执行任务 `googleJavaFormat`格式化java文件。 +``` +./gradlew goJF +``` +执行任务 `verifyGoogleJavaFormat`验证java文件是否格式化完成 +``` +./gradlew verGJF +``` + +## 持续集成(CI) + +持续集成框架 + +* travis-ci: [![Build Status](https://travis-ci.org/FISCO-BCOS/java-sdk.svg?branch=master)](https://travis-ci.org/FISCO-BCOS/java-sdk) + + +代码质量 + +* Codacy: [![Codacy Badge](https://app.codacy.com/project/badge/Grade/d830a3be25c04b04b032870e4184482a)](https://www.codacy.com/gh/FISCO-BCOS/java-sdk/dashboard?utm_source=github.com&utm_medium=referral&utm_content=FISCO-BCOS/java-sdk&utm_campaign=Badge_Grade) + + diff --git a/docs/README_CN.md b/docs/README_CN.md new file mode 100644 index 000000000..5fcc695e4 --- /dev/null +++ b/docs/README_CN.md @@ -0,0 +1,52 @@ +![](images/FISCO_BCOS_Logo.svg) + +[English](../README.md) / 中文 + +# Java SDK + +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) +[![Build Status](https://travis-ci.org/FISCO-BCOS/java-sdk.svg?branch=master)](https://travis-ci.org/FISCO-BCOS/java-sdk) +[![CodeFactor](https://www.codefactor.io/repository/github/fisco-bcos/java-sdk/badge)](https://www.codefactor.io/repository/github/fisco-bcos/java-sdk) +[![GitHub All Releases](https://img.shields.io/github/downloads/FISCO-BCOS/java-sdk/total.svg)](https://github.com/FISCO-BCOS/java-sdk) + +这是FISCO BCOS客户端的Java SDK,提供了访问FISCO BCOS节点的Java API,支持节点状态查询、部署和调用合约等功能,基于Java SDK可开发区块链应用,目前支持FISCO BCOS 2.0+。 + +## 功能 +* 提供合约编译功能,将Solidity合约文件转换成Java合约文件 +* 提供Java SDK API,提供访问FISCO BCOS JSON-RPC 的功能,并支持预编译(Precompiled)合约调用 +* 提供自定义构造和发送交易功能 +* 提供AMOP功能 +* 支持合约事件推送 +* 支持ABI解析 +* 提供账户管理接口 + +## 新特性 +这个Java SDK是web3sdk(不推荐使用)的重构版本,其包含如下几个新特性: + +* 支持Toml配置文件的配置,简化配置项。 +* 支持连接不同群组的节点。 +* 支持AMOP动态订阅和取消订阅。 +* 支持解析结构体类型数据的ABI解析。 +* 使用Webank通用的加密包。 +* 添加群组管理模块,帮助应用管理多个群组中节点连接。 +* 使用模块化设计,便于组装再造。 + +## 贡献代码 +欢迎参与FISCO BCOS的社区建设: +- 点亮我们的小星星(点击项目左上方Star按钮)。 +- 提交代码(Pull requests),参考我们的[代码贡献流程](CONTRIBUTING_CN.md)。 +- [提问和提交BUG](https://github.com/FISCO-BCOS/java-sdk/issues)。 + +## 加入我们的社区 + +FISCO BCOS开源社区是国内活跃的开源社区,社区长期为机构和个人开发者提供各类支持与帮助。已有来自各行业的数千名技术爱好者在研究和使用FISCO BCOS。如您对FISCO BCOS开源技术及应用感兴趣,欢迎加入社区获得更多支持与帮助。 + + +![](https://media.githubusercontent.com/media/FISCO-BCOS/LargeFiles/master/images/QR_image.png) + + +## License + +![license](https://img.shields.io/badge/license-Apache%20v2-blue.svg) + +Web3SDK的开源协议为[Apache License 2.0](http://www.apache.org/licenses/). 详情参考[LICENSE](../LICENSE)。 \ No newline at end of file diff --git a/docs/images/FISCO_BCOS_Logo.svg b/docs/images/FISCO_BCOS_Logo.svg new file mode 100644 index 000000000..7bb0bb473 --- /dev/null +++ b/docs/images/FISCO_BCOS_Logo.svg @@ -0,0 +1,15 @@ + + + + logo/横/原色 + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..87b738cbd Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..a86ef2dd6 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +#distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 000000000..83f2acfdc --- /dev/null +++ b/gradlew @@ -0,0 +1,188 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..9109989e3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,103 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/sdk-abi/build.gradle b/sdk-abi/build.gradle new file mode 100644 index 000000000..f6c20be3b --- /dev/null +++ b/sdk-abi/build.gradle @@ -0,0 +1,51 @@ +// Apply the java-library plugin to add support for Java Library +plugins { + id 'java' +} +dependencies { + compile project(':sdk-crypto') + compile ("org.apache.commons:commons-lang3:${commonsLang3Version}") +} + +uploadArchives { + repositories { + mavenDeployer { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + + repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { + authentication(userName: ossrhUsername, password: ossrhPassword) + } + + snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { + authentication(userName: ossrhUsername, password: ossrhPassword) + } + + pom.project { + name project.name + packaging 'jar' + description = 'fisco-bcos java-sdk' + url = 'http://www.fisco-bcos.org' + + scm { + connection = 'https://github.com/FISCO-BCOS/java-sdk.git' + url = 'https://github.com/FISCO-BCOS/java-sdk.git' + } + + licenses { + license { + name = 'The Apache License, Version 2.0' + url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + + developers { + developer { + id = 'zhangsan' + name = 'zhangsan' + email = 'zhangsan@example.com' + } + } + } + } + } +} 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 new file mode 100644 index 000000000..e5efe5684 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/ABICodec.java @@ -0,0 +1,467 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.abi; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import org.fisco.bcos.sdk.abi.wrapper.ABICodecJsonWrapper; +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.EventLog; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ABICodec { + + private static final Logger logger = LoggerFactory.getLogger(ABICodec.class); + + private final CryptoSuite cryptoSuite; + public static final String TYPE_CONSTRUCTOR = "constructor"; + private ABIDefinitionFactory abiDefinitionFactory; + private final ABIObjectFactory abiObjectFactory = new ABIObjectFactory(); + private final ABICodecJsonWrapper abiCodecJsonWrapper = new ABICodecJsonWrapper(); + + public ABICodec(CryptoSuite cryptoSuite) { + super(); + this.cryptoSuite = cryptoSuite; + abiDefinitionFactory = new ABIDefinitionFactory(cryptoSuite); + } + + public CryptoSuite getCryptoSuite() { + return cryptoSuite; + } + + public String encodeConstructor(String ABI, String BIN, List params) + throws ABICodecException { + + ContractABIDefinition contractABIDefinition = abiDefinitionFactory.loadABI(ABI); + ABIDefinition abiDefinition = contractABIDefinition.getConstructor(); + @SuppressWarnings("static-access") + ABIObject inputABIObject = abiObjectFactory.createInputObject(abiDefinition); + ABICodecObject abiCodecObject = new ABICodecObject(); + try { + return BIN + abiCodecObject.encodeValue(inputABIObject, params).encode(); + } catch (Exception e) { + logger.error(" exception in encodeMethodFromObject : {}", e.getMessage()); + } + String errorMsg = " cannot encode in encodeMethodFromObject with appropriate interface ABI"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + + public String encodeConstructorFromString(String ABI, String BIN, List params) + throws ABICodecException { + ContractABIDefinition contractABIDefinition = abiDefinitionFactory.loadABI(ABI); + ABIDefinition abiDefinition = contractABIDefinition.getConstructor(); + @SuppressWarnings("static-access") + ABIObject inputABIObject = abiObjectFactory.createInputObject(abiDefinition); + + try { + return BIN + abiCodecJsonWrapper.encode(inputABIObject, params).encode(); + } catch (Exception e) { + logger.error(" exception in encodeMethodFromObject : {}", e.getMessage()); + } + String errorMsg = " cannot encode in encodeMethodFromObject with appropriate interface ABI"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + + public String encodeMethod(String ABI, String methodName, List params) + throws ABICodecException { + ContractABIDefinition contractABIDefinition = abiDefinitionFactory.loadABI(ABI); + List methods = contractABIDefinition.getFunctions().get(methodName); + for (ABIDefinition abiDefinition : methods) { + if (abiDefinition.getInputs().size() == params.size()) { + @SuppressWarnings("static-access") + ABIObject inputABIObject = abiObjectFactory.createInputObject(abiDefinition); + ABICodecObject abiCodecObject = new ABICodecObject(); + try { + String methodId = abiDefinition.getMethodId(cryptoSuite); + return methodId + abiCodecObject.encodeValue(inputABIObject, params).encode(); + } catch (Exception e) { + logger.error(" exception in encodeMethodFromObject : {}", e.getMessage()); + } + } + } + + String errorMsg = " cannot encode in encodeMethodFromObject with appropriate interface ABI"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + + public String encodeMethodById(String ABI, String methodId, List params) + throws ABICodecException { + ContractABIDefinition contractABIDefinition = abiDefinitionFactory.loadABI(ABI); + ABIDefinition abiDefinition = contractABIDefinition.getABIDefinitionByMethodId(methodId); + if (abiDefinition == null) { + String errorMsg = " methodId " + methodId + " is invalid"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + ABIObject inputABIObject = abiObjectFactory.createInputObject(abiDefinition); + ABICodecObject abiCodecObject = new ABICodecObject(); + try { + return methodId + abiCodecObject.encodeValue(inputABIObject, params).encode(); + } catch (Exception e) { + logger.error(" exception in encodeMethodByIdFromObject : {}", e.getMessage()); + } + + String errorMsg = + " cannot encode in encodeMethodByIdFromObject with appropriate interface ABI"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + + public String encodeMethodByInterface(String ABI, String methodInterface, List params) + throws ABICodecException { + FunctionEncoder functionEncoder = new FunctionEncoder(cryptoSuite); + String methodId = functionEncoder.buildMethodId(methodInterface); + return encodeMethodById(ABI, methodId, params); + } + + public String encodeMethodFromString(String ABI, String methodName, List params) + throws ABICodecException { + ContractABIDefinition contractABIDefinition = abiDefinitionFactory.loadABI(ABI); + List methods = contractABIDefinition.getFunctions().get(methodName); + if (methods == null) { + logger.debug( + "Invalid methodName: {}, all the functions are: {}", + methodName, + contractABIDefinition.getFunctions()); + throw new ABICodecException( + "Invalid method " + + methodName + + " , supported functions are: " + + contractABIDefinition.getFunctions().keySet()); + } + for (ABIDefinition abiDefinition : methods) { + if (abiDefinition.getInputs().size() == params.size()) { + ABIObject inputABIObject = abiObjectFactory.createInputObject(abiDefinition); + ABICodecJsonWrapper abiCodecJsonWrapper = new ABICodecJsonWrapper(); + try { + String methodId = abiDefinition.getMethodId(cryptoSuite); + return methodId + abiCodecJsonWrapper.encode(inputABIObject, params).encode(); + } catch (IOException e) { + logger.error(" exception in encodeMethodFromString : {}", e.getMessage()); + } + } + } + + String errorMsg = " cannot encode in encodeMethodFromString with appropriate interface ABI"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + + public String encodeMethodByIdFromString(String ABI, String methodId, List params) + throws ABICodecException { + ContractABIDefinition contractABIDefinition = abiDefinitionFactory.loadABI(ABI); + ABIDefinition abiDefinition = contractABIDefinition.getABIDefinitionByMethodId(methodId); + if (abiDefinition == null) { + String errorMsg = " methodId " + methodId + " is invalid"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + ABIObject inputABIObject = abiObjectFactory.createInputObject(abiDefinition); + ABICodecJsonWrapper abiCodecJsonWrapper = new ABICodecJsonWrapper(); + try { + return methodId + abiCodecJsonWrapper.encode(inputABIObject, params).encode(); + } catch (IOException e) { + logger.error(" exception in encodeMethodByIdFromString : {}", e.getMessage()); + } + + String errorMsg = + " cannot encode in encodeMethodByIdFromString with appropriate interface ABI"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + + public String encodeMethodByInterfaceFromString( + String ABI, String methodInterface, List params) throws ABICodecException { + FunctionEncoder functionEncoder = new FunctionEncoder(cryptoSuite); + String methodId = functionEncoder.buildMethodId(methodInterface); + return encodeMethodByIdFromString(ABI, methodId, params); + } + + public List decodeMethod(ABIDefinition abiDefinition, String output) + throws ABICodecException { + ABIObject outputABIObject = abiObjectFactory.createOutputObject(abiDefinition); + ABICodecObject abiCodecObject = new ABICodecObject(); + try { + return abiCodecObject.decodeJavaObject(outputABIObject, output); + } catch (Exception e) { + logger.error(" exception in decodeMethodToObject : {}", e.getMessage()); + } + String errorMsg = " cannot decode in decodeMethodToObject with appropriate interface ABI"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + + public List decodeMethod(String ABI, String methodName, String output) + throws ABICodecException { + ContractABIDefinition contractABIDefinition = abiDefinitionFactory.loadABI(ABI); + List methods = contractABIDefinition.getFunctions().get(methodName); + for (ABIDefinition abiDefinition : methods) { + ABIObject outputABIObject = abiObjectFactory.createOutputObject(abiDefinition); + ABICodecObject abiCodecObject = new ABICodecObject(); + try { + return abiCodecObject.decodeJavaObject(outputABIObject, output); + } catch (Exception e) { + logger.error(" exception in decodeMethodToObject : {}", e.getMessage()); + } + } + + String errorMsg = " cannot decode in decodeMethodToObject with appropriate interface ABI"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + + public List decodeMethodById(String ABI, String methodId, String output) + throws ABICodecException { + ContractABIDefinition contractABIDefinition = abiDefinitionFactory.loadABI(ABI); + ABIDefinition abiDefinition = contractABIDefinition.getABIDefinitionByMethodId(methodId); + if (abiDefinition == null) { + String errorMsg = " methodId " + methodId + " is invalid"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + ABIObject outputABIObject = abiObjectFactory.createOutputObject(abiDefinition); + ABICodecObject abiCodecObject = new ABICodecObject(); + try { + return abiCodecObject.decodeJavaObject(outputABIObject, output); + } catch (Exception e) { + logger.error(" exception in decodeMethodByIdToObject : {}", e.getMessage()); + } + + String errorMsg = " cannot decode in decodeMethodToObject with appropriate interface ABI"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + + public List decodeMethodByInterface(String ABI, String methodInterface, String output) + throws ABICodecException { + FunctionEncoder functionEncoder = new FunctionEncoder(cryptoSuite); + String methodId = functionEncoder.buildMethodId(methodInterface); + return decodeMethodById(ABI, methodId, output); + } + + public List decodeMethodToString(String ABI, String methodName, String output) + throws ABICodecException { + ContractABIDefinition contractABIDefinition = abiDefinitionFactory.loadABI(ABI); + List methods = contractABIDefinition.getFunctions().get(methodName); + if (methods == null) { + throw new ABICodecException( + "Invalid method " + + methodName + + ", supported methods are: " + + contractABIDefinition.getFunctions().keySet()); + } + for (ABIDefinition abiDefinition : methods) { + ABIObject outputABIObject = abiObjectFactory.createOutputObject(abiDefinition); + ABICodecJsonWrapper abiCodecJsonWrapper = new ABICodecJsonWrapper(); + try { + return abiCodecJsonWrapper.decode(outputABIObject, output); + } catch (Exception e) { + logger.error(" exception in decodeMethodToString : {}", e.getMessage()); + } + } + + String errorMsg = " cannot decode in decodeMethodToString with appropriate interface ABI"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + + public List decodeMethodByIdToString(String ABI, String methodId, String output) + throws ABICodecException { + ContractABIDefinition contractABIDefinition = abiDefinitionFactory.loadABI(ABI); + ABIDefinition abiDefinition = contractABIDefinition.getABIDefinitionByMethodId(methodId); + if (abiDefinition == null) { + String errorMsg = " methodId " + methodId + " is invalid"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + ABIObject outputABIObject = abiObjectFactory.createOutputObject(abiDefinition); + ABICodecJsonWrapper abiCodecJsonWrapper = new ABICodecJsonWrapper(); + try { + return abiCodecJsonWrapper.decode(outputABIObject, output); + } catch (UnsupportedOperationException e) { + logger.error(" exception in decodeMethodByIdToString : {}", e.getMessage()); + } + + String errorMsg = + " cannot decode in decodeMethodByIdToString with appropriate interface ABI"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + + public List decodeMethodByInterfaceToString( + String ABI, String methodInterface, String output) throws ABICodecException { + FunctionEncoder functionEncoder = new FunctionEncoder(cryptoSuite); + String methodId = functionEncoder.buildMethodId(methodInterface); + return decodeMethodByIdToString(ABI, methodId, output); + } + + public List decodeEvent(String ABI, String eventName, EventLog log) + throws ABICodecException { + ContractABIDefinition contractABIDefinition = abiDefinitionFactory.loadABI(ABI); + List events = contractABIDefinition.getEvents().get(eventName); + if (events == null) { + throw new ABICodecException( + "Invalid event " + + eventName + + ", supported events are: " + + contractABIDefinition.getEvents().keySet()); + } + for (ABIDefinition abiDefinition : events) { + ABIObject inputObject = abiObjectFactory.createEventInputObject(abiDefinition); + ABICodecObject abiCodecObject = new ABICodecObject(); + try { + List params = abiCodecObject.decodeJavaObject(inputObject, log.getData()); + List topics = log.getTopics(); + return mergeEventParamsAndTopics(abiDefinition, params, topics); + } catch (Exception e) { + logger.error(" exception in decodeEventToObject : {}", e.getMessage()); + } + } + + String errorMsg = " cannot decode in decodeEventToObject with appropriate interface ABI"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + + public List decodeEventByTopic(String ABI, String eventTopic, EventLog log) + throws ABICodecException { + ContractABIDefinition contractABIDefinition = abiDefinitionFactory.loadABI(ABI); + ABIDefinition abiDefinition = + contractABIDefinition.getABIDefinitionByEventTopic(eventTopic); + ABIObject inputObject = abiObjectFactory.createEventInputObject(abiDefinition); + ABICodecObject abiCodecObject = new ABICodecObject(); + try { + List params = abiCodecObject.decodeJavaObject(inputObject, log.getData()); + List topics = log.getTopics(); + return mergeEventParamsAndTopics(abiDefinition, params, topics); + } catch (Exception e) { + logger.error(" exception in decodeEventByTopicToObject : {}", e.getMessage()); + } + + String errorMsg = + " cannot decode in decodeEventByTopicToObject with appropriate interface ABI"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + + public List decodeEventByInterface(String ABI, String eventSignature, EventLog log) + throws ABICodecException { + FunctionEncoder functionEncoder = new FunctionEncoder(cryptoSuite); + String methodId = functionEncoder.buildMethodId(eventSignature); + return decodeEventByTopic(ABI, methodId, log); + } + + public List decodeEventToString(String ABI, String eventName, EventLog log) + throws ABICodecException { + ContractABIDefinition contractABIDefinition = abiDefinitionFactory.loadABI(ABI); + List events = contractABIDefinition.getEvents().get(eventName); + if (events == null) { + throw new ABICodecException( + "Invalid event " + + eventName + + ", current supported events are: " + + contractABIDefinition.getEvents().keySet()); + } + for (ABIDefinition abiDefinition : events) { + ABIObject inputObject = abiObjectFactory.createEventInputObject(abiDefinition); + ABICodecJsonWrapper abiCodecJsonWrapper = new ABICodecJsonWrapper(); + try { + List params = abiCodecJsonWrapper.decode(inputObject, log.getData()); + List topics = log.getTopics(); + return mergeEventParamsAndTopicsToString(abiDefinition, params, topics); + } catch (Exception e) { + logger.error(" exception in decodeEventToString : {}", e.getMessage()); + } + } + + String errorMsg = " cannot decode in decodeEventToString with appropriate interface ABI"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + + public List decodeEventByTopicToString(String ABI, String eventTopic, EventLog log) + throws ABICodecException { + ContractABIDefinition contractABIDefinition = abiDefinitionFactory.loadABI(ABI); + ABIDefinition abiDefinition = + contractABIDefinition.getABIDefinitionByEventTopic(eventTopic); + ABIObject inputObject = abiObjectFactory.createEventInputObject(abiDefinition); + ABICodecJsonWrapper abiCodecJsonWrapper = new ABICodecJsonWrapper(); + try { + List params = abiCodecJsonWrapper.decode(inputObject, log.getData()); + List topics = log.getTopics(); + return mergeEventParamsAndTopicsToString(abiDefinition, params, topics); + } catch (Exception e) { + logger.error(" exception in decodeEventByTopicToString : {}", e.getMessage()); + } + + String errorMsg = + " cannot decode in decodeEventByTopicToString with appropriate interface ABI"; + logger.error(errorMsg); + throw new ABICodecException(errorMsg); + } + + public List decodeEventByInterfaceToString( + String ABI, String eventSignature, EventLog log) throws ABICodecException { + FunctionEncoder functionEncoder = new FunctionEncoder(cryptoSuite); + String methodId = functionEncoder.buildMethodId(eventSignature); + return decodeEventByTopicToString(ABI, methodId, log); + } + + private List mergeEventParamsAndTopics( + ABIDefinition abiDefinition, List params, List topics) { + List ret = new ArrayList<>(); + int paramIdx = 0; + int topicIdx = 1; + for (ABIDefinition.NamedType namedType : abiDefinition.getInputs()) { + if (namedType.isIndexed()) { + ret.add(topics.get(topicIdx)); + topicIdx++; + } else { + ret.add(params.get(paramIdx)); + paramIdx++; + } + } + return ret; + } + + private List mergeEventParamsAndTopicsToString( + ABIDefinition abiDefinition, List params, List topics) { + List ret = new ArrayList<>(); + int paramIdx = 0; + int topicIdx = 1; + for (ABIDefinition.NamedType namedType : abiDefinition.getInputs()) { + if (namedType.isIndexed()) { + ret.add(topics.get(topicIdx)); + topicIdx++; + } else { + ret.add(params.get(paramIdx)); + paramIdx++; + } + } + return ret; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/ABICodecException.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/ABICodecException.java new file mode 100644 index 000000000..bd555c670 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/ABICodecException.java @@ -0,0 +1,23 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.abi; + +public class ABICodecException extends Exception { + + public ABICodecException(String message) { + super(message); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/Constant.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/Constant.java new file mode 100644 index 000000000..0eb7880ff --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/Constant.java @@ -0,0 +1,12 @@ +package org.fisco.bcos.sdk.abi; + +import java.math.BigInteger; + +public class Constant { + public static final BigInteger MAX_UINT256 = + new BigInteger("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16); + public static final BigInteger MAX_INT256 = + new BigInteger("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16); + public static final BigInteger MIN_INT256 = + new BigInteger("-7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16); +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/EventEncoder.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/EventEncoder.java new file mode 100644 index 000000000..661abd7c0 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/EventEncoder.java @@ -0,0 +1,57 @@ +package org.fisco.bcos.sdk.abi; + +import java.util.List; +import java.util.stream.Collectors; +import org.fisco.bcos.sdk.abi.datatypes.Event; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.utils.Numeric; + +/** + * Ethereum filter encoding. Further limited details are available here. + */ +public class EventEncoder { + + private CryptoSuite cryptoSuite; + + public EventEncoder(CryptoSuite cryptoSuite) { + this.cryptoSuite = cryptoSuite; + } + + public String encode(Event event) { + + String methodSignature = buildMethodSignature(event.getName(), event.getParameters()); + + return buildEventSignature(methodSignature); + } + + private String buildMethodSignature( + String methodName, List> parameters) { + + StringBuilder result = new StringBuilder(); + result.append(methodName); + result.append("("); + String params = + parameters.stream().map(p -> Utils.getTypeName(p)).collect(Collectors.joining(",")); + result.append(params); + result.append(")"); + return result.toString(); + } + + public String buildEventSignature(String methodSignature) { + byte[] input = methodSignature.getBytes(); + byte[] hash = cryptoSuite.hash(input); + return Numeric.toHexString(hash); + } + + /** @return the cryptoSuite */ + public CryptoSuite getCryptoSuite() { + return cryptoSuite; + } + + /** @param cryptoSuite the cryptoSuite to set */ + public void setCryptoSuite(CryptoSuite cryptoSuite) { + this.cryptoSuite = cryptoSuite; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/EventValues.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/EventValues.java new file mode 100644 index 000000000..d9a310617 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/EventValues.java @@ -0,0 +1,23 @@ +package org.fisco.bcos.sdk.abi; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** Persisted solidity event parameters. */ +public class EventValues { + private final List indexedValues; + private final List nonIndexedValues; + + public EventValues(List indexedValues, List nonIndexedValues) { + this.indexedValues = indexedValues; + this.nonIndexedValues = nonIndexedValues; + } + + public List getIndexedValues() { + return indexedValues; + } + + public List getNonIndexedValues() { + return nonIndexedValues; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/FunctionEncoder.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/FunctionEncoder.java new file mode 100644 index 000000000..914442dcb --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/FunctionEncoder.java @@ -0,0 +1,88 @@ +package org.fisco.bcos.sdk.abi; + +import java.math.BigInteger; +import java.util.List; +import java.util.stream.Collectors; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Uint; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.utils.Numeric; + +/** + * Ethereum Contract Application Binary Interface (ABI) encoding for functions. Further details are + * available here. + */ +public class FunctionEncoder { + + private CryptoSuite cryptoSuite; + + public FunctionEncoder(CryptoSuite cryptoSuite) { + this.cryptoSuite = cryptoSuite; + } + + public String encode(Function function) { + List parameters = function.getInputParameters(); + + String methodSignature = buildMethodSignature(function.getName(), parameters); + String methodId = buildMethodId(methodSignature); + + StringBuilder result = new StringBuilder(); + result.append(methodId); + + return encodeParameters(parameters, result); + } + + public static String encodeConstructor(List parameters) { + return encodeParameters(parameters, new StringBuilder()); + } + + public static String encodeParameters(List parameters, StringBuilder result) { + int dynamicDataOffset = Utils.getLength(parameters) * Type.MAX_BYTE_LENGTH; + StringBuilder dynamicData = new StringBuilder(); + + for (Type parameter : parameters) { + String encodedValue = TypeEncoder.encode(parameter); + + if (parameter.dynamicType()) { + String encodedDataOffset = + TypeEncoder.encodeNumeric(new Uint(BigInteger.valueOf(dynamicDataOffset))); + result.append(encodedDataOffset); + dynamicData.append(encodedValue); + dynamicDataOffset += (encodedValue.length() >> 1); + } else { + result.append(encodedValue); + } + } + result.append(dynamicData); + + return result.toString(); + } + + public static String buildMethodSignature(String methodName, List parameters) { + StringBuilder result = new StringBuilder(); + result.append(methodName); + result.append("("); + String params = + parameters.stream().map(Type::getTypeAsString).collect(Collectors.joining(",")); + result.append(params); + result.append(")"); + return result.toString(); + } + + public String buildMethodId(String methodSignature) { + byte[] input = methodSignature.getBytes(); + byte[] hash = cryptoSuite.hash(input); + return Numeric.toHexString(hash).substring(0, 10); + } + + /** @return the cryptoSuite */ + public CryptoSuite getCryptoSuite() { + return cryptoSuite; + } + + /** @param cryptoSuite the cryptoSuite to set */ + public void setCryptoSuite(CryptoSuite cryptoSuite) { + this.cryptoSuite = cryptoSuite; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/FunctionReturnDecoder.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/FunctionReturnDecoder.java new file mode 100644 index 000000000..cd9dea534 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/FunctionReturnDecoder.java @@ -0,0 +1,133 @@ +package org.fisco.bcos.sdk.abi; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.Array; +import org.fisco.bcos.sdk.abi.datatypes.Bytes; +import org.fisco.bcos.sdk.abi.datatypes.BytesType; +import org.fisco.bcos.sdk.abi.datatypes.DynamicArray; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Bytes32; +import org.fisco.bcos.sdk.utils.Numeric; +import org.fisco.bcos.sdk.utils.StringUtils; + +/** Decodes values returned by function or event calls. */ +public class FunctionReturnDecoder { + + private FunctionReturnDecoder() {} + + /** + * Decode ABI encoded return values from smart contract function call. + * + * @param rawInput ABI encoded input + * @param outputParameters list of return types as {@link TypeReference} + * @return {@link List} of values returned by function, {@link Collections#emptyList()} if + * invalid response + */ + public static List decode(String rawInput, List> outputParameters) { + String input = Numeric.cleanHexPrefix(rawInput); + + if (StringUtils.isEmpty(input)) { + return Collections.emptyList(); + } else { + return build(input, outputParameters); + } + } + + /** + * Decodes an indexed parameter associated with an event. Indexed parameters are individually + * encoded, unlike non-indexed parameters which are encoded as per ABI-encoded function + * parameters and return values. + * + *

If any of the following types are indexed, the Keccak-256 hashes of the values are + * returned instead. These are returned as a bytes32 value. + * + *

    + *
  • Arrays + *
  • Strings + *
  • Bytes + *
+ * + *

See the Solidity + * documentation for further information. + * + * @param rawInput ABI encoded input + * @param typeReference of expected result type + * @param type of TypeReference + * @return the decode value + */ + @SuppressWarnings("unchecked") + public static Type decodeIndexedValue( + String rawInput, TypeReference typeReference) { + String input = Numeric.cleanHexPrefix(rawInput); + + try { + Class type = typeReference.getClassType(); + + if (Bytes.class.isAssignableFrom(type)) { + return TypeDecoder.decodeBytes(input, (Class) Class.forName(type.getName())); + } else if (Array.class.isAssignableFrom(type) + || BytesType.class.isAssignableFrom(type) + || Utf8String.class.isAssignableFrom(type)) { + return TypeDecoder.decodeBytes(input, Bytes32.class); + } else { + return TypeDecoder.decode(input, 0, type); + } + } catch (ClassNotFoundException e) { + throw new UnsupportedOperationException("Invalid class reference provided", e); + } + } + + private static List build(String input, List> outputParameters) { + List results = new ArrayList<>(outputParameters.size()); + + int offset = 0; + for (TypeReference typeReference : outputParameters) { + try { + @SuppressWarnings("unchecked") + Class cls = (Class) typeReference.getClassType(); + + int hexStringDataOffset = getDataOffset(input, offset, typeReference.getType()); + + Type result; + if (DynamicArray.class.isAssignableFrom(cls)) { + result = + TypeDecoder.decodeDynamicArray( + input, hexStringDataOffset, typeReference.getType()); + } else if (StaticArray.class.isAssignableFrom(cls)) { + int length = + Integer.parseInt( + cls.getSimpleName() + .substring(StaticArray.class.getSimpleName().length())); + result = + TypeDecoder.decodeStaticArray( + input, hexStringDataOffset, typeReference.getType(), length); + } else { + result = TypeDecoder.decode(input, hexStringDataOffset, cls); + } + + results.add(result); + + offset += + Utils.getOffset(typeReference.getType()) + * TypeDecoder.MAX_BYTE_LENGTH_FOR_HEX_STRING; + + } catch (ClassNotFoundException e) { + throw new UnsupportedOperationException("Invalid class reference provided", e); + } + } + return results; + } + + private static int getDataOffset( + String input, int offset, java.lang.reflect.Type type) throws ClassNotFoundException { + if (Utils.dynamicType(type)) { + return TypeDecoder.decodeUintAsInt(input, offset) << 1; + } else { + return offset; + } + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/TypeDecoder.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/TypeDecoder.java new file mode 100644 index 000000000..b50ce4d6f --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/TypeDecoder.java @@ -0,0 +1,291 @@ +package org.fisco.bcos.sdk.abi; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.ParameterizedType; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiFunction; +import org.fisco.bcos.sdk.abi.datatypes.Address; +import org.fisco.bcos.sdk.abi.datatypes.Array; +import org.fisco.bcos.sdk.abi.datatypes.Bool; +import org.fisco.bcos.sdk.abi.datatypes.Bytes; +import org.fisco.bcos.sdk.abi.datatypes.DynamicArray; +import org.fisco.bcos.sdk.abi.datatypes.DynamicBytes; +import org.fisco.bcos.sdk.abi.datatypes.Fixed; +import org.fisco.bcos.sdk.abi.datatypes.FixedPointType; +import org.fisco.bcos.sdk.abi.datatypes.Int; +import org.fisco.bcos.sdk.abi.datatypes.IntType; +import org.fisco.bcos.sdk.abi.datatypes.NumericType; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Ufixed; +import org.fisco.bcos.sdk.abi.datatypes.Uint; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Uint160; +import org.fisco.bcos.sdk.utils.Numeric; + +/** + * Ethereum Contract Application Binary Interface (ABI) decoding for types. Decoding is not + * documented, but is the reverse of the encoding details located here. + */ +public class TypeDecoder { + + static final int MAX_BYTE_LENGTH_FOR_HEX_STRING = Type.MAX_BYTE_LENGTH << 1; + + @SuppressWarnings("unchecked") + public static T decode(String input, int offset, Class type) { + if (NumericType.class.isAssignableFrom(type)) { + return (T) decodeNumeric(input.substring(offset), (Class) type); + } else if (Address.class.isAssignableFrom(type)) { + return (T) decodeAddress(input.substring(offset)); + } else if (Bool.class.isAssignableFrom(type)) { + return (T) decodeBool(input, offset); + } else if (Bytes.class.isAssignableFrom(type)) { + return (T) decodeBytes(input, offset, (Class) type); + } else if (DynamicBytes.class.isAssignableFrom(type)) { + return (T) decodeDynamicBytes(input, offset); + } else if (Utf8String.class.isAssignableFrom(type)) { + return (T) decodeUtf8String(input, offset); + } else if (Array.class.isAssignableFrom(type)) { + throw new UnsupportedOperationException( + "Array types must be wrapped in a TypeReference"); + } else { + throw new UnsupportedOperationException("Type cannot be encoded: " + type.getClass()); + } + } + + static Address decodeAddress(String input) { + return new Address(decodeNumeric(input, Uint160.class)); + } + + static T decodeNumeric(String input, Class type) { + try { + byte[] inputByteArray = Numeric.hexStringToByteArray(input); + int typeLengthAsBytes = getTypeLengthInBytes(type); + + byte[] resultByteArray = new byte[typeLengthAsBytes + 1]; + + if (Int.class.isAssignableFrom(type) || Fixed.class.isAssignableFrom(type)) { + resultByteArray[0] = inputByteArray[0]; // take MSB as sign bit + } + + int valueOffset = Type.MAX_BYTE_LENGTH - typeLengthAsBytes; + System.arraycopy(inputByteArray, valueOffset, resultByteArray, 1, typeLengthAsBytes); + + BigInteger numericValue = new BigInteger(resultByteArray); + return type.getConstructor(BigInteger.class).newInstance(numericValue); + + } catch (NoSuchMethodException + | SecurityException + | InstantiationException + | IllegalAccessException + | IllegalArgumentException + | InvocationTargetException e) { + throw new UnsupportedOperationException( + "Unable to create instance of " + type.getName(), e); + } + } + + static int getTypeLengthInBytes(Class type) { + return getTypeLength(type) >> 3; // divide by 8 + } + + static int getTypeLength(Class type) { + if (IntType.class.isAssignableFrom(type)) { + String regex = "(" + Uint.class.getSimpleName() + "|" + Int.class.getSimpleName() + ")"; + String[] splitName = type.getSimpleName().split(regex); + if (splitName.length == 2) { + return Integer.parseInt(splitName[1]); + } + } else if (FixedPointType.class.isAssignableFrom(type)) { + String regex = + "(" + Ufixed.class.getSimpleName() + "|" + Fixed.class.getSimpleName() + ")"; + String[] splitName = type.getSimpleName().split(regex); + if (splitName.length == 2) { + String[] bitsCounts = splitName[1].split("x"); + return Integer.parseInt(bitsCounts[0]) + Integer.parseInt(bitsCounts[1]); + } + } + return Type.MAX_BIT_LENGTH; + } + + static int decodeUintAsInt(String rawInput, int offset) { + String input = rawInput.substring(offset, offset + MAX_BYTE_LENGTH_FOR_HEX_STRING); + return decode(input, 0, Uint.class).getValue().intValue(); + } + + static Bool decodeBool(String rawInput, int offset) { + String input = rawInput.substring(offset, offset + MAX_BYTE_LENGTH_FOR_HEX_STRING); + BigInteger numericValue = Numeric.toBigInt(input); + boolean value = numericValue.equals(BigInteger.ONE); + return new Bool(value); + } + + static T decodeBytes(String input, Class type) { + return decodeBytes(input, 0, type); + } + + static T decodeBytes(String input, int offset, Class type) { + try { + String simpleName = type.getSimpleName(); + String[] splitName = simpleName.split(Bytes.class.getSimpleName()); + int length = Integer.parseInt(splitName[1]); + int hexStringLength = length << 1; + + byte[] bytes = + Numeric.hexStringToByteArray(input.substring(offset, offset + hexStringLength)); + return type.getConstructor(byte[].class).newInstance(bytes); + } catch (NoSuchMethodException + | SecurityException + | InstantiationException + | IllegalAccessException + | IllegalArgumentException + | InvocationTargetException e) { + throw new UnsupportedOperationException( + "Unable to create instance of " + type.getName(), e); + } + } + + static DynamicBytes decodeDynamicBytes(String input, int offset) { + int encodedLength = decodeUintAsInt(input, offset); + int hexStringEncodedLength = encodedLength << 1; + + int valueOffset = offset + MAX_BYTE_LENGTH_FOR_HEX_STRING; + + String data = input.substring(valueOffset, valueOffset + hexStringEncodedLength); + byte[] bytes = Numeric.hexStringToByteArray(data); + + return new DynamicBytes(bytes); + } + + static Utf8String decodeUtf8String(String input, int offset) { + DynamicBytes dynamicBytesResult = decodeDynamicBytes(input, offset); + byte[] bytes = dynamicBytesResult.getValue(); + + return new Utf8String(new String(bytes, StandardCharsets.UTF_8)); + } + + /** + * Decode the staticArray Static array length cannot be passed as a type + * + * @param input the staticArray need to be decoded + * @param offset the size of the staticArray need to be decoded + * @param type the type of the result + * @param length the length of array + * @param the generic type + * @return the decoded result + */ + @SuppressWarnings("unchecked") + public static T decodeStaticArray( + String input, int offset, java.lang.reflect.Type type, int length) { + + BiFunction, String, T> function = + (elements, typeName) -> { + if (elements.isEmpty()) { + throw new UnsupportedOperationException( + "Zero length fixed array is invalid type"); + } else { + return instantiateStaticArray(type, elements); + } + }; + + return decodeArrayElements(input, offset, type, length, function); + } + + @SuppressWarnings("unchecked") + private static T instantiateStaticArray( + java.lang.reflect.Type type, List elements) { + try { + + Class cls = Utils.getClassType(type); + return cls.getConstructor(List.class).newInstance(elements); + + } catch (ReflectiveOperationException e) { + // noinspection unchecked + return (T) new StaticArray<>(elements); + } + } + + @SuppressWarnings("unchecked") + public static T decodeDynamicArray( + String input, int offset, java.lang.reflect.Type type) { + + int length = decodeUintAsInt(input, offset); + + BiFunction, String, T> function = + (elements, typeName) -> { + if (elements.isEmpty()) { + return (T) DynamicArray.empty(typeName); + } else { + return (T) new DynamicArray<>(elements); + } + }; + + int valueOffset = offset + MAX_BYTE_LENGTH_FOR_HEX_STRING; + + return decodeArrayElements(input, valueOffset, type, length, function); + } + + @SuppressWarnings("rawtypes") + private static T decodeArrayElements( + String input, + int offset, + java.lang.reflect.Type type, + int length, + BiFunction, String, T> consumer) { + + try { + List elements = new ArrayList<>(length); + + java.lang.reflect.Type[] types = ((ParameterizedType) type).getActualTypeArguments(); + Class paraType = Utils.getClassType(types[0]); + + for (int i = 0; i < length; ++i) { + + int currEleOffset = + offset + (i * MAX_BYTE_LENGTH_FOR_HEX_STRING * Utils.getOffset(types[0])); + + T t = null; + if (Array.class.isAssignableFrom(paraType)) { // nest array + int size = 0; + if (StaticArray.class.isAssignableFrom(paraType)) { + size = + Integer.parseInt( + Utils.getClassType(types[0]) + .getSimpleName() + .substring( + StaticArray.class + .getSimpleName() + .length())); + t = decodeStaticArray(input, currEleOffset, types[0], size); + } else { + int getOffset = TypeDecoder.decodeUintAsInt(input, currEleOffset) << 1; + t = decodeDynamicArray(input, offset + getOffset, types[0]); + } + + } else { + if (Utf8String.class.isAssignableFrom(paraType) + || DynamicBytes.class.isAssignableFrom(paraType)) { // dynamicType + int getOffset = TypeDecoder.decodeUintAsInt(input, currEleOffset) << 1; + t = decode(input, offset + getOffset, paraType); + } else { + t = decode(input, currEleOffset, paraType); + } + } + + elements.add(t); + } + + String typeName = Utils.getSimpleTypeName(paraType); + + return consumer.apply(elements, typeName); + + } catch (ClassNotFoundException e) { + throw new UnsupportedOperationException( + "Unable to access parameterized type " + type.getTypeName(), e); + } + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/TypeEncoder.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/TypeEncoder.java new file mode 100644 index 000000000..5739cd286 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/TypeEncoder.java @@ -0,0 +1,174 @@ +package org.fisco.bcos.sdk.abi; + +import static org.fisco.bcos.sdk.abi.datatypes.Type.MAX_BYTE_LENGTH; + +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import org.fisco.bcos.sdk.abi.datatypes.*; +import org.fisco.bcos.sdk.utils.Numeric; + +/** + * Ethereum Contract Application Binary Interface (ABI) encoding for types. Further details are + * available here. + */ +public class TypeEncoder { + + private TypeEncoder() {} + + @SuppressWarnings("unchecked") + public static String encode(Type parameter) { + if (parameter instanceof NumericType) { + return encodeNumeric(((NumericType) parameter)); + } else if (parameter instanceof Address) { + return encodeAddress((Address) parameter); + } else if (parameter instanceof Bool) { + return encodeBool((Bool) parameter); + } else if (parameter instanceof Bytes) { + return encodeBytes((Bytes) parameter); + } else if (parameter instanceof DynamicBytes) { + return encodeDynamicBytes((DynamicBytes) parameter); + } else if (parameter instanceof Utf8String) { + return encodeString((Utf8String) parameter); + } else if (parameter instanceof StaticArray) { + return encodeArrayValues((StaticArray) parameter); + } else if (parameter instanceof DynamicArray) { + return encodeDynamicArray((DynamicArray) parameter); + } else { + throw new UnsupportedOperationException( + "Type cannot be encoded: " + parameter.getClass()); + } + } + + public static String encodeAddress(Address address) { + return encodeNumeric(address.toUint160()); + } + + public static String encodeNumeric(NumericType numericType) { + byte[] rawValue = toByteArray(numericType); + byte paddingValue = getPaddingValue(numericType); + byte[] paddedRawValue = new byte[MAX_BYTE_LENGTH]; + if (paddingValue != 0) { + for (int i = 0; i < paddedRawValue.length; i++) { + paddedRawValue[i] = paddingValue; + } + } + + System.arraycopy( + rawValue, 0, paddedRawValue, MAX_BYTE_LENGTH - rawValue.length, rawValue.length); + return Numeric.toHexStringNoPrefix(paddedRawValue); + } + + private static byte getPaddingValue(NumericType numericType) { + if (numericType.getValue().signum() == -1) { + return (byte) 0xff; + } else { + return 0; + } + } + + private static byte[] toByteArray(NumericType numericType) { + BigInteger value = numericType.getValue(); + if (numericType instanceof Ufixed || numericType instanceof Uint) { + if (value.bitLength() == Type.MAX_BIT_LENGTH) { + // As BigInteger is signed, if we have a 256 bit value, the resultant + // byte array will contain a sign byte in it's MSB, which we should + // ignore for this unsigned integer type. + byte[] byteArray = new byte[MAX_BYTE_LENGTH]; + System.arraycopy(value.toByteArray(), 1, byteArray, 0, MAX_BYTE_LENGTH); + return byteArray; + } + } + return value.toByteArray(); + } + + static String encodeBool(Bool value) { + byte[] rawValue = new byte[MAX_BYTE_LENGTH]; + if (value.getValue()) { + rawValue[rawValue.length - 1] = 1; + } + return Numeric.toHexStringNoPrefix(rawValue); + } + + static String encodeBytes(BytesType bytesType) { + byte[] value = bytesType.getValue(); + int length = value.length; + int mod = length % MAX_BYTE_LENGTH; + + byte[] dest; + if (mod != 0) { + int padding = MAX_BYTE_LENGTH - mod; + dest = new byte[length + padding]; + System.arraycopy(value, 0, dest, 0, length); + } else { + dest = value; + } + return Numeric.toHexStringNoPrefix(dest); + } + + static String encodeDynamicBytes(DynamicBytes dynamicBytes) { + int size = dynamicBytes.getValue().length; + String encodedLength = encode(new Uint(BigInteger.valueOf(size))); + String encodedValue = encodeBytes(dynamicBytes); + + StringBuilder result = new StringBuilder(); + result.append(encodedLength); + result.append(encodedValue); + return result.toString(); + } + + static String encodeString(Utf8String string) { + byte[] utfEncoded = string.getValue().getBytes(StandardCharsets.UTF_8); + return encodeDynamicBytes(new DynamicBytes(utfEncoded)); + } + + static String encodeArrayValues(Array value) { + + StringBuilder encodedOffset = new StringBuilder(); + StringBuilder encodedValue = new StringBuilder(); + + int offset = value.getValue().size() * MAX_BYTE_LENGTH; + + for (Type type : value.getValue()) { + String r = encode(type); + encodedValue.append(r); + if (type.dynamicType()) { + encodedOffset.append(encode(new Uint(BigInteger.valueOf(offset)))); + offset += (r.length() >> 1); + } + } + + StringBuilder result = new StringBuilder(); + result.append(encodedOffset); + result.append(encodedValue); + + return result.toString(); + } + + static String encodeDynamicArray(DynamicArray value) { + + StringBuilder encodedSize = new StringBuilder(); + StringBuilder encodedOffset = new StringBuilder(); + StringBuilder encodedValue = new StringBuilder(); + + encodedSize.append(encode(new Uint(BigInteger.valueOf(value.getValue().size())))); + + int offset = value.getValue().size() * MAX_BYTE_LENGTH; + + for (Type type : value.getValue()) { + String r = encode(type); + encodedValue.append(r); + + if (type.dynamicType()) { + encodedOffset.append(encode(new Uint(BigInteger.valueOf(offset)))); + offset += (r.length() >> 1); + } + } + + StringBuilder result = new StringBuilder(); + result.append(encodedSize); + result.append(encodedOffset); + result.append(encodedValue); + + return result.toString(); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/TypeMappingException.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/TypeMappingException.java new file mode 100644 index 000000000..58361e908 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/TypeMappingException.java @@ -0,0 +1,16 @@ +package org.fisco.bcos.sdk.abi; + +public class TypeMappingException extends RuntimeException { + + public TypeMappingException(Exception e) { + super(e); + } + + public TypeMappingException(String message) { + super(message); + } + + public TypeMappingException(String message, Exception e) { + super(message, e); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/TypeReference.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/TypeReference.java new file mode 100644 index 000000000..48a9d3217 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/TypeReference.java @@ -0,0 +1,77 @@ +package org.fisco.bcos.sdk.abi; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import org.fisco.bcos.sdk.abi.datatypes.Array; + +/** + * Type wrapper to get around limitations of Java's type erasure. This is so that we can pass around + * Typed {@link Array} types. + * + *

See this blog post + * for further details. + * + *

It may make sense to switch to using Java's reflection Type to avoid + * working around this fundamental generics limitation. + */ +public abstract class TypeReference + implements Comparable> { + + private final Type type; + private final boolean indexed; + + protected TypeReference() { + this(false); + } + + protected TypeReference(boolean indexed) { + Type superclass = getClass().getGenericSuperclass(); + if (superclass instanceof Class) { + throw new RuntimeException("Missing type parameter."); + } + this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0]; + this.indexed = indexed; + } + + public int compareTo(TypeReference o) { + // taken from the blog post comments - this results in an errror if the + // type parameter is left out. + return 0; + } + + public Type getType() { + return type; + } + + public boolean isIndexed() { + return indexed; + } + + /** + * Workaround to ensure type does not come back as T due to erasure, this enables you to create + * a TypeReference via {@link Class Class<T>}. + * + * @return the parameterized Class type if applicable, otherwise a regular class + * @throws ClassNotFoundException if the class type cannot be determined + */ + @SuppressWarnings("unchecked") + public Class getClassType() throws ClassNotFoundException { + return Utils.getClassType(getType()); + } + + public static TypeReference create( + Class cls) { + return create(cls, false); + } + + public static TypeReference create( + Class cls, boolean indexed) { + return new TypeReference(indexed) { + @Override + public Type getType() { + return cls; + } + }; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/Utils.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/Utils.java new file mode 100644 index 000000000..c6c9229ad --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/Utils.java @@ -0,0 +1,225 @@ +package org.fisco.bcos.sdk.abi; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.ParameterizedType; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import org.fisco.bcos.sdk.abi.datatypes.DynamicArray; +import org.fisco.bcos.sdk.abi.datatypes.DynamicBytes; +import org.fisco.bcos.sdk.abi.datatypes.Fixed; +import org.fisco.bcos.sdk.abi.datatypes.Int; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Ufixed; +import org.fisco.bcos.sdk.abi.datatypes.Uint; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; + +/** Utility functions. */ +public class Utils { + private Utils() {} + + public static String getTypeName(TypeReference typeReference) { + return getTypeName(typeReference.getType()); + } + + public static String getTypeName(java.lang.reflect.Type type) { + try { + + Class cls = Utils.getClassType(type); + if (type instanceof ParameterizedType) { // array + return getParameterizedTypeName(type); + } else { // simple type + return getSimpleTypeName(cls); + } + + } catch (ClassNotFoundException e) { + throw new UnsupportedOperationException("Invalid class reference provided", e); + } + } + + private static String getParameterizedTypeName( + java.lang.reflect.Type type) { + + try { + Class cls = Utils.getClassType(type); + + if (DynamicArray.class.isAssignableFrom(cls)) { + return getTypeName(((ParameterizedType) type).getActualTypeArguments()[0]) + "[]"; + } else if (StaticArray.class.isAssignableFrom(cls)) { + + int length = + Integer.parseInt( + cls.getSimpleName() + .substring(StaticArray.class.getSimpleName().length())); + + return getTypeName(((ParameterizedType) type).getActualTypeArguments()[0]) + + "[" + + length + + "]"; + + } else { + throw new UnsupportedOperationException("Invalid type provided " + cls.getName()); + } + } catch (ClassNotFoundException e) { + throw new UnsupportedOperationException("Invalid class reference provided", e); + } + } + + static String getSimpleTypeName(Class type) { + String simpleName = type.getSimpleName().toLowerCase(); + + if (type.equals(Uint.class) + || type.equals(Int.class) + || type.equals(Ufixed.class) + || type.equals(Fixed.class)) { + return simpleName + "256"; + } else if (type.equals(Utf8String.class)) { + return "string"; + } else if (type.equals(DynamicBytes.class)) { + return "bytes"; + } else { + return simpleName; + } + } + + @SuppressWarnings("rawtypes") + public static boolean dynamicType(java.lang.reflect.Type type) + throws ClassNotFoundException { + + Class cls = Utils.getClassType(type); + // dynamic type + if (Utf8String.class.isAssignableFrom(cls) + || DynamicBytes.class.isAssignableFrom(cls) + || DynamicArray.class.isAssignableFrom(cls)) { + return true; + } + + // not static type + if (!StaticArray.class.isAssignableFrom(cls)) { + return false; + } + + // unpack static array for checking if dynamic type + java.lang.reflect.Type[] types = ((ParameterizedType) type).getActualTypeArguments(); + return dynamicType(types[0]); + } + + public static int getLength(List parameters) { + int count = 0; + for (Type type : parameters) { + count += type.offset(); + } + return count; + } + + public static int getOffset(java.lang.reflect.Type type) + throws ClassNotFoundException { + + if (Utils.dynamicType(type)) { + return 1; + } + + Class cls = Utils.getClassType(type); + if (StaticArray.class.isAssignableFrom(cls)) { + int length = + Integer.parseInt( + cls.getSimpleName() + .substring(StaticArray.class.getSimpleName().length())); + java.lang.reflect.Type[] types = ((ParameterizedType) type).getActualTypeArguments(); + return getOffset(types[0]) * length; + } else { + return 1; + } + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + public static Class getClassType(java.lang.reflect.Type type) + throws ClassNotFoundException { + if (type instanceof ParameterizedType) { + return (Class) ((ParameterizedType) type).getRawType(); + } else { + return (Class) Class.forName(type.getTypeName()); + } + } + + @SuppressWarnings("unchecked") + private static Class getParameterizedTypeFromArray( + java.lang.reflect.Type type) throws ClassNotFoundException { + + java.lang.reflect.Type[] types = ((ParameterizedType) type).getActualTypeArguments(); + + return Utils.getClassType(types[0]); + } + + @SuppressWarnings("unchecked") + public static List> convert(List> input) { + List> result = new ArrayList<>(input.size()); + result.addAll( + input.stream() + .map(typeReference -> (TypeReference) typeReference) + .collect(Collectors.toList())); + return result; + } + + public static , E extends Type> List typeMap( + List> input, Class outerDestType, Class innerType) { + List result = new ArrayList<>(); + try { + Constructor constructor = outerDestType.getDeclaredConstructor(List.class); + for (List ts : input) { + E e = constructor.newInstance(typeMap(ts, innerType)); + result.add(e); + } + } catch (NoSuchMethodException + | IllegalAccessException + | InstantiationException + | InvocationTargetException e) { + throw new TypeMappingException(e); + } + return result; + } + + public static > List typeMap(List input, Class destType) + throws TypeMappingException { + + List result = new ArrayList(input.size()); + + if (!input.isEmpty()) { + try { + Constructor constructor = + destType.getDeclaredConstructor(input.get(0).getClass()); + for (T value : input) { + result.add(constructor.newInstance(value)); + } + } catch (NoSuchMethodException + | IllegalAccessException + | InvocationTargetException + | InstantiationException e) { + throw new TypeMappingException(e); + } + } + return result; + } + + @SuppressWarnings("rawtypes") + public static List typeMapWithoutGenericType(List input, Class destType) + throws TypeMappingException { + List result = new ArrayList(input.size()); + if (!input.isEmpty()) { + try { + Constructor constructor = destType.getDeclaredConstructor(input.get(0).getClass()); + for (Object value : input) { + result.add(constructor.newInstance(value)); + } + } catch (NoSuchMethodException + | IllegalAccessException + | InvocationTargetException + | InstantiationException e) { + throw new TypeMappingException(e); + } + } + return result; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Address.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Address.java new file mode 100644 index 000000000..7fbc4b6b0 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Address.java @@ -0,0 +1,76 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.generated.Uint160; +import org.fisco.bcos.sdk.utils.Numeric; + +/** Address type, which is equivalent to uint160. */ +public class Address implements Type { + + public static final String TYPE_NAME = "address"; + public static final int LENGTH = 160; + public static final int LENGTH_IN_HEX = LENGTH >> 2; + public static final Address DEFAULT = new Address(BigInteger.ZERO); + + private final Uint160 value; + + public Address(Uint160 value) { + this.value = value; + } + + public Address(BigInteger value) { + this(new Uint160(value)); + } + + public Address(String hexValue) { + this(Numeric.toBigInt(hexValue)); + } + + public Uint160 toUint160() { + return value; + } + + @Override + public String getTypeAsString() { + return TYPE_NAME; + } + + @Override + public String toString() { + return Numeric.toHexStringWithPrefixZeroPadded(value.getValue(), LENGTH_IN_HEX); + } + + @Override + public String getValue() { + return toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Address address = (Address) o; + + return value != null ? value.equals(address.value) : address.value == null; + } + + @Override + public int hashCode() { + return value != null ? value.hashCode() : 0; + } + + @Override + public boolean dynamicType() { + return false; + } + + @Override + public int offset() { + return 1; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Array.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Array.java new file mode 100644 index 000000000..797e7a1ee --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Array.java @@ -0,0 +1,83 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** Fixed size array. */ +public abstract class Array implements Type> { + + private String type; + protected final List value; + + @SafeVarargs + Array(String type, T... values) { + if (!valid(values, type)) { + throw new UnsupportedOperationException( + "If empty list is provided, use empty array instance"); + } + + this.type = type; + this.value = Arrays.asList(values); + } + + Array(String type, List values) { + if (!valid(values, type)) { + throw new UnsupportedOperationException( + "If empty list is provided, use empty array instance"); + } + + this.type = type; + this.value = values; + } + + Array(String type) { + this.type = type; + this.value = Collections.emptyList(); + } + + @Override + public List getValue() { + return value; + } + + @Override + public String getTypeAsString() { + return type; + } + + private boolean valid(T[] values, String type) { + return (values != null && values.length != 0) || type != null; + } + + private boolean valid(List values, String type) { + return (values != null && values.size() != 0) || type != null; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Array array = (Array) o; + + if (!type.equals(array.type)) { + return false; + } + return value != null ? value.equals(array.value) : array.value == null; + } + + @Override + public int hashCode() { + int result = type.hashCode(); + result = 31 * result + (value != null ? value.hashCode() : 0); + return result; + } + + @Override + public abstract boolean dynamicType(); +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Bool.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Bool.java new file mode 100644 index 000000000..8798cfc5f --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Bool.java @@ -0,0 +1,57 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +/** Boolean type. */ +public class Bool implements Type { + + public static final String TYPE_NAME = "bool"; + public static final Bool DEFAULT = new Bool(false); + + private boolean value; + + public Bool(boolean value) { + this.value = value; + } + + public Bool(Boolean value) { + this.value = value; + } + + @Override + public String getTypeAsString() { + return TYPE_NAME; + } + + @Override + public Boolean getValue() { + return value; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Bool bool = (Bool) o; + + return value == bool.value; + } + + @Override + public int hashCode() { + return (value ? 1 : 0); + } + + @Override + public boolean dynamicType() { + return false; + } + + @Override + public int offset() { + return 1; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Bytes.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Bytes.java new file mode 100644 index 000000000..0644645fc --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Bytes.java @@ -0,0 +1,30 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +/** Statically allocated sequence of bytes. */ +public class Bytes extends BytesType { + + public static final String TYPE_NAME = "bytes"; + + public Bytes(int byteSize, byte[] value) { + super(value, TYPE_NAME + value.length); + if (!isValid(byteSize, value)) { + throw new UnsupportedOperationException( + "Input byte array must be in range 0 < M <= 32 and length must match type"); + } + } + + private boolean isValid(int byteSize, byte[] value) { + int length = value.length; + return length > 0 && length <= 32 && length == byteSize; + } + + @Override + public boolean dynamicType() { + return false; + } + + @Override + public int offset() { + return 1; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/BytesType.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/BytesType.java new file mode 100644 index 000000000..ad7a27cf9 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/BytesType.java @@ -0,0 +1,52 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +import java.util.Arrays; + +/** Binary sequence of bytes. */ +public abstract class BytesType implements Type { + + private byte[] value; + private String type; + + public BytesType(byte[] src, String type) { + this.value = src; + this.type = type; + } + + @Override + public byte[] getValue() { + return value; + } + + @Override + public String getTypeAsString() { + return type; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + BytesType bytesType = (BytesType) o; + + if (!Arrays.equals(value, bytesType.value)) { + return false; + } + return type.equals(bytesType.type); + } + + @Override + public int hashCode() { + int result = Arrays.hashCode(value); + result = 31 * result + type.hashCode(); + return result; + } + + @Override + public abstract boolean dynamicType(); +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/DynamicArray.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/DynamicArray.java new file mode 100644 index 000000000..01cd26929 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/DynamicArray.java @@ -0,0 +1,34 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +import java.util.List; + +/** Dynamic array type. */ +public class DynamicArray extends Array { + + @SafeVarargs + public DynamicArray(T... values) { + super(values[0].getTypeAsString() + "[]", values); + } + + public DynamicArray(List values) { + super(values.get(0).getTypeAsString() + "[]", values); + } + + private DynamicArray(String type) { + super(type); + } + + public static DynamicArray empty(String type) { + return new DynamicArray(type); + } + + @Override + public boolean dynamicType() { + return true; + } + + @Override + public int offset() { + return 1; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/DynamicBytes.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/DynamicBytes.java new file mode 100644 index 000000000..37f6fe6d0 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/DynamicBytes.java @@ -0,0 +1,22 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +/** Dynamically allocated sequence of bytes. */ +public class DynamicBytes extends BytesType { + + public static final String TYPE_NAME = "bytes"; + public static final DynamicBytes DEFAULT = new DynamicBytes(new byte[] {}); + + public DynamicBytes(byte[] value) { + super(value, TYPE_NAME); + } + + @Override + public boolean dynamicType() { + return true; + } + + @Override + public int offset() { + return 1; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Event.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Event.java new file mode 100644 index 000000000..4046750af --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Event.java @@ -0,0 +1,33 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +import java.util.List; +import java.util.stream.Collectors; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.Utils; + +/** Event wrapper type. */ +public class Event { + private String name; + private List> parameters; + + public Event(String name, List> parameters) { + this.name = name; + this.parameters = Utils.convert(parameters); + } + + public String getName() { + return name; + } + + public List> getParameters() { + return parameters; + } + + public List> getIndexedParameters() { + return parameters.stream().filter(TypeReference::isIndexed).collect(Collectors.toList()); + } + + public List> getNonIndexedParameters() { + return parameters.stream().filter(p -> !p.isIndexed()).collect(Collectors.toList()); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Fixed.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Fixed.java new file mode 100644 index 000000000..a5cfd7d69 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Fixed.java @@ -0,0 +1,36 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +import java.math.BigInteger; + +/** Signed fixed type. */ +public class Fixed extends FixedPointType { + + public static final String TYPE_NAME = "fixed"; + public static final Fixed DEFAULT = new Fixed(BigInteger.ZERO); + + protected Fixed(int mBitSize, int nBitSize, BigInteger value) { + super(TYPE_NAME, mBitSize, nBitSize, value); + } + + public Fixed(BigInteger value) { + this(DEFAULT_BIT_LENGTH, DEFAULT_BIT_LENGTH, value); + } + + public Fixed(BigInteger m, BigInteger n) { + this(convert(m, n)); + } + + protected Fixed(int mBitSize, int nBitSize, BigInteger m, BigInteger n) { + this(convert(mBitSize, nBitSize, m, n)); + } + + @Override + public boolean dynamicType() { + return false; + } + + @Override + public int offset() { + return 1; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/FixedPointType.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/FixedPointType.java new file mode 100644 index 000000000..4448d956d --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/FixedPointType.java @@ -0,0 +1,43 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +import java.math.BigInteger; + +/** Common fixed-point type properties. */ +public abstract class FixedPointType extends NumericType { + + static final int DEFAULT_BIT_LENGTH = MAX_BIT_LENGTH >> 1; + + public FixedPointType(String typePrefix, int mBitSize, int nBitSize, BigInteger value) { + super(typePrefix + mBitSize + "x" + nBitSize, value); + if (!valid(mBitSize, nBitSize, value)) { + throw new UnsupportedOperationException( + "Bitsize must be 8 bit aligned, and in range 0 < bitSize <= 256"); + } + } + + boolean valid(int mBitSize, int nBitSize, BigInteger value) { + return isValidBitSize(mBitSize, nBitSize) && isValidBitCount(mBitSize, nBitSize, value); + } + + static boolean isValidBitSize(int mBitSize, int nBitSize) { + int bitSize = mBitSize + nBitSize; + return mBitSize % 8 == 0 && nBitSize % 8 == 0 && bitSize > 0 && bitSize <= MAX_BIT_LENGTH; + } + + private static boolean isValidBitCount(int mBitSize, int nBitSize, BigInteger value) { + return value.bitCount() <= mBitSize + nBitSize; + } + + static BigInteger convert(BigInteger m, BigInteger n) { + return convert(DEFAULT_BIT_LENGTH, DEFAULT_BIT_LENGTH, m, n); + } + + static BigInteger convert(int mBitSize, int nBitSize, BigInteger m, BigInteger n) { + BigInteger mPadded = m.shiftLeft(nBitSize); + int nBitLength = n.bitLength(); + + // find next multiple of 4 + int shift = (nBitLength + 3) & ~0x03; + return mPadded.or(n.shiftLeft(nBitSize - shift)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Function.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Function.java new file mode 100644 index 000000000..21f51939d --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Function.java @@ -0,0 +1,38 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.Utils; + +/** Function type. */ +public class Function { + private String name; + private List inputParameters; + private List> outputParameters; + + public Function( + String name, List inputParameters, List> outputParameters) { + this.name = name; + this.inputParameters = inputParameters; + this.outputParameters = Utils.convert(outputParameters); + } + + public Function() { + this.name = ""; + this.inputParameters = Collections.emptyList(); + this.outputParameters = Collections.>emptyList(); + } + + public String getName() { + return name; + } + + public List getInputParameters() { + return inputParameters; + } + + public List> getOutputParameters() { + return outputParameters; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Int.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Int.java new file mode 100644 index 000000000..874faf38e --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Int.java @@ -0,0 +1,46 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.Constant; + +/** Integer type. */ +public class Int extends IntType { + + public static final String TYPE_NAME = "int"; + public static final Int DEFAULT = new Int(BigInteger.ZERO); + + public Int(BigInteger value) { + // "int" values should be declared as int256 in computing function selectors + this(MAX_BIT_LENGTH, value); + } + + /** + * check if value between MIN_INT256 ~ MIN_INT256 + * + * @param value the value need to be checked + * @return true/false + */ + public boolean validInt(BigInteger value) { + return value.compareTo(Constant.MIN_INT256) >= 0 + && value.compareTo(Constant.MAX_INT256) <= 0; + } + + @Override + boolean valid(int bitSize, BigInteger value) { + return super.valid(bitSize, value) && validInt(value); + } + + protected Int(int bitSize, BigInteger value) { + super(TYPE_NAME, bitSize, value); + } + + @Override + public boolean dynamicType() { + return false; + } + + @Override + public int offset() { + return 1; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/IntType.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/IntType.java new file mode 100644 index 000000000..3a1adf421 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/IntType.java @@ -0,0 +1,27 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +import java.math.BigInteger; + +/** Common integer properties. */ +public abstract class IntType extends NumericType { + + public IntType(String typePrefix, int bitSize, BigInteger value) { + super(typePrefix + bitSize, value); + if (!valid(bitSize, value)) { + throw new UnsupportedOperationException( + "Bitsize must be 8 bit aligned, and in range 0 < bitSize <= 256, and in valid range."); + } + } + + boolean valid(int bitSize, BigInteger value) { + return isValidBitSize(bitSize) && isValidBitCount(bitSize, value); + } + + static boolean isValidBitSize(int bitSize) { + return bitSize % 8 == 0 && bitSize > 0 && bitSize <= MAX_BIT_LENGTH; + } + + private static boolean isValidBitCount(int bitSize, BigInteger value) { + return value.bitLength() <= bitSize; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/NumericType.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/NumericType.java new file mode 100644 index 000000000..b8a01e1ef --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/NumericType.java @@ -0,0 +1,50 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +import java.math.BigInteger; + +/** Common numeric type. */ +public abstract class NumericType implements Type { + + private String type; + BigInteger value; + + public NumericType(String type, BigInteger value) { + this.type = type; + this.value = value; + } + + @Override + public String getTypeAsString() { + return type; + } + + @Override + public BigInteger getValue() { + return value; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + NumericType that = (NumericType) o; + + if (!type.equals(that.type)) { + return false; + } + + return value != null ? value.equals(that.value) : that.value == null; + } + + @Override + public int hashCode() { + int result = type.hashCode(); + result = 31 * result + (value != null ? value.hashCode() : 0); + return result; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/StaticArray.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/StaticArray.java new file mode 100644 index 000000000..957271c33 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/StaticArray.java @@ -0,0 +1,89 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +import java.util.List; + +/** Static array type. */ +public class StaticArray extends Array { + /** + * Warning: increasing this constant will cause more generated StaticArrayN types, see: + * AbiTypesGenerator#generateStaticArrayTypes + */ + public static int MAX_SIZE_OF_STATIC_ARRAY = 1024; + + private Integer expectedSize; + + @SafeVarargs + public StaticArray(T... values) { + super(values[0].getTypeAsString() + "[" + values.length + "]", values); + isValid(); + } + + @SafeVarargs + public StaticArray(int expectedSize, T... values) { + super(values[0].getTypeAsString() + "[" + values.length + "]", values); + this.expectedSize = expectedSize; + isValid(); + } + + public StaticArray(List values) { + super(values.get(0).getTypeAsString() + "[" + values.size() + "]", values); + isValid(); + } + + public StaticArray(int expectedSize, List values) { + super(values.get(0).getTypeAsString() + "[" + values.size() + "]", values); + this.expectedSize = expectedSize; + isValid(); + } + + private void isValid() { + if (expectedSize == null && value.size() > MAX_SIZE_OF_STATIC_ARRAY) { + throw new UnsupportedOperationException( + "Static arrays with a length greater than 1024 are not supported."); + } else if (expectedSize != null && value.size() != expectedSize) { + throw new UnsupportedOperationException( + "Expected array of type [" + + getClass().getSimpleName() + + "] to have [" + + expectedSize + + "] elements."); + } + } + + @SuppressWarnings("unchecked") + @Override + public boolean dynamicType() { + Type obj = value.get(0); + + if (obj instanceof StaticArray) { + return ((T) obj).dynamicType(); + } else if ((obj instanceof NumericType) + || (obj instanceof Address) + || (obj instanceof Bool) + || (obj instanceof Bytes)) { + return false; + } else if ((obj instanceof DynamicBytes) + || (obj instanceof Utf8String) + || (obj instanceof DynamicArray)) { + return true; + } else { + throw new UnsupportedOperationException("Type cannot be encoded: " + obj.getClass()); + } + } + + @Override + public int offset() { + + if (dynamicType()) { + return 1; + } + + Object obj = value.get(0); + + if (obj instanceof StaticArray) { + return ((Type) obj).offset() * getValue().size(); + } + + return getValue().size(); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Type.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Type.java new file mode 100644 index 000000000..ca9cd09de --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Type.java @@ -0,0 +1,15 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +/** ABI Types. */ +public interface Type { + int MAX_BIT_LENGTH = 256; + int MAX_BYTE_LENGTH = MAX_BIT_LENGTH / 8; + + T getValue(); + + String getTypeAsString(); + + boolean dynamicType(); + + public int offset(); +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Ufixed.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Ufixed.java new file mode 100644 index 000000000..4dce94741 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Ufixed.java @@ -0,0 +1,41 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +import java.math.BigInteger; + +/** Signed fixed type. */ +public class Ufixed extends FixedPointType { + + public static final String TYPE_NAME = "ufixed"; + public static final Ufixed DEFAULT = new Ufixed(BigInteger.ZERO); + + protected Ufixed(int mBitSize, int nBitSize, BigInteger value) { + super(TYPE_NAME, mBitSize, nBitSize, value); + } + + public Ufixed(BigInteger value) { + this(DEFAULT_BIT_LENGTH, DEFAULT_BIT_LENGTH, value); + } + + public Ufixed(BigInteger m, BigInteger n) { + this(convert(m, n)); + } + + protected Ufixed(int mBitSize, int nBitSize, BigInteger m, BigInteger n) { + this(convert(mBitSize, nBitSize, m, n)); + } + + @Override + boolean valid(int mBitSize, int nBitSize, BigInteger value) { + return super.valid(mBitSize, nBitSize, value) && value.signum() != -1; + } + + @Override + public boolean dynamicType() { + return false; + } + + @Override + public int offset() { + return 1; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Uint.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Uint.java new file mode 100644 index 000000000..d6198d47f --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Uint.java @@ -0,0 +1,49 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.Constant; + +/** Unsigned integer type. */ +public class Uint extends IntType { + + public static final String TYPE_NAME = "uint"; + public static final Uint DEFAULT = new Uint(BigInteger.ZERO); + /** This constructor is required by the {@link Address} type. */ + Uint(String typePrefix, int bitSize, BigInteger value) { + super(typePrefix, bitSize, value); + } + + protected Uint(int bitSize, BigInteger value) { + this(TYPE_NAME, bitSize, value); + } + + public Uint(BigInteger value) { + // "int" values should be declared as int256 in computing function selectors + this(MAX_BIT_LENGTH, value); + } + + /** + * check if value between 0 ~ MAX_UINT256 + * + * @param value the value need to be checked + * @return true/false + */ + public boolean validUint(BigInteger value) { + return value.compareTo(BigInteger.ZERO) >= 0 && value.compareTo(Constant.MAX_UINT256) <= 0; + } + + @Override + boolean valid(int bitSize, BigInteger value) { + return super.valid(bitSize, value) && value.signum() != -1 && validUint(value); + } + + @Override + public boolean dynamicType() { + return false; + } + + @Override + public int offset() { + return 1; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Utf8String.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Utf8String.java new file mode 100644 index 000000000..d978d2880 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/Utf8String.java @@ -0,0 +1,58 @@ +package org.fisco.bcos.sdk.abi.datatypes; + +/** UTF-8 encoded string type. */ +public class Utf8String implements Type { + + public static final String TYPE_NAME = "string"; + public static final Utf8String DEFAULT = new Utf8String(""); + + private String value; + + public Utf8String(String value) { + this.value = value; + } + + @Override + public String getValue() { + return value; + } + + @Override + public String getTypeAsString() { + return TYPE_NAME; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Utf8String that = (Utf8String) o; + + return value != null ? value.equals(that.value) : that.value == null; + } + + @Override + public int hashCode() { + return value != null ? value.hashCode() : 0; + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean dynamicType() { + return true; + } + + @Override + public int offset() { + return 1; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/AbiTypes.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/AbiTypes.java new file mode 100644 index 000000000..460529124 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/AbiTypes.java @@ -0,0 +1,225 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Address; +import org.fisco.bcos.sdk.abi.datatypes.Bool; +import org.fisco.bcos.sdk.abi.datatypes.DynamicBytes; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesMapperGenerator in the codegen module to update. + */ +public final class AbiTypes { + private AbiTypes() {} + + public static Class getType(String type) { + switch (type) { + case "address": + return Address.class; + case "bool": + return Bool.class; + case "string": + return Utf8String.class; + case "bytes": + return DynamicBytes.class; + case "uint8": + return Uint8.class; + case "int8": + return Int8.class; + case "uint16": + return Uint16.class; + case "int16": + return Int16.class; + case "uint24": + return Uint24.class; + case "int24": + return Int24.class; + case "uint32": + return Uint32.class; + case "int32": + return Int32.class; + case "uint40": + return Uint40.class; + case "int40": + return Int40.class; + case "uint48": + return Uint48.class; + case "int48": + return Int48.class; + case "uint56": + return Uint56.class; + case "int56": + return Int56.class; + case "uint64": + return Uint64.class; + case "int64": + return Int64.class; + case "uint72": + return Uint72.class; + case "int72": + return Int72.class; + case "uint80": + return Uint80.class; + case "int80": + return Int80.class; + case "uint88": + return Uint88.class; + case "int88": + return Int88.class; + case "uint96": + return Uint96.class; + case "int96": + return Int96.class; + case "uint104": + return Uint104.class; + case "int104": + return Int104.class; + case "uint112": + return Uint112.class; + case "int112": + return Int112.class; + case "uint120": + return Uint120.class; + case "int120": + return Int120.class; + case "uint128": + return Uint128.class; + case "int128": + return Int128.class; + case "uint136": + return Uint136.class; + case "int136": + return Int136.class; + case "uint144": + return Uint144.class; + case "int144": + return Int144.class; + case "uint152": + return Uint152.class; + case "int152": + return Int152.class; + case "uint160": + return Uint160.class; + case "int160": + return Int160.class; + case "uint168": + return Uint168.class; + case "int168": + return Int168.class; + case "uint176": + return Uint176.class; + case "int176": + return Int176.class; + case "uint184": + return Uint184.class; + case "int184": + return Int184.class; + case "uint192": + return Uint192.class; + case "int192": + return Int192.class; + case "uint200": + return Uint200.class; + case "int200": + return Int200.class; + case "uint208": + return Uint208.class; + case "int208": + return Int208.class; + case "uint216": + return Uint216.class; + case "int216": + return Int216.class; + case "uint224": + return Uint224.class; + case "int224": + return Int224.class; + case "uint232": + return Uint232.class; + case "int232": + return Int232.class; + case "uint240": + return Uint240.class; + case "int240": + return Int240.class; + case "uint248": + return Uint248.class; + case "int248": + return Int248.class; + case "uint256": + return Uint256.class; + case "int256": + return Int256.class; + case "bytes1": + return Bytes1.class; + case "bytes2": + return Bytes2.class; + case "bytes3": + return Bytes3.class; + case "bytes4": + return Bytes4.class; + case "bytes5": + return Bytes5.class; + case "bytes6": + return Bytes6.class; + case "bytes7": + return Bytes7.class; + case "bytes8": + return Bytes8.class; + case "bytes9": + return Bytes9.class; + case "bytes10": + return Bytes10.class; + case "bytes11": + return Bytes11.class; + case "bytes12": + return Bytes12.class; + case "bytes13": + return Bytes13.class; + case "bytes14": + return Bytes14.class; + case "bytes15": + return Bytes15.class; + case "bytes16": + return Bytes16.class; + case "bytes17": + return Bytes17.class; + case "bytes18": + return Bytes18.class; + case "bytes19": + return Bytes19.class; + case "bytes20": + return Bytes20.class; + case "bytes21": + return Bytes21.class; + case "bytes22": + return Bytes22.class; + case "bytes23": + return Bytes23.class; + case "bytes24": + return Bytes24.class; + case "bytes25": + return Bytes25.class; + case "bytes26": + return Bytes26.class; + case "bytes27": + return Bytes27.class; + case "bytes28": + return Bytes28.class; + case "bytes29": + return Bytes29.class; + case "bytes30": + return Bytes30.class; + case "bytes31": + return Bytes31.class; + case "bytes32": + return Bytes32.class; + default: + throw new UnsupportedOperationException("Unsupported type encountered: " + type); + } + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes1.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes1.java new file mode 100644 index 000000000..d1446254e --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes1.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes1 extends Bytes { + public static final Bytes1 DEFAULT = new Bytes1(new byte[1]); + + public Bytes1(byte[] value) { + super(1, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes10.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes10.java new file mode 100644 index 000000000..f2b318019 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes10.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes10 extends Bytes { + public static final Bytes10 DEFAULT = new Bytes10(new byte[10]); + + public Bytes10(byte[] value) { + super(10, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes11.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes11.java new file mode 100644 index 000000000..5deef2905 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes11.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes11 extends Bytes { + public static final Bytes11 DEFAULT = new Bytes11(new byte[11]); + + public Bytes11(byte[] value) { + super(11, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes12.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes12.java new file mode 100644 index 000000000..1664078a1 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes12.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes12 extends Bytes { + public static final Bytes12 DEFAULT = new Bytes12(new byte[12]); + + public Bytes12(byte[] value) { + super(12, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes13.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes13.java new file mode 100644 index 000000000..9b422f0cd --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes13.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes13 extends Bytes { + public static final Bytes13 DEFAULT = new Bytes13(new byte[13]); + + public Bytes13(byte[] value) { + super(13, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes14.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes14.java new file mode 100644 index 000000000..b2f0756b9 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes14.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes14 extends Bytes { + public static final Bytes14 DEFAULT = new Bytes14(new byte[14]); + + public Bytes14(byte[] value) { + super(14, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes15.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes15.java new file mode 100644 index 000000000..1a4f6b727 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes15.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes15 extends Bytes { + public static final Bytes15 DEFAULT = new Bytes15(new byte[15]); + + public Bytes15(byte[] value) { + super(15, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes16.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes16.java new file mode 100644 index 000000000..c944b7feb --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes16.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes16 extends Bytes { + public static final Bytes16 DEFAULT = new Bytes16(new byte[16]); + + public Bytes16(byte[] value) { + super(16, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes17.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes17.java new file mode 100644 index 000000000..540b4734f --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes17.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes17 extends Bytes { + public static final Bytes17 DEFAULT = new Bytes17(new byte[17]); + + public Bytes17(byte[] value) { + super(17, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes18.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes18.java new file mode 100644 index 000000000..14470e067 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes18.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes18 extends Bytes { + public static final Bytes18 DEFAULT = new Bytes18(new byte[18]); + + public Bytes18(byte[] value) { + super(18, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes19.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes19.java new file mode 100644 index 000000000..8d4070bc8 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes19.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes19 extends Bytes { + public static final Bytes19 DEFAULT = new Bytes19(new byte[19]); + + public Bytes19(byte[] value) { + super(19, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes2.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes2.java new file mode 100644 index 000000000..21ef575ad --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes2.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes2 extends Bytes { + public static final Bytes2 DEFAULT = new Bytes2(new byte[2]); + + public Bytes2(byte[] value) { + super(2, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes20.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes20.java new file mode 100644 index 000000000..81af614ed --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes20.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes20 extends Bytes { + public static final Bytes20 DEFAULT = new Bytes20(new byte[20]); + + public Bytes20(byte[] value) { + super(20, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes21.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes21.java new file mode 100644 index 000000000..7d8a07cc8 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes21.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes21 extends Bytes { + public static final Bytes21 DEFAULT = new Bytes21(new byte[21]); + + public Bytes21(byte[] value) { + super(21, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes22.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes22.java new file mode 100644 index 000000000..cac31ef7a --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes22.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes22 extends Bytes { + public static final Bytes22 DEFAULT = new Bytes22(new byte[22]); + + public Bytes22(byte[] value) { + super(22, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes23.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes23.java new file mode 100644 index 000000000..348b68919 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes23.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes23 extends Bytes { + public static final Bytes23 DEFAULT = new Bytes23(new byte[23]); + + public Bytes23(byte[] value) { + super(23, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes24.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes24.java new file mode 100644 index 000000000..38e2219c7 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes24.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes24 extends Bytes { + public static final Bytes24 DEFAULT = new Bytes24(new byte[24]); + + public Bytes24(byte[] value) { + super(24, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes25.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes25.java new file mode 100644 index 000000000..d092a5040 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes25.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes25 extends Bytes { + public static final Bytes25 DEFAULT = new Bytes25(new byte[25]); + + public Bytes25(byte[] value) { + super(25, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes26.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes26.java new file mode 100644 index 000000000..c5b237de5 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes26.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes26 extends Bytes { + public static final Bytes26 DEFAULT = new Bytes26(new byte[26]); + + public Bytes26(byte[] value) { + super(26, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes27.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes27.java new file mode 100644 index 000000000..c1891a19c --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes27.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes27 extends Bytes { + public static final Bytes27 DEFAULT = new Bytes27(new byte[27]); + + public Bytes27(byte[] value) { + super(27, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes28.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes28.java new file mode 100644 index 000000000..6db753ff4 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes28.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes28 extends Bytes { + public static final Bytes28 DEFAULT = new Bytes28(new byte[28]); + + public Bytes28(byte[] value) { + super(28, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes29.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes29.java new file mode 100644 index 000000000..ee36929d0 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes29.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes29 extends Bytes { + public static final Bytes29 DEFAULT = new Bytes29(new byte[29]); + + public Bytes29(byte[] value) { + super(29, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes3.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes3.java new file mode 100644 index 000000000..02a52eebb --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes3.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes3 extends Bytes { + public static final Bytes3 DEFAULT = new Bytes3(new byte[3]); + + public Bytes3(byte[] value) { + super(3, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes30.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes30.java new file mode 100644 index 000000000..475d1cbc1 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes30.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes30 extends Bytes { + public static final Bytes30 DEFAULT = new Bytes30(new byte[30]); + + public Bytes30(byte[] value) { + super(30, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes31.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes31.java new file mode 100644 index 000000000..237bb680c --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes31.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes31 extends Bytes { + public static final Bytes31 DEFAULT = new Bytes31(new byte[31]); + + public Bytes31(byte[] value) { + super(31, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes32.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes32.java new file mode 100644 index 000000000..cb1e3a5cd --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes32.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes32 extends Bytes { + public static final Bytes32 DEFAULT = new Bytes32(new byte[32]); + + public Bytes32(byte[] value) { + super(32, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes4.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes4.java new file mode 100644 index 000000000..3bba13b8a --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes4.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes4 extends Bytes { + public static final Bytes4 DEFAULT = new Bytes4(new byte[4]); + + public Bytes4(byte[] value) { + super(4, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes5.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes5.java new file mode 100644 index 000000000..37d4e9c0c --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes5.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes5 extends Bytes { + public static final Bytes5 DEFAULT = new Bytes5(new byte[5]); + + public Bytes5(byte[] value) { + super(5, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes6.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes6.java new file mode 100644 index 000000000..0363c872e --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes6.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes6 extends Bytes { + public static final Bytes6 DEFAULT = new Bytes6(new byte[6]); + + public Bytes6(byte[] value) { + super(6, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes7.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes7.java new file mode 100644 index 000000000..cbd9e62d2 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes7.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes7 extends Bytes { + public static final Bytes7 DEFAULT = new Bytes7(new byte[7]); + + public Bytes7(byte[] value) { + super(7, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes8.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes8.java new file mode 100644 index 000000000..d0ca2bbf5 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes8.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes8 extends Bytes { + public static final Bytes8 DEFAULT = new Bytes8(new byte[8]); + + public Bytes8(byte[] value) { + super(8, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes9.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes9.java new file mode 100644 index 000000000..4d22eda8b --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Bytes9.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import org.fisco.bcos.sdk.abi.datatypes.Bytes; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Bytes9 extends Bytes { + public static final Bytes9 DEFAULT = new Bytes9(new byte[9]); + + public Bytes9(byte[] value) { + super(9, value); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int104.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int104.java new file mode 100644 index 000000000..91f430be1 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int104.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int104 extends Int { + public static final Int104 DEFAULT = new Int104(BigInteger.ZERO); + + public Int104(BigInteger value) { + super(104, value); + } + + public Int104(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int112.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int112.java new file mode 100644 index 000000000..1f1a8cf0b --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int112.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int112 extends Int { + public static final Int112 DEFAULT = new Int112(BigInteger.ZERO); + + public Int112(BigInteger value) { + super(112, value); + } + + public Int112(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int120.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int120.java new file mode 100644 index 000000000..cd7e1708b --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int120.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int120 extends Int { + public static final Int120 DEFAULT = new Int120(BigInteger.ZERO); + + public Int120(BigInteger value) { + super(120, value); + } + + public Int120(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int128.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int128.java new file mode 100644 index 000000000..344bf0060 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int128.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int128 extends Int { + public static final Int128 DEFAULT = new Int128(BigInteger.ZERO); + + public Int128(BigInteger value) { + super(128, value); + } + + public Int128(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int136.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int136.java new file mode 100644 index 000000000..856a44920 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int136.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int136 extends Int { + public static final Int136 DEFAULT = new Int136(BigInteger.ZERO); + + public Int136(BigInteger value) { + super(136, value); + } + + public Int136(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int144.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int144.java new file mode 100644 index 000000000..44aa9e51a --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int144.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int144 extends Int { + public static final Int144 DEFAULT = new Int144(BigInteger.ZERO); + + public Int144(BigInteger value) { + super(144, value); + } + + public Int144(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int152.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int152.java new file mode 100644 index 000000000..3bca3375e --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int152.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int152 extends Int { + public static final Int152 DEFAULT = new Int152(BigInteger.ZERO); + + public Int152(BigInteger value) { + super(152, value); + } + + public Int152(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int16.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int16.java new file mode 100644 index 000000000..804552972 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int16.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int16 extends Int { + public static final Int16 DEFAULT = new Int16(BigInteger.ZERO); + + public Int16(BigInteger value) { + super(16, value); + } + + public Int16(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int160.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int160.java new file mode 100644 index 000000000..ff39da4a8 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int160.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int160 extends Int { + public static final Int160 DEFAULT = new Int160(BigInteger.ZERO); + + public Int160(BigInteger value) { + super(160, value); + } + + public Int160(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int168.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int168.java new file mode 100644 index 000000000..cca780247 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int168.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int168 extends Int { + public static final Int168 DEFAULT = new Int168(BigInteger.ZERO); + + public Int168(BigInteger value) { + super(168, value); + } + + public Int168(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int176.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int176.java new file mode 100644 index 000000000..1091766a1 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int176.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int176 extends Int { + public static final Int176 DEFAULT = new Int176(BigInteger.ZERO); + + public Int176(BigInteger value) { + super(176, value); + } + + public Int176(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int184.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int184.java new file mode 100644 index 000000000..79bb8634e --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int184.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int184 extends Int { + public static final Int184 DEFAULT = new Int184(BigInteger.ZERO); + + public Int184(BigInteger value) { + super(184, value); + } + + public Int184(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int192.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int192.java new file mode 100644 index 000000000..83a1a3989 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int192.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int192 extends Int { + public static final Int192 DEFAULT = new Int192(BigInteger.ZERO); + + public Int192(BigInteger value) { + super(192, value); + } + + public Int192(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int200.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int200.java new file mode 100644 index 000000000..78350dceb --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int200.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int200 extends Int { + public static final Int200 DEFAULT = new Int200(BigInteger.ZERO); + + public Int200(BigInteger value) { + super(200, value); + } + + public Int200(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int208.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int208.java new file mode 100644 index 000000000..0a4f4bb37 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int208.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int208 extends Int { + public static final Int208 DEFAULT = new Int208(BigInteger.ZERO); + + public Int208(BigInteger value) { + super(208, value); + } + + public Int208(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int216.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int216.java new file mode 100644 index 000000000..5c57bc4e1 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int216.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int216 extends Int { + public static final Int216 DEFAULT = new Int216(BigInteger.ZERO); + + public Int216(BigInteger value) { + super(216, value); + } + + public Int216(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int224.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int224.java new file mode 100644 index 000000000..f0cabec18 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int224.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int224 extends Int { + public static final Int224 DEFAULT = new Int224(BigInteger.ZERO); + + public Int224(BigInteger value) { + super(224, value); + } + + public Int224(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int232.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int232.java new file mode 100644 index 000000000..82e5315ca --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int232.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int232 extends Int { + public static final Int232 DEFAULT = new Int232(BigInteger.ZERO); + + public Int232(BigInteger value) { + super(232, value); + } + + public Int232(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int24.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int24.java new file mode 100644 index 000000000..30e160d2f --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int24.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int24 extends Int { + public static final Int24 DEFAULT = new Int24(BigInteger.ZERO); + + public Int24(BigInteger value) { + super(24, value); + } + + public Int24(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int240.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int240.java new file mode 100644 index 000000000..f796a3430 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int240.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int240 extends Int { + public static final Int240 DEFAULT = new Int240(BigInteger.ZERO); + + public Int240(BigInteger value) { + super(240, value); + } + + public Int240(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int248.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int248.java new file mode 100644 index 000000000..4de02c9d2 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int248.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int248 extends Int { + public static final Int248 DEFAULT = new Int248(BigInteger.ZERO); + + public Int248(BigInteger value) { + super(248, value); + } + + public Int248(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int256.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int256.java new file mode 100644 index 000000000..fc5c1562e --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int256.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int256 extends Int { + public static final Int256 DEFAULT = new Int256(BigInteger.ZERO); + + public Int256(BigInteger value) { + super(256, value); + } + + public Int256(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int32.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int32.java new file mode 100644 index 000000000..3f0441a95 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int32.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int32 extends Int { + public static final Int32 DEFAULT = new Int32(BigInteger.ZERO); + + public Int32(BigInteger value) { + super(32, value); + } + + public Int32(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int40.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int40.java new file mode 100644 index 000000000..5807a2ac8 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int40.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int40 extends Int { + public static final Int40 DEFAULT = new Int40(BigInteger.ZERO); + + public Int40(BigInteger value) { + super(40, value); + } + + public Int40(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int48.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int48.java new file mode 100644 index 000000000..3533d5af6 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int48.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int48 extends Int { + public static final Int48 DEFAULT = new Int48(BigInteger.ZERO); + + public Int48(BigInteger value) { + super(48, value); + } + + public Int48(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int56.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int56.java new file mode 100644 index 000000000..d9ca278a3 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int56.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int56 extends Int { + public static final Int56 DEFAULT = new Int56(BigInteger.ZERO); + + public Int56(BigInteger value) { + super(56, value); + } + + public Int56(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int64.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int64.java new file mode 100644 index 000000000..d5a0020b2 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int64.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int64 extends Int { + public static final Int64 DEFAULT = new Int64(BigInteger.ZERO); + + public Int64(BigInteger value) { + super(64, value); + } + + public Int64(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int72.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int72.java new file mode 100644 index 000000000..e42301c56 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int72.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int72 extends Int { + public static final Int72 DEFAULT = new Int72(BigInteger.ZERO); + + public Int72(BigInteger value) { + super(72, value); + } + + public Int72(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int8.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int8.java new file mode 100644 index 000000000..caadabbfc --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int8.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int8 extends Int { + public static final Int8 DEFAULT = new Int8(BigInteger.ZERO); + + public Int8(BigInteger value) { + super(8, value); + } + + public Int8(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int80.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int80.java new file mode 100644 index 000000000..823826afb --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int80.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int80 extends Int { + public static final Int80 DEFAULT = new Int80(BigInteger.ZERO); + + public Int80(BigInteger value) { + super(80, value); + } + + public Int80(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int88.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int88.java new file mode 100644 index 000000000..3337b1cb4 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int88.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int88 extends Int { + public static final Int88 DEFAULT = new Int88(BigInteger.ZERO); + + public Int88(BigInteger value) { + super(88, value); + } + + public Int88(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int96.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int96.java new file mode 100644 index 000000000..70ffdf022 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Int96.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Int; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Int96 extends Int { + public static final Int96 DEFAULT = new Int96(BigInteger.ZERO); + + public Int96(BigInteger value) { + super(96, value); + } + + public Int96(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray1.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray1.java new file mode 100644 index 000000000..a3628ca82 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray1.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray1 extends StaticArray { + public StaticArray1(List values) { + super(1, values); + } + + @SafeVarargs + public StaticArray1(T... values) { + super(1, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray10.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray10.java new file mode 100644 index 000000000..549208a12 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray10.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray10 extends StaticArray { + public StaticArray10(List values) { + super(10, values); + } + + @SafeVarargs + public StaticArray10(T... values) { + super(10, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray11.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray11.java new file mode 100644 index 000000000..b64644485 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray11.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray11 extends StaticArray { + public StaticArray11(List values) { + super(11, values); + } + + @SafeVarargs + public StaticArray11(T... values) { + super(11, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray12.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray12.java new file mode 100644 index 000000000..b520868d7 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray12.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray12 extends StaticArray { + public StaticArray12(List values) { + super(12, values); + } + + @SafeVarargs + public StaticArray12(T... values) { + super(12, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray128.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray128.java new file mode 100644 index 000000000..a4469527b --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray128.java @@ -0,0 +1,35 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use org.web3j.codegen.AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray128 extends StaticArray { + @Deprecated + public StaticArray128(List values) { + super(128, values); + } + + @Deprecated + @SafeVarargs + public StaticArray128(T... values) { + super(128, values); + } + // + // public StaticArray128(Class type, List values) { + // super(type, 128, values); + // } + // + // @SafeVarargs + // public StaticArray128(Class type, T... values) { + // super(type, 128, values); + // } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray13.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray13.java new file mode 100644 index 000000000..32391fa9f --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray13.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray13 extends StaticArray { + public StaticArray13(List values) { + super(13, values); + } + + @SafeVarargs + public StaticArray13(T... values) { + super(13, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray14.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray14.java new file mode 100644 index 000000000..680d29e0a --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray14.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray14 extends StaticArray { + public StaticArray14(List values) { + super(14, values); + } + + @SafeVarargs + public StaticArray14(T... values) { + super(14, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray15.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray15.java new file mode 100644 index 000000000..c9f4b07bb --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray15.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray15 extends StaticArray { + public StaticArray15(List values) { + super(15, values); + } + + @SafeVarargs + public StaticArray15(T... values) { + super(15, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray16.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray16.java new file mode 100644 index 000000000..92e5a8442 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray16.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray16 extends StaticArray { + public StaticArray16(List values) { + super(16, values); + } + + @SafeVarargs + public StaticArray16(T... values) { + super(16, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray17.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray17.java new file mode 100644 index 000000000..c0e5a44b6 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray17.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray17 extends StaticArray { + public StaticArray17(List values) { + super(17, values); + } + + @SafeVarargs + public StaticArray17(T... values) { + super(17, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray18.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray18.java new file mode 100644 index 000000000..10261b048 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray18.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray18 extends StaticArray { + public StaticArray18(List values) { + super(18, values); + } + + @SafeVarargs + public StaticArray18(T... values) { + super(18, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray19.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray19.java new file mode 100644 index 000000000..861b9b68a --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray19.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray19 extends StaticArray { + public StaticArray19(List values) { + super(19, values); + } + + @SafeVarargs + public StaticArray19(T... values) { + super(19, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray2.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray2.java new file mode 100644 index 000000000..af50b5ed0 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray2.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray2 extends StaticArray { + public StaticArray2(List values) { + super(2, values); + } + + @SafeVarargs + public StaticArray2(T... values) { + super(2, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray20.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray20.java new file mode 100644 index 000000000..3a4ef52aa --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray20.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray20 extends StaticArray { + public StaticArray20(List values) { + super(20, values); + } + + @SafeVarargs + public StaticArray20(T... values) { + super(20, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray21.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray21.java new file mode 100644 index 000000000..83fad2583 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray21.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray21 extends StaticArray { + public StaticArray21(List values) { + super(21, values); + } + + @SafeVarargs + public StaticArray21(T... values) { + super(21, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray22.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray22.java new file mode 100644 index 000000000..ba6d078d6 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray22.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray22 extends StaticArray { + public StaticArray22(List values) { + super(22, values); + } + + @SafeVarargs + public StaticArray22(T... values) { + super(22, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray23.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray23.java new file mode 100644 index 000000000..f29d51ef1 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray23.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray23 extends StaticArray { + public StaticArray23(List values) { + super(23, values); + } + + @SafeVarargs + public StaticArray23(T... values) { + super(23, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray24.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray24.java new file mode 100644 index 000000000..9928e5bf8 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray24.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray24 extends StaticArray { + public StaticArray24(List values) { + super(24, values); + } + + @SafeVarargs + public StaticArray24(T... values) { + super(24, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray25.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray25.java new file mode 100644 index 000000000..fd204865e --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray25.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray25 extends StaticArray { + public StaticArray25(List values) { + super(25, values); + } + + @SafeVarargs + public StaticArray25(T... values) { + super(25, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray26.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray26.java new file mode 100644 index 000000000..919179488 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray26.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray26 extends StaticArray { + public StaticArray26(List values) { + super(26, values); + } + + @SafeVarargs + public StaticArray26(T... values) { + super(26, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray27.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray27.java new file mode 100644 index 000000000..d9df13688 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray27.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray27 extends StaticArray { + public StaticArray27(List values) { + super(27, values); + } + + @SafeVarargs + public StaticArray27(T... values) { + super(27, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray28.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray28.java new file mode 100644 index 000000000..90b6f2ea3 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray28.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray28 extends StaticArray { + public StaticArray28(List values) { + super(28, values); + } + + @SafeVarargs + public StaticArray28(T... values) { + super(28, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray29.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray29.java new file mode 100644 index 000000000..e245cd4ae --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray29.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray29 extends StaticArray { + public StaticArray29(List values) { + super(29, values); + } + + @SafeVarargs + public StaticArray29(T... values) { + super(29, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray3.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray3.java new file mode 100644 index 000000000..b412b5316 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray3.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray3 extends StaticArray { + public StaticArray3(List values) { + super(3, values); + } + + @SafeVarargs + public StaticArray3(T... values) { + super(3, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray30.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray30.java new file mode 100644 index 000000000..e933c647c --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray30.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray30 extends StaticArray { + public StaticArray30(List values) { + super(30, values); + } + + @SafeVarargs + public StaticArray30(T... values) { + super(30, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray31.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray31.java new file mode 100644 index 000000000..7a2112811 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray31.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray31 extends StaticArray { + public StaticArray31(List values) { + super(31, values); + } + + @SafeVarargs + public StaticArray31(T... values) { + super(31, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray32.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray32.java new file mode 100644 index 000000000..fe69fa45c --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray32.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray32 extends StaticArray { + public StaticArray32(List values) { + super(32, values); + } + + @SafeVarargs + public StaticArray32(T... values) { + super(32, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray4.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray4.java new file mode 100644 index 000000000..e6194e7da --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray4.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray4 extends StaticArray { + public StaticArray4(List values) { + super(4, values); + } + + @SafeVarargs + public StaticArray4(T... values) { + super(4, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray5.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray5.java new file mode 100644 index 000000000..c39451be5 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray5.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray5 extends StaticArray { + public StaticArray5(List values) { + super(5, values); + } + + @SafeVarargs + public StaticArray5(T... values) { + super(5, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray6.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray6.java new file mode 100644 index 000000000..2fdd2b60a --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray6.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray6 extends StaticArray { + public StaticArray6(List values) { + super(6, values); + } + + @SafeVarargs + public StaticArray6(T... values) { + super(6, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray7.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray7.java new file mode 100644 index 000000000..c31125d69 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray7.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray7 extends StaticArray { + public StaticArray7(List values) { + super(7, values); + } + + @SafeVarargs + public StaticArray7(T... values) { + super(7, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray8.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray8.java new file mode 100644 index 000000000..e36ad5cc8 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray8.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray8 extends StaticArray { + public StaticArray8(List values) { + super(8, values); + } + + @SafeVarargs + public StaticArray8(T... values) { + super(8, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray9.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray9.java new file mode 100644 index 000000000..bd297958b --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/StaticArray9.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class StaticArray9 extends StaticArray { + public StaticArray9(List values) { + super(9, values); + } + + @SafeVarargs + public StaticArray9(T... values) { + super(9, values); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint104.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint104.java new file mode 100644 index 000000000..346bd2535 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint104.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint104 extends Uint { + public static final Uint104 DEFAULT = new Uint104(BigInteger.ZERO); + + public Uint104(BigInteger value) { + super(104, value); + } + + public Uint104(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint112.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint112.java new file mode 100644 index 000000000..1b2516e7f --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint112.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint112 extends Uint { + public static final Uint112 DEFAULT = new Uint112(BigInteger.ZERO); + + public Uint112(BigInteger value) { + super(112, value); + } + + public Uint112(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint120.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint120.java new file mode 100644 index 000000000..0eaebfc9a --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint120.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint120 extends Uint { + public static final Uint120 DEFAULT = new Uint120(BigInteger.ZERO); + + public Uint120(BigInteger value) { + super(120, value); + } + + public Uint120(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint128.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint128.java new file mode 100644 index 000000000..0c57ba77d --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint128.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint128 extends Uint { + public static final Uint128 DEFAULT = new Uint128(BigInteger.ZERO); + + public Uint128(BigInteger value) { + super(128, value); + } + + public Uint128(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint136.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint136.java new file mode 100644 index 000000000..d713bfb12 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint136.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint136 extends Uint { + public static final Uint136 DEFAULT = new Uint136(BigInteger.ZERO); + + public Uint136(BigInteger value) { + super(136, value); + } + + public Uint136(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint144.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint144.java new file mode 100644 index 000000000..aef591023 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint144.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint144 extends Uint { + public static final Uint144 DEFAULT = new Uint144(BigInteger.ZERO); + + public Uint144(BigInteger value) { + super(144, value); + } + + public Uint144(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint152.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint152.java new file mode 100644 index 000000000..3d0d1226c --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint152.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint152 extends Uint { + public static final Uint152 DEFAULT = new Uint152(BigInteger.ZERO); + + public Uint152(BigInteger value) { + super(152, value); + } + + public Uint152(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint16.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint16.java new file mode 100644 index 000000000..5addb5687 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint16.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint16 extends Uint { + public static final Uint16 DEFAULT = new Uint16(BigInteger.ZERO); + + public Uint16(BigInteger value) { + super(16, value); + } + + public Uint16(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint160.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint160.java new file mode 100644 index 000000000..2a6fff516 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint160.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint160 extends Uint { + public static final Uint160 DEFAULT = new Uint160(BigInteger.ZERO); + + public Uint160(BigInteger value) { + super(160, value); + } + + public Uint160(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint168.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint168.java new file mode 100644 index 000000000..f929b00f7 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint168.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint168 extends Uint { + public static final Uint168 DEFAULT = new Uint168(BigInteger.ZERO); + + public Uint168(BigInteger value) { + super(168, value); + } + + public Uint168(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint176.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint176.java new file mode 100644 index 000000000..1bf2c031c --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint176.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint176 extends Uint { + public static final Uint176 DEFAULT = new Uint176(BigInteger.ZERO); + + public Uint176(BigInteger value) { + super(176, value); + } + + public Uint176(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint184.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint184.java new file mode 100644 index 000000000..c8316e336 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint184.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint184 extends Uint { + public static final Uint184 DEFAULT = new Uint184(BigInteger.ZERO); + + public Uint184(BigInteger value) { + super(184, value); + } + + public Uint184(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint192.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint192.java new file mode 100644 index 000000000..81e5216ed --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint192.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint192 extends Uint { + public static final Uint192 DEFAULT = new Uint192(BigInteger.ZERO); + + public Uint192(BigInteger value) { + super(192, value); + } + + public Uint192(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint200.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint200.java new file mode 100644 index 000000000..b14a21e92 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint200.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint200 extends Uint { + public static final Uint200 DEFAULT = new Uint200(BigInteger.ZERO); + + public Uint200(BigInteger value) { + super(200, value); + } + + public Uint200(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint208.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint208.java new file mode 100644 index 000000000..d558bfbd1 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint208.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint208 extends Uint { + public static final Uint208 DEFAULT = new Uint208(BigInteger.ZERO); + + public Uint208(BigInteger value) { + super(208, value); + } + + public Uint208(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint216.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint216.java new file mode 100644 index 000000000..e947abc3b --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint216.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint216 extends Uint { + public static final Uint216 DEFAULT = new Uint216(BigInteger.ZERO); + + public Uint216(BigInteger value) { + super(216, value); + } + + public Uint216(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint224.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint224.java new file mode 100644 index 000000000..17a0b2086 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint224.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint224 extends Uint { + public static final Uint224 DEFAULT = new Uint224(BigInteger.ZERO); + + public Uint224(BigInteger value) { + super(224, value); + } + + public Uint224(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint232.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint232.java new file mode 100644 index 000000000..4940a511e --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint232.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint232 extends Uint { + public static final Uint232 DEFAULT = new Uint232(BigInteger.ZERO); + + public Uint232(BigInteger value) { + super(232, value); + } + + public Uint232(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint24.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint24.java new file mode 100644 index 000000000..ad31fe02b --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint24.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint24 extends Uint { + public static final Uint24 DEFAULT = new Uint24(BigInteger.ZERO); + + public Uint24(BigInteger value) { + super(24, value); + } + + public Uint24(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint240.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint240.java new file mode 100644 index 000000000..494a16e79 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint240.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint240 extends Uint { + public static final Uint240 DEFAULT = new Uint240(BigInteger.ZERO); + + public Uint240(BigInteger value) { + super(240, value); + } + + public Uint240(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint248.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint248.java new file mode 100644 index 000000000..65736b5a9 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint248.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint248 extends Uint { + public static final Uint248 DEFAULT = new Uint248(BigInteger.ZERO); + + public Uint248(BigInteger value) { + super(248, value); + } + + public Uint248(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint256.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint256.java new file mode 100644 index 000000000..cfc78549a --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint256.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint256 extends Uint { + public static final Uint256 DEFAULT = new Uint256(BigInteger.ZERO); + + public Uint256(BigInteger value) { + super(256, value); + } + + public Uint256(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint32.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint32.java new file mode 100644 index 000000000..12aa9af7f --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint32.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint32 extends Uint { + public static final Uint32 DEFAULT = new Uint32(BigInteger.ZERO); + + public Uint32(BigInteger value) { + super(32, value); + } + + public Uint32(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint40.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint40.java new file mode 100644 index 000000000..03aa46eb9 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint40.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint40 extends Uint { + public static final Uint40 DEFAULT = new Uint40(BigInteger.ZERO); + + public Uint40(BigInteger value) { + super(40, value); + } + + public Uint40(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint48.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint48.java new file mode 100644 index 000000000..25fddad29 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint48.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint48 extends Uint { + public static final Uint48 DEFAULT = new Uint48(BigInteger.ZERO); + + public Uint48(BigInteger value) { + super(48, value); + } + + public Uint48(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint56.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint56.java new file mode 100644 index 000000000..d0bf94023 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint56.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint56 extends Uint { + public static final Uint56 DEFAULT = new Uint56(BigInteger.ZERO); + + public Uint56(BigInteger value) { + super(56, value); + } + + public Uint56(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint64.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint64.java new file mode 100644 index 000000000..2cc9e4fdf --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint64.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint64 extends Uint { + public static final Uint64 DEFAULT = new Uint64(BigInteger.ZERO); + + public Uint64(BigInteger value) { + super(64, value); + } + + public Uint64(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint72.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint72.java new file mode 100644 index 000000000..1f2ff459e --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint72.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint72 extends Uint { + public static final Uint72 DEFAULT = new Uint72(BigInteger.ZERO); + + public Uint72(BigInteger value) { + super(72, value); + } + + public Uint72(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint8.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint8.java new file mode 100644 index 000000000..8b945e0e6 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint8.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint8 extends Uint { + public static final Uint8 DEFAULT = new Uint8(BigInteger.ZERO); + + public Uint8(BigInteger value) { + super(8, value); + } + + public Uint8(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint80.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint80.java new file mode 100644 index 000000000..66a7e78f4 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint80.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint80 extends Uint { + public static final Uint80 DEFAULT = new Uint80(BigInteger.ZERO); + + public Uint80(BigInteger value) { + super(80, value); + } + + public Uint80(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint88.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint88.java new file mode 100644 index 000000000..f8b24ac32 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint88.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint88 extends Uint { + public static final Uint88 DEFAULT = new Uint88(BigInteger.ZERO); + + public Uint88(BigInteger value) { + super(88, value); + } + + public Uint88(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint96.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint96.java new file mode 100644 index 000000000..4eaf7d9c6 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/Uint96.java @@ -0,0 +1,24 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Uint; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use AbiTypesGenerator in the codegen module to update. + */ +public class Uint96 extends Uint { + public static final Uint96 DEFAULT = new Uint96(BigInteger.ZERO); + + public Uint96(BigInteger value) { + super(96, value); + } + + public Uint96(long value) { + this(BigInteger.valueOf(value)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/Tuple.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/Tuple.java new file mode 100644 index 000000000..7a6e71903 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/Tuple.java @@ -0,0 +1,7 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples; + +/** Tuple abstraction. */ +public interface Tuple { + + int getSize(); +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple1.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple1.java new file mode 100644 index 000000000..4c7e8fa69 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple1.java @@ -0,0 +1,53 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple1 implements Tuple { + private static final int SIZE = 1; + + private final T1 value1; + + public Tuple1(T1 value1) { + this.value1 = value1; + } + + public T1 getValue1() { + return value1; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple1 tuple1 = (Tuple1) o; + return value1 != null ? value1.equals(tuple1.value1) : tuple1.value1 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + return result; + } + + @Override + public String toString() { + return "Tuple1{" + "value1=" + value1 + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple10.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple10.java new file mode 100644 index 000000000..51988647b --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple10.java @@ -0,0 +1,183 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple10 implements Tuple { + private static final int SIZE = 10; + + private final T1 value1; + + private final T2 value2; + + private final T3 value3; + + private final T4 value4; + + private final T5 value5; + + private final T6 value6; + + private final T7 value7; + + private final T8 value8; + + private final T9 value9; + + private final T10 value10; + + public Tuple10( + T1 value1, + T2 value2, + T3 value3, + T4 value4, + T5 value5, + T6 value6, + T7 value7, + T8 value8, + T9 value9, + T10 value10) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + this.value4 = value4; + this.value5 = value5; + this.value6 = value6; + this.value7 = value7; + this.value8 = value8; + this.value9 = value9; + this.value10 = value10; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + public T3 getValue3() { + return value3; + } + + public T4 getValue4() { + return value4; + } + + public T5 getValue5() { + return value5; + } + + public T6 getValue6() { + return value6; + } + + public T7 getValue7() { + return value7; + } + + public T8 getValue8() { + return value8; + } + + public T9 getValue9() { + return value9; + } + + public T10 getValue10() { + return value10; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple10 tuple10 = (Tuple10) o; + if (value1 != null ? !value1.equals(tuple10.value1) : tuple10.value1 != null) { + return false; + } + if (value2 != null ? !value2.equals(tuple10.value2) : tuple10.value2 != null) { + return false; + } + if (value3 != null ? !value3.equals(tuple10.value3) : tuple10.value3 != null) { + return false; + } + if (value4 != null ? !value4.equals(tuple10.value4) : tuple10.value4 != null) { + return false; + } + if (value5 != null ? !value5.equals(tuple10.value5) : tuple10.value5 != null) { + return false; + } + if (value6 != null ? !value6.equals(tuple10.value6) : tuple10.value6 != null) { + return false; + } + if (value7 != null ? !value7.equals(tuple10.value7) : tuple10.value7 != null) { + return false; + } + if (value8 != null ? !value8.equals(tuple10.value8) : tuple10.value8 != null) { + return false; + } + if (value9 != null ? !value9.equals(tuple10.value9) : tuple10.value9 != null) { + return false; + } + return value10 != null ? value10.equals(tuple10.value10) : tuple10.value10 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + result = 31 * result + (value4 != null ? value4.hashCode() : 0); + result = 31 * result + (value5 != null ? value5.hashCode() : 0); + result = 31 * result + (value6 != null ? value6.hashCode() : 0); + result = 31 * result + (value7 != null ? value7.hashCode() : 0); + result = 31 * result + (value8 != null ? value8.hashCode() : 0); + result = 31 * result + (value9 != null ? value9.hashCode() : 0); + result = 31 * result + (value10 != null ? value10.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple10{" + + "value1=" + + value1 + + ", value2=" + + value2 + + ", value3=" + + value3 + + ", value4=" + + value4 + + ", value5=" + + value5 + + ", value6=" + + value6 + + ", value7=" + + value7 + + ", value8=" + + value8 + + ", value9=" + + value9 + + ", value10=" + + value10 + + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple11.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple11.java new file mode 100644 index 000000000..900de99d3 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple11.java @@ -0,0 +1,198 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple11 implements Tuple { + private static final int SIZE = 11; + + private final T1 value1; + + private final T2 value2; + + private final T3 value3; + + private final T4 value4; + + private final T5 value5; + + private final T6 value6; + + private final T7 value7; + + private final T8 value8; + + private final T9 value9; + + private final T10 value10; + + private final T11 value11; + + public Tuple11( + T1 value1, + T2 value2, + T3 value3, + T4 value4, + T5 value5, + T6 value6, + T7 value7, + T8 value8, + T9 value9, + T10 value10, + T11 value11) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + this.value4 = value4; + this.value5 = value5; + this.value6 = value6; + this.value7 = value7; + this.value8 = value8; + this.value9 = value9; + this.value10 = value10; + this.value11 = value11; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + public T3 getValue3() { + return value3; + } + + public T4 getValue4() { + return value4; + } + + public T5 getValue5() { + return value5; + } + + public T6 getValue6() { + return value6; + } + + public T7 getValue7() { + return value7; + } + + public T8 getValue8() { + return value8; + } + + public T9 getValue9() { + return value9; + } + + public T10 getValue10() { + return value10; + } + + public T11 getValue11() { + return value11; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple11 tuple11 = + (Tuple11) o; + if (value1 != null ? !value1.equals(tuple11.value1) : tuple11.value1 != null) { + return false; + } + if (value2 != null ? !value2.equals(tuple11.value2) : tuple11.value2 != null) { + return false; + } + if (value3 != null ? !value3.equals(tuple11.value3) : tuple11.value3 != null) { + return false; + } + if (value4 != null ? !value4.equals(tuple11.value4) : tuple11.value4 != null) { + return false; + } + if (value5 != null ? !value5.equals(tuple11.value5) : tuple11.value5 != null) { + return false; + } + if (value6 != null ? !value6.equals(tuple11.value6) : tuple11.value6 != null) { + return false; + } + if (value7 != null ? !value7.equals(tuple11.value7) : tuple11.value7 != null) { + return false; + } + if (value8 != null ? !value8.equals(tuple11.value8) : tuple11.value8 != null) { + return false; + } + if (value9 != null ? !value9.equals(tuple11.value9) : tuple11.value9 != null) { + return false; + } + if (value10 != null ? !value10.equals(tuple11.value10) : tuple11.value10 != null) { + return false; + } + return value11 != null ? value11.equals(tuple11.value11) : tuple11.value11 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + result = 31 * result + (value4 != null ? value4.hashCode() : 0); + result = 31 * result + (value5 != null ? value5.hashCode() : 0); + result = 31 * result + (value6 != null ? value6.hashCode() : 0); + result = 31 * result + (value7 != null ? value7.hashCode() : 0); + result = 31 * result + (value8 != null ? value8.hashCode() : 0); + result = 31 * result + (value9 != null ? value9.hashCode() : 0); + result = 31 * result + (value10 != null ? value10.hashCode() : 0); + result = 31 * result + (value11 != null ? value11.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple11{" + + "value1=" + + value1 + + ", value2=" + + value2 + + ", value3=" + + value3 + + ", value4=" + + value4 + + ", value5=" + + value5 + + ", value6=" + + value6 + + ", value7=" + + value7 + + ", value8=" + + value8 + + ", value9=" + + value9 + + ", value10=" + + value10 + + ", value11=" + + value11 + + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple12.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple12.java new file mode 100644 index 000000000..2c9de95c7 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple12.java @@ -0,0 +1,212 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple12 implements Tuple { + private static final int SIZE = 12; + + private final T1 value1; + + private final T2 value2; + + private final T3 value3; + + private final T4 value4; + + private final T5 value5; + + private final T6 value6; + + private final T7 value7; + + private final T8 value8; + + private final T9 value9; + + private final T10 value10; + + private final T11 value11; + + private final T12 value12; + + public Tuple12( + T1 value1, + T2 value2, + T3 value3, + T4 value4, + T5 value5, + T6 value6, + T7 value7, + T8 value8, + T9 value9, + T10 value10, + T11 value11, + T12 value12) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + this.value4 = value4; + this.value5 = value5; + this.value6 = value6; + this.value7 = value7; + this.value8 = value8; + this.value9 = value9; + this.value10 = value10; + this.value11 = value11; + this.value12 = value12; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + public T3 getValue3() { + return value3; + } + + public T4 getValue4() { + return value4; + } + + public T5 getValue5() { + return value5; + } + + public T6 getValue6() { + return value6; + } + + public T7 getValue7() { + return value7; + } + + public T8 getValue8() { + return value8; + } + + public T9 getValue9() { + return value9; + } + + public T10 getValue10() { + return value10; + } + + public T11 getValue11() { + return value11; + } + + public T12 getValue12() { + return value12; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple12 tuple12 = + (Tuple12) o; + if (value1 != null ? !value1.equals(tuple12.value1) : tuple12.value1 != null) { + return false; + } + if (value2 != null ? !value2.equals(tuple12.value2) : tuple12.value2 != null) { + return false; + } + if (value3 != null ? !value3.equals(tuple12.value3) : tuple12.value3 != null) { + return false; + } + if (value4 != null ? !value4.equals(tuple12.value4) : tuple12.value4 != null) { + return false; + } + if (value5 != null ? !value5.equals(tuple12.value5) : tuple12.value5 != null) { + return false; + } + if (value6 != null ? !value6.equals(tuple12.value6) : tuple12.value6 != null) { + return false; + } + if (value7 != null ? !value7.equals(tuple12.value7) : tuple12.value7 != null) { + return false; + } + if (value8 != null ? !value8.equals(tuple12.value8) : tuple12.value8 != null) { + return false; + } + if (value9 != null ? !value9.equals(tuple12.value9) : tuple12.value9 != null) { + return false; + } + if (value10 != null ? !value10.equals(tuple12.value10) : tuple12.value10 != null) { + return false; + } + if (value11 != null ? !value11.equals(tuple12.value11) : tuple12.value11 != null) { + return false; + } + return value12 != null ? value12.equals(tuple12.value12) : tuple12.value12 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + result = 31 * result + (value4 != null ? value4.hashCode() : 0); + result = 31 * result + (value5 != null ? value5.hashCode() : 0); + result = 31 * result + (value6 != null ? value6.hashCode() : 0); + result = 31 * result + (value7 != null ? value7.hashCode() : 0); + result = 31 * result + (value8 != null ? value8.hashCode() : 0); + result = 31 * result + (value9 != null ? value9.hashCode() : 0); + result = 31 * result + (value10 != null ? value10.hashCode() : 0); + result = 31 * result + (value11 != null ? value11.hashCode() : 0); + result = 31 * result + (value12 != null ? value12.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple12{" + + "value1=" + + value1 + + ", value2=" + + value2 + + ", value3=" + + value3 + + ", value4=" + + value4 + + ", value5=" + + value5 + + ", value6=" + + value6 + + ", value7=" + + value7 + + ", value8=" + + value8 + + ", value9=" + + value9 + + ", value10=" + + value10 + + ", value11=" + + value11 + + ", value12=" + + value12 + + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple13.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple13.java new file mode 100644 index 000000000..b0a9d87d0 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple13.java @@ -0,0 +1,227 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple13 + implements Tuple { + private static final int SIZE = 13; + + private final T1 value1; + + private final T2 value2; + + private final T3 value3; + + private final T4 value4; + + private final T5 value5; + + private final T6 value6; + + private final T7 value7; + + private final T8 value8; + + private final T9 value9; + + private final T10 value10; + + private final T11 value11; + + private final T12 value12; + + private final T13 value13; + + public Tuple13( + T1 value1, + T2 value2, + T3 value3, + T4 value4, + T5 value5, + T6 value6, + T7 value7, + T8 value8, + T9 value9, + T10 value10, + T11 value11, + T12 value12, + T13 value13) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + this.value4 = value4; + this.value5 = value5; + this.value6 = value6; + this.value7 = value7; + this.value8 = value8; + this.value9 = value9; + this.value10 = value10; + this.value11 = value11; + this.value12 = value12; + this.value13 = value13; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + public T3 getValue3() { + return value3; + } + + public T4 getValue4() { + return value4; + } + + public T5 getValue5() { + return value5; + } + + public T6 getValue6() { + return value6; + } + + public T7 getValue7() { + return value7; + } + + public T8 getValue8() { + return value8; + } + + public T9 getValue9() { + return value9; + } + + public T10 getValue10() { + return value10; + } + + public T11 getValue11() { + return value11; + } + + public T12 getValue12() { + return value12; + } + + public T13 getValue13() { + return value13; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple13 tuple13 = + (Tuple13) o; + if (value1 != null ? !value1.equals(tuple13.value1) : tuple13.value1 != null) { + return false; + } + if (value2 != null ? !value2.equals(tuple13.value2) : tuple13.value2 != null) { + return false; + } + if (value3 != null ? !value3.equals(tuple13.value3) : tuple13.value3 != null) { + return false; + } + if (value4 != null ? !value4.equals(tuple13.value4) : tuple13.value4 != null) { + return false; + } + if (value5 != null ? !value5.equals(tuple13.value5) : tuple13.value5 != null) { + return false; + } + if (value6 != null ? !value6.equals(tuple13.value6) : tuple13.value6 != null) { + return false; + } + if (value7 != null ? !value7.equals(tuple13.value7) : tuple13.value7 != null) { + return false; + } + if (value8 != null ? !value8.equals(tuple13.value8) : tuple13.value8 != null) { + return false; + } + if (value9 != null ? !value9.equals(tuple13.value9) : tuple13.value9 != null) { + return false; + } + if (value10 != null ? !value10.equals(tuple13.value10) : tuple13.value10 != null) { + return false; + } + if (value11 != null ? !value11.equals(tuple13.value11) : tuple13.value11 != null) { + return false; + } + if (value12 != null ? !value12.equals(tuple13.value12) : tuple13.value12 != null) { + return false; + } + return value13 != null ? value13.equals(tuple13.value13) : tuple13.value13 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + result = 31 * result + (value4 != null ? value4.hashCode() : 0); + result = 31 * result + (value5 != null ? value5.hashCode() : 0); + result = 31 * result + (value6 != null ? value6.hashCode() : 0); + result = 31 * result + (value7 != null ? value7.hashCode() : 0); + result = 31 * result + (value8 != null ? value8.hashCode() : 0); + result = 31 * result + (value9 != null ? value9.hashCode() : 0); + result = 31 * result + (value10 != null ? value10.hashCode() : 0); + result = 31 * result + (value11 != null ? value11.hashCode() : 0); + result = 31 * result + (value12 != null ? value12.hashCode() : 0); + result = 31 * result + (value13 != null ? value13.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple13{" + + "value1=" + + value1 + + ", value2=" + + value2 + + ", value3=" + + value3 + + ", value4=" + + value4 + + ", value5=" + + value5 + + ", value6=" + + value6 + + ", value7=" + + value7 + + ", value8=" + + value8 + + ", value9=" + + value9 + + ", value10=" + + value10 + + ", value11=" + + value11 + + ", value12=" + + value12 + + ", value13=" + + value13 + + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple14.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple14.java new file mode 100644 index 000000000..ae2600ea2 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple14.java @@ -0,0 +1,241 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple14 + implements Tuple { + private static final int SIZE = 14; + + private final T1 value1; + + private final T2 value2; + + private final T3 value3; + + private final T4 value4; + + private final T5 value5; + + private final T6 value6; + + private final T7 value7; + + private final T8 value8; + + private final T9 value9; + + private final T10 value10; + + private final T11 value11; + + private final T12 value12; + + private final T13 value13; + + private final T14 value14; + + public Tuple14( + T1 value1, + T2 value2, + T3 value3, + T4 value4, + T5 value5, + T6 value6, + T7 value7, + T8 value8, + T9 value9, + T10 value10, + T11 value11, + T12 value12, + T13 value13, + T14 value14) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + this.value4 = value4; + this.value5 = value5; + this.value6 = value6; + this.value7 = value7; + this.value8 = value8; + this.value9 = value9; + this.value10 = value10; + this.value11 = value11; + this.value12 = value12; + this.value13 = value13; + this.value14 = value14; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + public T3 getValue3() { + return value3; + } + + public T4 getValue4() { + return value4; + } + + public T5 getValue5() { + return value5; + } + + public T6 getValue6() { + return value6; + } + + public T7 getValue7() { + return value7; + } + + public T8 getValue8() { + return value8; + } + + public T9 getValue9() { + return value9; + } + + public T10 getValue10() { + return value10; + } + + public T11 getValue11() { + return value11; + } + + public T12 getValue12() { + return value12; + } + + public T13 getValue13() { + return value13; + } + + public T14 getValue14() { + return value14; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple14 tuple14 = + (Tuple14) o; + if (value1 != null ? !value1.equals(tuple14.value1) : tuple14.value1 != null) { + return false; + } + if (value2 != null ? !value2.equals(tuple14.value2) : tuple14.value2 != null) { + return false; + } + if (value3 != null ? !value3.equals(tuple14.value3) : tuple14.value3 != null) { + return false; + } + if (value4 != null ? !value4.equals(tuple14.value4) : tuple14.value4 != null) { + return false; + } + if (value5 != null ? !value5.equals(tuple14.value5) : tuple14.value5 != null) { + return false; + } + if (value6 != null ? !value6.equals(tuple14.value6) : tuple14.value6 != null) { + return false; + } + if (value7 != null ? !value7.equals(tuple14.value7) : tuple14.value7 != null) { + return false; + } + if (value8 != null ? !value8.equals(tuple14.value8) : tuple14.value8 != null) { + return false; + } + if (value9 != null ? !value9.equals(tuple14.value9) : tuple14.value9 != null) { + return false; + } + if (value10 != null ? !value10.equals(tuple14.value10) : tuple14.value10 != null) { + return false; + } + if (value11 != null ? !value11.equals(tuple14.value11) : tuple14.value11 != null) { + return false; + } + if (value12 != null ? !value12.equals(tuple14.value12) : tuple14.value12 != null) { + return false; + } + if (value13 != null ? !value13.equals(tuple14.value13) : tuple14.value13 != null) { + return false; + } + return value14 != null ? value14.equals(tuple14.value14) : tuple14.value14 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + result = 31 * result + (value4 != null ? value4.hashCode() : 0); + result = 31 * result + (value5 != null ? value5.hashCode() : 0); + result = 31 * result + (value6 != null ? value6.hashCode() : 0); + result = 31 * result + (value7 != null ? value7.hashCode() : 0); + result = 31 * result + (value8 != null ? value8.hashCode() : 0); + result = 31 * result + (value9 != null ? value9.hashCode() : 0); + result = 31 * result + (value10 != null ? value10.hashCode() : 0); + result = 31 * result + (value11 != null ? value11.hashCode() : 0); + result = 31 * result + (value12 != null ? value12.hashCode() : 0); + result = 31 * result + (value13 != null ? value13.hashCode() : 0); + result = 31 * result + (value14 != null ? value14.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple14{" + + "value1=" + + value1 + + ", value2=" + + value2 + + ", value3=" + + value3 + + ", value4=" + + value4 + + ", value5=" + + value5 + + ", value6=" + + value6 + + ", value7=" + + value7 + + ", value8=" + + value8 + + ", value9=" + + value9 + + ", value10=" + + value10 + + ", value11=" + + value11 + + ", value12=" + + value12 + + ", value13=" + + value13 + + ", value14=" + + value14 + + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple15.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple15.java new file mode 100644 index 000000000..25344bba7 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple15.java @@ -0,0 +1,255 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple15 + implements Tuple { + private static final int SIZE = 15; + + private final T1 value1; + + private final T2 value2; + + private final T3 value3; + + private final T4 value4; + + private final T5 value5; + + private final T6 value6; + + private final T7 value7; + + private final T8 value8; + + private final T9 value9; + + private final T10 value10; + + private final T11 value11; + + private final T12 value12; + + private final T13 value13; + + private final T14 value14; + + private final T15 value15; + + public Tuple15( + T1 value1, + T2 value2, + T3 value3, + T4 value4, + T5 value5, + T6 value6, + T7 value7, + T8 value8, + T9 value9, + T10 value10, + T11 value11, + T12 value12, + T13 value13, + T14 value14, + T15 value15) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + this.value4 = value4; + this.value5 = value5; + this.value6 = value6; + this.value7 = value7; + this.value8 = value8; + this.value9 = value9; + this.value10 = value10; + this.value11 = value11; + this.value12 = value12; + this.value13 = value13; + this.value14 = value14; + this.value15 = value15; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + public T3 getValue3() { + return value3; + } + + public T4 getValue4() { + return value4; + } + + public T5 getValue5() { + return value5; + } + + public T6 getValue6() { + return value6; + } + + public T7 getValue7() { + return value7; + } + + public T8 getValue8() { + return value8; + } + + public T9 getValue9() { + return value9; + } + + public T10 getValue10() { + return value10; + } + + public T11 getValue11() { + return value11; + } + + public T12 getValue12() { + return value12; + } + + public T13 getValue13() { + return value13; + } + + public T14 getValue14() { + return value14; + } + + public T15 getValue15() { + return value15; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple15 tuple15 = + (Tuple15) o; + if (value1 != null ? !value1.equals(tuple15.value1) : tuple15.value1 != null) { + return false; + } + if (value2 != null ? !value2.equals(tuple15.value2) : tuple15.value2 != null) { + return false; + } + if (value3 != null ? !value3.equals(tuple15.value3) : tuple15.value3 != null) { + return false; + } + if (value4 != null ? !value4.equals(tuple15.value4) : tuple15.value4 != null) { + return false; + } + if (value5 != null ? !value5.equals(tuple15.value5) : tuple15.value5 != null) { + return false; + } + if (value6 != null ? !value6.equals(tuple15.value6) : tuple15.value6 != null) { + return false; + } + if (value7 != null ? !value7.equals(tuple15.value7) : tuple15.value7 != null) { + return false; + } + if (value8 != null ? !value8.equals(tuple15.value8) : tuple15.value8 != null) { + return false; + } + if (value9 != null ? !value9.equals(tuple15.value9) : tuple15.value9 != null) { + return false; + } + if (value10 != null ? !value10.equals(tuple15.value10) : tuple15.value10 != null) { + return false; + } + if (value11 != null ? !value11.equals(tuple15.value11) : tuple15.value11 != null) { + return false; + } + if (value12 != null ? !value12.equals(tuple15.value12) : tuple15.value12 != null) { + return false; + } + if (value13 != null ? !value13.equals(tuple15.value13) : tuple15.value13 != null) { + return false; + } + if (value14 != null ? !value14.equals(tuple15.value14) : tuple15.value14 != null) { + return false; + } + return value15 != null ? value15.equals(tuple15.value15) : tuple15.value15 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + result = 31 * result + (value4 != null ? value4.hashCode() : 0); + result = 31 * result + (value5 != null ? value5.hashCode() : 0); + result = 31 * result + (value6 != null ? value6.hashCode() : 0); + result = 31 * result + (value7 != null ? value7.hashCode() : 0); + result = 31 * result + (value8 != null ? value8.hashCode() : 0); + result = 31 * result + (value9 != null ? value9.hashCode() : 0); + result = 31 * result + (value10 != null ? value10.hashCode() : 0); + result = 31 * result + (value11 != null ? value11.hashCode() : 0); + result = 31 * result + (value12 != null ? value12.hashCode() : 0); + result = 31 * result + (value13 != null ? value13.hashCode() : 0); + result = 31 * result + (value14 != null ? value14.hashCode() : 0); + result = 31 * result + (value15 != null ? value15.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple15{" + + "value1=" + + value1 + + ", value2=" + + value2 + + ", value3=" + + value3 + + ", value4=" + + value4 + + ", value5=" + + value5 + + ", value6=" + + value6 + + ", value7=" + + value7 + + ", value8=" + + value8 + + ", value9=" + + value9 + + ", value10=" + + value10 + + ", value11=" + + value11 + + ", value12=" + + value12 + + ", value13=" + + value13 + + ", value14=" + + value14 + + ", value15=" + + value15 + + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple16.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple16.java new file mode 100644 index 000000000..ea971375f --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple16.java @@ -0,0 +1,269 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple16 + implements Tuple { + private static final int SIZE = 16; + + private final T1 value1; + + private final T2 value2; + + private final T3 value3; + + private final T4 value4; + + private final T5 value5; + + private final T6 value6; + + private final T7 value7; + + private final T8 value8; + + private final T9 value9; + + private final T10 value10; + + private final T11 value11; + + private final T12 value12; + + private final T13 value13; + + private final T14 value14; + + private final T15 value15; + + private final T16 value16; + + public Tuple16( + T1 value1, + T2 value2, + T3 value3, + T4 value4, + T5 value5, + T6 value6, + T7 value7, + T8 value8, + T9 value9, + T10 value10, + T11 value11, + T12 value12, + T13 value13, + T14 value14, + T15 value15, + T16 value16) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + this.value4 = value4; + this.value5 = value5; + this.value6 = value6; + this.value7 = value7; + this.value8 = value8; + this.value9 = value9; + this.value10 = value10; + this.value11 = value11; + this.value12 = value12; + this.value13 = value13; + this.value14 = value14; + this.value15 = value15; + this.value16 = value16; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + public T3 getValue3() { + return value3; + } + + public T4 getValue4() { + return value4; + } + + public T5 getValue5() { + return value5; + } + + public T6 getValue6() { + return value6; + } + + public T7 getValue7() { + return value7; + } + + public T8 getValue8() { + return value8; + } + + public T9 getValue9() { + return value9; + } + + public T10 getValue10() { + return value10; + } + + public T11 getValue11() { + return value11; + } + + public T12 getValue12() { + return value12; + } + + public T13 getValue13() { + return value13; + } + + public T14 getValue14() { + return value14; + } + + public T15 getValue15() { + return value15; + } + + public T16 getValue16() { + return value16; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple16 tuple16 = + (Tuple16) o; + if (value1 != null ? !value1.equals(tuple16.value1) : tuple16.value1 != null) { + return false; + } + if (value2 != null ? !value2.equals(tuple16.value2) : tuple16.value2 != null) { + return false; + } + if (value3 != null ? !value3.equals(tuple16.value3) : tuple16.value3 != null) { + return false; + } + if (value4 != null ? !value4.equals(tuple16.value4) : tuple16.value4 != null) { + return false; + } + if (value5 != null ? !value5.equals(tuple16.value5) : tuple16.value5 != null) { + return false; + } + if (value6 != null ? !value6.equals(tuple16.value6) : tuple16.value6 != null) { + return false; + } + if (value7 != null ? !value7.equals(tuple16.value7) : tuple16.value7 != null) { + return false; + } + if (value8 != null ? !value8.equals(tuple16.value8) : tuple16.value8 != null) { + return false; + } + if (value9 != null ? !value9.equals(tuple16.value9) : tuple16.value9 != null) { + return false; + } + if (value10 != null ? !value10.equals(tuple16.value10) : tuple16.value10 != null) { + return false; + } + if (value11 != null ? !value11.equals(tuple16.value11) : tuple16.value11 != null) { + return false; + } + if (value12 != null ? !value12.equals(tuple16.value12) : tuple16.value12 != null) { + return false; + } + if (value13 != null ? !value13.equals(tuple16.value13) : tuple16.value13 != null) { + return false; + } + if (value14 != null ? !value14.equals(tuple16.value14) : tuple16.value14 != null) { + return false; + } + if (value15 != null ? !value15.equals(tuple16.value15) : tuple16.value15 != null) { + return false; + } + return value16 != null ? value16.equals(tuple16.value16) : tuple16.value16 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + result = 31 * result + (value4 != null ? value4.hashCode() : 0); + result = 31 * result + (value5 != null ? value5.hashCode() : 0); + result = 31 * result + (value6 != null ? value6.hashCode() : 0); + result = 31 * result + (value7 != null ? value7.hashCode() : 0); + result = 31 * result + (value8 != null ? value8.hashCode() : 0); + result = 31 * result + (value9 != null ? value9.hashCode() : 0); + result = 31 * result + (value10 != null ? value10.hashCode() : 0); + result = 31 * result + (value11 != null ? value11.hashCode() : 0); + result = 31 * result + (value12 != null ? value12.hashCode() : 0); + result = 31 * result + (value13 != null ? value13.hashCode() : 0); + result = 31 * result + (value14 != null ? value14.hashCode() : 0); + result = 31 * result + (value15 != null ? value15.hashCode() : 0); + result = 31 * result + (value16 != null ? value16.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple16{" + + "value1=" + + value1 + + ", value2=" + + value2 + + ", value3=" + + value3 + + ", value4=" + + value4 + + ", value5=" + + value5 + + ", value6=" + + value6 + + ", value7=" + + value7 + + ", value8=" + + value8 + + ", value9=" + + value9 + + ", value10=" + + value10 + + ", value11=" + + value11 + + ", value12=" + + value12 + + ", value13=" + + value13 + + ", value14=" + + value14 + + ", value15=" + + value15 + + ", value16=" + + value16 + + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple17.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple17.java new file mode 100644 index 000000000..68ce13707 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple17.java @@ -0,0 +1,284 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple17< + T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17> + implements Tuple { + private static final int SIZE = 17; + + private final T1 value1; + + private final T2 value2; + + private final T3 value3; + + private final T4 value4; + + private final T5 value5; + + private final T6 value6; + + private final T7 value7; + + private final T8 value8; + + private final T9 value9; + + private final T10 value10; + + private final T11 value11; + + private final T12 value12; + + private final T13 value13; + + private final T14 value14; + + private final T15 value15; + + private final T16 value16; + + private final T17 value17; + + public Tuple17( + T1 value1, + T2 value2, + T3 value3, + T4 value4, + T5 value5, + T6 value6, + T7 value7, + T8 value8, + T9 value9, + T10 value10, + T11 value11, + T12 value12, + T13 value13, + T14 value14, + T15 value15, + T16 value16, + T17 value17) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + this.value4 = value4; + this.value5 = value5; + this.value6 = value6; + this.value7 = value7; + this.value8 = value8; + this.value9 = value9; + this.value10 = value10; + this.value11 = value11; + this.value12 = value12; + this.value13 = value13; + this.value14 = value14; + this.value15 = value15; + this.value16 = value16; + this.value17 = value17; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + public T3 getValue3() { + return value3; + } + + public T4 getValue4() { + return value4; + } + + public T5 getValue5() { + return value5; + } + + public T6 getValue6() { + return value6; + } + + public T7 getValue7() { + return value7; + } + + public T8 getValue8() { + return value8; + } + + public T9 getValue9() { + return value9; + } + + public T10 getValue10() { + return value10; + } + + public T11 getValue11() { + return value11; + } + + public T12 getValue12() { + return value12; + } + + public T13 getValue13() { + return value13; + } + + public T14 getValue14() { + return value14; + } + + public T15 getValue15() { + return value15; + } + + public T16 getValue16() { + return value16; + } + + public T17 getValue17() { + return value17; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple17 tuple17 = + (Tuple17) o; + if (value1 != null ? !value1.equals(tuple17.value1) : tuple17.value1 != null) { + return false; + } + if (value2 != null ? !value2.equals(tuple17.value2) : tuple17.value2 != null) { + return false; + } + if (value3 != null ? !value3.equals(tuple17.value3) : tuple17.value3 != null) { + return false; + } + if (value4 != null ? !value4.equals(tuple17.value4) : tuple17.value4 != null) { + return false; + } + if (value5 != null ? !value5.equals(tuple17.value5) : tuple17.value5 != null) { + return false; + } + if (value6 != null ? !value6.equals(tuple17.value6) : tuple17.value6 != null) { + return false; + } + if (value7 != null ? !value7.equals(tuple17.value7) : tuple17.value7 != null) { + return false; + } + if (value8 != null ? !value8.equals(tuple17.value8) : tuple17.value8 != null) { + return false; + } + if (value9 != null ? !value9.equals(tuple17.value9) : tuple17.value9 != null) { + return false; + } + if (value10 != null ? !value10.equals(tuple17.value10) : tuple17.value10 != null) { + return false; + } + if (value11 != null ? !value11.equals(tuple17.value11) : tuple17.value11 != null) { + return false; + } + if (value12 != null ? !value12.equals(tuple17.value12) : tuple17.value12 != null) { + return false; + } + if (value13 != null ? !value13.equals(tuple17.value13) : tuple17.value13 != null) { + return false; + } + if (value14 != null ? !value14.equals(tuple17.value14) : tuple17.value14 != null) { + return false; + } + if (value15 != null ? !value15.equals(tuple17.value15) : tuple17.value15 != null) { + return false; + } + if (value16 != null ? !value16.equals(tuple17.value16) : tuple17.value16 != null) { + return false; + } + return value17 != null ? value17.equals(tuple17.value17) : tuple17.value17 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + result = 31 * result + (value4 != null ? value4.hashCode() : 0); + result = 31 * result + (value5 != null ? value5.hashCode() : 0); + result = 31 * result + (value6 != null ? value6.hashCode() : 0); + result = 31 * result + (value7 != null ? value7.hashCode() : 0); + result = 31 * result + (value8 != null ? value8.hashCode() : 0); + result = 31 * result + (value9 != null ? value9.hashCode() : 0); + result = 31 * result + (value10 != null ? value10.hashCode() : 0); + result = 31 * result + (value11 != null ? value11.hashCode() : 0); + result = 31 * result + (value12 != null ? value12.hashCode() : 0); + result = 31 * result + (value13 != null ? value13.hashCode() : 0); + result = 31 * result + (value14 != null ? value14.hashCode() : 0); + result = 31 * result + (value15 != null ? value15.hashCode() : 0); + result = 31 * result + (value16 != null ? value16.hashCode() : 0); + result = 31 * result + (value17 != null ? value17.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple17{" + + "value1=" + + value1 + + ", value2=" + + value2 + + ", value3=" + + value3 + + ", value4=" + + value4 + + ", value5=" + + value5 + + ", value6=" + + value6 + + ", value7=" + + value7 + + ", value8=" + + value8 + + ", value9=" + + value9 + + ", value10=" + + value10 + + ", value11=" + + value11 + + ", value12=" + + value12 + + ", value13=" + + value13 + + ", value14=" + + value14 + + ", value15=" + + value15 + + ", value16=" + + value16 + + ", value17=" + + value17 + + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple18.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple18.java new file mode 100644 index 000000000..1025e9d52 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple18.java @@ -0,0 +1,298 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple18< + T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18> + implements Tuple { + private static final int SIZE = 18; + + private final T1 value1; + + private final T2 value2; + + private final T3 value3; + + private final T4 value4; + + private final T5 value5; + + private final T6 value6; + + private final T7 value7; + + private final T8 value8; + + private final T9 value9; + + private final T10 value10; + + private final T11 value11; + + private final T12 value12; + + private final T13 value13; + + private final T14 value14; + + private final T15 value15; + + private final T16 value16; + + private final T17 value17; + + private final T18 value18; + + public Tuple18( + T1 value1, + T2 value2, + T3 value3, + T4 value4, + T5 value5, + T6 value6, + T7 value7, + T8 value8, + T9 value9, + T10 value10, + T11 value11, + T12 value12, + T13 value13, + T14 value14, + T15 value15, + T16 value16, + T17 value17, + T18 value18) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + this.value4 = value4; + this.value5 = value5; + this.value6 = value6; + this.value7 = value7; + this.value8 = value8; + this.value9 = value9; + this.value10 = value10; + this.value11 = value11; + this.value12 = value12; + this.value13 = value13; + this.value14 = value14; + this.value15 = value15; + this.value16 = value16; + this.value17 = value17; + this.value18 = value18; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + public T3 getValue3() { + return value3; + } + + public T4 getValue4() { + return value4; + } + + public T5 getValue5() { + return value5; + } + + public T6 getValue6() { + return value6; + } + + public T7 getValue7() { + return value7; + } + + public T8 getValue8() { + return value8; + } + + public T9 getValue9() { + return value9; + } + + public T10 getValue10() { + return value10; + } + + public T11 getValue11() { + return value11; + } + + public T12 getValue12() { + return value12; + } + + public T13 getValue13() { + return value13; + } + + public T14 getValue14() { + return value14; + } + + public T15 getValue15() { + return value15; + } + + public T16 getValue16() { + return value16; + } + + public T17 getValue17() { + return value17; + } + + public T18 getValue18() { + return value18; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple18 tuple18 = + (Tuple18) o; + if (value1 != null ? !value1.equals(tuple18.value1) : tuple18.value1 != null) { + return false; + } + if (value2 != null ? !value2.equals(tuple18.value2) : tuple18.value2 != null) { + return false; + } + if (value3 != null ? !value3.equals(tuple18.value3) : tuple18.value3 != null) { + return false; + } + if (value4 != null ? !value4.equals(tuple18.value4) : tuple18.value4 != null) { + return false; + } + if (value5 != null ? !value5.equals(tuple18.value5) : tuple18.value5 != null) { + return false; + } + if (value6 != null ? !value6.equals(tuple18.value6) : tuple18.value6 != null) { + return false; + } + if (value7 != null ? !value7.equals(tuple18.value7) : tuple18.value7 != null) { + return false; + } + if (value8 != null ? !value8.equals(tuple18.value8) : tuple18.value8 != null) { + return false; + } + if (value9 != null ? !value9.equals(tuple18.value9) : tuple18.value9 != null) { + return false; + } + if (value10 != null ? !value10.equals(tuple18.value10) : tuple18.value10 != null) { + return false; + } + if (value11 != null ? !value11.equals(tuple18.value11) : tuple18.value11 != null) { + return false; + } + if (value12 != null ? !value12.equals(tuple18.value12) : tuple18.value12 != null) { + return false; + } + if (value13 != null ? !value13.equals(tuple18.value13) : tuple18.value13 != null) { + return false; + } + if (value14 != null ? !value14.equals(tuple18.value14) : tuple18.value14 != null) { + return false; + } + if (value15 != null ? !value15.equals(tuple18.value15) : tuple18.value15 != null) { + return false; + } + if (value16 != null ? !value16.equals(tuple18.value16) : tuple18.value16 != null) { + return false; + } + if (value17 != null ? !value17.equals(tuple18.value17) : tuple18.value17 != null) { + return false; + } + return value18 != null ? value18.equals(tuple18.value18) : tuple18.value18 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + result = 31 * result + (value4 != null ? value4.hashCode() : 0); + result = 31 * result + (value5 != null ? value5.hashCode() : 0); + result = 31 * result + (value6 != null ? value6.hashCode() : 0); + result = 31 * result + (value7 != null ? value7.hashCode() : 0); + result = 31 * result + (value8 != null ? value8.hashCode() : 0); + result = 31 * result + (value9 != null ? value9.hashCode() : 0); + result = 31 * result + (value10 != null ? value10.hashCode() : 0); + result = 31 * result + (value11 != null ? value11.hashCode() : 0); + result = 31 * result + (value12 != null ? value12.hashCode() : 0); + result = 31 * result + (value13 != null ? value13.hashCode() : 0); + result = 31 * result + (value14 != null ? value14.hashCode() : 0); + result = 31 * result + (value15 != null ? value15.hashCode() : 0); + result = 31 * result + (value16 != null ? value16.hashCode() : 0); + result = 31 * result + (value17 != null ? value17.hashCode() : 0); + result = 31 * result + (value18 != null ? value18.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple18{" + + "value1=" + + value1 + + ", value2=" + + value2 + + ", value3=" + + value3 + + ", value4=" + + value4 + + ", value5=" + + value5 + + ", value6=" + + value6 + + ", value7=" + + value7 + + ", value8=" + + value8 + + ", value9=" + + value9 + + ", value10=" + + value10 + + ", value11=" + + value11 + + ", value12=" + + value12 + + ", value13=" + + value13 + + ", value14=" + + value14 + + ", value15=" + + value15 + + ", value16=" + + value16 + + ", value17=" + + value17 + + ", value18=" + + value18 + + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple19.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple19.java new file mode 100644 index 000000000..218d3056c --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple19.java @@ -0,0 +1,330 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple19< + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19> + implements Tuple { + private static final int SIZE = 19; + + private final T1 value1; + + private final T2 value2; + + private final T3 value3; + + private final T4 value4; + + private final T5 value5; + + private final T6 value6; + + private final T7 value7; + + private final T8 value8; + + private final T9 value9; + + private final T10 value10; + + private final T11 value11; + + private final T12 value12; + + private final T13 value13; + + private final T14 value14; + + private final T15 value15; + + private final T16 value16; + + private final T17 value17; + + private final T18 value18; + + private final T19 value19; + + public Tuple19( + T1 value1, + T2 value2, + T3 value3, + T4 value4, + T5 value5, + T6 value6, + T7 value7, + T8 value8, + T9 value9, + T10 value10, + T11 value11, + T12 value12, + T13 value13, + T14 value14, + T15 value15, + T16 value16, + T17 value17, + T18 value18, + T19 value19) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + this.value4 = value4; + this.value5 = value5; + this.value6 = value6; + this.value7 = value7; + this.value8 = value8; + this.value9 = value9; + this.value10 = value10; + this.value11 = value11; + this.value12 = value12; + this.value13 = value13; + this.value14 = value14; + this.value15 = value15; + this.value16 = value16; + this.value17 = value17; + this.value18 = value18; + this.value19 = value19; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + public T3 getValue3() { + return value3; + } + + public T4 getValue4() { + return value4; + } + + public T5 getValue5() { + return value5; + } + + public T6 getValue6() { + return value6; + } + + public T7 getValue7() { + return value7; + } + + public T8 getValue8() { + return value8; + } + + public T9 getValue9() { + return value9; + } + + public T10 getValue10() { + return value10; + } + + public T11 getValue11() { + return value11; + } + + public T12 getValue12() { + return value12; + } + + public T13 getValue13() { + return value13; + } + + public T14 getValue14() { + return value14; + } + + public T15 getValue15() { + return value15; + } + + public T16 getValue16() { + return value16; + } + + public T17 getValue17() { + return value17; + } + + public T18 getValue18() { + return value18; + } + + public T19 getValue19() { + return value19; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple19 tuple19 = + (Tuple19) o; + if (value1 != null ? !value1.equals(tuple19.value1) : tuple19.value1 != null) { + return false; + } + if (value2 != null ? !value2.equals(tuple19.value2) : tuple19.value2 != null) { + return false; + } + if (value3 != null ? !value3.equals(tuple19.value3) : tuple19.value3 != null) { + return false; + } + if (value4 != null ? !value4.equals(tuple19.value4) : tuple19.value4 != null) { + return false; + } + if (value5 != null ? !value5.equals(tuple19.value5) : tuple19.value5 != null) { + return false; + } + if (value6 != null ? !value6.equals(tuple19.value6) : tuple19.value6 != null) { + return false; + } + if (value7 != null ? !value7.equals(tuple19.value7) : tuple19.value7 != null) { + return false; + } + if (value8 != null ? !value8.equals(tuple19.value8) : tuple19.value8 != null) { + return false; + } + if (value9 != null ? !value9.equals(tuple19.value9) : tuple19.value9 != null) { + return false; + } + if (value10 != null ? !value10.equals(tuple19.value10) : tuple19.value10 != null) { + return false; + } + if (value11 != null ? !value11.equals(tuple19.value11) : tuple19.value11 != null) { + return false; + } + if (value12 != null ? !value12.equals(tuple19.value12) : tuple19.value12 != null) { + return false; + } + if (value13 != null ? !value13.equals(tuple19.value13) : tuple19.value13 != null) { + return false; + } + if (value14 != null ? !value14.equals(tuple19.value14) : tuple19.value14 != null) { + return false; + } + if (value15 != null ? !value15.equals(tuple19.value15) : tuple19.value15 != null) { + return false; + } + if (value16 != null ? !value16.equals(tuple19.value16) : tuple19.value16 != null) { + return false; + } + if (value17 != null ? !value17.equals(tuple19.value17) : tuple19.value17 != null) { + return false; + } + if (value18 != null ? !value18.equals(tuple19.value18) : tuple19.value18 != null) { + return false; + } + return value19 != null ? value19.equals(tuple19.value19) : tuple19.value19 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + result = 31 * result + (value4 != null ? value4.hashCode() : 0); + result = 31 * result + (value5 != null ? value5.hashCode() : 0); + result = 31 * result + (value6 != null ? value6.hashCode() : 0); + result = 31 * result + (value7 != null ? value7.hashCode() : 0); + result = 31 * result + (value8 != null ? value8.hashCode() : 0); + result = 31 * result + (value9 != null ? value9.hashCode() : 0); + result = 31 * result + (value10 != null ? value10.hashCode() : 0); + result = 31 * result + (value11 != null ? value11.hashCode() : 0); + result = 31 * result + (value12 != null ? value12.hashCode() : 0); + result = 31 * result + (value13 != null ? value13.hashCode() : 0); + result = 31 * result + (value14 != null ? value14.hashCode() : 0); + result = 31 * result + (value15 != null ? value15.hashCode() : 0); + result = 31 * result + (value16 != null ? value16.hashCode() : 0); + result = 31 * result + (value17 != null ? value17.hashCode() : 0); + result = 31 * result + (value18 != null ? value18.hashCode() : 0); + result = 31 * result + (value19 != null ? value19.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple19{" + + "value1=" + + value1 + + ", value2=" + + value2 + + ", value3=" + + value3 + + ", value4=" + + value4 + + ", value5=" + + value5 + + ", value6=" + + value6 + + ", value7=" + + value7 + + ", value8=" + + value8 + + ", value9=" + + value9 + + ", value10=" + + value10 + + ", value11=" + + value11 + + ", value12=" + + value12 + + ", value13=" + + value13 + + ", value14=" + + value14 + + ", value15=" + + value15 + + ", value16=" + + value16 + + ", value17=" + + value17 + + ", value18=" + + value18 + + ", value19=" + + value19 + + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple2.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple2.java new file mode 100644 index 000000000..03b454fd6 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple2.java @@ -0,0 +1,64 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple2 implements Tuple { + private static final int SIZE = 2; + + private final T1 value1; + + private final T2 value2; + + public Tuple2(T1 value1, T2 value2) { + this.value1 = value1; + this.value2 = value2; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple2 tuple2 = (Tuple2) o; + if (value1 != null ? !value1.equals(tuple2.value1) : tuple2.value1 != null) { + return false; + } + return value2 != null ? value2.equals(tuple2.value2) : tuple2.value2 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple2{" + "value1=" + value1 + ", value2=" + value2 + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple20.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple20.java new file mode 100644 index 000000000..decc72f73 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple20.java @@ -0,0 +1,345 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple20< + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20> + implements Tuple { + private static final int SIZE = 20; + + private final T1 value1; + + private final T2 value2; + + private final T3 value3; + + private final T4 value4; + + private final T5 value5; + + private final T6 value6; + + private final T7 value7; + + private final T8 value8; + + private final T9 value9; + + private final T10 value10; + + private final T11 value11; + + private final T12 value12; + + private final T13 value13; + + private final T14 value14; + + private final T15 value15; + + private final T16 value16; + + private final T17 value17; + + private final T18 value18; + + private final T19 value19; + + private final T20 value20; + + public Tuple20( + T1 value1, + T2 value2, + T3 value3, + T4 value4, + T5 value5, + T6 value6, + T7 value7, + T8 value8, + T9 value9, + T10 value10, + T11 value11, + T12 value12, + T13 value13, + T14 value14, + T15 value15, + T16 value16, + T17 value17, + T18 value18, + T19 value19, + T20 value20) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + this.value4 = value4; + this.value5 = value5; + this.value6 = value6; + this.value7 = value7; + this.value8 = value8; + this.value9 = value9; + this.value10 = value10; + this.value11 = value11; + this.value12 = value12; + this.value13 = value13; + this.value14 = value14; + this.value15 = value15; + this.value16 = value16; + this.value17 = value17; + this.value18 = value18; + this.value19 = value19; + this.value20 = value20; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + public T3 getValue3() { + return value3; + } + + public T4 getValue4() { + return value4; + } + + public T5 getValue5() { + return value5; + } + + public T6 getValue6() { + return value6; + } + + public T7 getValue7() { + return value7; + } + + public T8 getValue8() { + return value8; + } + + public T9 getValue9() { + return value9; + } + + public T10 getValue10() { + return value10; + } + + public T11 getValue11() { + return value11; + } + + public T12 getValue12() { + return value12; + } + + public T13 getValue13() { + return value13; + } + + public T14 getValue14() { + return value14; + } + + public T15 getValue15() { + return value15; + } + + public T16 getValue16() { + return value16; + } + + public T17 getValue17() { + return value17; + } + + public T18 getValue18() { + return value18; + } + + public T19 getValue19() { + return value19; + } + + public T20 getValue20() { + return value20; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple20 tuple20 = + (Tuple20) o; + if (value1 != null ? !value1.equals(tuple20.value1) : tuple20.value1 != null) { + return false; + } + if (value2 != null ? !value2.equals(tuple20.value2) : tuple20.value2 != null) { + return false; + } + if (value3 != null ? !value3.equals(tuple20.value3) : tuple20.value3 != null) { + return false; + } + if (value4 != null ? !value4.equals(tuple20.value4) : tuple20.value4 != null) { + return false; + } + if (value5 != null ? !value5.equals(tuple20.value5) : tuple20.value5 != null) { + return false; + } + if (value6 != null ? !value6.equals(tuple20.value6) : tuple20.value6 != null) { + return false; + } + if (value7 != null ? !value7.equals(tuple20.value7) : tuple20.value7 != null) { + return false; + } + if (value8 != null ? !value8.equals(tuple20.value8) : tuple20.value8 != null) { + return false; + } + if (value9 != null ? !value9.equals(tuple20.value9) : tuple20.value9 != null) { + return false; + } + if (value10 != null ? !value10.equals(tuple20.value10) : tuple20.value10 != null) { + return false; + } + if (value11 != null ? !value11.equals(tuple20.value11) : tuple20.value11 != null) { + return false; + } + if (value12 != null ? !value12.equals(tuple20.value12) : tuple20.value12 != null) { + return false; + } + if (value13 != null ? !value13.equals(tuple20.value13) : tuple20.value13 != null) { + return false; + } + if (value14 != null ? !value14.equals(tuple20.value14) : tuple20.value14 != null) { + return false; + } + if (value15 != null ? !value15.equals(tuple20.value15) : tuple20.value15 != null) { + return false; + } + if (value16 != null ? !value16.equals(tuple20.value16) : tuple20.value16 != null) { + return false; + } + if (value17 != null ? !value17.equals(tuple20.value17) : tuple20.value17 != null) { + return false; + } + if (value18 != null ? !value18.equals(tuple20.value18) : tuple20.value18 != null) { + return false; + } + if (value19 != null ? !value19.equals(tuple20.value19) : tuple20.value19 != null) { + return false; + } + return value20 != null ? value20.equals(tuple20.value20) : tuple20.value20 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + result = 31 * result + (value4 != null ? value4.hashCode() : 0); + result = 31 * result + (value5 != null ? value5.hashCode() : 0); + result = 31 * result + (value6 != null ? value6.hashCode() : 0); + result = 31 * result + (value7 != null ? value7.hashCode() : 0); + result = 31 * result + (value8 != null ? value8.hashCode() : 0); + result = 31 * result + (value9 != null ? value9.hashCode() : 0); + result = 31 * result + (value10 != null ? value10.hashCode() : 0); + result = 31 * result + (value11 != null ? value11.hashCode() : 0); + result = 31 * result + (value12 != null ? value12.hashCode() : 0); + result = 31 * result + (value13 != null ? value13.hashCode() : 0); + result = 31 * result + (value14 != null ? value14.hashCode() : 0); + result = 31 * result + (value15 != null ? value15.hashCode() : 0); + result = 31 * result + (value16 != null ? value16.hashCode() : 0); + result = 31 * result + (value17 != null ? value17.hashCode() : 0); + result = 31 * result + (value18 != null ? value18.hashCode() : 0); + result = 31 * result + (value19 != null ? value19.hashCode() : 0); + result = 31 * result + (value20 != null ? value20.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple20{" + + "value1=" + + value1 + + ", value2=" + + value2 + + ", value3=" + + value3 + + ", value4=" + + value4 + + ", value5=" + + value5 + + ", value6=" + + value6 + + ", value7=" + + value7 + + ", value8=" + + value8 + + ", value9=" + + value9 + + ", value10=" + + value10 + + ", value11=" + + value11 + + ", value12=" + + value12 + + ", value13=" + + value13 + + ", value14=" + + value14 + + ", value15=" + + value15 + + ", value16=" + + value16 + + ", value17=" + + value17 + + ", value18=" + + value18 + + ", value19=" + + value19 + + ", value20=" + + value20 + + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple3.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple3.java new file mode 100644 index 000000000..f037dd91f --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple3.java @@ -0,0 +1,75 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple3 implements Tuple { + private static final int SIZE = 3; + + private final T1 value1; + + private final T2 value2; + + private final T3 value3; + + public Tuple3(T1 value1, T2 value2, T3 value3) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + public T3 getValue3() { + return value3; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple3 tuple3 = (Tuple3) o; + if (value1 != null ? !value1.equals(tuple3.value1) : tuple3.value1 != null) { + return false; + } + if (value2 != null ? !value2.equals(tuple3.value2) : tuple3.value2 != null) { + return false; + } + return value3 != null ? value3.equals(tuple3.value3) : tuple3.value3 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple3{" + "value1=" + value1 + ", value2=" + value2 + ", value3=" + value3 + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple4.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple4.java new file mode 100644 index 000000000..47a79573e --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple4.java @@ -0,0 +1,95 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple4 implements Tuple { + private static final int SIZE = 4; + + private final T1 value1; + + private final T2 value2; + + private final T3 value3; + + private final T4 value4; + + public Tuple4(T1 value1, T2 value2, T3 value3, T4 value4) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + this.value4 = value4; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + public T3 getValue3() { + return value3; + } + + public T4 getValue4() { + return value4; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple4 tuple4 = (Tuple4) o; + if (value1 != null ? !value1.equals(tuple4.value1) : tuple4.value1 != null) { + return false; + } + if (value2 != null ? !value2.equals(tuple4.value2) : tuple4.value2 != null) { + return false; + } + if (value3 != null ? !value3.equals(tuple4.value3) : tuple4.value3 != null) { + return false; + } + return value4 != null ? value4.equals(tuple4.value4) : tuple4.value4 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + result = 31 * result + (value4 != null ? value4.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple4{" + + "value1=" + + value1 + + ", value2=" + + value2 + + ", value3=" + + value3 + + ", value4=" + + value4 + + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple5.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple5.java new file mode 100644 index 000000000..39b762e84 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple5.java @@ -0,0 +1,108 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple5 implements Tuple { + private static final int SIZE = 5; + + private final T1 value1; + + private final T2 value2; + + private final T3 value3; + + private final T4 value4; + + private final T5 value5; + + public Tuple5(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + this.value4 = value4; + this.value5 = value5; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + public T3 getValue3() { + return value3; + } + + public T4 getValue4() { + return value4; + } + + public T5 getValue5() { + return value5; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple5 tuple5 = (Tuple5) o; + if (value1 != null ? !value1.equals(tuple5.value1) : tuple5.value1 != null) { + return false; + } + if (value2 != null ? !value2.equals(tuple5.value2) : tuple5.value2 != null) { + return false; + } + if (value3 != null ? !value3.equals(tuple5.value3) : tuple5.value3 != null) { + return false; + } + if (value4 != null ? !value4.equals(tuple5.value4) : tuple5.value4 != null) { + return false; + } + return value5 != null ? value5.equals(tuple5.value5) : tuple5.value5 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + result = 31 * result + (value4 != null ? value4.hashCode() : 0); + result = 31 * result + (value5 != null ? value5.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple5{" + + "value1=" + + value1 + + ", value2=" + + value2 + + ", value3=" + + value3 + + ", value4=" + + value4 + + ", value5=" + + value5 + + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple6.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple6.java new file mode 100644 index 000000000..c9545e866 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple6.java @@ -0,0 +1,121 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple6 implements Tuple { + private static final int SIZE = 6; + + private final T1 value1; + + private final T2 value2; + + private final T3 value3; + + private final T4 value4; + + private final T5 value5; + + private final T6 value6; + + public Tuple6(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + this.value4 = value4; + this.value5 = value5; + this.value6 = value6; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + public T3 getValue3() { + return value3; + } + + public T4 getValue4() { + return value4; + } + + public T5 getValue5() { + return value5; + } + + public T6 getValue6() { + return value6; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple6 tuple6 = (Tuple6) o; + if (value1 != null ? !value1.equals(tuple6.value1) : tuple6.value1 != null) { + return false; + } + if (value2 != null ? !value2.equals(tuple6.value2) : tuple6.value2 != null) { + return false; + } + if (value3 != null ? !value3.equals(tuple6.value3) : tuple6.value3 != null) { + return false; + } + if (value4 != null ? !value4.equals(tuple6.value4) : tuple6.value4 != null) { + return false; + } + if (value5 != null ? !value5.equals(tuple6.value5) : tuple6.value5 != null) { + return false; + } + return value6 != null ? value6.equals(tuple6.value6) : tuple6.value6 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + result = 31 * result + (value4 != null ? value4.hashCode() : 0); + result = 31 * result + (value5 != null ? value5.hashCode() : 0); + result = 31 * result + (value6 != null ? value6.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple6{" + + "value1=" + + value1 + + ", value2=" + + value2 + + ", value3=" + + value3 + + ", value4=" + + value4 + + ", value5=" + + value5 + + ", value6=" + + value6 + + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple7.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple7.java new file mode 100644 index 000000000..787b364ea --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple7.java @@ -0,0 +1,134 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple7 implements Tuple { + private static final int SIZE = 7; + + private final T1 value1; + + private final T2 value2; + + private final T3 value3; + + private final T4 value4; + + private final T5 value5; + + private final T6 value6; + + private final T7 value7; + + public Tuple7(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + this.value4 = value4; + this.value5 = value5; + this.value6 = value6; + this.value7 = value7; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + public T3 getValue3() { + return value3; + } + + public T4 getValue4() { + return value4; + } + + public T5 getValue5() { + return value5; + } + + public T6 getValue6() { + return value6; + } + + public T7 getValue7() { + return value7; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple7 tuple7 = (Tuple7) o; + if (value1 != null ? !value1.equals(tuple7.value1) : tuple7.value1 != null) { + return false; + } + if (value2 != null ? !value2.equals(tuple7.value2) : tuple7.value2 != null) { + return false; + } + if (value3 != null ? !value3.equals(tuple7.value3) : tuple7.value3 != null) { + return false; + } + if (value4 != null ? !value4.equals(tuple7.value4) : tuple7.value4 != null) { + return false; + } + if (value5 != null ? !value5.equals(tuple7.value5) : tuple7.value5 != null) { + return false; + } + if (value6 != null ? !value6.equals(tuple7.value6) : tuple7.value6 != null) { + return false; + } + return value7 != null ? value7.equals(tuple7.value7) : tuple7.value7 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + result = 31 * result + (value4 != null ? value4.hashCode() : 0); + result = 31 * result + (value5 != null ? value5.hashCode() : 0); + result = 31 * result + (value6 != null ? value6.hashCode() : 0); + result = 31 * result + (value7 != null ? value7.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple7{" + + "value1=" + + value1 + + ", value2=" + + value2 + + ", value3=" + + value3 + + ", value4=" + + value4 + + ", value5=" + + value5 + + ", value6=" + + value6 + + ", value7=" + + value7 + + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple8.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple8.java new file mode 100644 index 000000000..d5b534d70 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple8.java @@ -0,0 +1,155 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple8 implements Tuple { + private static final int SIZE = 8; + + private final T1 value1; + + private final T2 value2; + + private final T3 value3; + + private final T4 value4; + + private final T5 value5; + + private final T6 value6; + + private final T7 value7; + + private final T8 value8; + + public Tuple8( + T1 value1, + T2 value2, + T3 value3, + T4 value4, + T5 value5, + T6 value6, + T7 value7, + T8 value8) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + this.value4 = value4; + this.value5 = value5; + this.value6 = value6; + this.value7 = value7; + this.value8 = value8; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + public T3 getValue3() { + return value3; + } + + public T4 getValue4() { + return value4; + } + + public T5 getValue5() { + return value5; + } + + public T6 getValue6() { + return value6; + } + + public T7 getValue7() { + return value7; + } + + public T8 getValue8() { + return value8; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple8 tuple8 = (Tuple8) o; + if (value1 != null ? !value1.equals(tuple8.value1) : tuple8.value1 != null) { + return false; + } + if (value2 != null ? !value2.equals(tuple8.value2) : tuple8.value2 != null) { + return false; + } + if (value3 != null ? !value3.equals(tuple8.value3) : tuple8.value3 != null) { + return false; + } + if (value4 != null ? !value4.equals(tuple8.value4) : tuple8.value4 != null) { + return false; + } + if (value5 != null ? !value5.equals(tuple8.value5) : tuple8.value5 != null) { + return false; + } + if (value6 != null ? !value6.equals(tuple8.value6) : tuple8.value6 != null) { + return false; + } + if (value7 != null ? !value7.equals(tuple8.value7) : tuple8.value7 != null) { + return false; + } + return value8 != null ? value8.equals(tuple8.value8) : tuple8.value8 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + result = 31 * result + (value4 != null ? value4.hashCode() : 0); + result = 31 * result + (value5 != null ? value5.hashCode() : 0); + result = 31 * result + (value6 != null ? value6.hashCode() : 0); + result = 31 * result + (value7 != null ? value7.hashCode() : 0); + result = 31 * result + (value8 != null ? value8.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple8{" + + "value1=" + + value1 + + ", value2=" + + value2 + + ", value3=" + + value3 + + ", value4=" + + value4 + + ", value5=" + + value5 + + ", value6=" + + value6 + + ", value7=" + + value7 + + ", value8=" + + value8 + + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple9.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple9.java new file mode 100644 index 000000000..305826ea5 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/datatypes/generated/tuples/generated/Tuple9.java @@ -0,0 +1,169 @@ +package org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated; + +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.Tuple; + +/** + * Auto generated code. + * + *

Do not modifiy! + * + *

Please use TupleGenerator in the codegen module to update. + */ +public final class Tuple9 implements Tuple { + private static final int SIZE = 9; + + private final T1 value1; + + private final T2 value2; + + private final T3 value3; + + private final T4 value4; + + private final T5 value5; + + private final T6 value6; + + private final T7 value7; + + private final T8 value8; + + private final T9 value9; + + public Tuple9( + T1 value1, + T2 value2, + T3 value3, + T4 value4, + T5 value5, + T6 value6, + T7 value7, + T8 value8, + T9 value9) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + this.value4 = value4; + this.value5 = value5; + this.value6 = value6; + this.value7 = value7; + this.value8 = value8; + this.value9 = value9; + } + + public T1 getValue1() { + return value1; + } + + public T2 getValue2() { + return value2; + } + + public T3 getValue3() { + return value3; + } + + public T4 getValue4() { + return value4; + } + + public T5 getValue5() { + return value5; + } + + public T6 getValue6() { + return value6; + } + + public T7 getValue7() { + return value7; + } + + public T8 getValue8() { + return value8; + } + + public T9 getValue9() { + return value9; + } + + @Override + public int getSize() { + return SIZE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tuple9 tuple9 = (Tuple9) o; + if (value1 != null ? !value1.equals(tuple9.value1) : tuple9.value1 != null) { + return false; + } + if (value2 != null ? !value2.equals(tuple9.value2) : tuple9.value2 != null) { + return false; + } + if (value3 != null ? !value3.equals(tuple9.value3) : tuple9.value3 != null) { + return false; + } + if (value4 != null ? !value4.equals(tuple9.value4) : tuple9.value4 != null) { + return false; + } + if (value5 != null ? !value5.equals(tuple9.value5) : tuple9.value5 != null) { + return false; + } + if (value6 != null ? !value6.equals(tuple9.value6) : tuple9.value6 != null) { + return false; + } + if (value7 != null ? !value7.equals(tuple9.value7) : tuple9.value7 != null) { + return false; + } + if (value8 != null ? !value8.equals(tuple9.value8) : tuple9.value8 != null) { + return false; + } + return value9 != null ? value9.equals(tuple9.value9) : tuple9.value9 == null; + } + + @Override + public int hashCode() { + int result = value1.hashCode(); + result = 31 * result + (value2 != null ? value2.hashCode() : 0); + result = 31 * result + (value3 != null ? value3.hashCode() : 0); + result = 31 * result + (value4 != null ? value4.hashCode() : 0); + result = 31 * result + (value5 != null ? value5.hashCode() : 0); + result = 31 * result + (value6 != null ? value6.hashCode() : 0); + result = 31 * result + (value7 != null ? value7.hashCode() : 0); + result = 31 * result + (value8 != null ? value8.hashCode() : 0); + result = 31 * result + (value9 != null ? value9.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Tuple9{" + + "value1=" + + value1 + + ", value2=" + + value2 + + ", value3=" + + value3 + + ", value4=" + + value4 + + ", value5=" + + value5 + + ", value6=" + + value6 + + ", value7=" + + value7 + + ", value8=" + + value8 + + ", value9=" + + value9 + + "}"; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/tools/ContractAbiUtil.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/tools/ContractAbiUtil.java new file mode 100644 index 000000000..61d23acf3 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/tools/ContractAbiUtil.java @@ -0,0 +1,57 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package org.fisco.bcos.sdk.abi.tools; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.List; +import org.fisco.bcos.sdk.abi.wrapper.ABIDefinition; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** ContractAbiUtil. */ +public class ContractAbiUtil { + + private static final Logger logger = LoggerFactory.getLogger(ContractAbiUtil.class); + + public static final String TYPE_CONSTRUCTOR = "constructor"; + public static final String TYPE_FUNCTION = "function"; + public static final String TYPE_EVENT = "event"; + + /** + * @param contractAbi the contract abi + * @return the abi definition + */ + public static List getFuncABIDefinition(String contractAbi) { + List result = new ArrayList<>(); + try { + ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(); + ABIDefinition[] ABIDefinitions = + objectMapper.readValue(contractAbi, ABIDefinition[].class); + + for (ABIDefinition ABIDefinition : ABIDefinitions) { + if (TYPE_FUNCTION.equals(ABIDefinition.getType()) + || TYPE_CONSTRUCTOR.equals(ABIDefinition.getType())) { + result.add(ABIDefinition); + } + } + } catch (JsonProcessingException e) { + logger.warn(" invalid json, abi: {}, e: {} ", contractAbi, e); + } + return result; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/tools/TopicTools.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/tools/TopicTools.java new file mode 100644 index 000000000..65cad5535 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/tools/TopicTools.java @@ -0,0 +1,60 @@ +package org.fisco.bcos.sdk.abi.tools; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.TypeEncoder; +import org.fisco.bcos.sdk.abi.datatypes.Bytes; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.utils.AddressUtils; +import org.fisco.bcos.sdk.utils.Numeric; + +public class TopicTools { + + public static final int MAX_NUM_TOPIC_EVENT_LOG = 4; + public static final String LATEST = "latest"; + + private CryptoSuite cryptoSuite; + + public TopicTools(CryptoSuite cryptoSuite) { + this.cryptoSuite = cryptoSuite; + } + + public String integerToTopic(BigInteger i) { + return Numeric.toHexStringWithPrefixZeroPadded(i, 64); + } + + public String boolToTopic(boolean b) { + if (b) { + return Numeric.toHexStringWithPrefixZeroPadded(BigInteger.ONE, 64); + } else { + return Numeric.toHexStringWithPrefixZeroPadded(BigInteger.ZERO, 64); + } + } + + public String addressToTopic(String s) { + if (!AddressUtils.isValidAddress(s)) { + throw new IllegalArgumentException("invalid address"); + } + + return "0x000000000000000000000000" + Numeric.cleanHexPrefix(s); + } + + public String stringToTopic(String s) { + byte[] hash = cryptoSuite.hash(s.getBytes()); + return Numeric.toHexString(hash); + } + + public String bytesToTopic(byte[] b) { + byte[] hash = cryptoSuite.hash(b); + return Numeric.toHexString(hash); + } + + public String byteNToTopic(byte[] b) { + // byte[] can't be more than 32 byte + if (b.length > 32) { + throw new IllegalArgumentException("byteN can't be more than 32 byte"); + } + + Bytes bs = new Bytes(b.length, b); + return Numeric.prependHexPrefix(TypeEncoder.encode(bs)); + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABICodecJsonWrapper.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABICodecJsonWrapper.java new file mode 100644 index 000000000..349d6b116 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABICodecJsonWrapper.java @@ -0,0 +1,501 @@ +package org.fisco.bcos.sdk.abi.wrapper; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import java.io.IOException; +import java.security.InvalidParameterException; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Iterator; +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.Address; +import org.fisco.bcos.sdk.abi.datatypes.Bool; +import org.fisco.bcos.sdk.abi.datatypes.Bytes; +import org.fisco.bcos.sdk.abi.datatypes.DynamicBytes; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Int256; +import org.fisco.bcos.sdk.abi.datatypes.generated.Uint256; +import org.fisco.bcos.sdk.abi.wrapper.ABIObject.ListType; +import org.fisco.bcos.sdk.utils.Numeric; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ABICodecJsonWrapper { + + private static final Logger logger = LoggerFactory.getLogger(ABICodecJsonWrapper.class); + + private ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(); + + private void errorReport(String path, String expected, String actual) + throws InvalidParameterException { + String errorMessage = + "Arguments mismatch: " + path + ", expected: " + expected + ", actual: " + actual; + logger.error(errorMessage); + throw new InvalidParameterException(errorMessage); + } + + private ABIObject encodeNode(String path, ABIObject template, JsonNode node) { + ABIObject abiObject = template.newObject(); + + switch (abiObject.getType()) { + case VALUE: + { + if (!node.isValueNode()) { + errorReport( + path, + abiObject.getType().toString(), + node.getNodeType().toString()); + } + + switch (template.getValueType()) { + case BOOL: + { + if (!node.isBoolean()) { + errorReport( + path, + template.getValueType().toString(), + node.getNodeType().toString()); + } + + abiObject.setBoolValue(new Bool(node.asBoolean())); + break; + } + case INT: + { + if (!node.isNumber() && !node.isBigInteger()) { + errorReport( + path, + template.getValueType().toString(), + node.getNodeType().toString()); + } + + if (node.isNumber()) { + abiObject.setNumericValue(new Int256(node.asLong())); + } else { + abiObject.setNumericValue(new Int256(node.bigIntegerValue())); + } + + break; + } + case UINT: + { + if (!node.isNumber() && !node.isBigInteger()) { + errorReport( + path, + template.getValueType().toString(), + node.getNodeType().toString()); + } + + if (node.isNumber()) { + abiObject.setNumericValue(new Uint256(node.asLong())); + } else { + abiObject.setNumericValue(new Uint256(node.bigIntegerValue())); + } + + break; + } + case ADDRESS: + { + if (!node.isTextual()) { + errorReport( + path, + template.getValueType().toString(), + node.getNodeType().toString()); + } + + try { + abiObject.setAddressValue(new Address(node.asText())); + } catch (Exception e) { + errorReport( + "Invalid address value", + template.getValueType().toString(), + node.asText()); + } + break; + } + case BYTES: + { + if (!node.isTextual()) { + errorReport( + path, + template.getValueType().toString(), + node.getNodeType().toString()); + } + + // Binary data requires base64 encoding + byte[] bytesValue = Base64.getDecoder().decode(node.asText()); + abiObject.setBytesValue(new Bytes(bytesValue.length, bytesValue)); + break; + } + case DBYTES: + { + if (!node.isTextual()) { + errorReport( + path, + template.getValueType().toString(), + node.getNodeType().toString()); + } + + byte[] bytesValue = Base64.getDecoder().decode(node.asText()); + abiObject.setDynamicBytesValue(new DynamicBytes(bytesValue)); + break; + } + case STRING: + { + if (!node.isTextual()) { + errorReport( + path, + template.getValueType().toString(), + node.getNodeType().toString()); + } + + abiObject.setStringValue(new Utf8String(node.asText())); + break; + } + } + break; + } + case LIST: + { + if (!node.isArray()) { + errorReport( + path, + abiObject.getType().toString(), + node.getNodeType().toString()); + } + + if ((abiObject.getListType() == ListType.FIXED) + && (node.size() != abiObject.getListLength())) { + errorReport( + "fixed list arguments size", + String.valueOf(abiObject.getListLength()), + String.valueOf(node.size())); + } + + int i = 0; + Iterator iterator = node.iterator(); + while (iterator.hasNext()) { + abiObject + .getListValues() + .add( + encodeNode( + path + ".<" + String.valueOf(i) + ">", + abiObject.getListValueType(), + iterator.next())); + } + + break; + } + case STRUCT: + { + if (!node.isArray() && !node.isObject()) { + errorReport( + path, + abiObject.getType().toString(), + node.getNodeType().toString()); + } + + if (node.size() != abiObject.getStructFields().size()) { + errorReport( + "struct arguments size", + String.valueOf(abiObject.getListLength()), + String.valueOf(node.size())); + } + + if (node.isArray()) { + for (int i = 0; i < abiObject.getStructFields().size(); i++) { + ABIObject field = abiObject.getStructFields().get(i); + abiObject + .getStructFields() + .set( + i, + encodeNode( + path + "." + field.getName(), + field, + node.get(i))); + } + } else { + for (int i = 0; i < abiObject.getStructFields().size(); ++i) { + ABIObject field = abiObject.getStructFields().get(i); + JsonNode structNode = node.get(field.getName()); + + if (structNode == null) { + errorReport( + path + "miss field value, field name: " + field.getName(), + template.getValueType().toString(), + node.getNodeType().toString()); + } + + abiObject + .getStructFields() + .set( + i, + encodeNode( + path + "." + field.getName(), + field, + structNode)); + } + } + + break; + } + } + + return abiObject; + } + + public ABIObject encode(ABIObject template, List inputs) throws IOException { + + ABIObject abiObject = template.newObject(); + + // check parameters match + if (inputs.size() != abiObject.getStructFields().size()) { + errorReport( + "arguments size", + String.valueOf(abiObject.getStructFields().size()), + String.valueOf(inputs.size())); + } + + for (int i = 0; i < abiObject.getStructFields().size(); ++i) { + + ABIObject argObject = abiObject.getStructFields().get(i).newObject(); + String value = inputs.get(i); + + switch (argObject.getType()) { + case VALUE: + { + try { + switch (argObject.getValueType()) { + case BOOL: + { + argObject.setBoolValue(new Bool(Boolean.valueOf(value))); + break; + } + case UINT: + { + argObject.setNumericValue( + new Uint256(Numeric.decodeQuantity(value))); + break; + } + case INT: + { + argObject.setNumericValue( + new Int256(Numeric.decodeQuantity(value))); + break; + } + case ADDRESS: + { + argObject.setAddressValue(new Address(value)); + break; + } + case BYTES: + { + // Binary data requires base64 encoding + byte[] bytesValue = + Base64.getDecoder() + .decode(Numeric.cleanHexPrefix(value)); + argObject.setBytesValue( + new Bytes(bytesValue.length, bytesValue)); + break; + } + case DBYTES: + { + // Binary data requires base64 encoding + byte[] bytesValue = + Base64.getDecoder() + .decode(Numeric.cleanHexPrefix(value)); + argObject.setDynamicBytesValue( + new DynamicBytes(bytesValue)); + break; + } + case STRING: + { + argObject.setStringValue(new Utf8String(value)); + break; + } + default: + { + throw new UnsupportedOperationException( + "Unrecognized valueType: " + + argObject.getValueType()); + } + } + } catch (Exception e) { + logger.error(" e: {}", e.getMessage()); + errorReport("ROOT", argObject.getValueType().toString(), value); + } + + break; + } + case STRUCT: + case LIST: + { + JsonNode argNode = objectMapper.readTree(value.getBytes()); + argObject = encodeNode("ROOT", argObject, argNode); + break; + } + } + + abiObject.getStructFields().set(i, argObject); + } + + return abiObject; + } + + public JsonNode decode(ABIObject abiObject) { + JsonNodeFactory jsonNodeFactory = objectMapper.getNodeFactory(); + + switch (abiObject.getType()) { + case VALUE: + { + switch (abiObject.getValueType()) { + case BOOL: + { + return jsonNodeFactory.booleanNode( + abiObject.getBoolValue().getValue()); + } + case INT: + case UINT: + { + return jsonNodeFactory.numberNode( + abiObject.getNumericValue().getValue()); + } + case ADDRESS: + { + return jsonNodeFactory.textNode( + abiObject.getAddressValue().toString()); + } + case BYTES: + { + return jsonNodeFactory.binaryNode( + abiObject.getBytesValue().getValue()); + } + case DBYTES: + { + return jsonNodeFactory.binaryNode( + abiObject.getDynamicBytesValue().getValue()); + } + case STRING: + { + return jsonNodeFactory.textNode( + abiObject.getStringValue().getValue()); + } + } + break; + } + case LIST: + { + ArrayNode arrayNode = jsonNodeFactory.arrayNode(); + + for (ABIObject listObject : abiObject.getListValues()) { + arrayNode.add(decode(listObject)); + } + + return arrayNode; + } + case STRUCT: + { + ArrayNode structNode = jsonNodeFactory.arrayNode(); + + for (ABIObject listObject : abiObject.getStructFields()) { + structNode.add(decode(listObject)); + } + + return structNode; + } + } + + return null; + } + + public List decode(ABIObject template, String buffer) { + + if (logger.isTraceEnabled()) { + logger.trace(" ABIObject: {}, abi: {}", template.toString(), buffer); + } + + buffer = Numeric.cleanHexPrefix(buffer); + + ABIObject abiObject = template.decode(buffer); + + JsonNode jsonNode = decode(abiObject); + + List result = new ArrayList(); + for (int i = 0; i < abiObject.getStructFields().size(); ++i) { + ABIObject argObject = abiObject.getStructFields().get(i); + JsonNode argNode = jsonNode.get(i); + + switch (argObject.getType()) { + case VALUE: + { + switch (argObject.getValueType()) { + case BOOL: + { + result.add(String.valueOf(argObject.getBoolValue().getValue())); + break; + } + case UINT: + case INT: + { + result.add(argObject.getNumericValue().getValue().toString()); + break; + } + case ADDRESS: + { + result.add( + String.valueOf(argObject.getAddressValue().toString())); + break; + } + case BYTES: + { + byte[] base64Bytes = + Base64.getEncoder() + .encode(argObject.getBytesValue().getValue()); + result.add(new String(base64Bytes)); + break; + } + case DBYTES: + { + byte[] base64Bytes = + Base64.getEncoder() + .encode( + argObject + .getDynamicBytesValue() + .getValue()); + result.add(new String(base64Bytes)); + break; + } + case STRING: + { + result.add( + String.valueOf(argObject.getStringValue().getValue())); + break; + } + default: + { + throw new UnsupportedOperationException( + " Unsupported valueType: " + argObject.getValueType()); + } + } + break; + } + case LIST: + case STRUCT: + { + result.add(argNode.toPrettyString()); + break; + } + default: + { + throw new UnsupportedOperationException( + " Unsupported objectType: " + argObject.getType()); + } + } + } + + return result; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABICodecObject.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABICodecObject.java new file mode 100644 index 000000000..6f5467cc0 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABICodecObject.java @@ -0,0 +1,377 @@ +package org.fisco.bcos.sdk.abi.wrapper; + +import java.lang.reflect.Field; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.fisco.bcos.sdk.abi.datatypes.Address; +import org.fisco.bcos.sdk.abi.datatypes.Bool; +import org.fisco.bcos.sdk.abi.datatypes.Bytes; +import org.fisco.bcos.sdk.abi.datatypes.DynamicBytes; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Int256; +import org.fisco.bcos.sdk.abi.datatypes.generated.Uint256; +import org.fisco.bcos.sdk.abi.wrapper.ABIObject.ListType; +import org.fisco.bcos.sdk.utils.Numeric; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ABICodecObject { + + private static final Logger logger = LoggerFactory.getLogger(ABICodecObject.class); + + private void errorReport(String path, String expected, String actual) + throws InvalidParameterException { + String errorMessage = + "Arguments mismatch: " + path + ", expected: " + expected + ", actual: " + actual; + logger.error(errorMessage); + throw new InvalidParameterException(errorMessage); + } + + public ABIObject encodeList(ABIObject template, Object value) { + + ABIObject abiObject = template.newObject(); + + // check abi type + if (abiObject.getType() != ABIObject.ObjectType.LIST + && abiObject.getType() != ABIObject.ObjectType.STRUCT) { + errorReport( + " abi type mismatch of " + abiObject.getName(), + "LIST/STRUCT", + abiObject.getType().toString()); + } + + List list = new ArrayList(); + if (value instanceof List) { + list = (List) value; + } else { + Object[] objs = (Object[]) value; + for (Object obj : objs) { + list.add(obj); + } + } + if ((abiObject.getListType() == ListType.FIXED) + && (list.size() != abiObject.getListLength())) { + errorReport( + "fixed list arguments size", + String.valueOf(abiObject.getListLength()), + String.valueOf(list.size())); + } + + for (int i = 0; i < list.size(); i++) { + ABIObject nodeObject = abiObject.getListValueType().newObject(); + switch (nodeObject.getType()) { + case VALUE: + { + nodeObject = encodeValue(nodeObject, list.get(i)); + break; + } + case STRUCT: + { + nodeObject = encodeStruct(nodeObject, list.get(i)); + break; + } + case LIST: + { + nodeObject = encodeList(nodeObject, list.get(i)); + break; + } + default: + { + throw new UnsupportedOperationException( + " Unsupported objectType: " + nodeObject.getType()); + } + } + abiObject.getListValues().add(nodeObject); + } + + return abiObject; + } + + public ABIObject encodeStruct(ABIObject template, Object value) { + ABIObject abiObject = template.newObject(); + + // check abi type + if (abiObject.getType() != ABIObject.ObjectType.STRUCT) { + errorReport( + " abi type mismatch of " + abiObject.getName(), + "STRUCT", + abiObject.getType().toString()); + } + + if (value instanceof java.util.List) { + List list = (List) value; + for (int i = 0; i < abiObject.getStructFields().size(); i++) { + ABIObject nodeObject = abiObject.getStructFields().get(i); + switch (nodeObject.getType()) { + case VALUE: + { + nodeObject = encodeValue(nodeObject, list.get(i)); + break; + } + case STRUCT: + { + nodeObject = encodeStruct(nodeObject, list.get(i)); + break; + } + case LIST: + { + nodeObject = encodeList(nodeObject, list.get(i)); + break; + } + default: + { + throw new UnsupportedOperationException( + " Unsupported objectType: " + nodeObject.getType()); + } + } + abiObject.getStructFields().set(i, nodeObject); + } + } else { + Field[] fields = value.getClass().getDeclaredFields(); + Map v = new HashMap<>(); + try { + for (Field f : fields) { + f.setAccessible(true); + v.put(f.getName(), f.get(value)); + } + } catch (IllegalAccessException e) { + logger.error(e.getMessage()); + } + for (int i = 0; i < abiObject.getStructFields().size(); ++i) { + ABIObject nodeObject = abiObject.getStructFields().get(i); + switch (nodeObject.getType()) { + case VALUE: + { + nodeObject = encodeValue(nodeObject, v.get(nodeObject.getName())); + break; + } + case STRUCT: + { + nodeObject = encodeStruct(nodeObject, v.get(nodeObject.getName())); + break; + } + case LIST: + { + nodeObject = encodeList(nodeObject, v.get(nodeObject.getName())); + break; + } + default: + { + throw new UnsupportedOperationException( + " Unsupported objectType: " + nodeObject.getType()); + } + } + abiObject.getStructFields().set(i, nodeObject); + } + } + + return abiObject; + } + + public ABIObject encodeValue(ABIObject template, Object value) { + ABIObject abiObject = template.newObject(); + if (abiObject.getType() == ABIObject.ObjectType.LIST) { + abiObject = encodeList(abiObject, value); + } else if (abiObject.getType() == ABIObject.ObjectType.STRUCT) { + abiObject = encodeStruct(abiObject, value); + } else { + switch (abiObject.getValueType()) { + case BOOL: + { + if (value instanceof Boolean) { + abiObject.setBoolValue(new Bool((Boolean) value)); + } else { + errorReport( + " valueType mismatch", + abiObject.getValueType().getClass().getName(), + value.getClass().getName()); + } + break; + } + case UINT: + { + if (value instanceof BigInteger) { + abiObject.setNumericValue(new Uint256((BigInteger) value)); + } else if (StringUtils.isNumeric(value.toString())) { + abiObject.setNumericValue( + new Uint256((new BigInteger(value.toString())))); + } else { + errorReport( + " valueType mismatch", + abiObject.getValueType().getClass().getName(), + value.getClass().getName()); + } + break; + } + case INT: + { + if (value instanceof BigInteger) { + abiObject.setNumericValue(new Int256((BigInteger) value)); + } else if (StringUtils.isNumeric(value.toString())) { + abiObject.setNumericValue( + new Uint256((new BigInteger(value.toString())))); + } else { + errorReport( + " valueType mismatch", + abiObject.getValueType().getClass().getName(), + value.getClass().getName()); + } + break; + } + case ADDRESS: + { + if (value instanceof String) { + abiObject.setAddressValue(new Address((String) value)); + } else { + errorReport( + " valueType mismatch", + abiObject.getValueType().getClass().getName(), + value.getClass().getName()); + } + break; + } + case BYTES: + { + if (value instanceof byte[]) { + byte[] bytesValue = (byte[]) value; + abiObject.setBytesValue(new Bytes(bytesValue.length, bytesValue)); + + } else { + errorReport( + " valueType mismatch", + abiObject.getValueType().getClass().getName(), + value.getClass().getName()); + } + break; + } + case DBYTES: + { + if (value instanceof byte[]) { + byte[] bytesValue = (byte[]) value; + abiObject.setDynamicBytesValue(new DynamicBytes(bytesValue)); + } else { + errorReport( + " valueType mismatch", + abiObject.getValueType().getClass().getName(), + value.getClass().getName()); + break; + } + break; + } + case STRING: + { + if (value instanceof String) { + abiObject.setStringValue(new Utf8String((String) value)); + } else { + errorReport( + " valueType mismatch", + abiObject.getValueType().getClass().getName(), + value.getClass().getName()); + } + break; + } + default: + { + throw new InvalidParameterException( + "Unrecognized valueType: " + abiObject.getValueType()); + } + } + } + + return abiObject; + } + + public List decodeJavaObject(ABIObject template, String input) { + + if (logger.isTraceEnabled()) { + logger.trace(" ABIObject: {}, abi: {}", template.toString(), input); + } + + input = Numeric.cleanHexPrefix(input); + + ABIObject abiObject = template.decode(input); + + // ABIObject -> java List + List result = decodeJavaObject(abiObject); + + return result; + } + + private List decodeJavaObject(ABIObject template) throws UnsupportedOperationException { + List result = new ArrayList(); + List argObjects; + if (template.getType() == ABIObject.ObjectType.STRUCT) { + argObjects = template.getStructFields(); + } else { + argObjects = template.getListValues(); + } + for (int i = 0; i < argObjects.size(); ++i) { + ABIObject argObject = argObjects.get(i); + switch (argObject.getType()) { + case VALUE: + { + switch (argObject.getValueType()) { + case BOOL: + { + result.add(argObject.getBoolValue().getValue()); + break; + } + case UINT: + case INT: + { + result.add(argObject.getNumericValue().getValue()); + break; + } + case ADDRESS: + { + result.add(argObject.getAddressValue().toString()); + break; + } + case BYTES: + { + result.add(new String(argObject.getBytesValue().getValue())); + break; + } + case DBYTES: + { + result.add( + new String( + argObject.getDynamicBytesValue().getValue())); + break; + } + case STRING: + { + result.add(argObject.getStringValue().toString()); + break; + } + default: + { + throw new UnsupportedOperationException( + " Unsupported valueType: " + argObject.getValueType()); + } + } + break; + } + case LIST: + case STRUCT: + { + List node = decodeJavaObject(argObject); + result.add(node); + break; + } + default: + { + throw new UnsupportedOperationException( + " Unsupported objectType: " + argObject.getType()); + } + } + } + + return result; + } +} 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 new file mode 100644 index 000000000..4809822ac --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABIDefinition.java @@ -0,0 +1,444 @@ +package org.fisco.bcos.sdk.abi.wrapper; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import org.fisco.bcos.sdk.abi.FunctionEncoder; +import org.fisco.bcos.sdk.crypto.CryptoSuite; + +/** + * ABIDefinition wrapper + * + *

Link https://solidity.readthedocs.io/en/develop/abi-spec.html#json
+ * type: "function", "constructor", "receive" (the "receive Ether" function) or "fallback" (the + * "default" function);
+ * name: the name of the function;
+ * inputs: an array of objects, each of which contains:
+ * name: the name of the parameter.
+ * type: the canonical type of the parameter (more below).
+ * components: used for tuple types (more below).
+ * outputs: an array of objects similar to inputs.
+ * stateMutability: a string with one of the following values: pure (specified to not read + * blockchain state), view (specified to not modify the blockchain state), nonpayable (function does + * not accept Ether - the default) and payable (function accepts Ether).
+ */ +public class ABIDefinition { + private String name; + private String type; + private boolean constant; + private boolean payable; + private boolean anonymous; + private String stateMutability; + + private List inputs; + private List outputs; + public static List CONSTANT_KEY = Arrays.asList("view"); + + public ABIDefinition() {} + + public ABIDefinition( + String name, + String type, + boolean constant, + boolean payable, + boolean anonymous, + String stateMutability) { + this.name = name; + this.type = type; + this.constant = constant; + this.payable = payable; + this.anonymous = anonymous; + this.stateMutability = stateMutability; + } + + public ABIDefinition( + boolean constant, + List inputs, + String name, + List outputs, + String type, + boolean payable) { + this(constant, inputs, name, outputs, type, payable, null); + } + + public ABIDefinition( + boolean constant, + List inputs, + String name, + List outputs, + String type, + boolean payable, + String stateMutability) { + this.constant = constant; + this.inputs = inputs; + this.name = name; + this.outputs = outputs; + this.type = type; + this.payable = payable; + this.stateMutability = stateMutability; + } + + public static ABIDefinition createDefaultConstructorABIDefinition() { + return new ABIDefinition( + false, new ArrayList<>(), null, null, "constructor", false, "nonpayable"); + } + + /** + * string method signature + * + * @return the method signature string + */ + public String getMethodSignatureAsString() { + StringBuilder result = new StringBuilder(); + result.append(name); + result.append("("); + String params = + getInputs() + .stream() + .map(abi -> abi.getTypeAsString()) + .collect(Collectors.joining(",")); + result.append(params); + result.append(")"); + return result.toString(); + } + + /** + * calculate the method id + * + * @param cryptoSuite the crypto suite used for hash calculation + * @return the method id + */ + public String getMethodId(CryptoSuite cryptoSuite) { + FunctionEncoder encoder = new FunctionEncoder(cryptoSuite); + return encoder.buildMethodId(getMethodSignatureAsString()); + } + + public boolean isConstant() { + return constant || CONSTANT_KEY.contains(this.getStateMutability()); + } + + public void setConstant(boolean constant) { + this.constant = constant; + } + + public List getInputs() { + return inputs; + } + + public void setInputs(List inputs) { + this.inputs = inputs; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getOutputs() { + return outputs; + } + + public boolean hasOutputs() { + return !outputs.isEmpty(); + } + + public void setOutputs(List outputs) { + this.outputs = outputs; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public boolean isPayable() { + return payable; + } + + public void setPayable(boolean payable) { + this.payable = payable; + } + + public String getStateMutability() { + return stateMutability; + } + + public void setStateMutability(String stateMutability) { + this.stateMutability = stateMutability; + } + + public boolean isAnonymous() { + return anonymous; + } + + public void setAnonymous(boolean anonymous) { + this.anonymous = anonymous; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ABIDefinition)) { + return false; + } + + ABIDefinition that = (ABIDefinition) o; + + if (isConstant() != that.isConstant()) { + return false; + } + if (isPayable() != that.isPayable()) { + return false; + } + if (getInputs() != null + ? !getInputs().equals(that.getInputs()) + : that.getInputs() != null) { + return false; + } + if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) { + return false; + } + if (getOutputs() != null + ? !getOutputs().equals(that.getOutputs()) + : that.getOutputs() != null) { + return false; + } + if (getStateMutability() != null + ? !getStateMutability().equals(that.getStateMutability()) + : that.getStateMutability() != null) { + return false; + } + return getType() != null ? getType().equals(that.getType()) : that.getType() == null; + } + + @Override + public int hashCode() { + int result = (isConstant() ? 1 : 0); + result = 31 * result + (getInputs() != null ? getInputs().hashCode() : 0); + result = 31 * result + (getName() != null ? getName().hashCode() : 0); + result = 31 * result + (getOutputs() != null ? getOutputs().hashCode() : 0); + result = 31 * result + (getType() != null ? getType().hashCode() : 0); + result = 31 * result + (isPayable() ? 1 : 0); + result = 31 * result + (getStateMutability() != null ? getStateMutability().hashCode() : 0); + return result; + } + + public static class Type { + public String type; + public String rawType; + public List dimensions = new ArrayList(); + + public Type(String name) { + int index = name.indexOf('['); + this.rawType = (-1 == index) ? name.trim() : name.substring(0, index); + this.type = name; + this.initialize(); + } + + private void initialize() { + Pattern p = Pattern.compile("\\[[0-9]{0,}\\]"); + Matcher m = p.matcher(type); + while (m.find()) { + String s = m.group(); + String dig = s.substring(s.indexOf('[') + 1, s.indexOf(']')).trim(); + if (dig.isEmpty()) { + dimensions.add(0); + } else { + dimensions.add(Integer.valueOf(dig)); + } + } + } + + @Override + public String toString() { + return "Type{" + + "name='" + + type + + '\'' + + ", baseName='" + + rawType + + '\'' + + ", dimensions=" + + dimensions + + '}'; + } + + public String getType() { + return type; + } + + public String getRawType() { + return rawType; + } + + public Type reduceDimensionAndGetType() { + if (isList()) { + String r = rawType; + for (int i = 0; i < dimensions.size() - 1; i++) { + r += ("[" + (dimensions.get(i) != 0 ? dimensions.get(i) : "") + "]"); + } + + return new Type(r); + } + + return new Type(rawType); + } + + public boolean isList() { + return !dimensions.isEmpty(); + } + + public boolean isDynamicList() { + return isList() && (dimensions.get(dimensions.size() - 1) == 0); + } + + public boolean isFixedList() { + return isList() && (dimensions.get(dimensions.size() - 1) != 0); + } + + public void setType(String type) { + this.type = type; + } + + public void setRawType(String rawType) { + this.rawType = rawType; + } + + public List getDimensions() { + return dimensions; + } + + public Integer getLastDimension() { + if (!isList()) { + return 0; + } + + return dimensions.get(dimensions.size() - 1); + } + + public void setDimensions(List dimensions) { + this.dimensions = dimensions; + } + } + + public static class NamedType { + private String name; + private String type; + private boolean indexed; + private List components; + + public NamedType() {} + + public NamedType(String name, String type) { + this(name, type, false); + } + + public NamedType(String name, String type, boolean indexed) { + this.name = name; + this.type = type; + this.indexed = indexed; + } + + public Type newType() { + return new Type(type); + } + + private String getTupleRawTypeAsString() { + StringBuilder result = new StringBuilder(); + String params = + getComponents() + .stream() + .map(abi -> abi.getTypeAsString()) + .collect(Collectors.joining(",")); + result.append(params); + return result.toString(); + } + + public String getTypeAsString() { + // not tuple, return + if (!type.startsWith("tuple")) { + return type; + } + + String tupleRawString = getTupleRawTypeAsString(); + String result = type.replaceAll("tuple", "(" + tupleRawString + ")"); + return result; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public boolean isIndexed() { + return indexed; + } + + public void setIndexed(boolean indexed) { + this.indexed = indexed; + } + + public List getComponents() { + return components; + } + + public void setComponents(List components) { + this.components = components; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + NamedType namedType = (NamedType) o; + return indexed == namedType.indexed + && Objects.equals(name, namedType.name) + && Objects.equals(type, namedType.type) + && Objects.equals(components, namedType.components); + } + + @Override + public int hashCode() { + return Objects.hash(name, type, indexed, components); + } + + @Override + public String toString() { + return "NamedType{" + + "name='" + + name + + '\'' + + ", type='" + + type + + '\'' + + ", indexed=" + + indexed + + ", components=" + + components + + '}'; + } + } +} 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 new file mode 100644 index 000000000..f5738ac0f --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABIDefinitionFactory.java @@ -0,0 +1,58 @@ +package org.fisco.bcos.sdk.abi.wrapper; + +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; + + public ABIDefinitionFactory(CryptoSuite cryptoSuite) { + this.cryptoSuite = cryptoSuite; + } + + /** + * load ABI and construct ContractABIDefinition. + * + * @param abi the abi need to be loaded + * @return the contract definition + */ + public ContractABIDefinition loadABI(String abi) { + try { + ABIDefinition[] abiDefinitions = + ObjectMapperFactory.getObjectMapper().readValue(abi, ABIDefinition[].class); + + ContractABIDefinition contractABIDefinition = new ContractABIDefinition(cryptoSuite); + for (ABIDefinition abiDefinition : abiDefinitions) { + if (abiDefinition.getType().equals("constructor")) { + contractABIDefinition.setConstructor(abiDefinition); + } else if (abiDefinition.getType().equals("function")) { + contractABIDefinition.addFunction(abiDefinition.getName(), abiDefinition); + } else if (abiDefinition.getType().equals("event")) { + contractABIDefinition.addEvent(abiDefinition.getName(), abiDefinition); + } else { + // skip and do nothing + } + + if (logger.isInfoEnabled()) { + logger.info(" abiDefinition: {}", abiDefinition); + } + } + if (contractABIDefinition.getConstructor() == null) { + contractABIDefinition.setConstructor( + ABIDefinition.createDefaultConstructorABIDefinition()); + } + logger.info(" contractABIDefinition {} ", contractABIDefinition); + + return contractABIDefinition; + + } catch (Exception e) { + logger.error(" e: ", e); + return null; + } + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABIObject.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABIObject.java new file mode 100644 index 000000000..1c0b44af9 --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABIObject.java @@ -0,0 +1,756 @@ +package org.fisco.bcos.sdk.abi.wrapper; + +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import org.fisco.bcos.sdk.abi.TypeDecoder; +import org.fisco.bcos.sdk.abi.TypeEncoder; +import org.fisco.bcos.sdk.abi.datatypes.Address; +import org.fisco.bcos.sdk.abi.datatypes.Bool; +import org.fisco.bcos.sdk.abi.datatypes.Bytes; +import org.fisco.bcos.sdk.abi.datatypes.DynamicBytes; +import org.fisco.bcos.sdk.abi.datatypes.NumericType; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Bytes32; +import org.fisco.bcos.sdk.abi.datatypes.generated.Int256; +import org.fisco.bcos.sdk.abi.datatypes.generated.Uint256; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ABIObject { + + private static final Logger logger = LoggerFactory.getLogger(ABIObject.class); + + public enum ObjectType { + VALUE, // uint, int, bool, address, bytes, bytes, string + STRUCT, // tuple + LIST // T[], T[M] + } + + public enum ValueType { + BOOL, // bool + UINT, // uint + INT, // int + BYTES, // byteN + ADDRESS, // address + STRING, // string + DBYTES, // bytes + FIXED, // fixedx + UFIXED, // ufixedx + } + + public enum ListType { + DYNAMIC, // T[] + FIXED, // T[M] + } + + private String name; // field name + + private ObjectType type; // for value + private ValueType valueType; + + private NumericType numericValue; + private Bytes bytesValue; + private Address addressValue; + private Bool boolValue; + private DynamicBytes dynamicBytesValue; + private Utf8String stringValue; + + private ListType listType; + private List listValues; // for list + private int listLength; // for list + private ABIObject listValueType; // for list + + private List structFields; // for struct + + public ABIObject(ObjectType type) { + this.type = type; + + switch (type) { + case VALUE: + { + break; + } + case STRUCT: + { + structFields = new LinkedList(); + break; + } + case LIST: + { + listValues = new LinkedList(); + break; + } + } + } + + public ABIObject(ValueType valueType) { + this.type = ObjectType.VALUE; + this.valueType = valueType; + } + + public ABIObject(ListType listType) { + this.type = ObjectType.LIST; + this.listType = listType; + this.listValues = new LinkedList(); + } + + public ABIObject(Uint256 uintValue) { + this(ValueType.UINT); + this.numericValue = uintValue; + } + + public ABIObject(Int256 intValue) { + this(ValueType.INT); + this.numericValue = intValue; + } + + public ABIObject(Address addressValue) { + this(ValueType.ADDRESS); + this.addressValue = addressValue; + } + + public ABIObject(Bool boolValue) { + this(ValueType.BOOL); + this.boolValue = boolValue; + } + + public ABIObject(Utf8String stringValue) { + this(ValueType.STRING); + this.stringValue = stringValue; + } + + public ABIObject(DynamicBytes dynamicBytesValue) { + this(ValueType.DBYTES); + this.dynamicBytesValue = dynamicBytesValue; + } + + public ABIObject(Bytes bytesValue) { + this(ValueType.BYTES); + this.bytesValue = bytesValue; + } + + public ABIObject newObjectWithoutValue() { + ABIObject abiObject = new ABIObject(this.type); + // value + abiObject.setValueType(this.getValueType()); + abiObject.setName(this.getName()); + + // list + abiObject.setListType(this.getListType()); + abiObject.setListLength(this.getListLength()); + + if (this.getListValueType() != null) { + abiObject.setListValueType(this.getListValueType().newObjectWithoutValue()); + } + + if (this.listValues != null) { + for (ABIObject obj : this.listValues) { + abiObject.listValues.add(obj.newObjectWithoutValue()); + } + } + + // tuple + if (this.structFields != null) { + for (ABIObject obj : this.structFields) { + abiObject.structFields.add(obj.newObjectWithoutValue()); + } + } + + return abiObject; + } + + // clone itself + public ABIObject newObject() { + + ABIObject abiObject = new ABIObject(this.type); + + // value + abiObject.setValueType(this.getValueType()); + abiObject.setName(this.getName()); + + if (this.getNumericValue() != null) { + abiObject.setNumericValue( + new NumericType( + this.getNumericValue().getTypeAsString(), + this.getNumericValue().getValue()) { + @Override + public boolean dynamicType() { + return false; + } + + @Override + public int offset() { + return 1; + } + }); + } + + if (this.getBoolValue() != null) { + abiObject.setBoolValue(new Bool(this.getBoolValue().getValue())); + } + + if (this.getStringValue() != null) { + abiObject.setStringValue(new Utf8String(this.getStringValue().getValue())); + } + + if (this.getDynamicBytesValue() != null) { + abiObject.setDynamicBytesValue( + new DynamicBytes(this.getDynamicBytesValue().getValue())); + } + + if (this.getAddressValue() != null) { + abiObject.setAddressValue(new Address(this.getAddressValue().toUint160())); + } + + if (this.getBytesValue() != null) { + abiObject.setBytesValue( + new Bytes( + this.getBytesValue().getValue().length, + this.getBytesValue().getValue())); + } + + // list + abiObject.setListType(this.getListType()); + abiObject.setListLength(this.getListLength()); + + if (this.getListValueType() != null) { + abiObject.setListValueType(this.getListValueType().newObject()); + } + + if (this.listValues != null) { + for (ABIObject obj : this.listValues) { + abiObject.listValues.add(obj.newObject()); + } + } + + // tuple + if (this.structFields != null) { + for (ABIObject obj : this.structFields) { + abiObject.structFields.add(obj.newObject()); + } + } + + return abiObject; + } + + /** + * Checks to see if the current type is dynamic + * + * @return true/false + */ + public boolean isDynamic() { + switch (type) { + case VALUE: + { + switch (valueType) { + case DBYTES: // bytes + case STRING: // string + return true; + default: + return false; + } + // break; + } + case LIST: + { + switch (listType) { + case FIXED: // T[M] + { + return listValueType.isDynamic(); + } + case DYNAMIC: // T[] + { + return true; + } + } + break; + } + case STRUCT: + { + for (ABIObject abiObject : structFields) { + if (abiObject.isDynamic()) { + return true; + } + } + return false; + } + } + + return false; + } + + /** + * dynamic offset of this object + * + * @return the offset of the ABIObject + */ + public int offset() { + if (isDynamic()) { // dynamic + return 1; + } + + int offset = 0; + if (type == ObjectType.VALUE) { // basic type + offset = 1; + } else if (type == ObjectType.STRUCT) { // tuple + int l = 0; + for (ABIObject abiObject : structFields) { + l += abiObject.offset(); + } + offset = l; + } else { // T[M] + int length = listLength; + int basicOffset = listValueType.offset(); + offset = length * basicOffset; + } + + return offset; + } + + public int offsetAsByteLength() { + return offset() * Type.MAX_BYTE_LENGTH; + } + + public int offsetAsHexLength() { + return offset() * (Type.MAX_BYTE_LENGTH << 1); + } + + /** + * encode this object + * + * @return the encoded object + */ + public String encode() { + + StringBuffer stringBuffer = new StringBuffer(); + switch (type) { + case VALUE: + { + switch (valueType) { + case UINT: + case INT: + { + stringBuffer.append(TypeEncoder.encode(numericValue)); + break; + } + case BOOL: + { + stringBuffer.append(TypeEncoder.encode(boolValue)); + break; + } + case FIXED: + case UFIXED: + { + throw new UnsupportedOperationException( + " Unsupported fixed/unfixed type. "); + // break; + } + case BYTES: + { + stringBuffer.append(TypeEncoder.encode(bytesValue)); + break; + } + case ADDRESS: + { + stringBuffer.append(TypeEncoder.encode(addressValue)); + break; + } + case DBYTES: + { + stringBuffer.append(TypeEncoder.encode(dynamicBytesValue)); + break; + } + case STRING: + { + stringBuffer.append(TypeEncoder.encode(stringValue)); + break; + } + default: + { + throw new UnsupportedOperationException( + " Unrecognized valueType: " + valueType); + } + } + break; + } + case STRUCT: + { + long dynamicOffset = 0; + for (ABIObject abiObject : structFields) { + dynamicOffset += abiObject.offsetAsByteLength(); + } + + StringBuffer fixedBuffer = new StringBuffer(); + StringBuffer dynamicBuffer = new StringBuffer(); + + for (ABIObject abiObject : structFields) { + String encodeValue = abiObject.encode(); + if (abiObject.isDynamic()) { + fixedBuffer.append(TypeEncoder.encode(new Uint256(dynamicOffset))); + dynamicBuffer.append(encodeValue); + dynamicOffset += (encodeValue.length() >> 1); + } else { + fixedBuffer.append(encodeValue); + } + } + + stringBuffer.append(fixedBuffer).append(dynamicBuffer); + break; + } + case LIST: + { + StringBuffer lengthBuffer = new StringBuffer(); + StringBuffer listValueBuffer = new StringBuffer(); + StringBuffer offsetBuffer = new StringBuffer(); + + if (listType == ListType.DYNAMIC) { + lengthBuffer.append(TypeEncoder.encode(new Uint256(listValues.size()))); + } + + int dynamicOffset = listValues.size() * Type.MAX_BYTE_LENGTH; + + for (ABIObject abiObject : listValues) { + String listValueEncode = abiObject.encode(); + listValueBuffer.append(abiObject.encode()); + if (abiObject.isDynamic()) { + offsetBuffer.append(TypeEncoder.encode(new Uint256(dynamicOffset))); + dynamicOffset += (listValueEncode.length() >> 1); + } + } + + stringBuffer.append(lengthBuffer).append(offsetBuffer).append(listValueBuffer); + break; + } + } + + if (logger.isTraceEnabled()) { + logger.trace("ABI: {}", stringBuffer.toString()); + } + + return stringBuffer.toString(); + } + + /** + * decode this object + * + * @param input the string to be decoded into ABIObject + * @return the decoded ABIObject + */ + public ABIObject decode(String input) { + return decode(input, 0); + } + + /** + * decode this object + * + * @return the decoded ABIObject + */ + private ABIObject decode(String input, int offset) { + + ABIObject abiObject = newObject(); + + switch (type) { + case VALUE: + { + switch (valueType) { + case BOOL: + { + abiObject.setBoolValue( + TypeDecoder.decode(input, offset, Bool.class)); + break; + } + case UINT: + { + abiObject.setNumericValue( + TypeDecoder.decode(input, offset, Uint256.class)); + break; + } + case INT: + { + abiObject.setNumericValue( + TypeDecoder.decode(input, offset, Int256.class)); + break; + } + case FIXED: + case UFIXED: + { + throw new UnsupportedOperationException( + " Unsupported fixed/unfixed type. "); + // break; + } + case BYTES: + { + abiObject.setBytesValue( + TypeDecoder.decode(input, offset, Bytes32.class)); + break; + } + case ADDRESS: + { + abiObject.setAddressValue( + TypeDecoder.decode(input, offset, Address.class)); + break; + } + case DBYTES: + { + abiObject.setDynamicBytesValue( + TypeDecoder.decode(input, offset, DynamicBytes.class)); + break; + } + case STRING: + { + abiObject.setStringValue( + TypeDecoder.decode(input, offset, Utf8String.class)); + break; + } + } + break; + } + case STRUCT: + { + int structOffset = offset; + int initialOffset = offset; + + for (int i = 0; i < structFields.size(); ++i) { + ABIObject structObject = abiObject.structFields.get(i); + ABIObject itemObject = null; + if (structObject.isDynamic()) { + int structValueOffset = + TypeDecoder.decode(input, structOffset, Uint256.class) + .getValue() + .intValue(); + itemObject = + structObject.decode( + input, initialOffset + (structValueOffset << 1)); + + } else { + itemObject = structObject.decode(input, structOffset); + } + + abiObject.structFields.set(i, itemObject); + structOffset += structObject.offsetAsHexLength(); + } + break; + } + case LIST: + { + int listOffset = offset; + int initialOffset = offset; + + int listLength = 0; + if (listType == ListType.DYNAMIC) { + // dynamic list length + listLength = + TypeDecoder.decode(input, listOffset, Uint256.class) + .getValue() + .intValue(); + listOffset += (Type.MAX_BYTE_LENGTH << 1); + initialOffset += (Type.MAX_BYTE_LENGTH << 1); + } else { + // fixed list length + listLength = abiObject.getListLength(); + } + + if (logger.isTraceEnabled()) { + logger.trace(" listType: {}, listLength: {}", listType, listLength); + } + + ABIObject listValueObject = abiObject.getListValueType(); + + for (int i = 0; i < listLength; i++) { + ABIObject itemABIObject = null; + + if (listValueObject.isDynamic()) { + int listValueOffset = + TypeDecoder.decode(input, listOffset, Uint256.class) + .getValue() + .intValue(); + itemABIObject = + abiObject + .getListValueType() + .decode(input, initialOffset + (listValueOffset << 1)); + } else { + itemABIObject = abiObject.getListValueType().decode(input, listOffset); + } + + listOffset += listValueObject.offsetAsHexLength(); + + abiObject.getListValues().add(itemABIObject); + } + break; + } + } + + return abiObject; + } + + public ObjectType getType() { + return type; + } + + public void setType(ObjectType type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ValueType getValueType() { + return valueType; + } + + public NumericType getNumericValue() { + return numericValue; + } + + public Bool getBoolValue() { + return boolValue; + } + + public void setBoolValue(Bool boolValue) { + this.type = ObjectType.VALUE; + this.valueType = ValueType.BOOL; + this.boolValue = boolValue; + } + + public void setNumericValue(NumericType numericValue) { + this.type = ObjectType.VALUE; + this.valueType = ValueType.UINT; + this.numericValue = numericValue; + } + + public Bytes getBytesValue() { + return bytesValue; + } + + public void setBytesValue(Bytes bytesValue) { + this.type = ObjectType.VALUE; + this.valueType = ValueType.BYTES; + this.bytesValue = bytesValue; + } + + public Address getAddressValue() { + return addressValue; + } + + public void setAddressValue(Address addressValue) { + this.type = ObjectType.VALUE; + this.valueType = ValueType.ADDRESS; + this.addressValue = addressValue; + } + + public List getStructFields() { + return structFields; + } + + public void setStructFields(List structFields) { + this.type = ObjectType.STRUCT; + this.structFields = structFields; + } + + public ListType getListType() { + return listType; + } + + public void setListType(ListType listType) { + this.listType = listType; + } + + public List getListValues() { + return listValues; + } + + public void setListValues(List listValues) { + this.type = ObjectType.LIST; + this.listValues = listValues; + } + + public void setValueType(ValueType valueType) { + this.valueType = valueType; + } + + public DynamicBytes getDynamicBytesValue() { + return dynamicBytesValue; + } + + public void setDynamicBytesValue(DynamicBytes dynamicBytesValue) { + this.dynamicBytesValue = dynamicBytesValue; + } + + public Utf8String getStringValue() { + return stringValue; + } + + public void setStringValue(Utf8String stringValue) { + this.stringValue = stringValue; + } + + public ABIObject getListValueType() { + return listValueType; + } + + public void setListValueType(ABIObject listValueType) { + this.listValueType = listValueType; + } + + public int getListLength() { + return listLength; + } + + public void setListLength(int listLength) { + this.listLength = listLength; + } + + @Override + public String toString() { + + String str = "ABIObject{" + "name='" + name + '\'' + ", type=" + type; + + if (type == ObjectType.VALUE) { + str += ", valueType=" + valueType; + switch (valueType) { + case BOOL: + str += ", booValueType="; + str += Objects.isNull(boolValue) ? "null" : boolValue.getValue(); + break; + case UINT: + case INT: + str += ", numericValue="; + str += Objects.isNull(numericValue) ? "null" : numericValue.getValue(); + break; + case ADDRESS: + str += ", addressValue="; + str += Objects.isNull(addressValue) ? "null" : addressValue.getValue(); + break; + case BYTES: + str += ", bytesValue="; + str += Objects.isNull(bytesValue) ? "null" : bytesValue.getValue(); + break; + case DBYTES: + str += ", dynamicBytesValue="; + str += + Objects.isNull(dynamicBytesValue) + ? "null" + : dynamicBytesValue.getValue(); + // case STRING: + default: + str += ", stringValue="; + str += Objects.isNull(stringValue) ? "null" : stringValue.getValue(); + } + } else if (type == ObjectType.LIST) { + str += ", listType=" + listType; + str += ", listValues=" + listValues + ", listLength=" + listLength; + } else if (type == ObjectType.STRUCT) { + str += ", structFields=" + structFields; + } + + str += '}'; + return str; + } +} diff --git a/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABIObjectFactory.java b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABIObjectFactory.java new file mode 100644 index 000000000..2e83cb97e --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ABIObjectFactory.java @@ -0,0 +1,150 @@ +package org.fisco.bcos.sdk.abi.wrapper; + +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ABIObjectFactory { + + private static final Logger logger = LoggerFactory.getLogger(ABIObjectFactory.class); + + public static ABIObject createInputObject(ABIDefinition abiDefinition) { + return createObject( + abiDefinition.getName(), abiDefinition.getType(), abiDefinition.getInputs()); + } + + public static ABIObject createOutputObject(ABIDefinition abiDefinition) { + return createObject( + abiDefinition.getName(), abiDefinition.getType(), abiDefinition.getOutputs()); + } + + private static ABIObject createObject( + String name, String type, List namedTypes) { + try { + ABIObject abiObject = new ABIObject(ABIObject.ObjectType.STRUCT); + + for (ABIDefinition.NamedType namedType : namedTypes) { + abiObject.getStructFields().add(buildTypeObject(namedType)); + } + + logger.info(" name: {}", name); + + return abiObject; + + } catch (Exception e) { + logger.error("namedTypes: {}, e: ", namedTypes, e); + } + + return null; + } + + public static ABIObject createEventInputObject(ABIDefinition abiDefinition) { + return creatEventObjectWithOutIndexed(abiDefinition.getInputs()); + } + + public static ABIObject creatEventObjectWithOutIndexed( + List namedTypes) { + try { + ABIObject abiObject = new ABIObject(ABIObject.ObjectType.STRUCT); + + for (ABIDefinition.NamedType namedType : namedTypes) { + if (!namedType.isIndexed()) { + abiObject.getStructFields().add(buildTypeObject(namedType)); + } + } + return abiObject; + } catch (Exception e) { + logger.error("namedTypes: {}, e: ", namedTypes, e); + } + return null; + } + + /** + * build ABIObject by raw type name + * + * @param rawType the rawType of the object + * @return the built ABIObject + */ + public static ABIObject buildRawTypeObject(String rawType) { + + ABIObject abiObject = null; + + if (rawType.startsWith("uint")) { + abiObject = new ABIObject(ABIObject.ValueType.UINT); + } else if (rawType.startsWith("int")) { + abiObject = new ABIObject(ABIObject.ValueType.INT); + } else if (rawType.startsWith("bool")) { + abiObject = new ABIObject(ABIObject.ValueType.BOOL); + } else if (rawType.startsWith("string")) { + abiObject = new ABIObject(ABIObject.ValueType.STRING); + } else if (rawType.equals("bytes")) { + abiObject = new ABIObject(ABIObject.ValueType.DBYTES); + } else if (rawType.startsWith("bytes")) { + abiObject = new ABIObject(ABIObject.ValueType.BYTES); + } else if (rawType.startsWith("address")) { + abiObject = new ABIObject(ABIObject.ValueType.ADDRESS); + } else if (rawType.startsWith("fixed") || rawType.startsWith("ufixed")) { + throw new UnsupportedOperationException("Unsupported type:" + rawType); + } else { + throw new UnsupportedOperationException("Unrecognized type:" + rawType); + } + + return abiObject; + } + + private static ABIObject buildTupleObject(ABIDefinition.NamedType namedType) { + return createObject(namedType.getName(), namedType.getType(), namedType.getComponents()); + } + + private static ABIObject buildListObject( + ABIDefinition.Type typeObj, ABIDefinition.NamedType namedType) { + + ABIObject abiObject = null; + if (typeObj.isList()) { + ABIObject listObject = new ABIObject(ABIObject.ObjectType.LIST); + listObject.setListType( + typeObj.isFixedList() ? ABIObject.ListType.FIXED : ABIObject.ListType.DYNAMIC); + if (typeObj.isFixedList()) { + listObject.setListLength(typeObj.getLastDimension()); + } + + listObject.setListValueType( + buildListObject(typeObj.reduceDimensionAndGetType(), namedType)); + abiObject = listObject; + } else if (typeObj.getRawType().startsWith("tuple")) { + abiObject = buildTupleObject(namedType); + } else { + abiObject = buildRawTypeObject(typeObj.getRawType()); + } + + return abiObject; + } + + public static ABIObject buildTypeObject(ABIDefinition.NamedType namedType) { + try { + String type = namedType.getType(); + // String name = namedType.getName(); + // boolean indexed = namedType.isIndexed(); + + ABIDefinition.Type typeObj = new ABIDefinition.Type(type); + String rawType = typeObj.getRawType(); + + ABIObject abiObject = null; + if (typeObj.isList()) { + abiObject = buildListObject(typeObj, namedType); + } else if (rawType.startsWith("tuple")) { + abiObject = buildTupleObject(namedType); + } else { + abiObject = buildRawTypeObject(rawType); + } + + abiObject.setName(namedType.getName()); + + return abiObject; + } catch (Exception e) { + logger.error(" e: ", e); + } + + return null; + } +} 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 new file mode 100644 index 000000000..a8b9fc9cb --- /dev/null +++ b/sdk-abi/src/main/java/org/fisco/bcos/sdk/abi/wrapper/ContractABIDefinition.java @@ -0,0 +1,110 @@ +package org.fisco.bcos.sdk.abi.wrapper; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.utils.Numeric; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ContractABIDefinition { + + private static final Logger logger = LoggerFactory.getLogger(ContractABIDefinition.class); + + private ABIDefinition constructor = null; + private Map> functions = new HashMap<>(); + private Map> events = new HashMap<>(); + // method id => function + private Map methodIDToFunctions = new HashMap<>(); + // event topic => topic + private Map eventTopicToEvents = new HashMap<>(); + private CryptoSuite cryptoSuite; + + public ContractABIDefinition(CryptoSuite cryptoSuite) { + this.cryptoSuite = cryptoSuite; + } + + public ABIDefinition getConstructor() { + return constructor; + } + + public void setConstructor(ABIDefinition constructor) { + this.constructor = constructor; + } + + public Map> getFunctions() { + return functions; + } + + public void setFunctions(Map> functions) { + this.functions = functions; + } + + public Map> getEvents() { + return events; + } + + public void setEvents(Map> events) { + this.events = events; + } + + public Map getMethodIDToFunctions() { + return methodIDToFunctions; + } + + public void setMethodIDToFunctions(Map methodIDToFunctions) { + this.methodIDToFunctions = methodIDToFunctions; + } + + public Map getEventTopicToEvents() { + return eventTopicToEvents; + } + + public void setEventTopicToEvents(Map eventTopicToEvents) { + this.eventTopicToEvents = eventTopicToEvents; + } + + public void addFunction(String name, ABIDefinition abiDefinition) { + + List abiDefinitions = functions.get(name); + if (abiDefinitions == null) { + functions.put(name, new ArrayList<>()); + abiDefinitions = functions.get(name); + } else { + logger.info(" overload method ??? name: {}, abiDefinition: {}", name, abiDefinition); + } + abiDefinitions.add(abiDefinition); + + // calculate method id and add abiDefinition to methodIdToFunctions + String methodId = abiDefinition.getMethodId(cryptoSuite); + methodIDToFunctions.put(methodId, abiDefinition); + + logger.info( + " name: {}, methodId: {}, methodSignature: {}, abi: {}", + name, + methodId, + abiDefinition.getMethodSignatureAsString(), + abiDefinition); + } + + public void addEvent(String name, ABIDefinition abiDefinition) { + events.putIfAbsent(name, new ArrayList<>()); + List abiDefinitions = events.get(name); + abiDefinitions.add(abiDefinition); + logger.info(" name: {}, abi: {}", name, abiDefinition); + + // calculate method id and add abiDefinition to eventTopicToEvents + String methodId = abiDefinition.getMethodId(cryptoSuite); + eventTopicToEvents.put(methodId, abiDefinition); + } + + public ABIDefinition getABIDefinitionByMethodId(String methodId) { + return methodIDToFunctions.get(Numeric.prependHexPrefix(methodId)); + } + + public ABIDefinition getABIDefinitionByEventTopic(String topic) { + return eventTopicToEvents.get(Numeric.prependHexPrefix(topic)); + } +} 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 new file mode 100644 index 000000000..27b88e5b2 --- /dev/null +++ b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABICodecTest.java @@ -0,0 +1,357 @@ +package org.fisco.bcos.sdk.test.abi; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +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.ABIObject; +import org.fisco.bcos.sdk.abi.wrapper.ABIObjectFactory; +import org.fisco.bcos.sdk.abi.wrapper.ContractABIDefinition; +import org.junit.Assert; +import org.junit.Test; + +class Item { + private BigInteger a; + private BigInteger b; + private BigInteger c; + + public Item(BigInteger a, BigInteger b, BigInteger c) { + this.a = a; + this.b = b; + this.c = c; + } +} + +class Info { + private String name; + private BigInteger count; + private Item[] items; + + public Info(String name, BigInteger count, Item[] items) { + this.name = name; + this.count = count; + this.items = items; + } +} + +public class ABICodecTest { + private String abiDesc = + "[\n" + + " {\n" + + " \"anonymous\": false,\n" + + " \"inputs\": [\n" + + " {\n" + + " \"indexed\": false,\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"a\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"components\": [\n" + + " {\n" + + " \"internalType\": \"string\",\n" + + " \"name\": \"name\",\n" + + " \"type\": \"string\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"count\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"components\": [\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"a\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"b\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"c\",\n" + + " \"type\": \"int256\"\n" + + " }\n" + + " ],\n" + + " \"internalType\": \"struct Proxy.Item[]\",\n" + + " \"name\": \"items\",\n" + + " \"type\": \"tuple[]\"\n" + + " }\n" + + " ],\n" + + " \"indexed\": false,\n" + + " \"internalType\": \"struct Proxy.Info[]\",\n" + + " \"name\": \"b\",\n" + + " \"type\": \"tuple[]\"\n" + + " },\n" + + " {\n" + + " \"indexed\": false,\n" + + " \"internalType\": \"string\",\n" + + " \"name\": \"c\",\n" + + " \"type\": \"string\"\n" + + " }\n" + + " ],\n" + + " \"name\": \"output1\",\n" + + " \"type\": \"event\"\n" + + " },\n" + + " {\n" + + " \"constant\": false,\n" + + " \"inputs\": [\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"a\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"components\": [\n" + + " {\n" + + " \"internalType\": \"string\",\n" + + " \"name\": \"name\",\n" + + " \"type\": \"string\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"count\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"components\": [\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"a\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"b\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"c\",\n" + + " \"type\": \"int256\"\n" + + " }\n" + + " ],\n" + + " \"internalType\": \"struct Proxy.Item[]\",\n" + + " \"name\": \"items\",\n" + + " \"type\": \"tuple[]\"\n" + + " }\n" + + " ],\n" + + " \"internalType\": \"struct Proxy.Info[]\",\n" + + " \"name\": \"b\",\n" + + " \"type\": \"tuple[]\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"string\",\n" + + " \"name\": \"c\",\n" + + " \"type\": \"string\"\n" + + " }\n" + + " ],\n" + + " \"name\": \"test\",\n" + + " \"outputs\": [\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"\",\n" + + " \"type\": \"int256\"\n" + + " }\n" + + " ],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"function\"\n" + + " },\n" + + " {\n" + + " \"constant\": false,\n" + + " \"inputs\": [],\n" + + " \"name\": \"test1\",\n" + + " \"outputs\": [\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"a\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"components\": [\n" + + " {\n" + + " \"internalType\": \"string\",\n" + + " \"name\": \"name\",\n" + + " \"type\": \"string\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"count\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"components\": [\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"a\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"b\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"c\",\n" + + " \"type\": \"int256\"\n" + + " }\n" + + " ],\n" + + " \"internalType\": \"struct Proxy.Item[]\",\n" + + " \"name\": \"items\",\n" + + " \"type\": \"tuple[]\"\n" + + " }\n" + + " ],\n" + + " \"internalType\": \"struct Proxy.Info[]\",\n" + + " \"name\": \"b\",\n" + + " \"type\": \"tuple[]\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"string\",\n" + + " \"name\": \"c\",\n" + + " \"type\": \"string\"\n" + + " }\n" + + " ],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"function\"\n" + + " },\n" + + " {\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"fallback\"\n" + + " }\n" + + "]"; + + // int a, Info[] memory b, string memory c + /* + * { + "0": "int256: a 100", + "1": "tuple(string,int256,tuple(int256,int256,int256)[])[]: b Hello world!,100,1,2,3,Hello world2!,200,5,6,7", + "2": "string: c Hello world!" + } + + struct Item { + int a; + int b; + int c; + } + + struct Info { + string name; + int count; + Item[] items; + } + + event output1(int a, Info[] b, string c); + + function() external { + + } + + function test(int a, Info[] memory b, string memory c) public returns(int) { + // emit output1(a, b, c); + } + */ + private String encoded = + "0000000000000000000000000000000000000000000000000000000000000064" + + "0000000000000000000000000000000000000000000000000000000000000060" + + "0000000000000000000000000000000000000000000000000000000000000300" + + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000000000000000000000000000000000000000040" + + "0000000000000000000000000000000000000000000000000000000000000160" + + "0000000000000000000000000000000000000000000000000000000000000060" + + "0000000000000000000000000000000000000000000000000000000000000064" + + "00000000000000000000000000000000000000000000000000000000000000a0" + + "000000000000000000000000000000000000000000000000000000000000000c" + + "48656c6c6f20776f726c64210000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000001" + + "0000000000000000000000000000000000000000000000000000000000000001" + + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000000000000000000000000000000000000000003" + + "0000000000000000000000000000000000000000000000000000000000000060" + + "00000000000000000000000000000000000000000000000000000000000000c8" + + "00000000000000000000000000000000000000000000000000000000000000a0" + + "000000000000000000000000000000000000000000000000000000000000000c" + + "48656c6c6f20776f726c64320000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000001" + + "0000000000000000000000000000000000000000000000000000000000000005" + + "0000000000000000000000000000000000000000000000000000000000000006" + + "0000000000000000000000000000000000000000000000000000000000000007" + + "000000000000000000000000000000000000000000000000000000000000000c" + + "48656c6c6f20776f726c64210000000000000000000000000000000000000000"; + + private String encodedWithMethodId = "0x00a3c75d" + encoded; + + @Test + public void testEncodeFromString() { + List args = new ArrayList(); + args.add("100"); + // [{"name": "Hello world!", "count": 100, "items": [{"a": 1, "b": 2, "c": 3}]}, {"name": + // "Hello world2", "count": 200, "items": [{"a": 1, "b": 2, "c": 3}]}] + args.add( + "[{\"name\": \"Hello world!\", \"count\": 100, \"items\": [{\"a\": 1, \"b\": 2, \"c\": 3}]}, {\"name\": \"Hello world2\", \"count\": 200, \"items\": [{\"a\": 5, \"b\": 6, \"c\": 7}]}]"); + args.add("Hello world!"); + + List argsObjects = new ArrayList(); + argsObjects.add(new BigInteger("100")); + List listParams = new ArrayList(); + Item item1 = new Item(new BigInteger("1"), new BigInteger("2"), new BigInteger("3")); + Item[] listItem1 = {item1}; + Info info1 = new Info("Hello world!", new BigInteger("100"), listItem1); + listParams.add(info1); + Item item2 = new Item(new BigInteger("5"), new BigInteger("6"), new BigInteger("7")); + Item[] listItem2 = {item2}; + Info info2 = new Info("Hello world2", new BigInteger("200"), listItem2); + listParams.add(info2); + argsObjects.add(listParams); + argsObjects.add("Hello world!"); + + ABICodec abiCodec = new ABICodec(Utils.getCryptoSuite()); + try { + // Method + // encode + Assert.assertEquals( + encodedWithMethodId, abiCodec.encodeMethodFromString(abiDesc, "test", args)); + Assert.assertEquals( + encodedWithMethodId, abiCodec.encodeMethod(abiDesc, "test", argsObjects)); + // decode + ContractABIDefinition contractABIDefinition = Utils.getContractABIDefinition(abiDesc); + ABIObject inputObject = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("test").get(0)); + ABICodecObject abiCodecObject = new ABICodecObject(); + List abiObjects = abiCodecObject.decodeJavaObject(inputObject, encoded); + Assert.assertEquals( + encodedWithMethodId, abiCodec.encodeMethod(abiDesc, "test", abiObjects)); + // MethodById String & JavaObject + ABIDefinition test = contractABIDefinition.getFunctions().get("test").get(0); + Assert.assertEquals( + encodedWithMethodId, + abiCodec.encodeMethodByIdFromString( + abiDesc, test.getMethodId(Utils.getCryptoSuite()), args)); + Assert.assertEquals( + encodedWithMethodId, + abiCodec.encodeMethodById( + abiDesc, test.getMethodId(Utils.getCryptoSuite()), abiObjects)); + // MethodByInterface String & JavaObject + Assert.assertEquals( + encodedWithMethodId, + abiCodec.encodeMethodByInterfaceFromString( + abiDesc, test.getMethodSignatureAsString(), args)); + Assert.assertEquals( + encodedWithMethodId, + abiCodec.encodeMethodByInterface( + abiDesc, test.getMethodSignatureAsString(), abiObjects)); + } catch (ABICodecException e) { + Assert.fail(e.getMessage()); + } + } +} diff --git a/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABIDefinitionTest.java b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABIDefinitionTest.java new file mode 100644 index 000000000..373dc77e9 --- /dev/null +++ b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABIDefinitionTest.java @@ -0,0 +1,160 @@ +package org.fisco.bcos.sdk.test.abi; + +import org.fisco.bcos.sdk.abi.wrapper.ABIDefinition; +import org.junit.Assert; +import org.junit.Test; + +public class ABIDefinitionTest { + @Test + public void typeIntTest() { + ABIDefinition.Type type = new ABIDefinition.Type("int"); + Assert.assertTrue(!type.isList()); + Assert.assertTrue(!type.isFixedList()); + Assert.assertTrue(!type.isDynamicList()); + Assert.assertTrue(type.getRawType().equals("int")); + Assert.assertTrue(type.getType().equals("int")); + Assert.assertTrue(type.getDimensions().isEmpty()); + Assert.assertTrue(type.getLastDimension() == 0); + } + + @Test + public void typeStringTest() { + ABIDefinition.Type type = new ABIDefinition.Type("string"); + Assert.assertTrue(!type.isList()); + Assert.assertTrue(!type.isFixedList()); + Assert.assertTrue(!type.isDynamicList()); + Assert.assertTrue(type.getRawType().equals("string")); + Assert.assertTrue(type.getType().equals("string")); + Assert.assertTrue(type.getDimensions().isEmpty()); + Assert.assertTrue(type.getLastDimension() == 0); + + ABIDefinition.Type type1 = type.reduceDimensionAndGetType(); + Assert.assertTrue(!type1.isList()); + Assert.assertTrue(!type1.isFixedList()); + Assert.assertTrue(!type1.isDynamicList()); + Assert.assertTrue(type1.getRawType().equals("string")); + Assert.assertTrue(type1.getType().equals("string")); + Assert.assertTrue(type1.getDimensions().size() == 0); + Assert.assertTrue(type1.getLastDimension() == 0); + } + + @Test + public void typeStringFixedTest() { + ABIDefinition.Type type = new ABIDefinition.Type("string[5]"); + Assert.assertTrue(type.isList()); + Assert.assertTrue(type.isFixedList()); + Assert.assertTrue(!type.isDynamicList()); + Assert.assertTrue(type.getRawType().equals("string")); + Assert.assertTrue(type.getType().equals("string[5]")); + Assert.assertTrue(type.getDimensions().size() == 1); + Assert.assertTrue(type.getLastDimension() == 5); + + ABIDefinition.Type type1 = type.reduceDimensionAndGetType(); + Assert.assertTrue(!type1.isList()); + Assert.assertTrue(!type1.isFixedList()); + Assert.assertTrue(!type1.isDynamicList()); + Assert.assertTrue(type1.getRawType().equals("string")); + Assert.assertTrue(type1.getType().equals("string")); + Assert.assertTrue(type1.getDimensions().size() == 0); + Assert.assertTrue(type1.getLastDimension() == 0); + } + + @Test + public void typeStringFixedDynamicTest() { + ABIDefinition.Type type = new ABIDefinition.Type("string[5][]"); + Assert.assertTrue(type.isList()); + Assert.assertTrue(!type.isFixedList()); + Assert.assertTrue(type.isDynamicList()); + Assert.assertTrue(type.getRawType().equals("string")); + Assert.assertTrue(type.getType().equals("string[5][]")); + Assert.assertTrue(type.getDimensions().size() == 2); + Assert.assertTrue(type.getLastDimension() == 0); + + ABIDefinition.Type type1 = type.reduceDimensionAndGetType(); + Assert.assertTrue(type1.isList()); + Assert.assertTrue(type1.isFixedList()); + Assert.assertTrue(!type1.isDynamicList()); + Assert.assertTrue(type1.getRawType().equals("string")); + Assert.assertTrue(type1.getType().equals("string[5]")); + Assert.assertTrue(type1.getDimensions().size() == 1); + Assert.assertTrue(type1.getLastDimension() == 5); + } + + @Test + public void typeStringDynamicDynamicDynamicTest() { + ABIDefinition.Type type = new ABIDefinition.Type("string[][][]"); + Assert.assertTrue(type.isList()); + Assert.assertTrue(!type.isFixedList()); + Assert.assertTrue(type.isDynamicList()); + Assert.assertTrue(type.getRawType().equals("string")); + Assert.assertTrue(type.getType().equals("string[][][]")); + Assert.assertTrue(type.getDimensions().size() == 3); + Assert.assertTrue(type.getLastDimension() == 0); + + ABIDefinition.Type type1 = type.reduceDimensionAndGetType(); + Assert.assertTrue(type1.isList()); + Assert.assertTrue(!type1.isFixedList()); + Assert.assertTrue(type1.isDynamicList()); + Assert.assertTrue(type1.getRawType().equals("string")); + Assert.assertTrue(type1.getType().equals("string[][]")); + Assert.assertTrue(type1.getDimensions().size() == 2); + Assert.assertTrue(type1.getLastDimension() == 0); + + ABIDefinition.Type type2 = type1.reduceDimensionAndGetType(); + Assert.assertTrue(type2.isList()); + Assert.assertTrue(!type2.isFixedList()); + Assert.assertTrue(type2.isDynamicList()); + Assert.assertTrue(type2.getRawType().equals("string")); + Assert.assertTrue(type2.getType().equals("string[]")); + Assert.assertTrue(type2.getDimensions().size() == 1); + Assert.assertTrue(type2.getLastDimension() == 0); + + ABIDefinition.Type type3 = type2.reduceDimensionAndGetType(); + Assert.assertTrue(!type3.isList()); + Assert.assertTrue(!type3.isFixedList()); + Assert.assertTrue(!type3.isDynamicList()); + Assert.assertTrue(type3.getRawType().equals("string")); + Assert.assertTrue(type3.getType().equals("string")); + Assert.assertTrue(type3.getDimensions().size() == 0); + Assert.assertTrue(type3.getLastDimension() == 0); + } + + @Test + public void typeStringFixedFixedFixedTest() { + ABIDefinition.Type type = new ABIDefinition.Type("string[8][9][10]"); + Assert.assertTrue(type.isList()); + Assert.assertTrue(type.isFixedList()); + Assert.assertTrue(!type.isDynamicList()); + Assert.assertTrue(type.getRawType().equals("string")); + Assert.assertTrue(type.getType().equals("string[8][9][10]")); + Assert.assertTrue(type.getDimensions().size() == 3); + Assert.assertTrue(type.getLastDimension() == 10); + + ABIDefinition.Type type1 = type.reduceDimensionAndGetType(); + Assert.assertTrue(type1.isList()); + Assert.assertTrue(type1.isFixedList()); + Assert.assertTrue(!type1.isDynamicList()); + Assert.assertTrue(type1.getRawType().equals("string")); + Assert.assertTrue(type1.getType().equals("string[8][9]")); + Assert.assertTrue(type1.getDimensions().size() == 2); + Assert.assertTrue(type1.getLastDimension() == 9); + + ABIDefinition.Type type2 = type1.reduceDimensionAndGetType(); + Assert.assertTrue(type2.isList()); + Assert.assertTrue(type2.isFixedList()); + Assert.assertTrue(!type2.isDynamicList()); + Assert.assertTrue(type2.getRawType().equals("string")); + Assert.assertTrue(type2.getType().equals("string[8]")); + Assert.assertTrue(type2.getDimensions().size() == 1); + Assert.assertTrue(type2.getLastDimension() == 8); + + ABIDefinition.Type type3 = type2.reduceDimensionAndGetType(); + Assert.assertTrue(!type3.isList()); + Assert.assertTrue(!type3.isFixedList()); + Assert.assertTrue(!type3.isDynamicList()); + Assert.assertTrue(type3.getRawType().equals("string")); + Assert.assertTrue(type3.getType().equals("string")); + Assert.assertTrue(type3.getDimensions().size() == 0); + Assert.assertTrue(type3.getLastDimension() == 0); + } +} diff --git a/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABIEventTest.java b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABIEventTest.java new file mode 100644 index 000000000..2d6c2e7f5 --- /dev/null +++ b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABIEventTest.java @@ -0,0 +1,33 @@ +package org.fisco.bcos.sdk.test.abi; + +import java.util.ArrayList; +import java.util.List; +import org.fisco.bcos.sdk.model.EventLog; +import org.fisco.bcos.sdk.abi.ABICodec; +import org.fisco.bcos.sdk.abi.ABICodecException; +import org.junit.Assert; +import org.junit.Test; + +public class ABIEventTest { + private static final String abi = + "[{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"_addrDArray\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"_addr\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getUint256\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"v\",\"type\":\"uint256\"}],\"name\":\"incrementUint256\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"_bytesV\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"_s\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"getSArray\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"bytesArray\",\"type\":\"bytes1[]\"}],\"name\":\"setBytesMapping\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b\",\"type\":\"bytes\"}],\"name\":\"setBytes\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i\",\"type\":\"int256\"},{\"name\":\"a\",\"type\":\"address[]\"},{\"name\":\"s\",\"type\":\"string\"}],\"name\":\"setValues\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"b\",\"type\":\"bytes1\"}],\"name\":\"getByBytes\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes1[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"_intV\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"emptyArgs\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"i\",\"type\":\"int256\"},{\"name\":\"s\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"LogIncrement\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"s\",\"type\":\"string\"}],\"name\":\"LogInit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"i\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"a\",\"type\":\"address[]\"},{\"indexed\":false,\"name\":\"s\",\"type\":\"string\"}],\"name\":\"LogSetValues\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"o\",\"type\":\"bytes\"},{\"indexed\":false,\"name\":\"b\",\"type\":\"bytes\"}],\"name\":\"LogSetBytes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"o\",\"type\":\"uint256[2]\"},{\"indexed\":false,\"name\":\"n\",\"type\":\"uint256[2]\"}],\"name\":\"LogSetSArray\",\"type\":\"event\"}]"; + private static final String encoded = + "0x0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000147365742076616c75657320e5ad97e7aca6e4b8b2000000000000000000000000"; + + @Test + public void testDecode() { + ABICodec abiCodec = new ABICodec(Utils.getCryptoSuite()); + try { + EventLog log = new EventLog(encoded, new ArrayList<>()); + List list = abiCodec.decodeEvent(abi, "LogSetValues", log); + Assert.assertEquals(list.size(), 3); + Assert.assertEquals(list.get(0).toString(), "20"); + Assert.assertEquals( + list.get(1).toString(), + "[0x0000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000003]"); + System.out.println("decode event log content, " + list); + } catch (ABICodecException e) { + Assert.fail(e.getMessage()); + } + } +} diff --git a/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABIObjectCodecTest.java b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABIObjectCodecTest.java new file mode 100644 index 000000000..ab3a3c72c --- /dev/null +++ b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABIObjectCodecTest.java @@ -0,0 +1,600 @@ +package org.fisco.bcos.sdk.test.abi; + +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; +import org.fisco.bcos.sdk.abi.wrapper.ABICodecJsonWrapper; +import org.fisco.bcos.sdk.abi.wrapper.ABIDefinition; +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.junit.Assert; +import org.junit.Test; + +public class ABIObjectCodecTest { + String abiDesc = + "[\n" + + " {\n" + + " \"anonymous\": false,\n" + + " \"inputs\": [\n" + + " {\n" + + " \"indexed\": false,\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"a\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"components\": [\n" + + " {\n" + + " \"internalType\": \"string\",\n" + + " \"name\": \"name\",\n" + + " \"type\": \"string\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"count\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"components\": [\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"a\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"b\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"c\",\n" + + " \"type\": \"int256\"\n" + + " }\n" + + " ],\n" + + " \"internalType\": \"struct Proxy.Item[]\",\n" + + " \"name\": \"items\",\n" + + " \"type\": \"tuple[]\"\n" + + " }\n" + + " ],\n" + + " \"indexed\": false,\n" + + " \"internalType\": \"struct Proxy.Info[]\",\n" + + " \"name\": \"b\",\n" + + " \"type\": \"tuple[]\"\n" + + " },\n" + + " {\n" + + " \"indexed\": false,\n" + + " \"internalType\": \"string\",\n" + + " \"name\": \"c\",\n" + + " \"type\": \"string\"\n" + + " }\n" + + " ],\n" + + " \"name\": \"output1\",\n" + + " \"type\": \"event\"\n" + + " },\n" + + " {\n" + + " \"constant\": false,\n" + + " \"inputs\": [\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"a\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"components\": [\n" + + " {\n" + + " \"internalType\": \"string\",\n" + + " \"name\": \"name\",\n" + + " \"type\": \"string\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"count\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"components\": [\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"a\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"b\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"c\",\n" + + " \"type\": \"int256\"\n" + + " }\n" + + " ],\n" + + " \"internalType\": \"struct Proxy.Item[]\",\n" + + " \"name\": \"items\",\n" + + " \"type\": \"tuple[]\"\n" + + " }\n" + + " ],\n" + + " \"internalType\": \"struct Proxy.Info[]\",\n" + + " \"name\": \"b\",\n" + + " \"type\": \"tuple[]\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"string\",\n" + + " \"name\": \"c\",\n" + + " \"type\": \"string\"\n" + + " }\n" + + " ],\n" + + " \"name\": \"test\",\n" + + " \"outputs\": [\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"\",\n" + + " \"type\": \"int256\"\n" + + " }\n" + + " ],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"function\"\n" + + " },\n" + + " {\n" + + " \"constant\": false,\n" + + " \"inputs\": [],\n" + + " \"name\": \"test1\",\n" + + " \"outputs\": [\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"a\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"components\": [\n" + + " {\n" + + " \"internalType\": \"string\",\n" + + " \"name\": \"name\",\n" + + " \"type\": \"string\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"count\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"components\": [\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"a\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"b\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"c\",\n" + + " \"type\": \"int256\"\n" + + " }\n" + + " ],\n" + + " \"internalType\": \"struct Proxy.Item[]\",\n" + + " \"name\": \"items\",\n" + + " \"type\": \"tuple[]\"\n" + + " }\n" + + " ],\n" + + " \"internalType\": \"struct Proxy.Info[]\",\n" + + " \"name\": \"b\",\n" + + " \"type\": \"tuple[]\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"string\",\n" + + " \"name\": \"c\",\n" + + " \"type\": \"string\"\n" + + " }\n" + + " ],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"function\"\n" + + " },\n" + + " {\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"fallback\"\n" + + " }\n" + + "]"; + + // int a, Info[] memory b, string memory c + /* + * { + "0": "int256: a 100", + "1": "tuple(string,int256,tuple(int256,int256,int256)[])[]: b Hello world!,100,1,2,3,Hello world2!,200,5,6,7", + "2": "string: c Hello world!" + } + + struct Item { + int a; + int b; + int c; + } + + struct Info { + string name; + int count; + Item[] items; + } + + event output1(int a, Info[] b, string c); + + function() external { + + } + + function test(int a, Info[] memory b, string memory c) public returns(int) { + // emit output1(a, b, c); + } + */ + String encoded = + "0000000000000000000000000000000000000000000000000000000000000064" + + "0000000000000000000000000000000000000000000000000000000000000060" + + "0000000000000000000000000000000000000000000000000000000000000300" + + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000000000000000000000000000000000000000040" + + "0000000000000000000000000000000000000000000000000000000000000160" + + "0000000000000000000000000000000000000000000000000000000000000060" + + "0000000000000000000000000000000000000000000000000000000000000064" + + "00000000000000000000000000000000000000000000000000000000000000a0" + + "000000000000000000000000000000000000000000000000000000000000000c" + + "48656c6c6f20776f726c64210000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000001" + + "0000000000000000000000000000000000000000000000000000000000000001" + + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000000000000000000000000000000000000000003" + + "0000000000000000000000000000000000000000000000000000000000000060" + + "00000000000000000000000000000000000000000000000000000000000000c8" + + "00000000000000000000000000000000000000000000000000000000000000a0" + + "000000000000000000000000000000000000000000000000000000000000000c" + + "48656c6c6f20776f726c64320000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000001" + + "0000000000000000000000000000000000000000000000000000000000000005" + + "0000000000000000000000000000000000000000000000000000000000000006" + + "0000000000000000000000000000000000000000000000000000000000000007" + + "000000000000000000000000000000000000000000000000000000000000000c" + + "48656c6c6f20776f726c64210000000000000000000000000000000000000000"; + + @Test + public void testLoadABIJSON() { + ContractABIDefinition contractABIDefinition = Utils.getContractABIDefinition(abiDesc); + + Assert.assertEquals(2, contractABIDefinition.getFunctions().size()); + Assert.assertEquals(1, contractABIDefinition.getEvents().size()); + + List functions = contractABIDefinition.getFunctions().get("test"); + ABIObjectFactory abiObjectFactory = new ABIObjectFactory(); + ABIObject inputABIObject = abiObjectFactory.createInputObject(functions.get(0)); + ABIObject obj = inputABIObject.decode(encoded); + ABICodecJsonWrapper abiCodecJsonWrapper = new ABICodecJsonWrapper(); + // List decodeJson = abiCodecJsonWrapper.decode(obj, encoded); + // Assert.assertEquals(Arrays.toString(decodeJson.toArray(new String[0])), "[ [ \"Hello + // world!\", 100, [ [ 1, 2, 3 ] ] ], [ \"Hello world2\", 200, [ [ 5, 6, 7 ] ] ], [ \"Hello + // world!\", 100, [ [ 1, 2, 3 ] ] ], [ \"Hello world2\", 200, [ [ 5, 6, 7 ] ] ] ]"); + String buffer = obj.encode(); + + Assert.assertEquals(encoded, buffer); + } + + @Test + public void testEncodeByJSON() throws Exception { + + ContractABIDefinition contractABIDefinition = Utils.getContractABIDefinition(abiDesc); + + List functions = contractABIDefinition.getFunctions().get("test"); + ABIObjectFactory abiObjectFactory = new ABIObjectFactory(); + ABIObject inputABIObject = abiObjectFactory.createInputObject(functions.get(0)); + + List args = new ArrayList(); + args.add("100"); + + // [{"name": "Hello world!", "count": 100, "items": [{"a": 1, "b": 2, "c": 3}]}, {"name": + // "Hello world2", "count": 200, "items": [{"a": 1, "b": 2, "c": 3}]}] + args.add( + "[{\"name\": \"Hello world!\", \"count\": 100, \"items\": [{\"a\": 1, \"b\": 2, \"c\": 3}]}, {\"name\": \"Hello world2\", \"count\": 200, \"items\": [{\"a\": 5, \"b\": 6, \"c\": 7}]}]"); + args.add("Hello world!"); + + ABICodecJsonWrapper abiCodecJsonWrapper = new ABICodecJsonWrapper(); + ABIObject encodedObj = abiCodecJsonWrapper.encode(inputABIObject, args); + + ABIObject inputABIObject0 = abiObjectFactory.createInputObject(functions.get(0)); + List decodeArgs = abiCodecJsonWrapper.decode(inputABIObject0, encoded); + + // Assert.assertArrayEquals(args.toArray(), decodeArgs.toArray()); + Assert.assertEquals(encoded, encodedObj.encode()); + } + + @Test + public void testBytesEncode() throws Exception { + String proxyDesc = + "[{\n" + + " \"constant\": false,\n" + + " \"inputs\": [{\n" + + " \"name\": \"_args\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"name\": \"commitTransaction\",\n" + + " \"outputs\": [{\n" + + " \"name\": \"\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"function\"\n" + + "}, {\n" + + " \"constant\": false,\n" + + " \"inputs\": [{\n" + + " \"name\": \"_args\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"name\": \"setMaxStep\",\n" + + " \"outputs\": [],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"function\"\n" + + "}, {\n" + + " \"constant\": true,\n" + + " \"inputs\": [{\n" + + " \"name\": \"_args\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"name\": \"getPaths\",\n" + + " \"outputs\": [{\n" + + " \"name\": \"\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"view\",\n" + + " \"type\": \"function\"\n" + + "}, {\n" + + " \"constant\": false,\n" + + " \"inputs\": [{\n" + + " \"name\": \"_args\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"name\": \"rollbackTransaction\",\n" + + " \"outputs\": [{\n" + + " \"name\": \"\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"function\"\n" + + "}, {\n" + + " \"constant\": true,\n" + + " \"inputs\": [],\n" + + " \"name\": \"getLatestTransaction\",\n" + + " \"outputs\": [{\n" + + " \"name\": \"\",\n" + + " \"type\": \"string\"\n" + + " }],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"view\",\n" + + " \"type\": \"function\"\n" + + "}, {\n" + + " \"constant\": false,\n" + + " \"inputs\": [{\n" + + " \"name\": \"_transactionID\",\n" + + " \"type\": \"string\"\n" + + " }, {\n" + + " \"name\": \"_seq\",\n" + + " \"type\": \"uint256\"\n" + + " }, {\n" + + " \"name\": \"_path\",\n" + + " \"type\": \"string\"\n" + + " }, {\n" + + " \"name\": \"_func\",\n" + + " \"type\": \"string\"\n" + + " }, {\n" + + " \"name\": \"_args\",\n" + + " \"type\": \"bytes\"\n" + + " }],\n" + + " \"name\": \"sendTransaction\",\n" + + " \"outputs\": [{\n" + + " \"name\": \"\",\n" + + " \"type\": \"bytes\"\n" + + " }],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"function\"\n" + + "}, {\n" + + " \"constant\": true,\n" + + " \"inputs\": [{\n" + + " \"name\": \"_args\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"name\": \"getVersion\",\n" + + " \"outputs\": [{\n" + + " \"name\": \"\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"pure\",\n" + + " \"type\": \"function\"\n" + + "}, {\n" + + " \"constant\": false,\n" + + " \"inputs\": [{\n" + + " \"name\": \"_args\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"name\": \"rollbackAndDeleteTransaction\",\n" + + " \"outputs\": [{\n" + + " \"name\": \"\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"function\"\n" + + "}, {\n" + + " \"constant\": true,\n" + + " \"inputs\": [],\n" + + " \"name\": \"getLatestTransactionInfo\",\n" + + " \"outputs\": [{\n" + + " \"name\": \"\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"view\",\n" + + " \"type\": \"function\"\n" + + "}, {\n" + + " \"constant\": true,\n" + + " \"inputs\": [{\n" + + " \"name\": \"_str\",\n" + + " \"type\": \"string\"\n" + + " }],\n" + + " \"name\": \"stringToUint256\",\n" + + " \"outputs\": [{\n" + + " \"name\": \"\",\n" + + " \"type\": \"uint256\"\n" + + " }],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"pure\",\n" + + " \"type\": \"function\"\n" + + "}, {\n" + + " \"constant\": false,\n" + + " \"inputs\": [{\n" + + " \"name\": \"_transactionID\",\n" + + " \"type\": \"string\"\n" + + " }, {\n" + + " \"name\": \"_path\",\n" + + " \"type\": \"string\"\n" + + " }, {\n" + + " \"name\": \"_func\",\n" + + " \"type\": \"string\"\n" + + " }, {\n" + + " \"name\": \"_args\",\n" + + " \"type\": \"bytes\"\n" + + " }],\n" + + " \"name\": \"constantCall\",\n" + + " \"outputs\": [{\n" + + " \"name\": \"\",\n" + + " \"type\": \"bytes\"\n" + + " }],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"function\"\n" + + "}, {\n" + + " \"constant\": true,\n" + + " \"inputs\": [{\n" + + " \"name\": \"_args\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"name\": \"getMaxStep\",\n" + + " \"outputs\": [{\n" + + " \"name\": \"\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"view\",\n" + + " \"type\": \"function\"\n" + + "}, {\n" + + " \"constant\": true,\n" + + " \"inputs\": [{\n" + + " \"name\": \"_args\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"name\": \"getTransactionInfo\",\n" + + " \"outputs\": [{\n" + + " \"name\": \"\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"view\",\n" + + " \"type\": \"function\"\n" + + "}, {\n" + + " \"constant\": false,\n" + + " \"inputs\": [{\n" + + " \"name\": \"_args\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"name\": \"addPath\",\n" + + " \"outputs\": [],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"function\"\n" + + "}, {\n" + + " \"constant\": false,\n" + + " \"inputs\": [{\n" + + " \"name\": \"_args\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"name\": \"startTransaction\",\n" + + " \"outputs\": [{\n" + + " \"name\": \"\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"function\"\n" + + "}, {\n" + + " \"constant\": false,\n" + + " \"inputs\": [{\n" + + " \"name\": \"_args\",\n" + + " \"type\": \"string[]\"\n" + + " }],\n" + + " \"name\": \"deletePathList\",\n" + + " \"outputs\": [],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"function\"\n" + + "}, {\n" + + " \"inputs\": [],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"constructor\"\n" + + "}]"; + + // ABIObjectCodecJsonWrapper abiFactory = new ABIObjectCodecJsonWrapper(); + ContractABIDefinition contractABIDefinition = Utils.getContractABIDefinition(proxyDesc); + + List functions = contractABIDefinition.getFunctions().get("constantCall"); + ABIObject inputABIObject = ABIObjectFactory.createInputObject(functions.get(0)); + + List args = new ArrayList(); + args.add("arg112345678901234567890123456789012345678901234567890"); + args.add("arg212345678901234567890123456789012345678901234567890"); + args.add("arg312345678901234567890123456789012345678901234567890"); + + String bytesValue = "0x123456789874321"; + byte[] encode = Base64.getEncoder().encode(bytesValue.getBytes()); + + args.add(new String(encode)); + + ABICodecJsonWrapper abiCodecJsonWrapper = new ABICodecJsonWrapper(); + ABIObject encodedObj = abiCodecJsonWrapper.encode(inputABIObject, args); + String buffer = encodedObj.encode(); + + List decodeArgs = abiCodecJsonWrapper.decode(inputABIObject, buffer); + Assert.assertArrayEquals(args.toArray(), decodeArgs.toArray()); + + List functions0 = + contractABIDefinition.getFunctions().get("commitTransaction"); + ABIObject inputABIObject0 = ABIObjectFactory.createInputObject(functions0.get(0)); + + List args0 = new ArrayList(); + args0.add( + "[\"arg112345678901234567890123456789012345678901234567890\",\"arg112345678901234567890123456789012345678901234567890\",\"arg112345678901234567890123456789012345678901234567890\",\"arg112345678901234567890123456789012345678901234567890\"]"); + + ABIObject encodedObj0 = abiCodecJsonWrapper.encode(inputABIObject0, args0); + String buffer0 = encodedObj0.encode(); + + List decodeArgs0 = abiCodecJsonWrapper.decode(inputABIObject0, buffer0); + + // Assert.assertArrayEquals(decodeArgs.toArray(new String[0]), args0.get(0)); + + for (int i = 0; i < args.size() - 1; i++) { + Assert.assertEquals(args.get(i), decodeArgs.get(i)); + } + + byte[] decode = Base64.getDecoder().decode(decodeArgs.get(args.size() - 1)); + + Assert.assertEquals(new String(decode), bytesValue); + } +} diff --git a/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABIObjectFactoryTest.java b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABIObjectFactoryTest.java new file mode 100644 index 000000000..17723d015 --- /dev/null +++ b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABIObjectFactoryTest.java @@ -0,0 +1,1309 @@ +package org.fisco.bcos.sdk.test.abi; + +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertTrue; + +import java.util.Objects; +import org.fisco.bcos.sdk.abi.FunctionEncoder; +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.junit.Assert; +import org.junit.Test; + +public class ABIObjectFactoryTest { + + @Test + public void buildRawTypeObjectTest() { + Assert.assertTrue( + ABIObjectFactory.buildRawTypeObject("uint").getValueType() + == ABIObject.ValueType.UINT); + Assert.assertTrue( + ABIObjectFactory.buildRawTypeObject("uint256").getValueType() + == ABIObject.ValueType.UINT); + Assert.assertTrue( + ABIObjectFactory.buildRawTypeObject("int").getValueType() + == ABIObject.ValueType.INT); + Assert.assertTrue( + ABIObjectFactory.buildRawTypeObject("int256").getValueType() + == ABIObject.ValueType.INT); + Assert.assertTrue( + ABIObjectFactory.buildRawTypeObject("bool").getValueType() + == ABIObject.ValueType.BOOL); + Assert.assertTrue( + ABIObjectFactory.buildRawTypeObject("address").getValueType() + == ABIObject.ValueType.ADDRESS); + Assert.assertTrue( + ABIObjectFactory.buildRawTypeObject("bytes").getValueType() + == ABIObject.ValueType.DBYTES); + Assert.assertTrue( + ABIObjectFactory.buildRawTypeObject("bytes1").getValueType() + == ABIObject.ValueType.BYTES); + Assert.assertTrue( + ABIObjectFactory.buildRawTypeObject("bytes32").getValueType() + == ABIObject.ValueType.BYTES); + Assert.assertTrue( + ABIObjectFactory.buildRawTypeObject("string").getValueType() + == ABIObject.ValueType.STRING); + } + + @Test + public void testContractABIDefinitionBuildMethodSignature() throws Exception { + + /* + + pragma solidity>=0.4.19 <0.7.0; + pragma experimental ABIEncoderV2; + contract Test{ + struct E { string s;} + struct S { uint a; uint[] b; T[] c;T t;E e;} + struct T { uint x; uint y;} + + function a(E memory e) public {} + function b( T memory t)public {} + function c(T memory t,E memory e) public {} + function d(uint ) public {} + function e(uint, string[]memory, bool) public {} + function f(S memory,T memory,E memory,uint)public {} + function g(S[] memory, T[] memory,E[] memory,uint256 [] memory)public {} + function h(S[4] memory, T[4] memory, E[4] memory, uint256[4] memory) public {} + } + + */ + + /* + { + "d92a9e33": "a((string))", + "5282e79c": "b((uint256,uint256))", + "f332a566": "c((uint256,uint256),(string))", + "7f6b590c": "d(uint256)", + "b45c9d9f": "e(uint256,string[],bool)", + "edb896f9": "f((uint256,uint256[],(uint256,uint256)[],(uint256,uint256),(string)),(uint256,uint256),(string),uint256)", + "adc86690": "g((uint256,uint256[],(uint256,uint256)[],(uint256,uint256),(string))[],(uint256,uint256)[],(string)[],uint256[])", + "7a3093eb": "h((uint256,uint256[],(uint256,uint256)[],(uint256,uint256),(string))[4],(uint256,uint256)[4],(string)[4],uint256[4])" + } + */ + + String abi = + "[{\"constant\":false,\"inputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"}],\"internalType\":\"struct Test.E\",\"name\":\"e\",\"type\":\"tuple\"}],\"name\":\"a\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T\",\"name\":\"t\",\"type\":\"tuple\"}],\"name\":\"b\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T\",\"name\":\"t\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"}],\"internalType\":\"struct Test.E\",\"name\":\"e\",\"type\":\"tuple\"}],\"name\":\"c\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"d\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"e\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"b\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T[]\",\"name\":\"c\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T\",\"name\":\"t\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"}],\"internalType\":\"struct Test.E\",\"name\":\"e\",\"type\":\"tuple\"}],\"internalType\":\"struct Test.S\",\"name\":\"\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T\",\"name\":\"\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"}],\"internalType\":\"struct Test.E\",\"name\":\"\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"f\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"b\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T[]\",\"name\":\"c\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T\",\"name\":\"t\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"}],\"internalType\":\"struct Test.E\",\"name\":\"e\",\"type\":\"tuple\"}],\"internalType\":\"struct Test.S[]\",\"name\":\"\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T[]\",\"name\":\"\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"}],\"internalType\":\"struct Test.E[]\",\"name\":\"\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"name\":\"g\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"b\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T[]\",\"name\":\"c\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T\",\"name\":\"t\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"}],\"internalType\":\"struct Test.E\",\"name\":\"e\",\"type\":\"tuple\"}],\"internalType\":\"struct Test.S[4]\",\"name\":\"\",\"type\":\"tuple[4]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T[4]\",\"name\":\"\",\"type\":\"tuple[4]\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"}],\"internalType\":\"struct Test.E[4]\",\"name\":\"\",\"type\":\"tuple[4]\"},{\"internalType\":\"uint256[4]\",\"name\":\"\",\"type\":\"uint256[4]\"}],\"name\":\"h\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"}]"; + + ContractABIDefinition contractABIDefinition = Utils.getContractABIDefinition(abi); + CryptoSuite cryptoSuite = Utils.getCryptoSuite(); + FunctionEncoder functionEncoder = new FunctionEncoder(cryptoSuite); + assertEquals( + contractABIDefinition.getFunctions().get("a").get(0).getMethodSignatureAsString(), + "a((string))"); + assertEquals( + functionEncoder.buildMethodId( + contractABIDefinition + .getFunctions() + .get("a") + .get(0) + .getMethodSignatureAsString()), + "0xd92a9e33"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0xd92a9e33"))); + + assertEquals( + contractABIDefinition.getFunctions().get("b").get(0).getMethodSignatureAsString(), + "b((uint256,uint256))"); + assertEquals( + functionEncoder.buildMethodId( + contractABIDefinition + .getFunctions() + .get("b") + .get(0) + .getMethodSignatureAsString()), + "0x5282e79c"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0x5282e79c"))); + + assertEquals( + contractABIDefinition.getFunctions().get("c").get(0).getMethodSignatureAsString(), + "c((uint256,uint256),(string))"); + assertEquals( + functionEncoder.buildMethodId( + contractABIDefinition + .getFunctions() + .get("c") + .get(0) + .getMethodSignatureAsString()), + "0xf332a566"); + + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0xf332a566"))); + + assertEquals( + contractABIDefinition.getFunctions().get("d").get(0).getMethodSignatureAsString(), + "d(uint256)"); + assertEquals( + functionEncoder.buildMethodId( + contractABIDefinition + .getFunctions() + .get("d") + .get(0) + .getMethodSignatureAsString()), + "0x7f6b590c"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0x7f6b590c"))); + + assertEquals( + contractABIDefinition.getFunctions().get("e").get(0).getMethodSignatureAsString(), + "e(uint256,string[],bool)"); + assertEquals( + functionEncoder.buildMethodId( + contractABIDefinition + .getFunctions() + .get("e") + .get(0) + .getMethodSignatureAsString()), + "0xb45c9d9f"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0xb45c9d9f"))); + + assertEquals( + contractABIDefinition.getFunctions().get("f").get(0).getMethodSignatureAsString(), + "f((uint256,uint256[],(uint256,uint256)[],(uint256,uint256),(string)),(uint256,uint256),(string),uint256)"); + assertEquals( + functionEncoder.buildMethodId( + contractABIDefinition + .getFunctions() + .get("f") + .get(0) + .getMethodSignatureAsString()), + "0xedb896f9"); + + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0xedb896f9"))); + + assertEquals( + contractABIDefinition.getFunctions().get("g").get(0).getMethodSignatureAsString(), + "g((uint256,uint256[],(uint256,uint256)[],(uint256,uint256),(string))[],(uint256,uint256)[],(string)[],uint256[])"); + assertEquals( + contractABIDefinition + .getFunctions() + .get("g") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0xadc86690"); + + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0xadc86690"))); + + assertEquals( + contractABIDefinition.getFunctions().get("h").get(0).getMethodSignatureAsString(), + "h((uint256,uint256[],(uint256,uint256)[],(uint256,uint256),(string))[4],(uint256,uint256)[4],(string)[4],uint256[4])"); + assertEquals( + contractABIDefinition + .getFunctions() + .get("h") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0x7a3093eb"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0xadc86690"))); + } + + @Test + public void testContractABIDefinitionDynamic() throws Exception { + + /* + + pragma solidity>=0.4.19 <0.7.0; + pragma experimental ABIEncoderV2; + contract Test{ + struct E { string s;} + struct S { uint a; uint[] b; T[] c;T t;E e;} + struct T { uint x; uint y;} + + function a(E memory e) public {} + function b( T memory t)public {} + function c(T memory t,E memory e) public {} + function d(uint ) public {} + function e(uint, string[]memory, bool) public {} + function f(S memory,T memory,E memory,uint)public {} + function g(S[] memory, T[] memory,E[] memory,uint256 [] memory)public {} + function h(S[4] memory, T[4] memory, E[4] memory, uint256[4] memory) public {} + } + + */ + + /* + { + "d92a9e33": "a((string))", + "5282e79c": "b((uint256,uint256))", + "f332a566": "c((uint256,uint256),(string))", + "7f6b590c": "d(uint256)", + "b45c9d9f": "e(uint256,string[],bool)", + "edb896f9": "f((uint256,uint256[],(uint256,uint256)[],(uint256,uint256),(string)),(uint256,uint256),(string),uint256)", + "adc86690": "g((uint256,uint256[],(uint256,uint256)[],(uint256,uint256),(string))[],(uint256,uint256)[],(string)[],uint256[])", + "7a3093eb": "h((uint256,uint256[],(uint256,uint256)[],(uint256,uint256),(string))[4],(uint256,uint256)[4],(string)[4],uint256[4])" + } + */ + + String abi = + "[{\"constant\":false,\"inputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"}],\"internalType\":\"struct Test.E\",\"name\":\"e\",\"type\":\"tuple\"}],\"name\":\"a\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T\",\"name\":\"t\",\"type\":\"tuple\"}],\"name\":\"b\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T\",\"name\":\"t\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"}],\"internalType\":\"struct Test.E\",\"name\":\"e\",\"type\":\"tuple\"}],\"name\":\"c\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"d\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"e\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"b\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T[]\",\"name\":\"c\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T\",\"name\":\"t\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"}],\"internalType\":\"struct Test.E\",\"name\":\"e\",\"type\":\"tuple\"}],\"internalType\":\"struct Test.S\",\"name\":\"\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T\",\"name\":\"\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"}],\"internalType\":\"struct Test.E\",\"name\":\"\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"f\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"b\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T[]\",\"name\":\"c\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T\",\"name\":\"t\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"}],\"internalType\":\"struct Test.E\",\"name\":\"e\",\"type\":\"tuple\"}],\"internalType\":\"struct Test.S[]\",\"name\":\"\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T[]\",\"name\":\"\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"}],\"internalType\":\"struct Test.E[]\",\"name\":\"\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"name\":\"g\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"b\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T[]\",\"name\":\"c\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T\",\"name\":\"t\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"}],\"internalType\":\"struct Test.E\",\"name\":\"e\",\"type\":\"tuple\"}],\"internalType\":\"struct Test.S[4]\",\"name\":\"\",\"type\":\"tuple[4]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct Test.T[4]\",\"name\":\"\",\"type\":\"tuple[4]\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"}],\"internalType\":\"struct Test.E[4]\",\"name\":\"\",\"type\":\"tuple[4]\"},{\"internalType\":\"uint256[4]\",\"name\":\"\",\"type\":\"uint256[4]\"}],\"name\":\"h\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"}]"; + + ContractABIDefinition contractABIDefinition = Utils.getContractABIDefinition(abi); + ABIObject inputObject0 = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("a").get(0)); + assertTrue(inputObject0.getStructFields().get(0).isDynamic()); + + ABIObject inputObject1 = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("b").get(0)); + assertTrue(!inputObject1.getStructFields().get(0).isDynamic()); + + ABIObject inputObject2 = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("c").get(0)); + assertTrue(!inputObject2.getStructFields().get(0).isDynamic()); + assertTrue(inputObject2.getStructFields().get(1).isDynamic()); + + ABIObject inputObject3 = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("d").get(0)); + assertTrue(!inputObject3.getStructFields().get(0).isDynamic()); + + ABIObject inputObject4 = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("e").get(0)); + assertTrue(!inputObject4.getStructFields().get(0).isDynamic()); + assertTrue(inputObject4.getStructFields().get(1).isDynamic()); + assertTrue(!inputObject4.getStructFields().get(2).isDynamic()); + + ABIObject inputObject5 = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("f").get(0)); + assertTrue(inputObject5.getStructFields().get(0).isDynamic()); + assertTrue(!inputObject5.getStructFields().get(1).isDynamic()); + assertTrue(inputObject5.getStructFields().get(2).isDynamic()); + assertTrue(!inputObject5.getStructFields().get(3).isDynamic()); + + ABIObject inputObject6 = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("g").get(0)); + assertTrue(inputObject6.getStructFields().get(0).isDynamic()); + assertTrue(inputObject6.getStructFields().get(1).isDynamic()); + assertTrue(inputObject6.getStructFields().get(2).isDynamic()); + assertTrue(inputObject6.getStructFields().get(3).isDynamic()); + + ABIObject inputObject7 = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("h").get(0)); + assertTrue(inputObject7.getStructFields().get(0).isDynamic()); + assertTrue(!inputObject7.getStructFields().get(1).isDynamic()); + assertTrue(inputObject7.getStructFields().get(2).isDynamic()); + assertTrue(!inputObject7.getStructFields().get(3).isDynamic()); + } + + @Test + public void testContractABIDefinitionBuildMethodSignature0() throws Exception { + /* +  + pragma solidity >=0.5.0 <0.6.0; + pragma experimental ABIEncoderV2; + + contract Proxy { + struct Item { + int a; + int b; + int c; + } + + struct Info { + string name; + int count; + Item[] items; + } + + event output1(int a, Info[] b, string c); + + // // test(int256,(string,int256,(int256,int256,int256)[])[],string) + function test(int a, Info[] memory b, string memory c) public returns(int) { + // emit output1(a, b, c); + } + + function test_empty() public returns(int a, Info[][] memory b, string memory c) { + + } + } + */ + + /* + "00a3c75d": "test(int256,(string,int256,(int256,int256,int256)[])[],string)", + "6057db30": "test1()" + */ + + String abi = + "[{\"constant\":false,\"inputs\":[{\"name\":\"a\",\"type\":\"int256\"},{\"components\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"count\",\"type\":\"int256\"},{\"components\":[{\"name\":\"a\",\"type\":\"int256\"},{\"name\":\"b\",\"type\":\"int256\"},{\"name\":\"c\",\"type\":\"int256\"}],\"name\":\"items\",\"type\":\"tuple[]\"}],\"name\":\"b\",\"type\":\"tuple[]\"},{\"name\":\"c\",\"type\":\"string\"}],\"name\":\"test\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"test1\",\"outputs\":[{\"name\":\"a\",\"type\":\"int256\"},{\"components\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"count\",\"type\":\"int256\"},{\"components\":[{\"name\":\"a\",\"type\":\"int256\"},{\"name\":\"b\",\"type\":\"int256\"},{\"name\":\"c\",\"type\":\"int256\"}],\"name\":\"items\",\"type\":\"tuple[]\"}],\"name\":\"b\",\"type\":\"tuple[][]\"},{\"name\":\"c\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"a\",\"type\":\"int256\"},{\"components\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"count\",\"type\":\"int256\"},{\"components\":[{\"name\":\"a\",\"type\":\"int256\"},{\"name\":\"b\",\"type\":\"int256\"},{\"name\":\"c\",\"type\":\"int256\"}],\"name\":\"items\",\"type\":\"tuple[]\"}],\"indexed\":false,\"name\":\"b\",\"type\":\"tuple[]\"},{\"indexed\":false,\"name\":\"c\",\"type\":\"string\"}],\"name\":\"output1\",\"type\":\"event\"}]"; + ContractABIDefinition contractABIDefinition = Utils.getContractABIDefinition(abi); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("test") + .get(0) + .getMethodSignatureAsString(), + "test(int256,(string,int256,(int256,int256,int256)[])[],string)"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("test") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0x00a3c75d"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0x00a3c75d"))); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("test1") + .get(0) + .getMethodSignatureAsString(), + "test1()"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("test1") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0x6b59084d"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0x6b59084d"))); + } + + @Test + public void testContractABIDefinitionDynamic0() throws Exception { + /* +  + pragma solidity >=0.5.0 <0.6.0; + pragma experimental ABIEncoderV2; + + contract Proxy { + struct Item { + int a; + int b; + int c; + } + + struct Info { + string name; + int count; + Item[] items; + } + + event output1(int a, Info[] b, string c); + + // // test(int256,(string,int256,(int256,int256,int256)[])[],string) + function test(int a, Info[] memory b, string memory c) public returns(int) { + // emit output1(a, b, c); + } + + function test_empty() public returns(int a, Info[][] memory b, string memory c) { + + } + } + */ + + /* + "00a3c75d": "test(int256,(string,int256,(int256,int256,int256)[])[],string)", + "6057db30": "test1()" + */ + + String abi = + "[{\"constant\":false,\"inputs\":[{\"name\":\"a\",\"type\":\"int256\"},{\"components\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"count\",\"type\":\"int256\"},{\"components\":[{\"name\":\"a\",\"type\":\"int256\"},{\"name\":\"b\",\"type\":\"int256\"},{\"name\":\"c\",\"type\":\"int256\"}],\"name\":\"items\",\"type\":\"tuple[]\"}],\"name\":\"b\",\"type\":\"tuple[]\"},{\"name\":\"c\",\"type\":\"string\"}],\"name\":\"test\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"test1\",\"outputs\":[{\"name\":\"a\",\"type\":\"int256\"},{\"components\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"count\",\"type\":\"int256\"},{\"components\":[{\"name\":\"a\",\"type\":\"int256\"},{\"name\":\"b\",\"type\":\"int256\"},{\"name\":\"c\",\"type\":\"int256\"}],\"name\":\"items\",\"type\":\"tuple[]\"}],\"name\":\"b\",\"type\":\"tuple[][]\"},{\"name\":\"c\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"a\",\"type\":\"int256\"},{\"components\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"count\",\"type\":\"int256\"},{\"components\":[{\"name\":\"a\",\"type\":\"int256\"},{\"name\":\"b\",\"type\":\"int256\"},{\"name\":\"c\",\"type\":\"int256\"}],\"name\":\"items\",\"type\":\"tuple[]\"}],\"indexed\":false,\"name\":\"b\",\"type\":\"tuple[]\"},{\"indexed\":false,\"name\":\"c\",\"type\":\"string\"}],\"name\":\"output1\",\"type\":\"event\"}]"; + ContractABIDefinition contractABIDefinition = Utils.getContractABIDefinition(abi); + + ABIObject inputObject = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("test").get(0)); + assertTrue(!inputObject.getStructFields().get(0).isDynamic()); + assertTrue(inputObject.getStructFields().get(1).isDynamic()); + assertTrue(inputObject.getStructFields().get(2).isDynamic()); + } + + @Test + public void testContractABIDefinitionBuildMethodSignature2() throws Exception { + /* + + pragma solidity >=0.5.0 <0.6.0; + pragma experimental ABIEncoderV2; + + contract WeCrossProxy { + + string constant version = "v1.0.0-rc4"; + + // per step of transaction + struct TransactionStep { + string path; + uint256 timestamp; + address contractAddress; + string func; + bytes args; + } + + // information of transaction + struct TransactionInfo { + string[] allPaths; // all paths related to this transaction + string[] paths; // paths related to current chain + address[] contractAddresses; // locked addressed in current chain + uint8 status; // 0-Start 1-Commit 2-Rollback + uint256 startTimestamp; + uint256 commitTimestamp; + uint256 rollbackTimestamp; + uint256[] seqs; // sequence of each step + uint256 stepNum; // step number + } + + struct ContractInfo { + bool locked; // isolation control, read-committed + string path; + string transactionID; + } + + constructor() public { + + } + + function getVersion(string[] memory _args) public pure + returns(string[] memory) + { + + } + + function getMaxStep(string[] memory _args) public view + returns(string[] memory) + { + + } + + function setMaxStep(string[] memory _args) public + { + + } + + function addPath(string[] memory _args) public + { + + } + + function getPaths(string[] memory _args) public view + returns (string[] memory) + { + + } + + function deletePathList(string[] memory _args) public + { + + } + + // constant call + function constantCall(string memory _transactionID, string memory _path, string memory _func, bytes memory _args) public + returns(bytes memory) + { + + } + + // non-constant call + function sendTransaction(string memory _transactionID, uint256 _seq, string memory _path, string memory _func, bytes memory _args) public + returns(bytes memory) + { + + } + + function startTransaction(string[] memory _args) public + returns(string[] memory) + { + + } + + + function commitTransaction(string[] memory _args) public + returns(string[] memory) + { + + } + + + function rollbackTransaction(string[] memory _args) public + returns(string[] memory) + { + + } + + + function getTransactionInfo(string[] memory _args) public view + returns(string[] memory) + { + + } + + // called by router to check transaction status + function getLatestTransactionInfo() public view + returns(string[] memory) + { + + } + + function rollbackAndDeleteTransaction(string[] memory _args) public + returns (string[] memory) + { + + } + + function getLatestTransaction() public view + returns (string memory) + { + + } + + function addTransaction(string memory _transactionID) internal + { + + } + + function deleteTransaction(string memory _transactionID) internal + returns (string[] memory) + { + + } + + function callContract(address _contractAddress, string memory _sig, bytes memory _args) internal + returns(bytes memory result) + { + + } + + function getAddressByPath(string memory _path) internal view + returns (address) + { + + } + + + function getNameByPath(string memory _path) internal pure + returns (string memory) + { + + } + + // "transactionSteps": [{"seq": 0, "contract": "0x12","path": "a.b.c","timestamp": "123","func": "test1(string)","args": "aaa"},{"seq": 1, "contract": "0x12","path": "a.b.c","timestamp": "123","func": "test2(string)","args": "bbb"}] + function transactionStepArrayToJson(string memory _transactionID, uint256[] memory _seqs, uint256 _len) internal view + returns(string memory result) + { + + } + + // {"seq": 0, "contract": "0x12","path": "a.b.c","timestamp": "123","func": "test2(string)","args": "bbb"} + function transactionStepToJson(TransactionStep memory _step, uint256 _seq) internal pure + returns(string memory) + { + + } + + + function stringToUint256(string memory _str) public pure + returns (uint256) + { + + } + } + */ + + /* + "e1207bee": "addPath(string[])", + "063ff7ef": "commitTransaction(string[])", + "b54138b0": "constantCall(string,string,string,bytes)", + "f4fa9d03": "deletePathList(string[])", + "6ccc29dc": "getLatestTransaction()", + "9edd3441": "getLatestTransactionInfo()", + "cb797d2f": "getMaxStep(string[])", + "4efcaed0": "getPaths(string[])", + "d55c01f7": "getTransactionInfo(string[])", + "8bc4827c": "getVersion(string[])", + "8c31f9ad": "rollbackAndDeleteTransaction(string[])", + "51cd3824": "rollbackTransaction(string[])", + "772d0b53": "sendTransaction(string,uint256,string,string,bytes)", + "18a56b67": "setMaxStep(string[])", + "e25a0866": "startTransaction(string[])", + "ac5d3723": "stringToUint256(string)" + */ + + String abi = + "[{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"addPath\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"commitTransaction\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string\",\"name\":\"_transactionID\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_path\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_func\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_args\",\"type\":\"bytes\"}],\"name\":\"constantCall\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"deletePathList\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getLatestTransaction\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getLatestTransactionInfo\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"getMaxStep\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"getPaths\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"getTransactionInfo\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"getVersion\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"rollbackAndDeleteTransaction\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"rollbackTransaction\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string\",\"name\":\"_transactionID\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"_seq\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_path\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_func\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_args\",\"type\":\"bytes\"}],\"name\":\"sendTransaction\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"setMaxStep\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"startTransaction\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"string\",\"name\":\"_str\",\"type\":\"string\"}],\"name\":\"stringToUint256\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"}]"; + ContractABIDefinition contractABIDefinition = Utils.getContractABIDefinition(abi); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("addPath") + .get(0) + .getMethodSignatureAsString(), + "addPath(string[])"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("addPath") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0xe1207bee"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0xe1207bee"))); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("commitTransaction") + .get(0) + .getMethodSignatureAsString(), + "commitTransaction(string[])"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("commitTransaction") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0x063ff7ef"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0x063ff7ef"))); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("constantCall") + .get(0) + .getMethodSignatureAsString(), + "constantCall(string,string,string,bytes)"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("constantCall") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0xb54138b0"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0xb54138b0"))); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("deletePathList") + .get(0) + .getMethodSignatureAsString(), + "deletePathList(string[])"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("deletePathList") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0xf4fa9d03"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0xf4fa9d03"))); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("getLatestTransaction") + .get(0) + .getMethodSignatureAsString(), + "getLatestTransaction()"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("getLatestTransaction") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0x6ccc29dc"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0x6ccc29dc"))); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("getLatestTransactionInfo") + .get(0) + .getMethodSignatureAsString(), + "getLatestTransactionInfo()"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("getLatestTransactionInfo") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0x9edd3441"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0x9edd3441"))); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("getMaxStep") + .get(0) + .getMethodSignatureAsString(), + "getMaxStep(string[])"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("getMaxStep") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0xcb797d2f"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0xcb797d2f"))); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("getPaths") + .get(0) + .getMethodSignatureAsString(), + "getPaths(string[])"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("getPaths") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0x4efcaed0"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0x4efcaed0"))); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("getTransactionInfo") + .get(0) + .getMethodSignatureAsString(), + "getTransactionInfo(string[])"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("getTransactionInfo") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0xd55c01f7"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0xd55c01f7"))); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("getVersion") + .get(0) + .getMethodSignatureAsString(), + "getVersion(string[])"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("getVersion") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0x8bc4827c"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0x8bc4827c"))); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("rollbackAndDeleteTransaction") + .get(0) + .getMethodSignatureAsString(), + "rollbackAndDeleteTransaction(string[])"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("rollbackAndDeleteTransaction") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0x8c31f9ad"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0x8c31f9ad"))); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("sendTransaction") + .get(0) + .getMethodSignatureAsString(), + "sendTransaction(string,uint256,string,string,bytes)"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("sendTransaction") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0x772d0b53"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0x772d0b53"))); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("rollbackTransaction") + .get(0) + .getMethodSignatureAsString(), + "rollbackTransaction(string[])"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("rollbackTransaction") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0x51cd3824"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0x51cd3824"))); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("setMaxStep") + .get(0) + .getMethodSignatureAsString(), + "setMaxStep(string[])"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("setMaxStep") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0x18a56b67"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0x18a56b67"))); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("startTransaction") + .get(0) + .getMethodSignatureAsString(), + "startTransaction(string[])"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("startTransaction") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0xe25a0866"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0xe25a0866"))); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("stringToUint256") + .get(0) + .getMethodSignatureAsString(), + "stringToUint256(string)"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("stringToUint256") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0xac5d3723"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0xac5d3723"))); + } + + @Test + public void testContractABIDefinitionDynamic1() throws Exception { + /* + + pragma solidity >=0.5.0 <0.6.0; + pragma experimental ABIEncoderV2; + + contract WeCrossProxy { + + string constant version = "v1.0.0-rc4"; + + // per step of transaction + struct TransactionStep { + string path; + uint256 timestamp; + address contractAddress; + string func; + bytes args; + } + + // information of transaction + struct TransactionInfo { + string[] allPaths; // all paths related to this transaction + string[] paths; // paths related to current chain + address[] contractAddresses; // locked addressed in current chain + uint8 status; // 0-Start 1-Commit 2-Rollback + uint256 startTimestamp; + uint256 commitTimestamp; + uint256 rollbackTimestamp; + uint256[] seqs; // sequence of each step + uint256 stepNum; // step number + } + + struct ContractInfo { + bool locked; // isolation control, read-committed + string path; + string transactionID; + } + + constructor() public { + + } + + function getVersion(string[] memory _args) public pure + returns(string[] memory) + { + + } + + function getMaxStep(string[] memory _args) public view + returns(string[] memory) + { + + } + + function setMaxStep(string[] memory _args) public + { + + } + + function addPath(string[] memory _args) public + { + + } + + function getPaths(string[] memory _args) public view + returns (string[] memory) + { + + } + + function deletePathList(string[] memory _args) public + { + + } + + // constant call + function constantCall(string memory _transactionID, string memory _path, string memory _func, bytes memory _args) public + returns(bytes memory) + { + + } + + // non-constant call + function sendTransaction(string memory _transactionID, uint256 _seq, string memory _path, string memory _func, bytes memory _args) public + returns(bytes memory) + { + + } + + function startTransaction(string[] memory _args) public + returns(string[] memory) + { + + } + + + function commitTransaction(string[] memory _args) public + returns(string[] memory) + { + + } + + + function rollbackTransaction(string[] memory _args) public + returns(string[] memory) + { + + } + + + function getTransactionInfo(string[] memory _args) public view + returns(string[] memory) + { + + } + + // called by router to check transaction status + function getLatestTransactionInfo() public view + returns(string[] memory) + { + + } + + function rollbackAndDeleteTransaction(string[] memory _args) public + returns (string[] memory) + { + + } + + function getLatestTransaction() public view + returns (string memory) + { + + } + + function addTransaction(string memory _transactionID) internal + { + + } + + function deleteTransaction(string memory _transactionID) internal + returns (string[] memory) + { + + } + + function callContract(address _contractAddress, string memory _sig, bytes memory _args) internal + returns(bytes memory result) + { + + } + + function getAddressByPath(string memory _path) internal view + returns (address) + { + + } + + + function getNameByPath(string memory _path) internal pure + returns (string memory) + { + + } + + // "transactionSteps": [{"seq": 0, "contract": "0x12","path": "a.b.c","timestamp": "123","func": "test1(string)","args": "aaa"},{"seq": 1, "contract": "0x12","path": "a.b.c","timestamp": "123","func": "test2(string)","args": "bbb"}] + function transactionStepArrayToJson(string memory _transactionID, uint256[] memory _seqs, uint256 _len) internal view + returns(string memory result) + { + + } + + // {"seq": 0, "contract": "0x12","path": "a.b.c","timestamp": "123","func": "test2(string)","args": "bbb"} + function transactionStepToJson(TransactionStep memory _step, uint256 _seq) internal pure + returns(string memory) + { + + } + + + function stringToUint256(string memory _str) public pure + returns (uint256) + { + + } + } + */ + + /* + "e1207bee": "addPath(string[])", + "063ff7ef": "commitTransaction(string[])", + "b54138b0": "constantCall(string,string,string,bytes)", + "f4fa9d03": "deletePathList(string[])", + "6ccc29dc": "getLatestTransaction()", + "9edd3441": "getLatestTransactionInfo()", + "cb797d2f": "getMaxStep(string[])", + "4efcaed0": "getPaths(string[])", + "d55c01f7": "getTransactionInfo(string[])", + "8bc4827c": "getVersion(string[])", + "8c31f9ad": "rollbackAndDeleteTransaction(string[])", + "51cd3824": "rollbackTransaction(string[])", + "772d0b53": "sendTransaction(string,uint256,string,string,bytes)", + "18a56b67": "setMaxStep(string[])", + "e25a0866": "startTransaction(string[])", + "ac5d3723": "stringToUint256(string)" + */ + + String abi = + "[{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"addPath\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"commitTransaction\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string\",\"name\":\"_transactionID\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_path\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_func\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_args\",\"type\":\"bytes\"}],\"name\":\"constantCall\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"deletePathList\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getLatestTransaction\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getLatestTransactionInfo\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"getMaxStep\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"getPaths\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"getTransactionInfo\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"getVersion\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"rollbackAndDeleteTransaction\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"rollbackTransaction\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string\",\"name\":\"_transactionID\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"_seq\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_path\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_func\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_args\",\"type\":\"bytes\"}],\"name\":\"sendTransaction\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"setMaxStep\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_args\",\"type\":\"string[]\"}],\"name\":\"startTransaction\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"string\",\"name\":\"_str\",\"type\":\"string\"}],\"name\":\"stringToUint256\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"}]"; + + ContractABIDefinition contractABIDefinition = Utils.getContractABIDefinition(abi); + ABIObject inputObject = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("commitTransaction").get(0)); + assertTrue(inputObject.getStructFields().get(0).isDynamic()); + + ABIObject inputObject0 = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("addPath").get(0)); + assertTrue(inputObject0.getStructFields().get(0).isDynamic()); + + ABIObject inputObject1 = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("constantCall").get(0)); + assertTrue(inputObject1.getStructFields().get(0).isDynamic()); + assertTrue(inputObject1.getStructFields().get(1).isDynamic()); + assertTrue(inputObject1.getStructFields().get(2).isDynamic()); + assertTrue(inputObject1.getStructFields().get(3).isDynamic()); + + ABIObject inputObject2 = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("deletePathList").get(0)); + assertTrue(inputObject2.getStructFields().get(0).isDynamic()); + + ABIObject inputObject3 = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("sendTransaction").get(0)); + assertTrue(inputObject3.getStructFields().get(0).isDynamic()); + assertTrue(!inputObject3.getStructFields().get(1).isDynamic()); + assertTrue(inputObject3.getStructFields().get(2).isDynamic()); + assertTrue(inputObject3.getStructFields().get(3).isDynamic()); + assertTrue(inputObject3.getStructFields().get(4).isDynamic()); + } + + @Test + public void testContractABIDefinitionBuildMethodSignature1() throws Exception { + /* + + pragma solidity ^0.4.24; + pragma experimental ABIEncoderV2; + contract TestContract + { + event TestEventSimpleParams(uint256 _u,int256 _i,bool _b,address _addr,bytes32 _bs32, string _s,bytes _bs); + event TestEventDArrayParams(uint256[] _u,int256[] _i,bool[] _b,address[] _addr,bytes32[] _bs32, string[] _s,bytes[] _bs); + event TestEventSArrayParams(uint256[4] _u,int256[4] _i,bool[4] _b,address[4] _addr,bytes32[4] _bs32, string[4] _s,bytes[4] _bs); + + function test0(uint256 _u,int256 _i,bool _b,address _addr,bytes32 _bs32, string _s,bytes _bs) public constant returns (uint256,int256,bool,address,bytes32,string,bytes) { + + } + + function test1(uint256[] _u,int256[] _i,bool[] _b,address[] _addr,bytes32[] _bs32,string[] _s,bytes[] _bs) public constant returns (uint256[],int256[],bool[],address[],bytes32[],string[],bytes[]) { + + } + + function test2(uint256[4] _u,int256[4] _i,bool[4] _b,address[4] _addr,bytes32[4] _bs32,string[4] _s,bytes[4] _bs) public constant returns (uint256[2],int256[2],bool[2],address[2],bytes32[2],string[2],bytes[2]) { + + } + } + */ + + /* + "f92a5e47": "test0(uint256,int256,bool,address,bytes32,string,bytes)", + "70be28d9": "test1(uint256[4],int256[4],bool[4],address[4],bytes32[4],string[4],bytes[4])", + "10c7e4ab": "test2(uint256[],int256[],bool[],address[],bytes32[],string[],bytes[])" + */ + + String abi = + "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_u\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"int256[]\",\"name\":\"_i\",\"type\":\"int256[]\"},{\"indexed\":false,\"internalType\":\"bool[]\",\"name\":\"_b\",\"type\":\"bool[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_addr\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"bytes32[]\",\"name\":\"_bs32\",\"type\":\"bytes32[]\"},{\"indexed\":false,\"internalType\":\"string[]\",\"name\":\"_s\",\"type\":\"string[]\"},{\"indexed\":false,\"internalType\":\"bytes[]\",\"name\":\"_bs\",\"type\":\"bytes[]\"}],\"name\":\"TestEventDArrayParams\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256[4]\",\"name\":\"_u\",\"type\":\"uint256[4]\"},{\"indexed\":false,\"internalType\":\"int256[4]\",\"name\":\"_i\",\"type\":\"int256[4]\"},{\"indexed\":false,\"internalType\":\"bool[4]\",\"name\":\"_b\",\"type\":\"bool[4]\"},{\"indexed\":false,\"internalType\":\"address[4]\",\"name\":\"_addr\",\"type\":\"address[4]\"},{\"indexed\":false,\"internalType\":\"bytes32[4]\",\"name\":\"_bs32\",\"type\":\"bytes32[4]\"},{\"indexed\":false,\"internalType\":\"string[4]\",\"name\":\"_s\",\"type\":\"string[4]\"},{\"indexed\":false,\"internalType\":\"bytes[4]\",\"name\":\"_bs\",\"type\":\"bytes[4]\"}],\"name\":\"TestEventSArrayParams\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_u\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"_i\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"_b\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"_bs32\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"_s\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"_bs\",\"type\":\"bytes\"}],\"name\":\"TestEventSimpleParams\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_u\",\"type\":\"uint256\"},{\"internalType\":\"int256\",\"name\":\"_i\",\"type\":\"int256\"},{\"internalType\":\"bool\",\"name\":\"_b\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"_bs32\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"_s\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_bs\",\"type\":\"bytes\"}],\"name\":\"test0\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_u\",\"type\":\"uint256[]\"},{\"internalType\":\"int256[]\",\"name\":\"_i\",\"type\":\"int256[]\"},{\"internalType\":\"bool[]\",\"name\":\"_b\",\"type\":\"bool[]\"},{\"internalType\":\"address[]\",\"name\":\"_addr\",\"type\":\"address[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"_bs32\",\"type\":\"bytes32[]\"},{\"internalType\":\"string[]\",\"name\":\"_s\",\"type\":\"string[]\"},{\"internalType\":\"bytes[]\",\"name\":\"_bs\",\"type\":\"bytes[]\"}],\"name\":\"test1\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"},{\"internalType\":\"int256[]\",\"name\":\"\",\"type\":\"int256[]\"},{\"internalType\":\"bool[]\",\"name\":\"\",\"type\":\"bool[]\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"},{\"internalType\":\"bytes[]\",\"name\":\"\",\"type\":\"bytes[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256[4]\",\"name\":\"_u\",\"type\":\"uint256[4]\"},{\"internalType\":\"int256[4]\",\"name\":\"_i\",\"type\":\"int256[4]\"},{\"internalType\":\"bool[4]\",\"name\":\"_b\",\"type\":\"bool[4]\"},{\"internalType\":\"address[4]\",\"name\":\"_addr\",\"type\":\"address[4]\"},{\"internalType\":\"bytes32[4]\",\"name\":\"_bs32\",\"type\":\"bytes32[4]\"},{\"internalType\":\"string[4]\",\"name\":\"_s\",\"type\":\"string[4]\"},{\"internalType\":\"bytes[4]\",\"name\":\"_bs\",\"type\":\"bytes[4]\"}],\"name\":\"test2\",\"outputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"\",\"type\":\"uint256[2]\"},{\"internalType\":\"int256[2]\",\"name\":\"\",\"type\":\"int256[2]\"},{\"internalType\":\"bool[2]\",\"name\":\"\",\"type\":\"bool[2]\"},{\"internalType\":\"address[2]\",\"name\":\"\",\"type\":\"address[2]\"},{\"internalType\":\"bytes32[2]\",\"name\":\"\",\"type\":\"bytes32[2]\"},{\"internalType\":\"string[2]\",\"name\":\"\",\"type\":\"string[2]\"},{\"internalType\":\"bytes[2]\",\"name\":\"\",\"type\":\"bytes[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"; + + ContractABIDefinition contractABIDefinition = Utils.getContractABIDefinition(abi); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("test0") + .get(0) + .getMethodSignatureAsString(), + "test0(uint256,int256,bool,address,bytes32,string,bytes)"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("test0") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0xf92a5e47"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0xf92a5e47"))); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("test2") + .get(0) + .getMethodSignatureAsString(), + "test2(uint256[4],int256[4],bool[4],address[4],bytes32[4],string[4],bytes[4])"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("test2") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0x10c7e4ab"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0x10c7e4ab"))); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("test1") + .get(0) + .getMethodSignatureAsString(), + "test1(uint256[],int256[],bool[],address[],bytes32[],string[],bytes[])"); + + assertEquals( + contractABIDefinition + .getFunctions() + .get("test1") + .get(0) + .getMethodId(Utils.getCryptoSuite()), + "0x70be28d9"); + assertTrue(Objects.nonNull(contractABIDefinition.getABIDefinitionByMethodId("0x70be28d9"))); + } + + @Test + public void testContractABIDefinitionDynamic2() throws Exception { + /* + + pragma solidity ^0.4.24; + pragma experimental ABIEncoderV2; + contract TestContract + { + event TestEventSimpleParams(uint256 _u,int256 _i,bool _b,address _addr,bytes32 _bs32, string _s,bytes _bs); + event TestEventDArrayParams(uint256[] _u,int256[] _i,bool[] _b,address[] _addr,bytes32[] _bs32, string[] _s,bytes[] _bs); + event TestEventSArrayParams(uint256[4] _u,int256[4] _i,bool[4] _b,address[4] _addr,bytes32[4] _bs32, string[4] _s,bytes[4] _bs); + + function test0(uint256 _u,int256 _i,bool _b,address _addr,bytes32 _bs32, string _s,bytes _bs) public constant returns (uint256,int256,bool,address,bytes32,string,bytes) { + + } + + function test1(uint256[] _u,int256[] _i,bool[] _b,address[] _addr,bytes32[] _bs32,string[] _s,bytes[] _bs) public constant returns (uint256[],int256[],bool[],address[],bytes32[],string[],bytes[]) { + + } + + function test2(uint256[4] _u,int256[4] _i,bool[4] _b,address[4] _addr,bytes32[4] _bs32,string[4] _s,bytes[4] _bs) public constant returns (uint256[2],int256[2],bool[2],address[2],bytes32[2],string[2],bytes[2]) { + + } + } + */ + + /* + "f92a5e47": "test0(uint256,int256,bool,address,bytes32,string,bytes)", + "70be28d9": "test2(uint256[4],int256[4],bool[4],address[4],bytes32[4],string[4],bytes[4])", + "10c7e4ab": "test1(uint256[],int256[],bool[],address[],bytes32[],string[],bytes[])" + */ + + String abi = + "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_u\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"int256[]\",\"name\":\"_i\",\"type\":\"int256[]\"},{\"indexed\":false,\"internalType\":\"bool[]\",\"name\":\"_b\",\"type\":\"bool[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_addr\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"bytes32[]\",\"name\":\"_bs32\",\"type\":\"bytes32[]\"},{\"indexed\":false,\"internalType\":\"string[]\",\"name\":\"_s\",\"type\":\"string[]\"},{\"indexed\":false,\"internalType\":\"bytes[]\",\"name\":\"_bs\",\"type\":\"bytes[]\"}],\"name\":\"TestEventDArrayParams\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256[4]\",\"name\":\"_u\",\"type\":\"uint256[4]\"},{\"indexed\":false,\"internalType\":\"int256[4]\",\"name\":\"_i\",\"type\":\"int256[4]\"},{\"indexed\":false,\"internalType\":\"bool[4]\",\"name\":\"_b\",\"type\":\"bool[4]\"},{\"indexed\":false,\"internalType\":\"address[4]\",\"name\":\"_addr\",\"type\":\"address[4]\"},{\"indexed\":false,\"internalType\":\"bytes32[4]\",\"name\":\"_bs32\",\"type\":\"bytes32[4]\"},{\"indexed\":false,\"internalType\":\"string[4]\",\"name\":\"_s\",\"type\":\"string[4]\"},{\"indexed\":false,\"internalType\":\"bytes[4]\",\"name\":\"_bs\",\"type\":\"bytes[4]\"}],\"name\":\"TestEventSArrayParams\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_u\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"_i\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"_b\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"_bs32\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"_s\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"_bs\",\"type\":\"bytes\"}],\"name\":\"TestEventSimpleParams\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_u\",\"type\":\"uint256\"},{\"internalType\":\"int256\",\"name\":\"_i\",\"type\":\"int256\"},{\"internalType\":\"bool\",\"name\":\"_b\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"_bs32\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"_s\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_bs\",\"type\":\"bytes\"}],\"name\":\"test0\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_u\",\"type\":\"uint256[]\"},{\"internalType\":\"int256[]\",\"name\":\"_i\",\"type\":\"int256[]\"},{\"internalType\":\"bool[]\",\"name\":\"_b\",\"type\":\"bool[]\"},{\"internalType\":\"address[]\",\"name\":\"_addr\",\"type\":\"address[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"_bs32\",\"type\":\"bytes32[]\"},{\"internalType\":\"string[]\",\"name\":\"_s\",\"type\":\"string[]\"},{\"internalType\":\"bytes[]\",\"name\":\"_bs\",\"type\":\"bytes[]\"}],\"name\":\"test1\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"},{\"internalType\":\"int256[]\",\"name\":\"\",\"type\":\"int256[]\"},{\"internalType\":\"bool[]\",\"name\":\"\",\"type\":\"bool[]\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"},{\"internalType\":\"bytes[]\",\"name\":\"\",\"type\":\"bytes[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256[4]\",\"name\":\"_u\",\"type\":\"uint256[4]\"},{\"internalType\":\"int256[4]\",\"name\":\"_i\",\"type\":\"int256[4]\"},{\"internalType\":\"bool[4]\",\"name\":\"_b\",\"type\":\"bool[4]\"},{\"internalType\":\"address[4]\",\"name\":\"_addr\",\"type\":\"address[4]\"},{\"internalType\":\"bytes32[4]\",\"name\":\"_bs32\",\"type\":\"bytes32[4]\"},{\"internalType\":\"string[4]\",\"name\":\"_s\",\"type\":\"string[4]\"},{\"internalType\":\"bytes[4]\",\"name\":\"_bs\",\"type\":\"bytes[4]\"}],\"name\":\"test2\",\"outputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"\",\"type\":\"uint256[2]\"},{\"internalType\":\"int256[2]\",\"name\":\"\",\"type\":\"int256[2]\"},{\"internalType\":\"bool[2]\",\"name\":\"\",\"type\":\"bool[2]\"},{\"internalType\":\"address[2]\",\"name\":\"\",\"type\":\"address[2]\"},{\"internalType\":\"bytes32[2]\",\"name\":\"\",\"type\":\"bytes32[2]\"},{\"internalType\":\"string[2]\",\"name\":\"\",\"type\":\"string[2]\"},{\"internalType\":\"bytes[2]\",\"name\":\"\",\"type\":\"bytes[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"; + + ContractABIDefinition contractABIDefinition = Utils.getContractABIDefinition(abi); + ABIObject inputObject1 = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("test0").get(0)); + assertTrue(!inputObject1.getStructFields().get(0).isDynamic()); + assertTrue(!inputObject1.getStructFields().get(1).isDynamic()); + assertTrue(!inputObject1.getStructFields().get(2).isDynamic()); + assertTrue(!inputObject1.getStructFields().get(3).isDynamic()); + assertTrue(!inputObject1.getStructFields().get(4).isDynamic()); + assertTrue(inputObject1.getStructFields().get(5).isDynamic()); + assertTrue(inputObject1.getStructFields().get(6).isDynamic()); + + ABIObject inputObject2 = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("test2").get(0)); + assertTrue(!inputObject2.getStructFields().get(0).isDynamic()); + assertTrue(!inputObject2.getStructFields().get(1).isDynamic()); + assertTrue(!inputObject2.getStructFields().get(2).isDynamic()); + assertTrue(!inputObject2.getStructFields().get(3).isDynamic()); + assertTrue(!inputObject2.getStructFields().get(4).isDynamic()); + assertTrue(inputObject2.getStructFields().get(5).isDynamic()); + assertTrue(inputObject2.getStructFields().get(6).isDynamic()); + + ABIObject inputObject3 = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("test1").get(0)); + assertTrue(inputObject3.getStructFields().get(0).isDynamic()); + assertTrue(inputObject3.getStructFields().get(1).isDynamic()); + assertTrue(inputObject3.getStructFields().get(2).isDynamic()); + assertTrue(inputObject3.getStructFields().get(3).isDynamic()); + assertTrue(inputObject3.getStructFields().get(4).isDynamic()); + assertTrue(inputObject3.getStructFields().get(5).isDynamic()); + assertTrue(inputObject3.getStructFields().get(6).isDynamic()); + } +} diff --git a/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABIObjectTest.java b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABIObjectTest.java new file mode 100644 index 000000000..4de4ed31d --- /dev/null +++ b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ABIObjectTest.java @@ -0,0 +1,606 @@ +package org.fisco.bcos.sdk.test.abi; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.Address; +import org.fisco.bcos.sdk.abi.datatypes.Bool; +import org.fisco.bcos.sdk.abi.datatypes.Bytes; +import org.fisco.bcos.sdk.abi.datatypes.DynamicBytes; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Bytes1; +import org.fisco.bcos.sdk.abi.datatypes.generated.Bytes10; +import org.fisco.bcos.sdk.abi.datatypes.generated.Bytes4; +import org.fisco.bcos.sdk.abi.datatypes.generated.Bytes6; +import org.fisco.bcos.sdk.abi.datatypes.generated.Int256; +import org.fisco.bcos.sdk.abi.datatypes.generated.Uint256; +import org.fisco.bcos.sdk.abi.wrapper.ABIDefinition; +import org.fisco.bcos.sdk.abi.wrapper.ABIObject; +import org.fisco.bcos.sdk.abi.wrapper.ABIObject.ObjectType; +import org.fisco.bcos.sdk.abi.wrapper.ABIObjectFactory; +import org.junit.Assert; +import org.junit.Test; + +public class ABIObjectTest { + + @Test + public void testMixedTypeEncode0() { + // int a, Info[] memory b, string memory c + /* + * { + "0": "int256: a 100", + "1": "tuple(string,int256,tuple(int256,int256,int256)[])[]: b Hello world!,100,1,2,3,Hello world2!,200,5,6,7", + "2": "string: c Hello world!" + } + */ + + String abiDesc = + "[\n" + + " {\n" + + " \"anonymous\": false,\n" + + " \"inputs\": [\n" + + " {\n" + + " \"indexed\": false,\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"a\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"components\": [\n" + + " {\n" + + " \"internalType\": \"string\",\n" + + " \"name\": \"name\",\n" + + " \"type\": \"string\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"count\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"components\": [\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"a\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"b\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"c\",\n" + + " \"type\": \"int256\"\n" + + " }\n" + + " ],\n" + + " \"internalType\": \"struct Proxy.Item[]\",\n" + + " \"name\": \"items\",\n" + + " \"type\": \"tuple[]\"\n" + + " }\n" + + " ],\n" + + " \"indexed\": false,\n" + + " \"internalType\": \"struct Proxy.Info[]\",\n" + + " \"name\": \"b\",\n" + + " \"type\": \"tuple[]\"\n" + + " },\n" + + " {\n" + + " \"indexed\": false,\n" + + " \"internalType\": \"string\",\n" + + " \"name\": \"c\",\n" + + " \"type\": \"string\"\n" + + " }\n" + + " ],\n" + + " \"name\": \"output1\",\n" + + " \"type\": \"event\"\n" + + " },\n" + + " {\n" + + " \"constant\": false,\n" + + " \"inputs\": [\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"a\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"components\": [\n" + + " {\n" + + " \"internalType\": \"string\",\n" + + " \"name\": \"name\",\n" + + " \"type\": \"string\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"count\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"components\": [\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"a\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"b\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"c\",\n" + + " \"type\": \"int256\"\n" + + " }\n" + + " ],\n" + + " \"internalType\": \"struct Proxy.Item[]\",\n" + + " \"name\": \"items\",\n" + + " \"type\": \"tuple[]\"\n" + + " }\n" + + " ],\n" + + " \"internalType\": \"struct Proxy.Info[]\",\n" + + " \"name\": \"b\",\n" + + " \"type\": \"tuple[]\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"string\",\n" + + " \"name\": \"c\",\n" + + " \"type\": \"string\"\n" + + " }\n" + + " ],\n" + + " \"name\": \"test\",\n" + + " \"outputs\": [\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"\",\n" + + " \"type\": \"int256\"\n" + + " }\n" + + " ],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"function\"\n" + + " },\n" + + " {\n" + + " \"constant\": false,\n" + + " \"inputs\": [],\n" + + " \"name\": \"test1\",\n" + + " \"outputs\": [\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"a\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"components\": [\n" + + " {\n" + + " \"internalType\": \"string\",\n" + + " \"name\": \"name\",\n" + + " \"type\": \"string\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"count\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"components\": [\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"a\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"b\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"int256\",\n" + + " \"name\": \"c\",\n" + + " \"type\": \"int256\"\n" + + " }\n" + + " ],\n" + + " \"internalType\": \"struct Proxy.Item[]\",\n" + + " \"name\": \"items\",\n" + + " \"type\": \"tuple[]\"\n" + + " }\n" + + " ],\n" + + " \"internalType\": \"struct Proxy.Info[]\",\n" + + " \"name\": \"b\",\n" + + " \"type\": \"tuple[]\"\n" + + " },\n" + + " {\n" + + " \"internalType\": \"string\",\n" + + " \"name\": \"c\",\n" + + " \"type\": \"string\"\n" + + " }\n" + + " ],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"function\"\n" + + " },\n" + + " {\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"fallback\"\n" + + " }\n" + + "]"; + + ABIObject listParams = new ABIObject(ABIObject.ListType.DYNAMIC); + + ABIObject item1 = new ABIObject(ObjectType.STRUCT); + item1.getStructFields().add(new ABIObject(new Utf8String("Hello world!"))); + item1.getStructFields().add(new ABIObject(new Uint256(100))); + item1.getStructFields().add(new ABIObject(ABIObject.ListType.DYNAMIC)); + + item1.getStructFields().get(2).getListValues().add(new ABIObject(ObjectType.STRUCT)); + + item1.getStructFields() + .get(2) + .getListValues() + .get(0) + .getStructFields() + .add(new ABIObject(new Uint256(1))); + item1.getStructFields() + .get(2) + .getListValues() + .get(0) + .getStructFields() + .add(new ABIObject(new Uint256(2))); + item1.getStructFields() + .get(2) + .getListValues() + .get(0) + .getStructFields() + .add(new ABIObject(new Uint256(3))); + + listParams.getListValues().add(item1); + + ABIObject item2 = new ABIObject(ObjectType.STRUCT); + item2.getStructFields().add(new ABIObject(new Utf8String("Hello world2"))); + item2.getStructFields().add(new ABIObject(new Uint256(200))); + item2.getStructFields().add(new ABIObject(ABIObject.ListType.DYNAMIC)); + + item2.getStructFields().get(2).getListValues().add(new ABIObject(ObjectType.STRUCT)); + + item2.getStructFields() + .get(2) + .getListValues() + .get(0) + .getStructFields() + .add(new ABIObject(new Uint256(5))); + item2.getStructFields() + .get(2) + .getListValues() + .get(0) + .getStructFields() + .add(new ABIObject(new Uint256(6))); + item2.getStructFields() + .get(2) + .getListValues() + .get(0) + .getStructFields() + .add(new ABIObject(new Uint256(7))); + + listParams.getListValues().add(item2); + + ABIObject abiObject = new ABIObject(ObjectType.STRUCT); + + abiObject.getStructFields().add(new ABIObject(new Uint256(100))); + abiObject.getStructFields().add(listParams); + abiObject.getStructFields().add(new ABIObject(new Utf8String("Hello world!"))); + + String encodeHex = abiObject.encode(); + + Assert.assertEquals( + "0000000000000000000000000000000000000000000000000000000000000064" + + "0000000000000000000000000000000000000000000000000000000000000060" + + "0000000000000000000000000000000000000000000000000000000000000300" + + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000000000000000000000000000000000000000040" + + "0000000000000000000000000000000000000000000000000000000000000160" + + "0000000000000000000000000000000000000000000000000000000000000060" + + "0000000000000000000000000000000000000000000000000000000000000064" + + "00000000000000000000000000000000000000000000000000000000000000a0" + + "000000000000000000000000000000000000000000000000000000000000000c" + + "48656c6c6f20776f726c64210000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000001" + + "0000000000000000000000000000000000000000000000000000000000000001" + + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000000000000000000000000000000000000000003" + + "0000000000000000000000000000000000000000000000000000000000000060" + + "00000000000000000000000000000000000000000000000000000000000000c8" + + "00000000000000000000000000000000000000000000000000000000000000a0" + + "000000000000000000000000000000000000000000000000000000000000000c" + + "48656c6c6f20776f726c64320000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000001" + + "0000000000000000000000000000000000000000000000000000000000000005" + + "0000000000000000000000000000000000000000000000000000000000000006" + + "0000000000000000000000000000000000000000000000000000000000000007" + + "000000000000000000000000000000000000000000000000000000000000000c" + + "48656c6c6f20776f726c64210000000000000000000000000000000000000000", + encodeHex); + + ABIDefinition abiDefinition = + Utils.getContractABIDefinition(abiDesc).getFunctions().get("test").get(0); + ABIObject inputObject = ABIObjectFactory.createInputObject(abiDefinition); + ABIObject decodeObject = inputObject.decode(encodeHex); + + Assert.assertEquals(encodeHex, decodeObject.encode()); + + ABIObject newObjectWithoutValue = inputObject.newObjectWithoutValue(); + Assert.assertEquals(encodeHex, newObjectWithoutValue.decode(encodeHex).encode()); + } + + @Test + public void testSingleValue() { + ABIObject abiObject = new ABIObject(new Utf8String("Greetings!")); + ABIObject structObject = new ABIObject(ObjectType.STRUCT); + structObject.getStructFields().add(abiObject); + assertThat( + structObject.encode(), + is( + "0000000000000000000000000000000000000000000000000000000000000020" + + "000000000000000000000000000000000000000000000000000000000000000a" + + "4772656574696e67732100000000000000000000000000000000000000000000")); + } + + @Test + public void testEncode1() { + + ABIObject abiObject = new ABIObject(ObjectType.STRUCT); + abiObject.getStructFields().add(new ABIObject(new Uint256(69))); + abiObject.getStructFields().add(new ABIObject(new Bool(true))); + + assertThat( + abiObject.encode(), + is( + "0000000000000000000000000000000000000000000000000000000000000045" + + "0000000000000000000000000000000000000000000000000000000000000001")); + + abiObject.getStructFields().clear(); + abiObject.getStructFields().add(new ABIObject(new Bytes(3, "abc".getBytes()))); + abiObject.getStructFields().add(new ABIObject(new Bytes(3, "def".getBytes()))); + + assertThat( + abiObject.encode(), + is( + "6162630000000000000000000000000000000000000000000000000000000000" + + "6465660000000000000000000000000000000000000000000000000000000000")); + + abiObject.getStructFields().clear(); + abiObject.getStructFields().add(new ABIObject(new DynamicBytes("dave".getBytes()))); + abiObject.getStructFields().add(new ABIObject(new Bool(true))); + + ABIObject listObject = new ABIObject(ABIObject.ListType.DYNAMIC); + listObject.getListValues().add(new ABIObject(new Uint256(1))); + listObject.getListValues().add(new ABIObject(new Uint256(2))); + listObject.getListValues().add(new ABIObject(new Uint256(3))); + + abiObject.getStructFields().add(listObject); + + assertThat( + abiObject.encode(), + is( + "0000000000000000000000000000000000000000000000000000000000000060" + + "0000000000000000000000000000000000000000000000000000000000000001" + + "00000000000000000000000000000000000000000000000000000000000000a0" + + "0000000000000000000000000000000000000000000000000000000000000004" + + "6461766500000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000003" + + "0000000000000000000000000000000000000000000000000000000000000001" + + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000000000000000000000000000000000000000003")); + + abiObject.getStructFields().clear(); + abiObject.getStructFields().add(new ABIObject(new Uint256(0x123))); + + ABIObject listObject0 = new ABIObject(ABIObject.ListType.DYNAMIC); + listObject0.getListValues().add(new ABIObject(new Uint256(0x456))); + listObject0.getListValues().add(new ABIObject(new Uint256(0x789))); + abiObject.getStructFields().add(listObject0); + + abiObject.getStructFields().add(new ABIObject(new Bytes10("1234567890".getBytes()))); + abiObject + .getStructFields() + .add(new ABIObject(new DynamicBytes("Hello, world!".getBytes()))); + + assertThat( + abiObject.encode(), + is( + "0000000000000000000000000000000000000000000000000000000000000123" + + "0000000000000000000000000000000000000000000000000000000000000080" + + "3132333435363738393000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000000000000000000000000000000000e0" + + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000000000000000000000000000000000000000456" + + "0000000000000000000000000000000000000000000000000000000000000789" + + "000000000000000000000000000000000000000000000000000000000000000d" + + "48656c6c6f2c20776f726c642100000000000000000000000000000000000000")); + + abiObject.getStructFields().clear(); + + ABIObject listObject1 = new ABIObject(ABIObject.ListType.DYNAMIC); + ABIObject listObject1_0 = new ABIObject(ABIObject.ListType.DYNAMIC); + ABIObject listObject1_1 = new ABIObject(ABIObject.ListType.DYNAMIC); + + listObject1_0.getListValues().add(new ABIObject(new Uint256(1))); + listObject1_0.getListValues().add(new ABIObject(new Uint256(2))); + + listObject1_1.getListValues().add(new ABIObject(new Uint256(3))); + + listObject1.getListValues().add(listObject1_0); + listObject1.getListValues().add(listObject1_1); + + ABIObject listObject2 = new ABIObject(ABIObject.ListType.DYNAMIC); + listObject2.getListValues().add(new ABIObject(new Utf8String("one"))); + listObject2.getListValues().add(new ABIObject(new Utf8String("two"))); + listObject2.getListValues().add(new ABIObject(new Utf8String("three"))); + + abiObject.getStructFields().add(listObject1); + abiObject.getStructFields().add(listObject2); + + assertThat( + abiObject.encode(), + is( + "0000000000000000000000000000000000000000000000000000000000000040" + + "0000000000000000000000000000000000000000000000000000000000000140" + + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000000000000000000000000000000000000000040" + + "00000000000000000000000000000000000000000000000000000000000000a0" + + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000000000000000000000000000000000000000001" + + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000000000000000000000000000000000000000001" + + "0000000000000000000000000000000000000000000000000000000000000003" + + "0000000000000000000000000000000000000000000000000000000000000003" + + "0000000000000000000000000000000000000000000000000000000000000060" + + "00000000000000000000000000000000000000000000000000000000000000a0" + + "00000000000000000000000000000000000000000000000000000000000000e0" + + "0000000000000000000000000000000000000000000000000000000000000003" + + "6f6e650000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000003" + + "74776f0000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000005" + + "7468726565000000000000000000000000000000000000000000000000000000")); + } + + @Test + public void testBoolTypeEncode() { + assertThat( + new ABIObject(new Bool(false)).encode(), + is("0000000000000000000000000000000000000000000000000000000000000000")); + assertThat( + new ABIObject(new Bool(true)).encode(), + is("0000000000000000000000000000000000000000000000000000000000000001")); + } + + @Test + public void testIntTypeEncode() { + assertThat( + new ABIObject(new Uint256(BigInteger.ZERO)).encode(), + is("0000000000000000000000000000000000000000000000000000000000000000")); + + assertThat( + new ABIObject(new Int256(BigInteger.ZERO)).encode(), + is("0000000000000000000000000000000000000000000000000000000000000000")); + + assertThat( + new ABIObject(new Uint256(Long.MAX_VALUE)).encode(), + is("0000000000000000000000000000000000000000000000007fffffffffffffff")); + + assertThat( + new ABIObject(new Int256(Long.MAX_VALUE)).encode(), + is("0000000000000000000000000000000000000000000000007fffffffffffffff")); + + assertThat( + new ABIObject( + new Uint256( + new BigInteger( + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", + 16))) + .encode(), + is("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe")); + } + + @Test + public void testEmptyListEncode() { + + assertThat( + new ABIObject(ABIObject.ListType.DYNAMIC).encode(), + is("0000000000000000000000000000000000000000000000000000000000000000")); + } + + @Test + public void testStringEncode() { + assertThat( + new ABIObject(new Utf8String("Hello, world!")).encode(), + is( + "000000000000000000000000000000000000000000000000000000000000000d" + + "48656c6c6f2c20776f726c642100000000000000000000000000000000000000")); + + assertThat( + new ABIObject(new Utf8String("")).encode(), + is("0000000000000000000000000000000000000000000000000000000000000000")); + } + + @Test + public void testAddressEncode() { + Address address = new Address("0xbe5422d15f39373eb0a97ff8c10fbd0e40e29338"); + assertThat( + new ABIObject(address).encode(), + is("000000000000000000000000be5422d15f39373eb0a97ff8c10fbd0e40e29338")); + } + + @Test + public void testStaticBytesEncode() { + Bytes staticBytes = new Bytes6(new byte[] {0, 1, 2, 3, 4, 5}); + assertThat( + new ABIObject(staticBytes).encode(), + is("0001020304050000000000000000000000000000000000000000000000000000")); + + Bytes empty = new Bytes1(new byte[] {0}); + assertThat( + new ABIObject(empty).encode(), + is("0000000000000000000000000000000000000000000000000000000000000000")); + + Bytes dave = new Bytes4("dave".getBytes()); + assertThat( + new ABIObject(dave).encode(), + is("6461766500000000000000000000000000000000000000000000000000000000")); + } + + @Test + public void testDynamicBytesEncode() { + DynamicBytes dynamicBytes = new DynamicBytes(new byte[] {0, 1, 2, 3, 4, 5}); + assertThat( + new ABIObject(dynamicBytes).encode(), + is( + "0000000000000000000000000000000000000000000000000000000000000006" + + "0001020304050000000000000000000000000000000000000000000000000000")); + + DynamicBytes empty = new DynamicBytes(new byte[] {0}); + assertThat( + new ABIObject(empty).encode(), + is( + "0000000000000000000000000000000000000000000000000000000000000001" + + "0000000000000000000000000000000000000000000000000000000000000000")); + + DynamicBytes dave = new DynamicBytes("dave".getBytes()); + assertThat( + new ABIObject(dave).encode(), + is( + "0000000000000000000000000000000000000000000000000000000000000004" + + "6461766500000000000000000000000000000000000000000000000000000000")); + + DynamicBytes loremIpsum = + new DynamicBytes( + ("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod " + + "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim " + + "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex " + + "ea commodo consequat. Duis aute irure dolor in reprehenderit in " + + "voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur " + + "sint occaecat cupidatat non proident, sunt in culpa qui officia " + + "deserunt mollit anim id est laborum.") + .getBytes()); + assertThat( + new ABIObject(loremIpsum).encode(), + is( + "00000000000000000000000000000000000000000000000000000000000001bd" + + "4c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73" + + "656374657475722061646970697363696e6720656c69742c2073656420646f20" + + "656975736d6f642074656d706f7220696e6369646964756e74207574206c6162" + + "6f726520657420646f6c6f7265206d61676e6120616c697175612e2055742065" + + "6e696d206164206d696e696d2076656e69616d2c2071756973206e6f73747275" + + "6420657865726369746174696f6e20756c6c616d636f206c61626f726973206e" + + "69736920757420616c697175697020657820656120636f6d6d6f646f20636f6e" + + "7365717561742e2044756973206175746520697275726520646f6c6f7220696e" + + "20726570726568656e646572697420696e20766f6c7570746174652076656c69" + + "7420657373652063696c6c756d20646f6c6f726520657520667567696174206e" + + "756c6c612070617269617475722e204578636570746575722073696e74206f63" + + "63616563617420637570696461746174206e6f6e2070726f6964656e742c2073" + + "756e7420696e2063756c706120717569206f666669636961206465736572756e" + + "74206d6f6c6c697420616e696d20696420657374206c61626f72756d2e000000")); + } +} diff --git a/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ContractTypeTest.java b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ContractTypeTest.java new file mode 100644 index 000000000..496d8e8d6 --- /dev/null +++ b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/ContractTypeTest.java @@ -0,0 +1,346 @@ +package org.fisco.bcos.sdk.test.abi; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Base64; +import java.util.List; +import org.fisco.bcos.sdk.abi.wrapper.ABICodecJsonWrapper; +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.junit.Assert; +import org.junit.Test; + +public class ContractTypeTest { + String abiDesc = + "[\n" + + "\t{\n" + + "\t\t\"constant\": false,\n" + + "\t\t\"inputs\": [\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_u\",\n" + + "\t\t\t\t\"type\": \"uint256[]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_b\",\n" + + "\t\t\t\t\"type\": \"bool[]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_addr\",\n" + + "\t\t\t\t\"type\": \"address[]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_bs32\",\n" + + "\t\t\t\t\"type\": \"bytes32[]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_s\",\n" + + "\t\t\t\t\"type\": \"string[]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_bs\",\n" + + "\t\t\t\t\"type\": \"bytes[]\"\n" + + "\t\t\t}\n" + + "\t\t],\n" + + "\t\t\"name\": \"setDynamicValue\",\n" + + "\t\t\"outputs\": [],\n" + + "\t\t\"payable\": false,\n" + + "\t\t\"stateMutability\": \"nonpayable\",\n" + + "\t\t\"type\": \"function\"\n" + + "\t},\n" + + "\t{\n" + + "\t\t\"constant\": false,\n" + + "\t\t\"inputs\": [\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_u\",\n" + + "\t\t\t\t\"type\": \"uint256[3]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_b\",\n" + + "\t\t\t\t\"type\": \"bool[3]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_addr\",\n" + + "\t\t\t\t\"type\": \"address[3]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_bs32\",\n" + + "\t\t\t\t\"type\": \"bytes32[3]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_s\",\n" + + "\t\t\t\t\"type\": \"string[3]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_bs\",\n" + + "\t\t\t\t\"type\": \"bytes[3]\"\n" + + "\t\t\t}\n" + + "\t\t],\n" + + "\t\t\"name\": \"setFixedValue\",\n" + + "\t\t\"outputs\": [],\n" + + "\t\t\"payable\": false,\n" + + "\t\t\"stateMutability\": \"nonpayable\",\n" + + "\t\t\"type\": \"function\"\n" + + "\t},\n" + + "\t{\n" + + "\t\t\"constant\": false,\n" + + "\t\t\"inputs\": [\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_u\",\n" + + "\t\t\t\t\"type\": \"uint256\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_b\",\n" + + "\t\t\t\t\"type\": \"bool\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_addr\",\n" + + "\t\t\t\t\"type\": \"address\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_bs32\",\n" + + "\t\t\t\t\"type\": \"bytes32\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_s\",\n" + + "\t\t\t\t\"type\": \"string\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_bs\",\n" + + "\t\t\t\t\"type\": \"bytes\"\n" + + "\t\t\t}\n" + + "\t\t],\n" + + "\t\t\"name\": \"setValue\",\n" + + "\t\t\"outputs\": [],\n" + + "\t\t\"payable\": false,\n" + + "\t\t\"stateMutability\": \"nonpayable\",\n" + + "\t\t\"type\": \"function\"\n" + + "\t},\n" + + "\t{\n" + + "\t\t\"constant\": true,\n" + + "\t\t\"inputs\": [],\n" + + "\t\t\"name\": \"getDynamicValue\",\n" + + "\t\t\"outputs\": [\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_u\",\n" + + "\t\t\t\t\"type\": \"uint256[]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_b\",\n" + + "\t\t\t\t\"type\": \"bool[]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_addr\",\n" + + "\t\t\t\t\"type\": \"address[]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_bs32\",\n" + + "\t\t\t\t\"type\": \"bytes32[]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_s\",\n" + + "\t\t\t\t\"type\": \"string[]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_bs\",\n" + + "\t\t\t\t\"type\": \"bytes[]\"\n" + + "\t\t\t}\n" + + "\t\t],\n" + + "\t\t\"payable\": false,\n" + + "\t\t\"stateMutability\": \"view\",\n" + + "\t\t\"type\": \"function\"\n" + + "\t},\n" + + "\t{\n" + + "\t\t\"constant\": true,\n" + + "\t\t\"inputs\": [],\n" + + "\t\t\"name\": \"getFixedValue\",\n" + + "\t\t\"outputs\": [\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_u\",\n" + + "\t\t\t\t\"type\": \"uint256[3]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_b\",\n" + + "\t\t\t\t\"type\": \"bool[3]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_addr\",\n" + + "\t\t\t\t\"type\": \"address[3]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_bs32\",\n" + + "\t\t\t\t\"type\": \"bytes32[3]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_s\",\n" + + "\t\t\t\t\"type\": \"string[3]\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_bs\",\n" + + "\t\t\t\t\"type\": \"bytes[3]\"\n" + + "\t\t\t}\n" + + "\t\t],\n" + + "\t\t\"payable\": false,\n" + + "\t\t\"stateMutability\": \"view\",\n" + + "\t\t\"type\": \"function\"\n" + + "\t},\n" + + "\t{\n" + + "\t\t\"constant\": true,\n" + + "\t\t\"inputs\": [],\n" + + "\t\t\"name\": \"getValue\",\n" + + "\t\t\"outputs\": [\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_u\",\n" + + "\t\t\t\t\"type\": \"uint256\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_b\",\n" + + "\t\t\t\t\"type\": \"bool\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_addr\",\n" + + "\t\t\t\t\"type\": \"address\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_bs32\",\n" + + "\t\t\t\t\"type\": \"bytes32\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_s\",\n" + + "\t\t\t\t\"type\": \"string\"\n" + + "\t\t\t},\n" + + "\t\t\t{\n" + + "\t\t\t\t\"name\": \"_bs\",\n" + + "\t\t\t\t\"type\": \"bytes\"\n" + + "\t\t\t}\n" + + "\t\t],\n" + + "\t\t\"payable\": false,\n" + + "\t\t\"stateMutability\": \"view\",\n" + + "\t\t\"type\": \"function\"\n" + + "\t}\n" + + "]"; + + /* + { + "20965255": "getValue()", + "ed4d0e39": "getDynamicValue()", + "c1cee39a": "getFixedValue()", + "dfed87e3": "setDynamicValue(uint256[],bool[],address[],bytes32[],string[],bytes[])", + "63e5584b": "setFixedValue(uint256[3],bool[3],address[3],bytes32[3],string[3],bytes[3])", + "11cfbe17": "setValue(uint256,bool,address,bytes32,string,bytes)" + }*/ + + private ContractABIDefinition contractABIDefinition = Utils.getContractABIDefinition(abiDesc); + + @Test + public void ContractFixedTypeCodecTest() throws IOException { + ABIObject inputObject = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("setFixedValue").get(0)); + + ABIObject outObject = + ABIObjectFactory.createOutputObject( + contractABIDefinition.getFunctions().get("getFixedValue").get(0)); + + String bytes1 = Base64.getEncoder().encodeToString("HelloWorld 11111".getBytes()); + String bytes2 = Base64.getEncoder().encodeToString("HelloWorld 22222".getBytes()); + String bytes3 = Base64.getEncoder().encodeToString("HelloWorld 33333".getBytes()); + + List params = + Arrays.asList( + "[1,2,3]", + "[true,false,true]", + "[\"0xa\",\"0xb\",\"0xc\"]", + "[\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\"]", + "[\"a\",\"b\",\"c\"]", + "[\"" + bytes1 + "\",\"" + bytes2 + "\",\"" + bytes3 + "\"]"); + + ABICodecJsonWrapper abiCodecJsonWrapper = new ABICodecJsonWrapper(); + ABIObject encodeObject = abiCodecJsonWrapper.encode(inputObject, params); + + List decodeResult = abiCodecJsonWrapper.decode(outObject, encodeObject.encode()); + + Assert.assertEquals(decodeResult.get(0), "[ 1, 2, 3 ]"); + Assert.assertEquals(decodeResult.get(1), "[ true, false, true ]"); + Assert.assertEquals( + decodeResult.get(2), + "[ \"0x000000000000000000000000000000000000000a\", \"0x000000000000000000000000000000000000000b\", \"0x000000000000000000000000000000000000000c\" ]"); + Assert.assertEquals( + decodeResult.get(3), + "[ \"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\", \"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\", \"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\" ]"); + + Assert.assertEquals(decodeResult.get(4), "[ \"a\", \"b\", \"c\" ]"); + Assert.assertEquals( + decodeResult.get(5), + "[ \"" + bytes1 + "\", \"" + bytes2 + "\", \"" + bytes3 + "\" ]"); + } + + @Test + public void ContractDynamicTypeCodecTest() throws IOException { + ABIObject inputObject = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("setDynamicValue").get(0)); + + ABIObject outObject = + ABIObjectFactory.createOutputObject( + contractABIDefinition.getFunctions().get("getDynamicValue").get(0)); + + String bytes1 = Base64.getEncoder().encodeToString("HelloWorld 11111".getBytes()); + String bytes2 = Base64.getEncoder().encodeToString("HelloWorld 22222".getBytes()); + String bytes3 = Base64.getEncoder().encodeToString("HelloWorld 33333".getBytes()); + + List params = + Arrays.asList( + "[1,2,3]", + "[true,false,true]", + "[\"0xa\",\"0xb\",\"0xc\"]", + "[\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\"]", + "[\"a\",\"b\",\"c\"]", + "[\"" + bytes1 + "\",\"" + bytes2 + "\",\"" + bytes3 + "\"]"); + + ABICodecJsonWrapper abiCodecJsonWrapper = new ABICodecJsonWrapper(); + ABIObject encodeObject = abiCodecJsonWrapper.encode(inputObject, params); + + List decodeResult = abiCodecJsonWrapper.decode(outObject, encodeObject.encode()); + + Assert.assertEquals(decodeResult.get(0), "[ 1, 2, 3 ]"); + Assert.assertEquals(decodeResult.get(1), "[ true, false, true ]"); + Assert.assertEquals( + decodeResult.get(2), + "[ \"0x000000000000000000000000000000000000000a\", \"0x000000000000000000000000000000000000000b\", \"0x000000000000000000000000000000000000000c\" ]"); + Assert.assertEquals( + decodeResult.get(3), + "[ \"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\", \"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\", \"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\" ]"); + + Assert.assertEquals(decodeResult.get(4), "[ \"a\", \"b\", \"c\" ]"); + Assert.assertEquals( + decodeResult.get(5), + "[ \"" + bytes1 + "\", \"" + bytes2 + "\", \"" + bytes3 + "\" ]"); + } + + @Test + public void ContractDynamicTypeEmptyParamsCodecTest() throws IOException { + ABIObject inputObject = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("setDynamicValue").get(0)); + + ABIObject outObject = + ABIObjectFactory.createOutputObject( + contractABIDefinition.getFunctions().get("getDynamicValue").get(0)); + + List params = Arrays.asList("[]", "[]", "[]", "[]", "[]", "[]"); + + ABICodecJsonWrapper abiCodecJsonWrapper = new ABICodecJsonWrapper(); + ABIObject encodeObject = abiCodecJsonWrapper.encode(inputObject, params); + + List decodeResult = abiCodecJsonWrapper.decode(outObject, encodeObject.encode()); + + Assert.assertEquals(decodeResult.get(0), "[ ]"); + Assert.assertEquals(decodeResult.get(1), "[ ]"); + Assert.assertEquals(decodeResult.get(2), "[ ]"); + Assert.assertEquals(decodeResult.get(3), "[ ]"); + + Assert.assertEquals(decodeResult.get(4), "[ ]"); + Assert.assertEquals(decodeResult.get(5), "[ ]"); + } +} diff --git a/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/TableTest.java b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/TableTest.java new file mode 100644 index 000000000..41c637e86 --- /dev/null +++ b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/TableTest.java @@ -0,0 +1,431 @@ +package org.fisco.bcos.sdk.test.abi; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Uint256; +import org.fisco.bcos.sdk.abi.wrapper.ABICodecJsonWrapper; +import org.fisco.bcos.sdk.abi.wrapper.ABIDefinition; +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.junit.Assert; +import org.junit.Test; + +public class TableTest { + /* + pragmasolidity^0.4.24; + pragmaexperimentalABIEncoderV2; + contractTableTest + { + functionselect(stringmemoryname)publicviewreturns(string[]memory,int256[]memory,string[]memory){} + functioninsert(stringmemoryname,int256item_id,stringmemoryitem_name)publicreturns(int256){} + functionupdate(stringmemoryname,int256item_id,stringmemoryitem_name)publicreturns(int256){} + functionremove(stringmemoryname,int256item_id)publicreturns(int256){} + } + */ + + private static final String abiDesc = + "[\n" + + " {\n" + + " \"constant\": false,\n" + + " \"inputs\": [\n" + + " {\n" + + " \"name\": \"name\",\n" + + " \"type\": \"string\"\n" + + " },\n" + + " {\n" + + " \"name\": \"item_id\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"name\": \"item_name\",\n" + + " \"type\": \"string\"\n" + + " }\n" + + " ],\n" + + " \"name\": \"update\",\n" + + " \"outputs\": [\n" + + " {\n" + + " \"name\": \"\",\n" + + " \"type\": \"int256\"\n" + + " }\n" + + " ],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"function\"\n" + + " },\n" + + " {\n" + + " \"constant\": false,\n" + + " \"inputs\": [\n" + + " {\n" + + " \"name\": \"name\",\n" + + " \"type\": \"string\"\n" + + " },\n" + + " {\n" + + " \"name\": \"item_id\",\n" + + " \"type\": \"int256\"\n" + + " }\n" + + " ],\n" + + " \"name\": \"remove\",\n" + + " \"outputs\": [\n" + + " {\n" + + " \"name\": \"\",\n" + + " \"type\": \"int256\"\n" + + " }\n" + + " ],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"function\"\n" + + " },\n" + + " {\n" + + " \"constant\": false,\n" + + " \"inputs\": [\n" + + " {\n" + + " \"name\": \"name\",\n" + + " \"type\": \"string\"\n" + + " },\n" + + " {\n" + + " \"name\": \"item_id\",\n" + + " \"type\": \"int256\"\n" + + " },\n" + + " {\n" + + " \"name\": \"item_name\",\n" + + " \"type\": \"string\"\n" + + " }\n" + + " ],\n" + + " \"name\": \"insert\",\n" + + " \"outputs\": [\n" + + " {\n" + + " \"name\": \"\",\n" + + " \"type\": \"int256\"\n" + + " }\n" + + " ],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"nonpayable\",\n" + + " \"type\": \"function\"\n" + + " },\n" + + " {\n" + + " \"constant\": true,\n" + + " \"inputs\": [\n" + + " {\n" + + " \"name\": \"name\",\n" + + " \"type\": \"string\"\n" + + " }\n" + + " ],\n" + + " \"name\": \"select\",\n" + + " \"outputs\": [\n" + + " {\n" + + " \"name\": \"\",\n" + + " \"type\": \"string[]\"\n" + + " },\n" + + " {\n" + + " \"name\": \"\",\n" + + " \"type\": \"int256[]\"\n" + + " },\n" + + " {\n" + + " \"name\": \"\",\n" + + " \"type\": \"string[]\"\n" + + " }\n" + + " ],\n" + + " \"payable\": false,\n" + + " \"stateMutability\": \"view\",\n" + + " \"type\": \"function\"\n" + + " }\n" + + "]"; + + /* + { + "ebf3b24f": "insert(string,int256,string)", + "c4f41ab3": "remove(string,int256)", + "fcd7e3c1": "select(string)", + "487a5a10": "update(string,int256,string)" + } + */ + + private static final ContractABIDefinition contractABIDefinition = + Utils.getContractABIDefinition(abiDesc); + private static final ABICodecJsonWrapper abiCodecJsonWrapper = new ABICodecJsonWrapper(); + + @Test + public void ABILoadTest() { + ContractABIDefinition contractABIDefinition = Utils.getContractABIDefinition(abiDesc); + ABIDefinition insert = contractABIDefinition.getFunctions().get("insert").get(0); + ABIDefinition update = contractABIDefinition.getFunctions().get("update").get(0); + ABIDefinition remove = contractABIDefinition.getFunctions().get("remove").get(0); + ABIDefinition select = contractABIDefinition.getFunctions().get("select").get(0); + + Assert.assertEquals(insert.getMethodId(Utils.getCryptoSuite()), "0xebf3b24f"); + Assert.assertEquals(remove.getMethodId(Utils.getCryptoSuite()), "0xc4f41ab3"); + Assert.assertEquals(update.getMethodId(Utils.getCryptoSuite()), "0x487a5a10"); + Assert.assertEquals(select.getMethodId(Utils.getCryptoSuite()), "0xfcd7e3c1"); + + Assert.assertEquals(insert.getMethodSignatureAsString(), "insert(string,int256,string)"); + Assert.assertEquals(remove.getMethodSignatureAsString(), "remove(string,int256)"); + Assert.assertEquals(update.getMethodSignatureAsString(), "update(string,int256,string)"); + Assert.assertEquals(select.getMethodSignatureAsString(), "select(string)"); + } + + @Test + public void ABIObjectTest() { + ContractABIDefinition contractABIDefinition = Utils.getContractABIDefinition(abiDesc); + ABIObject insertInputObject = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("insert").get(0)); + ABIObject insertOutputObject = + ABIObjectFactory.createOutputObject( + contractABIDefinition.getFunctions().get("insert").get(0)); + + Assert.assertEquals(insertInputObject.getStructFields().size(), 3); + Assert.assertEquals( + insertInputObject.getStructFields().get(0).getValueType(), + ABIObject.ValueType.STRING); + Assert.assertEquals( + insertInputObject.getStructFields().get(1).getValueType(), ABIObject.ValueType.INT); + Assert.assertEquals( + insertInputObject.getStructFields().get(2).getValueType(), + ABIObject.ValueType.STRING); + + Assert.assertTrue(insertInputObject.getStructFields().get(0).isDynamic()); + Assert.assertTrue(!insertInputObject.getStructFields().get(1).isDynamic()); + Assert.assertTrue(insertInputObject.getStructFields().get(2).isDynamic()); + + Assert.assertEquals(insertOutputObject.getStructFields().size(), 1); + Assert.assertEquals( + insertOutputObject.getStructFields().get(0).getValueType(), + ABIObject.ValueType.INT); + + ABIObject updateInputObject = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("update").get(0)); + ABIObject updateOutputObject = + ABIObjectFactory.createOutputObject( + contractABIDefinition.getFunctions().get("update").get(0)); + + Assert.assertEquals(updateInputObject.getStructFields().size(), 3); + Assert.assertEquals( + updateInputObject.getStructFields().get(0).getValueType(), + ABIObject.ValueType.STRING); + Assert.assertEquals( + updateInputObject.getStructFields().get(1).getValueType(), ABIObject.ValueType.INT); + Assert.assertEquals( + updateInputObject.getStructFields().get(2).getValueType(), + ABIObject.ValueType.STRING); + + Assert.assertTrue(updateInputObject.getStructFields().get(0).isDynamic()); + Assert.assertTrue(!updateInputObject.getStructFields().get(1).isDynamic()); + Assert.assertTrue(updateInputObject.getStructFields().get(2).isDynamic()); + + Assert.assertEquals(updateOutputObject.getStructFields().size(), 1); + Assert.assertEquals( + updateOutputObject.getStructFields().get(0).getValueType(), + ABIObject.ValueType.INT); + + ABIObject removeInputObject = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("remove").get(0)); + ABIObject removeOutputObject = + ABIObjectFactory.createOutputObject( + contractABIDefinition.getFunctions().get("remove").get(0)); + + Assert.assertEquals(removeInputObject.getStructFields().size(), 2); + Assert.assertEquals( + removeInputObject.getStructFields().get(0).getValueType(), + ABIObject.ValueType.STRING); + Assert.assertEquals( + removeInputObject.getStructFields().get(1).getValueType(), ABIObject.ValueType.INT); + + Assert.assertTrue(removeInputObject.getStructFields().get(0).isDynamic()); + Assert.assertTrue(!removeInputObject.getStructFields().get(1).isDynamic()); + + Assert.assertEquals(removeOutputObject.getStructFields().size(), 1); + Assert.assertEquals( + removeOutputObject.getStructFields().get(0).getValueType(), + ABIObject.ValueType.INT); + + ABIObject selectInputObject = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("select").get(0)); + ABIObject selectOutputObject = + ABIObjectFactory.createOutputObject( + contractABIDefinition.getFunctions().get("select").get(0)); + + Assert.assertEquals(selectInputObject.getStructFields().size(), 1); + Assert.assertEquals( + selectInputObject.getStructFields().get(0).getValueType(), + ABIObject.ValueType.STRING); + + Assert.assertTrue(selectInputObject.getStructFields().get(0).isDynamic()); + + Assert.assertEquals(selectOutputObject.getStructFields().size(), 3); + Assert.assertEquals( + selectOutputObject.getStructFields().get(0).getListType(), + ABIObject.ListType.DYNAMIC); + Assert.assertEquals( + selectOutputObject.getStructFields().get(1).getListType(), + ABIObject.ListType.DYNAMIC); + Assert.assertEquals( + selectOutputObject.getStructFields().get(2).getListType(), + ABIObject.ListType.DYNAMIC); + } + + @Test + public void ABIObjectCodecTest() { + ContractABIDefinition contractABIDefinition = Utils.getContractABIDefinition(abiDesc); + ABIObject insertInputObject = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("insert").get(0)); + ABIObject insertOutputObject = + ABIObjectFactory.createOutputObject( + contractABIDefinition.getFunctions().get("insert").get(0)); + + insertInputObject.getStructFields().set(0, new ABIObject(new Utf8String("hello"))); + insertInputObject.getStructFields().set(1, new ABIObject(new Uint256(100))); + insertInputObject.getStructFields().set(2, new ABIObject(new Utf8String("car"))); + String insertInputEncode = insertInputObject.encode(); + String insertEncode = + "0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000568656c6c6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036361720000000000000000000000000000000000000000000000000000000000"; + Assert.assertEquals(insertInputEncode, insertEncode); + Assert.assertEquals( + insertInputObject.decode(insertInputEncode).encode(), insertInputObject.encode()); + + insertOutputObject.getStructFields().set(0, new ABIObject(new Uint256(1111))); + String insertOutputEncode = insertOutputObject.encode(); + Assert.assertEquals( + insertOutputObject.decode(insertOutputEncode).encode(), insertOutputEncode); + + // ABIObject updateInputObject = + // ABIObjectFactory.createInputObject(contractABIDefinition.getFunctions().get("update").get(0)); + // ABIObject updateOutputObject = + // ABIObjectFactory.createOutputObject(contractABIDefinition.getFunctions().get("update").get(0)); + // + // ABIObject removeInputObject = + // ABIObjectFactory.createInputObject(contractABIDefinition.getFunctions().get("remove").get(0)); + // ABIObject removeOutputObject = + // ABIObjectFactory.createOutputObject(contractABIDefinition.getFunctions().get("remove").get(0)); + + // ABIObject selectInputObject = + // ABIObjectFactory.createInputObject(contractABIDefinition.getFunctions().get("select").get(0)); + // ABIObject selectOutputObject = + // ABIObjectFactory.createOutputObject(contractABIDefinition.getFunctions().get("select").get(0)); + } + + @Test + public void ABIObjectCodecJsonWrapperTest() throws IOException { + ContractABIDefinition contractABIDefinition = Utils.getContractABIDefinition(abiDesc); + + ABIObject insertInputObject = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("insert").get(0)); + ABIObject insertOutputObject = + ABIObjectFactory.createOutputObject( + contractABIDefinition.getFunctions().get("insert").get(0)); + + String encode_i = + abiCodecJsonWrapper + .encode(insertInputObject, Arrays.asList("hello", "100", "car")) + .encode(); + String encoded_i = + "0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000568656c6c6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036361720000000000000000000000000000000000000000000000000000000000"; + Assert.assertEquals(encode_i, encoded_i); + List json_decode_i = abiCodecJsonWrapper.decode(insertInputObject, encode_i); + Assert.assertEquals(json_decode_i.get(0), "hello"); + Assert.assertEquals(json_decode_i.get(1), "100"); + Assert.assertEquals(json_decode_i.get(2), "car"); + + String encode_o = + abiCodecJsonWrapper.encode(insertOutputObject, Arrays.asList("100")).encode(); + String encoded_o = "0000000000000000000000000000000000000000000000000000000000000064"; + Assert.assertEquals(encode_o, encoded_o); + List json_decode_o = abiCodecJsonWrapper.decode(insertOutputObject, encoded_o); + Assert.assertEquals(json_decode_o.get(0), "100"); + + ABIObject updateInputObject = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("update").get(0)); + ABIObject updateOutputObject = + ABIObjectFactory.createOutputObject( + contractABIDefinition.getFunctions().get("update").get(0)); + + String encode_i_u = + abiCodecJsonWrapper + .encode(updateInputObject, Arrays.asList("hello", "100", "car")) + .encode(); + String encoded_i_u = + "0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000568656c6c6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036361720000000000000000000000000000000000000000000000000000000000"; + Assert.assertEquals(encode_i_u, encoded_i_u); + + String encode_o_u = + abiCodecJsonWrapper.encode(updateOutputObject, Arrays.asList("100")).encode(); + String encoded_o_u = "0000000000000000000000000000000000000000000000000000000000000064"; + Assert.assertEquals(encode_o_u, encoded_o_u); + + List json_decode_i_o = abiCodecJsonWrapper.decode(updateInputObject, encoded_i_u); + Assert.assertEquals(json_decode_i_o.get(0), "hello"); + Assert.assertEquals(json_decode_i_o.get(1), "100"); + Assert.assertEquals(json_decode_i_o.get(2), "car"); + + List json_decode_o_o = abiCodecJsonWrapper.decode(updateOutputObject, encoded_o_u); + Assert.assertEquals(json_decode_o_o.get(0), "100"); + + ABIObject removeInputObject = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("remove").get(0)); + ABIObject removeOutputObject = + ABIObjectFactory.createOutputObject( + contractABIDefinition.getFunctions().get("remove").get(0)); + + String encode_i_r = + abiCodecJsonWrapper + .encode(removeInputObject, Arrays.asList("hello", "100")) + .encode(); + String encoded_i_r = + "00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000"; + Assert.assertEquals(encode_i_r, encoded_i_r); + + String encode_o_r = + abiCodecJsonWrapper.encode(removeOutputObject, Arrays.asList("100")).encode(); + String encoded_o_r = "0000000000000000000000000000000000000000000000000000000000000064"; + Assert.assertEquals(encode_o_r, encoded_o_r); + + List json_decode_r_i = abiCodecJsonWrapper.decode(removeInputObject, encoded_i_r); + Assert.assertEquals(json_decode_r_i.get(0), "hello"); + List json_decode_r_o = abiCodecJsonWrapper.decode(updateOutputObject, encoded_o_r); + Assert.assertEquals(json_decode_r_o.get(0), "100"); + + ABIObject selectInputObject = + ABIObjectFactory.createInputObject( + contractABIDefinition.getFunctions().get("select").get(0)); + ABIObject selectOutputObject = + ABIObjectFactory.createOutputObject( + contractABIDefinition.getFunctions().get("select").get(0)); + + String encode_i_s = + abiCodecJsonWrapper.encode(selectInputObject, Arrays.asList("hello")).encode(); + String encoded_i_s = + "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000"; + Assert.assertEquals(encode_i_s, encoded_i_s); + + String encode_o_s = + abiCodecJsonWrapper + .encode( + selectOutputObject, + Arrays.asList( + "[\"hello\",\"hello\",\"hello\"]", + "[100,100,100]", + "[\"car\",\"car\",\"car\"]")) + .encode(); + String encoded_o_s = + "000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000568656c6c6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000363617200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003636172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036361720000000000000000000000000000000000000000000000000000000000"; + Assert.assertEquals(encode_o_s, encoded_o_s); + + List json_decode_s_i = abiCodecJsonWrapper.decode(selectInputObject, encoded_i_s); + Assert.assertEquals(json_decode_s_i.get(0), "hello"); + + List json_decode_s_o = abiCodecJsonWrapper.decode(selectOutputObject, encoded_o_s); + + Assert.assertEquals(json_decode_s_o.get(0), "[ \"hello\", \"hello\", \"hello\" ]"); + Assert.assertEquals(json_decode_s_o.get(1), "[ 100, 100, 100 ]"); + Assert.assertEquals(json_decode_s_o.get(2), "[ \"car\", \"car\", \"car\" ]"); + } +} diff --git a/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/Utils.java b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/Utils.java new file mode 100644 index 000000000..a3ca3be57 --- /dev/null +++ b/sdk-abi/src/test/java/org/fisco/bcos/sdk/test/abi/Utils.java @@ -0,0 +1,34 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.test.abi; + +import org.fisco.bcos.sdk.abi.wrapper.ABIDefinitionFactory; +import org.fisco.bcos.sdk.abi.wrapper.ContractABIDefinition; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.model.CryptoType; + +public class Utils { + + public static CryptoSuite getCryptoSuite() { + return new CryptoSuite(CryptoType.ECDSA_TYPE); + } + + public static ContractABIDefinition getContractABIDefinition(String abiDesc) { + CryptoSuite cryptoSuite = getCryptoSuite(); + ABIDefinitionFactory abiDefinitionFactory = new ABIDefinitionFactory(cryptoSuite); + return abiDefinitionFactory.loadABI(abiDesc); + } +} diff --git a/sdk-amop/build.gradle b/sdk-amop/build.gradle new file mode 100644 index 000000000..fabecace9 --- /dev/null +++ b/sdk-amop/build.gradle @@ -0,0 +1,51 @@ +// Apply the java-library plugin to add support for Java Library +plugins { + id 'java' +} +dependencies { + compile project(':sdk-core') + compile project(':sdk-crypto') + compile ("com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}") +} +uploadArchives { + repositories { + mavenDeployer { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + + repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { + authentication(userName: ossrhUsername, password: ossrhPassword) + } + + snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { + authentication(userName: ossrhUsername, password: ossrhPassword) + } + + pom.project { + name project.name + packaging 'jar' + description = 'fisco-bcos java-sdk' + url = 'http://www.fisco-bcos.org' + + scm { + connection = 'https://github.com/FISCO-BCOS/java-sdk.git' + url = 'https://github.com/FISCO-BCOS/java-sdk.git' + } + + licenses { + license { + name = 'The Apache License, Version 2.0' + url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + + developers { + developer { + id = 'zhangsan' + name = 'zhangsan' + email = 'zhangsan@example.com' + } + } + } + } + } +} diff --git a/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/Amop.java b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/Amop.java new file mode 100644 index 000000000..c246da936 --- /dev/null +++ b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/Amop.java @@ -0,0 +1,137 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.amop; + +import java.util.List; +import java.util.Set; +import java.util.UUID; +import org.fisco.bcos.sdk.amop.topic.TopicManager; +import org.fisco.bcos.sdk.channel.Channel; +import org.fisco.bcos.sdk.channel.ResponseCallback; +import org.fisco.bcos.sdk.config.ConfigOption; +import org.fisco.bcos.sdk.crypto.keystore.KeyTool; + +/** + * AMOP module interface. + * + * @author Maggie + */ +public interface Amop { + /** + * Create a Amop object. + * + * @param channel the channel to send/receive message + * @param config the config object + * @return Amop instance + */ + static Amop build(Channel channel, ConfigOption config) { + return new AmopImp(channel, config); + } + + /** + * Subscribe a normal topic. + * + * @param topicName the topic name + * @param callback callback is called when receive a msg relate to this topic + */ + void subscribeTopic(String topicName, AmopCallback callback); + + /** + * Subscribe a private topic which need verify. + * + * @param topicName the topic name + * @param privateKeyTool the private key you used to prove your identity. + * @param callback callback is called when receive a msg relate to this topic + */ + void subscribePrivateTopics(String topicName, KeyTool privateKeyTool, AmopCallback callback); + + /** + * Config a topic which is need verification, after that user can send message to verified + * subscriber. + * + * @param topicName the topic name + * @param publicKeyTools the public keys of the target organizations that you want to + * communicate with + */ + void publishPrivateTopic(String topicName, List publicKeyTools); + + /** + * Unsubscribe a topic. + * + * @param topicName the topic name + */ + void unsubscribeTopic(String topicName); + + /** + * Send amop msg + * + * @param content the sent message + * @param callback the callback that will be called when receive the AMOP response + */ + void sendAmopMsg(AmopMsgOut content, ResponseCallback callback); + + /** + * Send amop msg + * + * @param content the broadcasted AMOP message + */ + void broadcastAmopMsg(AmopMsgOut content); + + /** + * Get all subscribe topics. + * + * @return topic name list + */ + Set getSubTopics(); + + /** + * Get list of subscribers to a topic + * + * @param topicName the topic you want to query + * @return List of subscribers + */ + List getTopicSubscribers(String topicName); + + /** + * set amop default callback + * + * @param cb the amop callback + */ + void setCallback(AmopCallback cb); + + /** Start. */ + void start(); + + /** Stop. */ + void stop(); + + /** If configured private topic, wait until finish verify */ + void waitFinishPrivateTopicVerify(); + + /** + * generate message sequence string + * + * @return Sequence string + */ + static String newSeq() { + String seq = UUID.randomUUID().toString().replaceAll("-", ""); + return seq; + } + + TopicManager getTopicManager(); + + void sendSubscribe(); +} diff --git a/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/AmopCallback.java b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/AmopCallback.java new file mode 100644 index 000000000..e4eb264c3 --- /dev/null +++ b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/AmopCallback.java @@ -0,0 +1,28 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.amop; + +import org.fisco.bcos.sdk.amop.topic.AmopMsgIn; + +public abstract class AmopCallback { + /** + * receiveAmopMsg is called when get a subscribed topic amop msg. + * + * @param msg the received AMOP message + * @return response content + */ + public abstract byte[] receiveAmopMsg(AmopMsgIn msg); +} diff --git a/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/AmopImp.java b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/AmopImp.java new file mode 100644 index 000000000..dc44ad435 --- /dev/null +++ b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/AmopImp.java @@ -0,0 +1,279 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.amop; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import org.fisco.bcos.sdk.amop.exception.AmopException; +import org.fisco.bcos.sdk.amop.topic.AmopMsgHandler; +import org.fisco.bcos.sdk.amop.topic.TopicManager; +import org.fisco.bcos.sdk.channel.Channel; +import org.fisco.bcos.sdk.channel.ResponseCallback; +import org.fisco.bcos.sdk.channel.model.Options; +import org.fisco.bcos.sdk.config.ConfigOption; +import org.fisco.bcos.sdk.config.model.AmopTopic; +import org.fisco.bcos.sdk.crypto.keystore.KeyTool; +import org.fisco.bcos.sdk.crypto.keystore.P12KeyStore; +import org.fisco.bcos.sdk.crypto.keystore.PEMKeyStore; +import org.fisco.bcos.sdk.model.AmopMsg; +import org.fisco.bcos.sdk.model.Message; +import org.fisco.bcos.sdk.model.MsgType; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Amop implement + * + * @author Maggie + */ +public class AmopImp implements Amop { + private static Logger logger = LoggerFactory.getLogger(AmopImp.class); + private Channel channel; + private TopicManager topicManager; + private AmopMsgHandler amopMsgHandler; + + public AmopImp(Channel channel, ConfigOption config) { + this.channel = channel; + topicManager = new TopicManager(); + try { + loadConfiguredTopics(config); + } catch (AmopException e) { + logger.error("Amop topic is not configured right, error:{}", e); + } + amopMsgHandler = new AmopMsgHandler(this.channel, topicManager); + this.channel.addMessageHandler(MsgType.REQUEST_TOPICCERT, amopMsgHandler); + this.channel.addMessageHandler(MsgType.AMOP_REQUEST, amopMsgHandler); + this.channel.addMessageHandler(MsgType.AMOP_MULBROADCAST, amopMsgHandler); + this.channel.addMessageHandler(MsgType.AMOP_RESPONSE, amopMsgHandler); + this.channel.addEstablishHandler(amopMsgHandler); + } + + @Override + public void subscribeTopic(String topicName, AmopCallback callback) { + logger.info("subscribe normal topic, topic:{}", topicName); + topicManager.addTopic(topicName, callback); + sendSubscribe(); + } + + @Override + public void subscribePrivateTopics( + String topicName, KeyTool privateKeyTool, AmopCallback callback) { + logger.info("subscribe private topic, topic:{}", topicName); + topicManager.addPrivateTopicSubscribe(topicName, privateKeyTool, callback); + sendSubscribe(); + } + + @Override + public void publishPrivateTopic(String topicName, List publicKeyTools) { + logger.info( + "setup private topic, topic:{} pubKey len:{}", topicName, publicKeyTools.size()); + topicManager.addPrivateTopicSend(topicName, publicKeyTools); + sendSubscribe(); + } + + @Override + public void unsubscribeTopic(String topicName) { + logger.info("unsubscribe topic, topic:{}", topicName); + topicManager.removeTopic(topicName); + sendSubscribe(); + } + + @Override + public void sendAmopMsg(AmopMsgOut content, ResponseCallback callback) { + if (!topicManager.canSendTopicMsg(content)) { + logger.error( + "can not send this amop private msg out, you have not configured the public keys. topic:{}", + content.getTopic()); + } + AmopMsg msg = new AmopMsg(); + msg.setResult(0); + msg.setSeq(newSeq()); + msg.setType((short) MsgType.AMOP_REQUEST.getType()); + msg.setTopic(content.getTopic()); + msg.setData(content.getContent()); + Options ops = new Options(); + ops.setTimeout(content.getTimeout()); + this.channel.asyncSendToRandom(msg, callback, ops); + logger.info( + "send amop msg to a random peer, seq{} topic{}", msg.getSeq(), content.getTopic()); + } + + @Override + public void broadcastAmopMsg(AmopMsgOut content) { + if (!topicManager.canSendTopicMsg(content)) { + logger.error( + "can not send this amop private msg out, you have not configured the public keys. topic:{}", + content.getTopic()); + } + AmopMsg amopMsg = new AmopMsg(); + amopMsg.setResult(0); + amopMsg.setSeq(newSeq()); + amopMsg.setType((short) MsgType.AMOP_MULBROADCAST.getType()); + amopMsg.setTopic(content.getTopic()); + amopMsg.setData(content.getContent()); + // Add broadcast callback + this.channel.broadcast(amopMsg.getMessage()); + logger.info( + "broadcast amop msg to peers, seq:{} topic:{}", + amopMsg.getSeq(), + amopMsg.getTopic()); + } + + @Override + public Set getSubTopics() { + return topicManager.getTopicNames(); + } + + @Override + public List getTopicSubscribers(String topicName) { + return null; + } + + @Override + public void setCallback(AmopCallback cb) { + topicManager.setCallback(cb); + } + + @Override + public void start() { + logger.info("amop module started"); + amopMsgHandler.setIsRunning(true); + sendSubscribe(); + } + + @Override + public void stop() { + logger.info("amop module stopped"); + amopMsgHandler.setIsRunning(false); + unSubscribeAll(); + } + + @Override + public void waitFinishPrivateTopicVerify() { + // todo add wait function + } + + private void unSubscribeAll() { + List peers = this.channel.getAvailablePeer(); + logger.info("unsubscribe all topics, inform {} peers", peers.size()); + for (String peer : peers) { + try { + unSubscribeToPeer(peer); + } catch (JsonProcessingException e) { + logger.error("Unsubscribe failed", e); + } + } + } + + @Override + public void sendSubscribe() { + topicManager.updatePrivateTopicUUID(); + List peers = this.channel.getAvailablePeer(); + logger.info("update subscribe inform {} peers", peers.size()); + for (String peer : peers) { + try { + updateSubscribeToPeer(peer); + } catch (JsonProcessingException e) { + logger.error( + "update amop subscription to node {}, json processed error, error message: {}", + peer, + e.getMessage()); + } + } + } + + private void updateSubscribeToPeer(String peer) throws JsonProcessingException { + byte[] topics = getSubData(topicManager.getSubByPeer(peer)); + Message msg = new Message(); + msg.setType((short) MsgType.AMOP_CLIENT_TOPICS.getType()); + msg.setResult(0); + msg.setSeq(newSeq()); + msg.setData(topics); + Options opt = new Options(); + this.channel.asyncSendToPeer(msg, peer, null, opt); + logger.debug("update topics to node, node:{}, topics:{}", peer, new String(topics)); + } + + private void unSubscribeToPeer(String peer) throws JsonProcessingException { + Message msg = new Message(); + msg.setType((short) MsgType.AMOP_CLIENT_TOPICS.getType()); + msg.setResult(0); + msg.setSeq(newSeq()); + byte[] topics = getSubData(topicManager.getBlockNotifyByPeer(peer)); + msg.setData(topics); + Options opt = new Options(); + this.channel.asyncSendToPeer(msg, peer, null, opt); + logger.info( + " send update topic message request, seq: {}, content: {}", + msg.getSeq(), + new String(msg.getData())); + } + + private String newSeq() { + return UUID.randomUUID().toString().replaceAll("-", ""); + } + + private byte[] getSubData(Set topics) throws JsonProcessingException { + byte[] topicBytes = + ObjectMapperFactory.getObjectMapper().writeValueAsBytes(topics.toArray()); + return topicBytes; + } + + private void loadConfiguredTopics(ConfigOption config) throws AmopException { + if (null == config.getAmopConfig() || null == config.getAmopConfig().getAmopTopicConfig()) { + return; + } + List topics = config.getAmopConfig().getAmopTopicConfig(); + for (AmopTopic topic : topics) { + if (null != topic.getPrivateKey()) { + String privKeyFile = topic.getPrivateKey(); + KeyTool keyTool; + + if (privKeyFile.endsWith("p12")) { + keyTool = new P12KeyStore(privKeyFile, topic.getPassword()); + } else { + keyTool = new PEMKeyStore(privKeyFile); + } + topicManager.addPrivateTopicSubscribe(topic.getTopicName(), keyTool, null); + } else if (null != topic.getPublicKeys()) { + List pubList = new ArrayList<>(); + for (String pubKey : topic.getPublicKeys()) { + KeyTool keyTool = new PEMKeyStore(pubKey); + pubList.add(keyTool); + } + topicManager.addPrivateTopicSend(topic.getTopicName(), pubList); + } else { + throw new AmopException( + "Amop private topic is not configured right, please check your config file. Topic name " + + topic.getTopicName() + + ", neither private key nor public key list configured."); + } + } + } + + public Set getAllTopics() { + return topicManager.getAllTopics(); + } + + @Override + public TopicManager getTopicManager() { + return this.topicManager; + } +} diff --git a/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/AmopMsgOut.java b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/AmopMsgOut.java new file mode 100644 index 000000000..c4156297a --- /dev/null +++ b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/AmopMsgOut.java @@ -0,0 +1,69 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.amop; + +import org.fisco.bcos.sdk.amop.topic.TopicManager; +import org.fisco.bcos.sdk.amop.topic.TopicType; + +public class AmopMsgOut { + private String topic; + private byte[] content; + private TopicType type = TopicType.NORMAL_TOPIC; + private long timeout = 5000; + + public long getTimeout() { + return timeout; + } + + public void setTimeout(long timeout) { + this.timeout = timeout; + } + + public String getTopic() { + if (type.equals(TopicType.NORMAL_TOPIC)) { + return topic; + } else { + return addNeedVerifyTopicPrefix(topic); + } + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public byte[] getContent() { + return content; + } + + public void setContent(byte[] content) { + this.content = content; + } + + public TopicType getType() { + return type; + } + + public void setType(TopicType type) { + this.type = type; + } + + private String addNeedVerifyTopicPrefix(String topicName) { + StringBuilder sb = new StringBuilder(); + sb.append(TopicManager.topicNeedVerifyPrefix); + sb.append(topicName); + return sb.toString(); + } +} diff --git a/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/exception/AmopException.java b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/exception/AmopException.java new file mode 100644 index 000000000..3a2b2601b --- /dev/null +++ b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/exception/AmopException.java @@ -0,0 +1,30 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.amop.exception; + +public class AmopException extends Exception { + public AmopException(String message) { + super(message); + } + + public AmopException(Throwable cause) { + super(cause); + } + + public AmopException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/AmopMsgHandler.java b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/AmopMsgHandler.java new file mode 100644 index 000000000..b677c3da6 --- /dev/null +++ b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/AmopMsgHandler.java @@ -0,0 +1,396 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.amop.topic; + +import static org.fisco.bcos.sdk.amop.topic.TopicManager.verifyChannelPrefix; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.socket.SocketChannel; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import org.fisco.bcos.sdk.amop.Amop; +import org.fisco.bcos.sdk.amop.AmopCallback; +import org.fisco.bcos.sdk.channel.Channel; +import org.fisco.bcos.sdk.channel.ResponseCallback; +import org.fisco.bcos.sdk.channel.model.Options; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keystore.KeyTool; +import org.fisco.bcos.sdk.model.AmopMsg; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.Message; +import org.fisco.bcos.sdk.model.MsgType; +import org.fisco.bcos.sdk.model.Response; +import org.fisco.bcos.sdk.network.MsgHandler; +import org.fisco.bcos.sdk.utils.Hex; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AmopMsgHandler implements MsgHandler { + private static Logger logger = LoggerFactory.getLogger(AmopMsgHandler.class); + private TopicManager topicManager; + private Channel channel; + private long defaultTimeout = 5000; + private Map seq2Callback = new ConcurrentHashMap<>(); + private boolean isRunning = false; + + public AmopMsgHandler(Channel channel, TopicManager topicManager) { + this.topicManager = topicManager; + this.channel = channel; + } + + public void setIsRunning(boolean isRunning) { + this.isRunning = isRunning; + } + + @Override + public void onConnect(ChannelHandlerContext ctx) { + if (!isRunning) { + logger.warn("Amop on connect, amop is not running, exit."); + return; + } + + String host = ((SocketChannel) ctx.channel()).remoteAddress().getAddress().getHostAddress(); + Integer port = ((SocketChannel) ctx.channel()).remoteAddress().getPort(); + String ipAndPort = host + ":" + port; + logger.info("Node connected, update topics to node. node:" + ipAndPort); + try { + Set topics = topicManager.getSubByPeer(ipAndPort); + byte[] topicBytes = + ObjectMapperFactory.getObjectMapper().writeValueAsBytes(topics.toArray()); + Message msg = new Message(); + msg.setType((short) MsgType.AMOP_CLIENT_TOPICS.getType()); + msg.setResult(0); + msg.setSeq(newSeq()); + msg.setData(topicBytes); + ctx.writeAndFlush(msg); + } catch (JsonProcessingException e) { + logger.warn("Amop on connect, subscribe error: {}", e.getMessage()); + } + } + + @Override + public void onMessage(ChannelHandlerContext ctx, Message msg) { + logger.trace( + "receive msg, msg type:{}, content:{}", msg.getType(), new String(msg.getData())); + if (!isRunning) { + logger.warn("Amop on msg, amop is not running, exit."); + } + + if (msg.getType() == (short) MsgType.AMOP_RESPONSE.getType()) { + // Receive a signed Amop message for authorization. + onAmopResponse(ctx, msg); + return; + } + + if (msg.getType() == (short) MsgType.REQUEST_TOPICCERT.getType()) { + // As amop private topic message sender + onVerifyRequest(ctx, msg); + } else if (msg.getType() == (short) MsgType.AMOP_REQUEST.getType() + || msg.getType() == (short) MsgType.AMOP_MULBROADCAST.getType()) { + AmopMsg amopMsg = new AmopMsg(msg); + try { + amopMsg.decodeAmopBody(msg.getData()); + } catch (Exception e) { + logger.error( + "Receive an invalid message, msg type:{}, seq:{}", + msg.getType(), + msg.getSeq()); + return; + } + if (isVerifyingPrivateTopic(amopMsg)) { + // Receive a private topic authorization message. + onPrivateTopicRandomValue(ctx, amopMsg); + } else { + // Receive an Amop message. + onAmopMsg(ctx, amopMsg); + } + } else { + logger.error( + "amop module receive a not supported type message, type:{}", msg.getType()); + } + } + + @Override + public void onDisconnect(ChannelHandlerContext ctx) {} + + public void onVerifyRequest(ChannelHandlerContext ctx, Message msg) { + logger.trace( + "private topic verify step 1: node request random number. seq:{} type:{}, content:{}", + msg.getSeq(), + msg.getType(), + new String(msg.getData())); + // Response to node at the first time. + responseVerifyRequest(ctx, msg); + + // Start a verify procedure + // Read message data to RequestVerifyData + String content = new String(msg.getData()); + RequestVerifyData data; + try { + data = + ObjectMapperFactory.getObjectMapper() + .readValue(content, RequestVerifyData.class); + } catch (JsonProcessingException e) { + logger.error( + "receive request start private topic verify message, message is invalid, seq:{} msgtype:{}", + msg.getSeq(), + msg.getType()); + return; + } + String topic = data.getTopic(); + String nodeId = data.getNodeId(); + + logger.trace( + "private topic verify step 1: node request random number. seq:{} topic:{} nodeId:{}", + msg.getSeq(), + topic, + nodeId); + // Reply random value to node + String rmdString = UUID.randomUUID().toString().replaceAll("-", ""); + AmopMsg respMsg = new AmopMsg(); + respMsg.setType((short) MsgType.AMOP_REQUEST.getType()); + respMsg.setSeq(Amop.newSeq()); + respMsg.setResult(0); + respMsg.setData(rmdString.getBytes()); + respMsg.setTopic(data.getTopicForCert()); + // send message out + Options opt = new Options(); + opt.setTimeout(defaultTimeout); + ResponseCallback callback = + new ResponseCallback() { + @Override + public void onResponse(Response response) { + if (0 != response.getErrorCode()) { + logger.error( + "get random value signature of amop private topic failed :{}:{}", + response.getErrorCode(), + response.getErrorMessage()); + return; + } + AmopMsg amopMsg = new AmopMsg(); + amopMsg.decodeAmopBody(response.getContentBytes()); + int valid = checkSignature(topic, rmdString.getBytes(), amopMsg.getData()); + try { + sendUpdateTopicStatus(valid, topic, nodeId, ctx); + } catch (JsonProcessingException e) { + logger.error("update topic status error: {}", e.getMessage()); + } + } + }; + logger.trace( + "private topic verify step 2: send out random number. seq:{} topic:{} data:{}", + respMsg.getSeq(), + respMsg.getTopic(), + new String(respMsg.getData())); + channel.asyncSendToRandom(respMsg.getMessage(), callback, opt); + } + + public void responseVerifyRequest(ChannelHandlerContext ctx, Message msg) { + Message response = new Message(); + response.setSeq(msg.getSeq()); + response.setResult(0); + response.setType((short) MsgType.REQUEST_TOPICCERT.getType()); + response.setData("".getBytes()); + ctx.writeAndFlush(response); + } + + public int checkSignature(String topic, byte[] randomValue, byte[] signature) { + List pubKeys = topicManager.getPublicKeysByTopic(topic); + Iterator pks = pubKeys.iterator(); + while (pks.hasNext()) { + KeyTool keyTool = pks.next(); + CryptoSuite cryptoSuite = new CryptoSuite(CryptoType.ECDSA_TYPE); + if (cryptoSuite.verify( + keyTool, + Hex.toHexString(cryptoSuite.hash(randomValue)), + Hex.toHexString(signature))) { + return 0; + } + } + return 1; + } + + private boolean isVerifyingPrivateTopic(AmopMsg amopMsg) { + return amopMsg.getTopic().length() > verifyChannelPrefix.length() + && verifyChannelPrefix.equals( + amopMsg.getTopic().substring(0, verifyChannelPrefix.length())); + } + + private String getSimpleTopic(String fullTopic) { + return fullTopic.substring(verifyChannelPrefix.length(), fullTopic.length() - 33); + } + + public void onPrivateTopicRandomValue(ChannelHandlerContext ctx, AmopMsg msg) { + logger.trace( + "private topic verify step 2: receive random value, seq:{} type:{} topic:{} data:{}", + msg.getSeq(), + msg.getType(), + msg.getTopic(), + new String(msg.getData())); + byte[] randValue = msg.getData(); + String topic = msg.getTopic(); + KeyTool keyTool = topicManager.getPrivateKeyByTopic(getSimpleTopic(topic)); + String signature = ""; + if (null == keyTool) { + logger.error("topic:{} not subscribed, reject message", getSimpleTopic(topic)); + return; + } else { + CryptoSuite cryptoSuite = new CryptoSuite(CryptoType.ECDSA_TYPE); + try { + signature = cryptoSuite.sign(keyTool, Hex.toHexString(cryptoSuite.hash(randValue))); + } catch (Exception e) { + logger.error( + "please check the public key of topic {} is correct configured, error {}", + topic, + e.getMessage()); + } + } + sendSignedRandomNumber(signature, topic, msg.getSeq(), ctx); + } + + public void onAmopMsg(ChannelHandlerContext ctx, AmopMsg amopMsg) { + logger.debug( + "receive a Amop message. seq:{} msgtype:{}", amopMsg.getSeq(), amopMsg.getType()); + if (!topicManager.isSubTopic(amopMsg.getTopic())) { + logger.warn( + "receive an amop msg which is not subscribed, topic:{}", amopMsg.getTopic()); + return; + } + AmopCallback callback = topicManager.getCallback(amopMsg.getTopic()); + if (callback == null) { + logger.error( + "can not process Amop message, callback for topic {} is not found", + amopMsg.getTopic()); + return; + } + AmopMsgIn msgIn = new AmopMsgIn(); + msgIn.setTopic(amopMsg.getTopic()); + msgIn.setMessageID(amopMsg.getSeq()); + msgIn.setContent(amopMsg.getData()); + msgIn.setResult(amopMsg.getResult()); + msgIn.setCtx(ctx); + msgIn.setType(amopMsg.getType()); + byte[] content = callback.receiveAmopMsg(msgIn); + + // Response the amop msg + if (amopMsg.getType() == (short) MsgType.AMOP_MULBROADCAST.getType()) { + // If received a broadcast msg, do not response. + return; + } + amopMsg.setResult(0); + amopMsg.setType((short) MsgType.AMOP_RESPONSE.getType()); + amopMsg.setData(content); + logger.trace( + "Send response, seq:{} topic:{} content:{}", + amopMsg.getSeq(), + amopMsg.getTopic(), + new String(content)); + ctx.writeAndFlush(amopMsg.getMessage()); + } + + public void onAmopResponse(ChannelHandlerContext ctx, Message msg) { + logger.debug("receive amop response. seq:{} msgtype:{} ", msg.getSeq(), msg.getType()); + ResponseCallback callback = seq2Callback.get(msg.getSeq()); + if (null != callback) { + Response resp = new Response(); + resp.setMessageID(msg.getSeq()); + resp.setErrorCode(msg.getResult()); + if (msg.getResult() != 0) { + resp.setErrorMessage("response errors"); + } + // 103: the AMOP_requests or the AMOP_multicast_requests have been rejected due to + // over bandwidth limit + if (msg.getResult() + == AmopRespError.REJECT_AMOP_REQ_FOR_OVER_BANDWIDTHLIMIT.getError()) { + logger.error( + "AMOP request was rejected due to over bandwidth limit, message: {}", + msg.getSeq()); + resp.setErrorMessage("AMOP request was rejected due to over bandwidth limit"); + } + + if (msg.getResult() == AmopRespError.NO_AVAILABLE_SESSION.getError()) { + logger.error( + "AMOP request was rejected due to over bandwidth limit, message: {}", + msg.getSeq()); + resp.setErrorMessage("AMOP request was rejected due to over bandwidth limit"); + } + + if (msg.getData() != null) { + AmopMsg amopMsg = new AmopMsg(); + amopMsg.decodeAmopBody(msg.getData()); + resp.setContent(new String(amopMsg.getData())); + } + callback.onResponse(resp); + } else { + logger.error("can not found response callback, timeout:{}", msg.getData()); + return; + } + } + + private void sendSignedRandomNumber( + String signature, String topic, String seq, ChannelHandlerContext ctx) { + AmopMsg msg = new AmopMsg(); + msg.setTopic(topic); + msg.setResult(0); + msg.setSeq(seq); + msg.setType((short) MsgType.AMOP_RESPONSE.getType()); + msg.setData(Hex.decode(signature)); + logger.trace( + "private topic verify step 3: sign on random value and send out, seq:{} type:{} topic:{} data:{}", + msg.getSeq(), + msg.getType(), + msg.getTopic(), + new String(msg.getData())); + ctx.writeAndFlush(msg.getMessage()); + } + + public void sendUpdateTopicStatus( + int valid, String topic, String nodeId, ChannelHandlerContext ctx) + throws JsonProcessingException { + UpdateTopicStatus updateTopicStatus = new UpdateTopicStatus(); + updateTopicStatus.setCheckResult(valid); + updateTopicStatus.setNodeId(nodeId); + updateTopicStatus.setTopic(topic); + String jsonStr = + ObjectMapperFactory.getObjectMapper().writeValueAsString(updateTopicStatus); + + Message msg = new Message(); + msg.setData(jsonStr.getBytes()); + msg.setSeq(newSeq()); + msg.setResult(0); + msg.setType((short) MsgType.UPDATE_TOPIICSTATUS.getType()); + logger.info( + "private topic verify step4: finish signature verify, send out msg to update topic status, seq:{} topic:{} valid:{}", + msg.getSeq(), + topic, + valid); + ctx.writeAndFlush(msg); + } + + public void addCallback(String seq, ResponseCallback callback) { + seq2Callback.put(seq, callback); + } + + private String newSeq() { + return UUID.randomUUID().toString().replaceAll("-", ""); + } +} diff --git a/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/AmopMsgIn.java b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/AmopMsgIn.java new file mode 100644 index 000000000..233527201 --- /dev/null +++ b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/AmopMsgIn.java @@ -0,0 +1,63 @@ +package org.fisco.bcos.sdk.amop.topic; + +import io.netty.channel.ChannelHandlerContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AmopMsgIn { + private static Logger logger = LoggerFactory.getLogger(AmopMsgIn.class); + private String messageID; + private byte[] content; + private String topic; + private Integer result; + protected Short type = 0; + private ChannelHandlerContext ctx; + + public String getMessageID() { + return messageID; + } + + public void setMessageID(String messageID) { + this.messageID = messageID; + } + + public byte[] getContent() { + return content; + } + + public void setContent(byte[] content) { + this.content = content; + } + + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public ChannelHandlerContext getCtx() { + return ctx; + } + + public void setCtx(ChannelHandlerContext ctx) { + this.ctx = ctx; + } + + public Integer getResult() { + return result; + } + + public void setResult(Integer result) { + this.result = result; + } + + public Short getType() { + return type; + } + + public void setType(Short type) { + this.type = type; + } +} diff --git a/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/AmopRespError.java b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/AmopRespError.java new file mode 100644 index 000000000..d4c63c65d --- /dev/null +++ b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/AmopRespError.java @@ -0,0 +1,32 @@ +package org.fisco.bcos.sdk.amop.topic; + +public enum AmopRespError { + /** Error code from node. */ + // nodes unreachable + NODES_UNREACHABLE(99), + // send failed after N times retry + MESSAGE_SEND_EXCEPTION(100), + // timeout + MESSAGE_TIMEOUT(102), + // no available session + NO_AVAILABLE_SESSION(104), + // decode error + MESSAGE_DECODE_ERROR(105), + // the AMOP_requests or the AMOP_multicast_requests have been rejected due to over bandwidth + // limit + REJECT_AMOP_REQ_FOR_OVER_BANDWIDTHLIMIT(103); + + private int error; + + private AmopRespError(int error) { + this.setError(error); + } + + public int getError() { + return error; + } + + public void setError(int error) { + this.error = error; + } +} diff --git a/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/RequestVerifyData.java b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/RequestVerifyData.java new file mode 100644 index 000000000..8f1c6cf03 --- /dev/null +++ b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/RequestVerifyData.java @@ -0,0 +1,31 @@ +package org.fisco.bcos.sdk.amop.topic; + +public class RequestVerifyData { + private String topic; + private String topicForCert; + private String nodeId; + + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public String getTopicForCert() { + return topicForCert; + } + + public void setTopicForCert(String topicForCert) { + this.topicForCert = topicForCert; + } + + public String getNodeId() { + return nodeId; + } + + public void setNodeId(String nodeId) { + this.nodeId = nodeId; + } +} diff --git a/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/TopicManager.java b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/TopicManager.java new file mode 100644 index 000000000..18c85fa36 --- /dev/null +++ b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/TopicManager.java @@ -0,0 +1,218 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.amop.topic; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import org.fisco.bcos.sdk.amop.AmopCallback; +import org.fisco.bcos.sdk.amop.AmopMsgOut; +import org.fisco.bcos.sdk.crypto.keystore.KeyTool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TopicManager { + private static Logger logger = LoggerFactory.getLogger(TopicManager.class); + private Map topic2PrivateKey = new ConcurrentHashMap<>(); + private Map> topic2PublicKeys = new ConcurrentHashMap<>(); + private Map topicName2FullName = new ConcurrentHashMap<>(); + private Map topic2Callback = new ConcurrentHashMap<>(); + private Set topics = Collections.synchronizedSet(new HashSet<>()); + private Map> peer2BlockNotify = new ConcurrentHashMap<>(); + private AmopCallback callback; + + public static final String verifyChannelPrefix = "#!$VerifyChannel_"; + public static final String pushChannelPrefix = "#!$PushChannel_"; + public static final String topicNeedVerifyPrefix = "#!$TopicNeedVerify_"; + + public void addTopic(String topicString, AmopCallback callback) { + topics.add(topicString); + topicName2FullName.put(topicString, topicString); + if (callback != null) { + topic2Callback.put(topicString, callback); + } + } + + public void addPrivateTopicSubscribe( + String topicName, KeyTool privateKeyStore, AmopCallback callback) { + String fullNameToSendToNode = makeVerifyChannelPrefixTopic(topicName); + logger.trace( + "add private topic subscribe, topic:{} full name:{}", + topicName, + fullNameToSendToNode); + topics.add(fullNameToSendToNode); + topics.add(addNeedVerifyTopicPrefix(topicName)); + topic2PrivateKey.put(addNeedVerifyTopicPrefix(topicName), privateKeyStore); + topicName2FullName.put(topicName, fullNameToSendToNode); + if (callback != null) { + topic2Callback.put(addNeedVerifyTopicPrefix(topicName), callback); + } + } + + public void addPrivateTopicSend(String topicName, List publicKeyTools) { + String fullNameToSendToNode = makePushChannelPrefixTopic(topicName); + logger.trace( + "add private topic to send, topic:{} full name:{}", + topicName, + fullNameToSendToNode); + topics.add(fullNameToSendToNode); + topic2PublicKeys.put(addNeedVerifyTopicPrefix(topicName), publicKeyTools); + topicName2FullName.put(topicName, fullNameToSendToNode); + } + + public void addPrivateTopicCallback(String topicName, AmopCallback callback) { + logger.trace("add private topic callback, topic:{}", topicName); + topic2Callback.put(addNeedVerifyTopicPrefix(topicName), callback); + } + + /** + * Make sure do not use same name of a normal and a private topic remove the topic + * + * @param topicName the topic name + */ + public void removeTopic(String topicName) { + logger.trace("remove topic, topic:{}", topicName); + String fullName = topicName2FullName.get(topicName); + if (null != fullName) { + topics.remove(fullName); + topics.remove(addNeedVerifyTopicPrefix(topicName)); + topicName2FullName.remove(topicName); + topic2PublicKeys.remove(addNeedVerifyTopicPrefix(topicName)); + topic2PrivateKey.remove(addNeedVerifyTopicPrefix(topicName)); + if (fullName.length() > topicName.length()) { + topic2Callback.remove(addNeedVerifyTopicPrefix(topicName)); + } else { + topic2Callback.remove(topicName); + } + logger.trace("success remove topic, topic:{}", topicName); + } + } + + public Set getSubByPeer(String peerIpPort) { + Set notify = peer2BlockNotify.get(peerIpPort); + Set peerSub = new HashSet<>(); + if (topics != null) { + peerSub.addAll(topics); + } + if (notify != null) { + peerSub.addAll(notify); + } + logger.trace("get sub by peer, peer:{}, sub:{}", peerIpPort, peerSub.size()); + return peerSub; + } + + public Set getBlockNotifyByPeer(String peerIpPort) { + Set notify = peer2BlockNotify.get(peerIpPort); + Set peerSub = new HashSet<>(); + if (notify != null) { + peerSub.addAll(notify); + } + logger.trace("get sub by peer, peer:{}, sub:{}", peerIpPort, peerSub.size()); + return peerSub; + } + + public Set getTopicNames() { + return topicName2FullName.keySet(); + } + + public void updateBlockNotify(String peerIpPort, List groupInfo) { + logger.debug( + "update block notify, peer: {}, groupInfo: {}", peerIpPort, groupInfo.toString()); + Set pnf = new HashSet<>(); + for (String group : groupInfo) { + pnf.add("_block_notify_" + group); + logger.debug( + "add block notify, peer: {}, topic: {}", peerIpPort, "_block_notify_" + group); + } + peer2BlockNotify.put(peerIpPort, pnf); + } + + public AmopCallback getCallback(String topicName) { + if (topic2Callback.get(topicName) != null) { + return topic2Callback.get(topicName); + } else { + return callback; + } + } + + public String getFullTopicString(String topicName) { + return topicName2FullName.get(topicName); + } + + public void setCallback(AmopCallback cb) { + this.callback = cb; + } + + public List getPublicKeysByTopic(String topic) { + return topic2PublicKeys.get(topic); + } + + public KeyTool getPrivateKeyByTopic(String topic) { + return topic2PrivateKey.get(topic); + } + + public boolean isSubTopic(String topic) { + return topics.contains(topic); + } + + public boolean canSendTopicMsg(AmopMsgOut out) { + if (out.getType() == TopicType.NORMAL_TOPIC) { + return true; + } else { + return topic2PublicKeys.keySet().contains(out.getTopic()); + } + } + + public void updatePrivateTopicUUID() { + for (Map.Entry topic : topicName2FullName.entrySet()) { + if (topic.getValue().contains(verifyChannelPrefix)) { + topics.remove(topic.getValue()); + String newFullname = makeVerifyChannelPrefixTopic(topic.getKey()); + topics.add(newFullname); + topicName2FullName.put(topic.getKey(), newFullname); + logger.trace("update uuid, old:{} new:{}", topic.getValue(), newFullname); + } + } + } + + public Set getAllTopics() { + return topics; + } + + private String addNeedVerifyTopicPrefix(String topicName) { + StringBuilder sb = new StringBuilder(); + sb.append(topicNeedVerifyPrefix); + sb.append(topicName); + return sb.toString(); + } + + private String makeVerifyChannelPrefixTopic(String topicName) { + StringBuilder sb = new StringBuilder(); + sb.append(verifyChannelPrefix).append(addNeedVerifyTopicPrefix(topicName)).append('_'); + sb.append(UUID.randomUUID().toString().replaceAll("-", "")); + return sb.toString(); + } + + private String makePushChannelPrefixTopic(String topicName) { + StringBuilder sb = new StringBuilder(); + sb.append(pushChannelPrefix).append(addNeedVerifyTopicPrefix(topicName)); + return sb.toString(); + } +} diff --git a/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/TopicType.java b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/TopicType.java new file mode 100644 index 000000000..fef12aee5 --- /dev/null +++ b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/TopicType.java @@ -0,0 +1,7 @@ +package org.fisco.bcos.sdk.amop.topic; + +public enum TopicType { + /** normal topic and private topic */ + NORMAL_TOPIC, + PRIVATE_TOPIC; +} diff --git a/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/UpdateTopicStatus.java b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/UpdateTopicStatus.java new file mode 100644 index 000000000..dd3327ff8 --- /dev/null +++ b/sdk-amop/src/main/java/org/fisco/bcos/sdk/amop/topic/UpdateTopicStatus.java @@ -0,0 +1,31 @@ +package org.fisco.bcos.sdk.amop.topic; + +public class UpdateTopicStatus { + private int checkResult; + private String nodeId; + private String topic; + + public int getCheckResult() { + return checkResult; + } + + public void setCheckResult(int checkResult) { + this.checkResult = checkResult; + } + + public String getNodeId() { + return nodeId; + } + + public void setNodeId(String nodeId) { + this.nodeId = nodeId; + } + + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } +} diff --git a/sdk-amop/src/test/java/org/fisco/bcos/sdk/amop/AmopMsgHandlerTest.java b/sdk-amop/src/test/java/org/fisco/bcos/sdk/amop/AmopMsgHandlerTest.java new file mode 100644 index 000000000..b5071449b --- /dev/null +++ b/sdk-amop/src/test/java/org/fisco/bcos/sdk/amop/AmopMsgHandlerTest.java @@ -0,0 +1,228 @@ +package org.fisco.bcos.sdk.amop; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.ArrayList; +import java.util.List; +import org.fisco.bcos.sdk.amop.topic.AmopMsgHandler; +import org.fisco.bcos.sdk.amop.topic.AmopMsgIn; +import org.fisco.bcos.sdk.amop.topic.RequestVerifyData; +import org.fisco.bcos.sdk.amop.topic.TopicManager; +import org.fisco.bcos.sdk.channel.ResponseCallback; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keystore.KeyTool; +import org.fisco.bcos.sdk.crypto.keystore.P12KeyStore; +import org.fisco.bcos.sdk.crypto.keystore.PEMKeyStore; +import org.fisco.bcos.sdk.model.AmopMsg; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.Message; +import org.fisco.bcos.sdk.model.MsgType; +import org.fisco.bcos.sdk.model.Response; +import org.fisco.bcos.sdk.utils.Hex; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; +import org.junit.Assert; +import org.junit.Test; + +public class AmopMsgHandlerTest { + // Sender + private AmopMsgHandler msgHandlerSender; + private TopicManager topicManagerSender; + private MockChannel chSender = new MockChannel(); + + // Receiver + private AmopMsgHandler msgHandlerSub; + private MockChannel chSub = new MockChannel(); + + // Mock + private MockChannelHandlerContext ctxSender = new MockChannelHandlerContext(); + private MockChannelHandlerContext ctxSub = new MockChannelHandlerContext(); + + @Test + public void testGetVerifyRequest() { + initEnv(); + String topic = "test"; + byte[] data = "Tell you something.".getBytes(); + topicManagerSender.addTopic(topic, null); + TestAmopCallback cb1 = new TestAmopCallback(topic, data); + + topicManagerSender.setCallback(cb1); + msgHandlerSender.onMessage(ctxSender, getAmopMsg(topic, data).getMessage()); + AmopMsgIn in = cb1.getMsg(); + Assert.assertEquals(new String(in.getContent()), new String(data)); + } + + @Test + public void testRequestVerify() throws JsonProcessingException { + initEnv(); + + // node make request + RequestVerifyData rvd = new RequestVerifyData(); + rvd.setNodeId("127.0.0.1:8000"); + rvd.setTopic("#!$TopicNeedVerify_priv1"); + rvd.setTopicForCert( + "#!$VerifyChannel_#!$TopicNeedVerify_priv1_5e14c53197adbcb719d915fb93342c25"); + String jsonStr = ObjectMapperFactory.getObjectMapper().writeValueAsString(rvd); + Message msg = new Message(); + msg.setType((short) MsgType.REQUEST_TOPICCERT.getType()); + msg.setSeq(Amop.newSeq()); + msg.setResult(0); + msg.setData(jsonStr.getBytes()); + + // sender receive message from node + msgHandlerSender.onMessage(ctxSender, msg); + Message outMsg = chSender.getMsg(); + Assert.assertNotNull(outMsg); + Assert.assertTrue(outMsg.getType() == (short) MsgType.AMOP_REQUEST.getType()); + AmopMsg outAmopMsg = new AmopMsg(outMsg); + outAmopMsg.decodeAmopBody(outMsg.getData()); + Assert.assertEquals(32, new String(outAmopMsg.getData()).length()); + } + + @Test + public void testSignRandom() throws JsonProcessingException { + // init env + initEnv(); + + // sender generate random number + senderGenRandom(); + + // subscriber sign on random number + byte[] randomValue = suberSignOnRamdom(); + + // verify signature + Message signedRandom = ctxSub.getMsg(); + AmopMsg amopMsg = new AmopMsg(signedRandom); + + amopMsg.decodeAmopBody(signedRandom.getData()); + CryptoSuite cryptoSuite = new CryptoSuite(CryptoType.ECDSA_TYPE); + Assert.assertTrue(amopMsg.getType() == (short) MsgType.AMOP_RESPONSE.getType()); + Assert.assertEquals( + "#!$VerifyChannel_#!$TopicNeedVerify_priv1_5e14c53197adbcb719d915fb93342c25", + amopMsg.getTopic()); + String keyFile = + AmopMsgHandlerTest.class + .getClassLoader() + .getResource( + "keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.public.pem") + .getPath(); + KeyTool km = new PEMKeyStore(keyFile); + Assert.assertTrue( + cryptoSuite.verify( + km, + Hex.toHexString(cryptoSuite.hash(randomValue)), + Hex.toHexString(amopMsg.getData()))); + } + + @Test + public void testVerifySign() throws JsonProcessingException { + // init env + initEnv(); + + // sender generate random number + senderGenRandom(); + + // subscriber sign on random number + suberSignOnRamdom(); + + // response random to sender + ResponseCallback cb = chSender.getCallback(); + Message signedRandomMsg = ctxSub.getMsg(); + Response response = new Response(); + if (signedRandomMsg.getResult() != 0) { + response.setErrorMessage("Response error"); + } + response.setErrorCode(signedRandomMsg.getResult()); + response.setMessageID(signedRandomMsg.getSeq()); + response.setContentBytes(signedRandomMsg.getData()); + response.setCtx(ctxSender); + cb.onResponse(response); + + // check result + Message respMsg = ctxSub.getMsg(); + System.out.println(respMsg == null); + Assert.assertTrue(respMsg.getType() == (short) MsgType.UPDATE_TOPIICSTATUS.getType()); + Assert.assertEquals(0, respMsg.getResult().intValue()); + } + + private byte[] suberSignOnRamdom() { + Message outMsg = chSender.getMsg(); + msgHandlerSub.onMessage(ctxSub, outMsg); + AmopMsg amopOutMsg = new AmopMsg(outMsg); + amopOutMsg.decodeAmopBody(outMsg.getData()); + byte[] randomValue = amopOutMsg.getData(); + return randomValue; + } + + private void senderGenRandom() throws JsonProcessingException { + RequestVerifyData rvd = new RequestVerifyData(); + rvd.setNodeId("127.0.0.1:8000"); + rvd.setTopic("#!$TopicNeedVerify_priv1"); + rvd.setTopicForCert( + "#!$VerifyChannel_#!$TopicNeedVerify_priv1_5e14c53197adbcb719d915fb93342c25"); + String jsonStr = ObjectMapperFactory.getObjectMapper().writeValueAsString(rvd); + Message msg = new Message(); + msg.setType((short) MsgType.REQUEST_TOPICCERT.getType()); + msg.setSeq(Amop.newSeq()); + msg.setResult(0); + msg.setData(jsonStr.getBytes()); + msgHandlerSender.onMessage(ctxSub, msg); + } + + private void initEnv() { + topicManagerSender = new TopicManager(); + msgHandlerSender = new AmopMsgHandler(chSender, topicManagerSender); + List list = new ArrayList<>(); + String keyFile = + AmopMsgHandlerTest.class + .getClassLoader() + .getResource( + "keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.public.pem") + .getPath(); + list.add(new PEMKeyStore(keyFile)); + topicManagerSender.addPrivateTopicSend("priv1", list); + + TopicManager topicManagerSub; + topicManagerSub = new TopicManager(); + msgHandlerSub = new AmopMsgHandler(chSub, topicManagerSub); + String privKey = + AmopMsgHandlerTest.class + .getClassLoader() + .getResource( + "keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.p12") + .getPath(); + topicManagerSub.addPrivateTopicSubscribe("priv1", new P12KeyStore(privKey, "123456"), null); + } + + private AmopMsg getAmopMsg(String topic, byte[] content) { + AmopMsg msg = new AmopMsg(); + msg.setSeq(Amop.newSeq()); + msg.setType((short) MsgType.AMOP_REQUEST.getType()); + msg.setResult(0); + msg.setTopic(topic); + msg.setData(content); + return msg; + } + + public class TestAmopCallback extends AmopCallback { + private byte[] content; + private String topic; + private AmopMsgIn msg; + + public TestAmopCallback(String topic, byte[] content) { + this.content = content; + this.topic = topic; + } + + @Override + public byte[] receiveAmopMsg(AmopMsgIn msg) { + this.msg = msg; + Assert.assertTrue(msg.getTopic().equals(topic)); + Assert.assertEquals(msg.getContent().length, content.length); + Assert.assertTrue(new String(msg.getContent()).equals(new String(content))); + return "I received".getBytes(); + } + + public AmopMsgIn getMsg() { + return msg; + } + } +} diff --git a/sdk-amop/src/test/java/org/fisco/bcos/sdk/amop/ConfigTest.java b/sdk-amop/src/test/java/org/fisco/bcos/sdk/amop/ConfigTest.java new file mode 100644 index 000000000..e246164ad --- /dev/null +++ b/sdk-amop/src/test/java/org/fisco/bcos/sdk/amop/ConfigTest.java @@ -0,0 +1,57 @@ +package org.fisco.bcos.sdk.amop; + +import java.util.Set; +import org.fisco.bcos.sdk.config.Config; +import org.fisco.bcos.sdk.config.ConfigOption; +import org.fisco.bcos.sdk.config.exceptions.ConfigException; +import org.fisco.bcos.sdk.model.CryptoType; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +public class ConfigTest { + private static final String senderConfig = + ConfigTest.class + .getClassLoader() + .getResource("amop/config-publisher-for-test.toml") + .getPath(); + private static final String subscriberConfig = + ConfigTest.class + .getClassLoader() + .getResource("amop/config-subscriber-for-test.toml") + .getPath(); + + @Ignore + @Test + public void testConfigSenderAmop() throws ConfigException { + System.out.println(senderConfig); + ConfigOption configOption = Config.load(senderConfig, CryptoType.ECDSA_TYPE); + AmopImp amopImp = new AmopImp(new MockChannel(), configOption); + + Set topics = amopImp.getAllTopics(); + for (String topic : topics) { + if (topic.length() > 29) { + Assert.assertEquals("#!$PushChannel_#!$TopicNeedVerify_privTopic", topic); + } else { + Assert.assertEquals("#!$TopicNeedVerify_privTopic", topic); + } + } + } + + @Ignore + @Test + public void testConfigSubscriberAmop() throws ConfigException { + ConfigOption configOption = Config.load(subscriberConfig, CryptoType.ECDSA_TYPE); + AmopImp amopImp = new AmopImp(new MockChannel(), configOption); + + Set topics = amopImp.getAllTopics(); + for (String topic : topics) { + if (topic.length() > 29) { + Assert.assertEquals( + "#!$VerifyChannel_#!$TopicNeedVerify_privTopic", topic.substring(0, 45)); + } else { + Assert.assertEquals("#!$TopicNeedVerify_privTopic", topic); + } + } + } +} diff --git a/sdk-amop/src/test/java/org/fisco/bcos/sdk/amop/MockChannel.java b/sdk-amop/src/test/java/org/fisco/bcos/sdk/amop/MockChannel.java new file mode 100644 index 000000000..8d4ebef0b --- /dev/null +++ b/sdk-amop/src/test/java/org/fisco/bcos/sdk/amop/MockChannel.java @@ -0,0 +1,124 @@ +package org.fisco.bcos.sdk.amop; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import org.fisco.bcos.sdk.channel.Channel; +import org.fisco.bcos.sdk.channel.PeerSelectRule; +import org.fisco.bcos.sdk.channel.ResponseCallback; +import org.fisco.bcos.sdk.channel.model.Options; +import org.fisco.bcos.sdk.model.Message; +import org.fisco.bcos.sdk.model.MsgType; +import org.fisco.bcos.sdk.model.Response; +import org.fisco.bcos.sdk.network.ConnectionInfo; +import org.fisco.bcos.sdk.network.MsgHandler; +import org.fisco.bcos.sdk.network.Network; + +public class MockChannel implements Channel { + + private Message msg; + private ResponseCallback callback; + + public Message getMsg() { + return msg; + } + + @Override + public Network getNetwork() { + return null; + } + + @Override + public void start() { + // do nothing + } + + @Override + public void stop() { + // do nothing + } + + @Override + public void addMessageHandler(MsgType type, MsgHandler handler) { + // do nothing + } + + @Override + public void addConnectHandler(MsgHandler handler) { + // do nothing + } + + @Override + public void addEstablishHandler(MsgHandler handler) { + // do nothing + } + + @Override + public void addDisconnectHandler(MsgHandler handler) { + // do nothing + } + + @Override + public void broadcastToGroup(Message out, String groupId) { + // do nothing + } + + @Override + public void broadcast(Message out) {} + + @Override + public Response sendToPeer(Message out, String peerIpPort) { + return null; + } + + @Override + public Response sendToPeerWithTimeOut(Message out, String peerIpPort, Options options) { + return null; + } + + @Override + public Response sendToRandomWithTimeOut(Message out, Options options) { + return null; + } + + @Override + public Response sendToPeerByRuleWithTimeOut(Message out, PeerSelectRule rule, Options options) { + return null; + } + + @Override + public void asyncSendToPeer( + Message out, String peerIpPort, ResponseCallback callback, Options options) { + // do nothing + } + + @Override + public void asyncSendToRandom(Message out, ResponseCallback callback, Options options) { + msg = out; + this.callback = callback; + } + + @Override + public void asyncSendToPeerByRule( + Message out, PeerSelectRule rule, ResponseCallback callback, Options options) { + // do nothing + } + + @Override + public List getConnectionInfo() { + return null; + } + + @Override + public List getAvailablePeer() { + List list = new ArrayList<>(); + return list; + } + + @Override + public void setThreadPool(ExecutorService threadPool) {} + + public ResponseCallback getCallback() { + return callback; + } +} diff --git a/sdk-amop/src/test/java/org/fisco/bcos/sdk/amop/MockChannelHandlerContext.java b/sdk-amop/src/test/java/org/fisco/bcos/sdk/amop/MockChannelHandlerContext.java new file mode 100644 index 000000000..edc95afb0 --- /dev/null +++ b/sdk-amop/src/test/java/org/fisco/bcos/sdk/amop/MockChannelHandlerContext.java @@ -0,0 +1,230 @@ +package org.fisco.bcos.sdk.amop; + +import io.netty.buffer.ByteBufAllocator; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelProgressivePromise; +import io.netty.channel.ChannelPromise; +import io.netty.util.Attribute; +import io.netty.util.AttributeKey; +import io.netty.util.concurrent.EventExecutor; +import java.net.SocketAddress; +import org.fisco.bcos.sdk.model.Message; + +public class MockChannelHandlerContext implements ChannelHandlerContext { + private Message msg; + + public Message getMsg() { + return msg; + } + + @Override + public Channel channel() { + return null; + } + + @Override + public EventExecutor executor() { + return null; + } + + @Override + public String name() { + return null; + } + + @Override + public ChannelHandler handler() { + return null; + } + + @Override + public boolean isRemoved() { + return false; + } + + @Override + public ChannelHandlerContext fireChannelRegistered() { + return null; + } + + @Override + public ChannelHandlerContext fireChannelUnregistered() { + return null; + } + + @Override + public ChannelHandlerContext fireChannelActive() { + return null; + } + + @Override + public ChannelHandlerContext fireChannelInactive() { + return null; + } + + @Override + public ChannelHandlerContext fireExceptionCaught(Throwable cause) { + return null; + } + + @Override + public ChannelHandlerContext fireUserEventTriggered(Object evt) { + return null; + } + + @Override + public ChannelHandlerContext fireChannelRead(Object msg) { + return null; + } + + @Override + public ChannelHandlerContext fireChannelReadComplete() { + return null; + } + + @Override + public ChannelHandlerContext fireChannelWritabilityChanged() { + return null; + } + + @Override + public ChannelFuture connect(SocketAddress remoteAddress) { + return null; + } + + @Override + public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) { + return null; + } + + @Override + public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) { + return null; + } + + @Override + public ChannelFuture connect( + SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) { + return null; + } + + @Override + public ChannelFuture disconnect() { + return null; + } + + @Override + public ChannelFuture disconnect(ChannelPromise promise) { + return null; + } + + @Override + public ChannelFuture close() { + return null; + } + + @Override + public ChannelFuture close(ChannelPromise promise) { + return null; + } + + @Override + public ChannelFuture deregister() { + return null; + } + + @Override + public ChannelFuture deregister(ChannelPromise promise) { + return null; + } + + @Override + public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) { + return null; + } + + @Override + public ChannelFuture bind(SocketAddress localAddress) { + return null; + } + + @Override + public ChannelHandlerContext read() { + return null; + } + + @Override + public ChannelFuture write(Object msg) { + return null; + } + + @Override + public ChannelFuture write(Object msg, ChannelPromise promise) { + return null; + } + + @Override + public ChannelHandlerContext flush() { + return null; + } + + @Override + public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) { + return null; + } + + @Override + public ChannelFuture writeAndFlush(Object msg) { + this.msg = (Message) msg; + return null; + } + + @Override + public ChannelPromise newPromise() { + return null; + } + + @Override + public ChannelProgressivePromise newProgressivePromise() { + return null; + } + + @Override + public ChannelFuture newSucceededFuture() { + return null; + } + + @Override + public ChannelFuture newFailedFuture(Throwable cause) { + return null; + } + + @Override + public ChannelPromise voidPromise() { + return null; + } + + @Override + public ChannelPipeline pipeline() { + return null; + } + + @Override + public ByteBufAllocator alloc() { + return null; + } + + @Override + public Attribute attr(AttributeKey key) { + return null; + } + + @Override + public boolean hasAttr(AttributeKey key) { + return false; + } +} diff --git a/sdk-amop/src/test/java/org/fisco/bcos/sdk/amop/TopicManagerTest.java b/sdk-amop/src/test/java/org/fisco/bcos/sdk/amop/TopicManagerTest.java new file mode 100644 index 000000000..e4ea370c8 --- /dev/null +++ b/sdk-amop/src/test/java/org/fisco/bcos/sdk/amop/TopicManagerTest.java @@ -0,0 +1,171 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.amop; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import org.fisco.bcos.sdk.amop.topic.AmopMsgIn; +import org.fisco.bcos.sdk.amop.topic.TopicManager; +import org.fisco.bcos.sdk.crypto.keystore.KeyTool; +import org.fisco.bcos.sdk.crypto.keystore.PEMKeyStore; +import org.junit.Assert; +import org.junit.Test; + +public class TopicManagerTest { + private AmopCallback cb1 = new TestAmopCallback(); + private AmopCallback cb2 = new TestAmopCallback(); + private AmopCallback cb3 = new TestAmopCallback(); + + @Test + public void testAddTopic() { + TopicManager topicManager = new TopicManager(); + topicManager.addTopic("test", null); + Assert.assertEquals("test", topicManager.getFullTopicString("test")); + + String keyFile = + TopicManagerTest.class + .getClassLoader() + .getResource( + "keystore/ecdsa/0x0fc3c4bb89bd90299db4c62be0174c4966286c00.pem") + .getPath(); + KeyTool keyTool = new PEMKeyStore(keyFile); + topicManager.addPrivateTopicSubscribe("priv", keyTool, null); + Assert.assertEquals( + "#!$TopicNeedVerify_priv", + topicManager.getFullTopicString("priv").substring(17, 40)); + + List list = new ArrayList<>(); + list.add(keyTool); + topicManager.addPrivateTopicSend("priv2", list); + Assert.assertEquals( + "#!$PushChannel_#!$TopicNeedVerify_priv2", + topicManager.getFullTopicString("priv2")); + + Set topics = topicManager.getTopicNames(); + Assert.assertTrue(topics.contains("test")); + Assert.assertEquals(3, topics.size()); + Assert.assertTrue(topics.contains("priv")); + Assert.assertTrue(topics.contains("priv2")); + } + + @Test + public void testCallback() { + TopicManager topicManager = getTestTopicManager(); + // test set default callback + Assert.assertNull(topicManager.getCallback("test")); + topicManager.setCallback(cb1); + Assert.assertNotNull(topicManager.getCallback("test")); + Assert.assertEquals(cb1, topicManager.getCallback("test")); + + // test set spacial callback + topicManager.addTopic("test", cb2); + Assert.assertEquals(cb2, topicManager.getCallback("test")); + + // test set private topic callback + topicManager.addPrivateTopicCallback("priv", cb3); + Assert.assertEquals(cb3, topicManager.getCallback("#!$TopicNeedVerify_priv")); + } + + @Test + public void testRemoveTopic() { + TopicManager topicManager = getTestTopicManager(); + topicManager.setCallback(cb1); + Set topics = topicManager.getTopicNames(); + Assert.assertTrue(topics.contains("priv2")); + Assert.assertEquals(cb3, topicManager.getCallback("#!$TopicNeedVerify_priv2")); + Assert.assertNotNull(topicManager.getPublicKeysByTopic("#!$TopicNeedVerify_priv2")); + Assert.assertEquals(3, topics.size()); + Assert.assertNull(topicManager.getPrivateKeyByTopic("#!$TopicNeedVerify_priv2")); + + topicManager.removeTopic("priv2"); + topics = topicManager.getTopicNames(); + Assert.assertFalse(topics.contains("priv2")); + Assert.assertEquals(cb1, topicManager.getCallback("#!$TopicNeedVerify_priv2")); + Assert.assertNull(topicManager.getPublicKeysByTopic("#!$TopicNeedVerify_priv2")); + Assert.assertEquals(2, topics.size()); + Assert.assertNull(topicManager.getPrivateKeyByTopic("#!$TopicNeedVerify_priv2")); + } + + @Test + public void testBlockNotify() { + TopicManager tm = getTestTopicManager(); + List group = new ArrayList<>(); + group.add("1"); + group.add("2"); + tm.updateBlockNotify("127.0.0.1:3033", group); + + Set topics = tm.getSubByPeer("127.0.0.1:3033"); + Assert.assertEquals(6, topics.size()); + Assert.assertTrue(topics.contains("_block_notify_1")); + Assert.assertTrue(topics.contains("_block_notify_2")); + + topics = tm.getSubByPeer("127.0.0.1:8000"); + Assert.assertEquals(4, topics.size()); + Assert.assertFalse(topics.contains("_block_notify_1")); + Assert.assertFalse(topics.contains("_block_notify_2")); + } + + @Test + public void testUpdateUUID() { + TopicManager tm = getTestTopicManager(); + Set topics = tm.getSubByPeer("127.0.0.1:3033"); + String before = ""; + String after = ""; + for (String topic : topics) { + if (topic.startsWith("#!$VerifyChannel_#!")) { + before = topic; + break; + } + } + tm.updatePrivateTopicUUID(); + topics = tm.getSubByPeer("127.0.0.1:3033"); + for (String topic : topics) { + if (topic.startsWith("#!$VerifyChannel_#!")) { + after = topic; + break; + } + } + Assert.assertFalse(before.equals(after)); + } + + private TopicManager getTestTopicManager() { + TopicManager topicManager = new TopicManager(); + topicManager.addTopic("test", null); + String keyFile = + TopicManagerTest.class + .getClassLoader() + .getResource( + "keystore/ecdsa/0x0fc3c4bb89bd90299db4c62be0174c4966286c00.pem") + .getPath(); + KeyTool keyTool = new PEMKeyStore(keyFile); + topicManager.addPrivateTopicSubscribe("priv", keyTool, null); + List list = new ArrayList<>(); + list.add(keyTool); + topicManager.addPrivateTopicSend("priv2", list); + topicManager.addPrivateTopicCallback("priv2", cb3); + return topicManager; + } + + public class TestAmopCallback extends AmopCallback { + + @Override + public byte[] receiveAmopMsg(AmopMsgIn msg) { + // do nothing + return "".getBytes(); + } + } +} diff --git a/sdk-amop/src/test/resources/keystore/ecdsa/0x0fc3c4bb89bd90299db4c62be0174c4966286c00.pem b/sdk-amop/src/test/resources/keystore/ecdsa/0x0fc3c4bb89bd90299db4c62be0174c4966286c00.pem new file mode 100644 index 000000000..b448c4cd7 --- /dev/null +++ b/sdk-amop/src/test/resources/keystore/ecdsa/0x0fc3c4bb89bd90299db4c62be0174c4966286c00.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgvFFrJgDuw6IW9FfcFM+D +oB7SLQ/CFJ/JEdwuxIb+V6OhRANCAATbv+5PdvWjvD28LmEnxKH1C3YUv/QTikSn +mu09QvZ/nHqnBXAgX5tgpYiMZBW2qDABJne0QVp5zNFTP+VjeGHf +-----END PRIVATE KEY----- diff --git a/sdk-amop/src/test/resources/keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.p12 b/sdk-amop/src/test/resources/keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.p12 new file mode 100644 index 000000000..09388e9a7 Binary files /dev/null and b/sdk-amop/src/test/resources/keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.p12 differ diff --git a/sdk-amop/src/test/resources/keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.public.pem b/sdk-amop/src/test/resources/keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.public.pem new file mode 100644 index 000000000..0b6ef051e --- /dev/null +++ b/sdk-amop/src/test/resources/keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.public.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE17ngD1bT95MFNZ+i19sWYCHnMIa9zS56 +KNbtJzReHy3ez4XbdDjoRX/UdO+cTOuJq7fV+mCiLykC7CbcpSrV5Q== +-----END PUBLIC KEY----- diff --git a/sdk-amop/src/test/resources/keystore/ecdsa/invalid.p12 b/sdk-amop/src/test/resources/keystore/ecdsa/invalid.p12 new file mode 100644 index 000000000..5e5138794 Binary files /dev/null and b/sdk-amop/src/test/resources/keystore/ecdsa/invalid.p12 differ diff --git a/sdk-amop/src/test/resources/keystore/ecdsa/invalid.pem b/sdk-amop/src/test/resources/keystore/ecdsa/invalid.pem new file mode 100644 index 000000000..ecc335ea0 --- /dev/null +++ b/sdk-amop/src/test/resources/keystore/ecdsa/invalid.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgvFFrJgDuw6IW9FfcFM+D +oB7SLQ/CFJ/JEdwuxIb+V6OhRANCAATbv+5PdvWjvD28LmEnxKH1C3YUv/QTikSn +mu09QvZ/nHqnBXAgX5tgpYiMZBW2qDABJne0QVp5zNFTP+VjeGf +-----END PRIVATE KEY----- diff --git a/sdk-amop/src/test/resources/keystore/gm/0x40b3558746e8f9a47a474774e8c4a9e67d4e3174.pem b/sdk-amop/src/test/resources/keystore/gm/0x40b3558746e8f9a47a474774e8c4a9e67d4e3174.pem new file mode 100644 index 000000000..f5395940b --- /dev/null +++ b/sdk-amop/src/test/resources/keystore/gm/0x40b3558746e8f9a47a474774e8c4a9e67d4e3174.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgkBdEw04q3/yf1/sS +6Mui2Ip5qvVL6bThFmAVModInxOhRANCAAQ7cs0oJEyFbT2Jtn0cX/IuHyaDW6/N +Y+mkrTQkoqV/K3WRSfRsaW3wi52Uc2hmdfxtredE0Mgr3FWY11ngFf2W +-----END PRIVATE KEY----- diff --git a/sdk-amop/src/test/resources/keystore/gm/0x6f68461309925093236df82b51df630a55d32377.p12 b/sdk-amop/src/test/resources/keystore/gm/0x6f68461309925093236df82b51df630a55d32377.p12 new file mode 100644 index 000000000..367c17da1 Binary files /dev/null and b/sdk-amop/src/test/resources/keystore/gm/0x6f68461309925093236df82b51df630a55d32377.p12 differ diff --git a/sdk-amop/src/test/resources/keystore/gm/invalid.p12 b/sdk-amop/src/test/resources/keystore/gm/invalid.p12 new file mode 100644 index 000000000..60862eb2f Binary files /dev/null and b/sdk-amop/src/test/resources/keystore/gm/invalid.p12 differ diff --git a/sdk-amop/src/test/resources/keystore/gm/invalid.pem b/sdk-amop/src/test/resources/keystore/gm/invalid.pem new file mode 100644 index 000000000..d63a94f80 --- /dev/null +++ b/sdk-amop/src/test/resources/keystore/gm/invalid.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgkBdEw04q3/yf1/sS +6Mui2Ip5qvVL6bThFmAVModInxOhRANCAAQ7cs0oJEyFbT2Jtn0cX/IuHyaDW6/N +Y+mkrTQkoqV/K3WRSfRsaW3wi52Uc2hmdfxtredE0Mgr3FWY11ngFf2 +-----END PRIVATE KEY----- diff --git a/sdk-codegen/build.gradle b/sdk-codegen/build.gradle new file mode 100644 index 000000000..73962b2b6 --- /dev/null +++ b/sdk-codegen/build.gradle @@ -0,0 +1,53 @@ +// Apply the java-library plugin to add support for Java Library +plugins { + id 'java' +} +dependencies { + compile project(':sdk-transaction') + compile ("com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}") + compile ("com.squareup:javapoet:${javapoetVersion}") + compile ("info.picocli:picocli:${picocliVersion}") +} + +uploadArchives { + repositories { + mavenDeployer { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + + repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { + authentication(userName: ossrhUsername, password: ossrhPassword) + } + + snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { + authentication(userName: ossrhUsername, password: ossrhPassword) + } + + pom.project { + name project.name + packaging 'jar' + description = 'fisco-bcos java-sdk' + url = 'http://www.fisco-bcos.org' + + scm { + connection = 'https://github.com/FISCO-BCOS/java-sdk.git' + url = 'https://github.com/FISCO-BCOS/java-sdk.git' + } + + licenses { + license { + name = 'The Apache License, Version 2.0' + url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + + developers { + developer { + id = 'zhangsan' + name = 'zhangsan' + email = 'zhangsan@example.com' + } + } + } + } + } +} diff --git a/sdk-codegen/src/main/java/org/fisco/bcos/sdk/codegen/CodeGenMain.java b/sdk-codegen/src/main/java/org/fisco/bcos/sdk/codegen/CodeGenMain.java new file mode 100644 index 000000000..94275231f --- /dev/null +++ b/sdk-codegen/src/main/java/org/fisco/bcos/sdk/codegen/CodeGenMain.java @@ -0,0 +1,87 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.codegen; + +import static org.fisco.bcos.sdk.utils.Collection.tail; + +import java.io.File; +import picocli.CommandLine; +import picocli.CommandLine.Command; +import picocli.CommandLine.Option; + +public class CodeGenMain { + public static final String COMMAND_SOLIDITY = "solidity"; + public static final String COMMAND_GENERATE = "generate"; + public static final String COMMAND_PREFIX = COMMAND_SOLIDITY + " " + COMMAND_GENERATE; + + public static void main(String[] args) { + if (args.length > 0 + && (args[0].equals(COMMAND_SOLIDITY) || args[0].equals(COMMAND_GENERATE))) { + args = tail(args); + } + CommandLine.run(new PicocliRunner(), args); + } + + @Command( + name = COMMAND_PREFIX, + mixinStandardHelpOptions = true, + version = "4.0", + sortOptions = false) + static class PicocliRunner implements Runnable { + @Option( + names = {"-a", "--abiFile"}, + description = "abi file with contract definition.", + required = true) + private File abiFile; + + @Option( + names = {"-b", "--binFile"}, + description = + "bin file with contract compiled code " + + "in order to generate deploy methods.", + required = true) + private File binFile; + + @Option( + names = {"-s", "--smBinFile"}, + description = + "sm bin file with contract compiled code " + + "in order to generate deploy methods.", + required = true) + private File smBinFile; + + @Option( + names = {"-o", "--outputDir"}, + description = "destination base directory.", + required = true) + private File destinationFileDir; + + @Option( + names = {"-p", "--package"}, + description = "base package name.", + required = true) + private String packageName; + + @Override + public void run() { + try { + new SolidityContractGenerator( + binFile, smBinFile, abiFile, destinationFileDir, packageName) + .generateJavaFiles(); + } catch (Exception e) { + CodeGenUtils.exitError(e); + } + } + } +} diff --git a/sdk-codegen/src/main/java/org/fisco/bcos/sdk/codegen/CodeGenUtils.java b/sdk-codegen/src/main/java/org/fisco/bcos/sdk/codegen/CodeGenUtils.java new file mode 100644 index 000000000..ad8c49a17 --- /dev/null +++ b/sdk-codegen/src/main/java/org/fisco/bcos/sdk/codegen/CodeGenUtils.java @@ -0,0 +1,98 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.codegen; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import org.fisco.bcos.sdk.abi.wrapper.ABIDefinition; +import org.fisco.bcos.sdk.codegen.exceptions.CodeGenException; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; + +public final class CodeGenUtils { + public static String parsePositionalArg(String[] args, int idx) { + if (args != null && args.length > idx) { + return args[idx]; + } else { + return ""; + } + } + + public static String parseParameterArgument(String[] args, String... parameters) { + for (String parameter : parameters) { + for (int i = 0; i < args.length; i++) { + if (args[i].equals(parameter) && i + 1 < args.length) { + String parameterValue = args[i + 1]; + if (!parameterValue.startsWith("-")) { + return parameterValue; + } + } + } + } + return ""; + } + + public static String getFileNameNoExtension(String fileName) { + String[] splitName = fileName.split("\\.(?=[^.]*$)"); + return splitName[0]; + } + + // load abi from the abi file + public static List loadContractAbiDefinition(File abiFile) + throws CodeGenException { + try { + return ObjectMapperFactory.getObjectMapper() + .readValue(abiFile, new TypeReference>() {}); + } catch (IOException e) { + throw new CodeGenException( + "loadContractAbiDefinition for " + + abiFile.getName().toString() + + " failed, error info: " + + e.getLocalizedMessage(), + e); + } + } + + public static List loadContractAbiDefinition(String abi) throws IOException { + ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(); + ABIDefinition[] abiDefinition = objectMapper.readValue(abi, ABIDefinition[].class); + return Arrays.asList(abiDefinition); + } + + public static byte[] readBytes(File file) throws CodeGenException, IOException { + byte[] bytes = new byte[(int) file.length()]; + FileInputStream fileInputStream = null; + try { + fileInputStream = new FileInputStream(file); + fileInputStream.read(bytes); + } catch (IOException e) { + throw new CodeGenException( + "read data from " + file + " failed, error information: " + e.getMessage(), e); + } finally { + if (fileInputStream != null) { + fileInputStream.close(); + } + } + return bytes; + } + + public static void exitError(Throwable throwable) { + System.err.println(throwable.getMessage()); + System.exit(1); + } +} diff --git a/sdk-codegen/src/main/java/org/fisco/bcos/sdk/codegen/SolidityContractGenerator.java b/sdk-codegen/src/main/java/org/fisco/bcos/sdk/codegen/SolidityContractGenerator.java new file mode 100644 index 000000000..6a9b091e8 --- /dev/null +++ b/sdk-codegen/src/main/java/org/fisco/bcos/sdk/codegen/SolidityContractGenerator.java @@ -0,0 +1,82 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.codegen; + +import java.io.File; +import java.io.IOException; +import org.fisco.bcos.sdk.codegen.exceptions.CodeGenException; + +/** Java wrapper source code generator for Solidity ABI format. */ +public class SolidityContractGenerator { + public static final String COMMAND_SOLIDITY = "solidity"; + public static final String COMMAND_GENERATE = "generate"; + public static final String COMMAND_PREFIX = COMMAND_SOLIDITY + " " + COMMAND_GENERATE; + + /* + * Usage: solidity generate [-hV] [-jt] [-st] -a= [-b=] + * -o= -p= + * -h, --help Show this help message and exit. + * -V, --version Print version information and exit. + * -a, --abiFile= abi file with contract definition. + * -b, --binFile= bin file with contract compiled code in order to + * generate deploy methods. + * -s, --smBinFile= sm bin file with contract compiled code in order to + * generate deploy methods. + * -o, --outputDir= + * destination base directory. + * -p, --package= + * base package name. + * -jt, --javaTypes use native java types. + * Default: true + * -st, --solidityTypes use solidity types. + */ + + private final File binFile; + private final File smBinFile; + private final File abiFile; + private final File destinationDir; + private String basePackageName; + + public SolidityContractGenerator( + File binFile, + File smBinFile, + File abiFile, + File destinationDir, + String basePackageName) { + this.binFile = binFile; + this.smBinFile = smBinFile; + this.abiFile = abiFile; + this.destinationDir = destinationDir; + this.basePackageName = basePackageName; + } + + public void generateJavaFiles() throws CodeGenException, IOException, ClassNotFoundException { + // get binary + byte[] binary = CodeGenUtils.readBytes(this.binFile); + // get binray for sm + byte[] smBinary = CodeGenUtils.readBytes(this.smBinFile); + // load abi + byte[] abiBytes = CodeGenUtils.readBytes(this.abiFile); + // get contractName + String contractName = CodeGenUtils.getFileNameNoExtension(this.abiFile.getName()); + new SolidityContractWrapper() + .generateJavaFiles( + contractName, + new String(binary), + new String(smBinary), + new String(abiBytes), + destinationDir.toString(), + basePackageName); + } +} diff --git a/sdk-codegen/src/main/java/org/fisco/bcos/sdk/codegen/SolidityContractWrapper.java b/sdk-codegen/src/main/java/org/fisco/bcos/sdk/codegen/SolidityContractWrapper.java new file mode 100644 index 000000000..f344d465b --- /dev/null +++ b/sdk-codegen/src/main/java/org/fisco/bcos/sdk/codegen/SolidityContractWrapper.java @@ -0,0 +1,1423 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.codegen; + +import com.squareup.javapoet.AnnotationSpec; +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.CodeBlock; +import com.squareup.javapoet.FieldSpec; +import com.squareup.javapoet.JavaFile; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterSpec; +import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import com.squareup.javapoet.TypeVariableName; +import java.io.File; +import java.io.IOException; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Modifier; +import org.fisco.bcos.sdk.abi.FunctionEncoder; +import org.fisco.bcos.sdk.abi.FunctionReturnDecoder; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.datatypes.Address; +import org.fisco.bcos.sdk.abi.datatypes.Bool; +import org.fisco.bcos.sdk.abi.datatypes.DynamicArray; +import org.fisco.bcos.sdk.abi.datatypes.DynamicBytes; +import org.fisco.bcos.sdk.abi.datatypes.Event; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.StaticArray; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.AbiTypes; +import org.fisco.bcos.sdk.abi.wrapper.ABIDefinition; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.codegen.exceptions.CodeGenException; +import org.fisco.bcos.sdk.contract.Contract; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.eventsub.EventCallback; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; +import org.fisco.bcos.sdk.utils.Collection; +import org.fisco.bcos.sdk.utils.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Generate Java Classes based on generated Solidity bin and abi files. */ +public class SolidityContractWrapper { + + private static final Logger logger = LoggerFactory.getLogger(SolidityContractWrapper.class); + + private static final int maxSolidityBinSize = 0x40000; + private static final int maxField = 8 * 1024; + + private static String BINARY_ARRAY_NAME = "BINARY_ARRAY"; + private static String SM_BINARY_ARRAY_NAME = "SM_BINARY_ARRAY"; + private static final String BINARY_NAME = "BINARY"; + private static final String SM_BINARY_NAME = "SM_BINARY"; + private static final String ABI_ARRAY_NAME = "ABI_ARRAY"; + private static final String ABI_NAME = "ABI"; + + private static final String GET_BINARY_FUNC = "getBinary"; + private static final String CLIENT = "client"; + private static final String CREDENTIAL = "credential"; + private static final String CRYPTOSUITE = "cryptoSuite"; + private static final String CONTRACT_ADDRESS = "contractAddress"; + private static final String FROM_BLOCK = "fromBlock"; + private static final String TO_BLOCK = "toBlock"; + private static final String CALLBACK_VALUE = "callback"; + private static final String OTHER_TOPICS = "otherTopics"; + private static final String FUNC_NAME_PREFIX = "FUNC_"; + private static final String EVENT_ENCODER = "eventEncoder"; + + private static final String regex = "(\\w+)(?:\\[(.*?)\\])(?:\\[(.*?)\\])?"; + private static final Pattern pattern = Pattern.compile(regex); + + public void generateJavaFiles( + String contractName, + String bin, + String smBin, + String abi, + String destinationDir, + String basePackageName) + throws IOException, ClassNotFoundException, UnsupportedOperationException, + CodeGenException { + String className = StringUtils.capitaliseFirstLetter(contractName); + + logger.info("bin: {}", bin); + logger.info("smBin: {}", smBin); + + if (bin.length() > maxSolidityBinSize) { + throw new UnsupportedOperationException( + " contract binary too long, max support is 256k, now is " + + Integer.valueOf(bin.length())); + } + + List abiDefinitions = CodeGenUtils.loadContractAbiDefinition(abi); + TypeSpec.Builder classBuilder = createClassBuilder(className, bin, smBin, abi); + + classBuilder.addMethod( + buildGetBinaryMethod(CryptoSuite.class, CryptoType.class, CRYPTOSUITE)); + classBuilder.addMethod(buildConstructor(CryptoKeyPair.class, CREDENTIAL)); + + classBuilder.addFields(buildFuncNameConstants(abiDefinitions)); + classBuilder.addMethods(buildFunctionDefinitions(classBuilder, abiDefinitions)); + classBuilder.addMethod(buildLoad(className, CryptoKeyPair.class, CREDENTIAL)); + classBuilder.addMethods(buildDeployMethods(className, abiDefinitions)); + + write(basePackageName, classBuilder.build(), destinationDir); + } + + protected void write(String packageName, TypeSpec typeSpec, String destinationDir) + throws IOException { + JavaFile javaFile = + JavaFile.builder(packageName, typeSpec) + .indent(" ") + .skipJavaLangImports(true) + .build(); + + javaFile.writeTo(new File(destinationDir)); + } + + private TypeSpec.Builder createClassBuilder( + String className, String binary, String smBinary, String abi) { + TypeSpec.Builder builder = + TypeSpec.classBuilder(className) + .addModifiers(Modifier.PUBLIC) + .superclass(Contract.class) + .addAnnotation( + AnnotationSpec.builder(SuppressWarnings.class) + .addMember("value", "$S", "unchecked") + .build()) + // binary fields + .addField(createArrayDefinition(BINARY_ARRAY_NAME, binary)) + .addField(createDefinition(BINARY_NAME, BINARY_ARRAY_NAME)) + .addField(createArrayDefinition(SM_BINARY_ARRAY_NAME, smBinary)) + .addField(createDefinition(SM_BINARY_NAME, SM_BINARY_ARRAY_NAME)) + // abi fields + .addField(createArrayDefinition(ABI_ARRAY_NAME, abi)) + .addField(createDefinition(ABI_NAME, ABI_ARRAY_NAME)); + + return builder; + } + + public List stringToArrayString(String binary) { + + List binaryArray = new ArrayList(); + + for (int offset = 0; offset < binary.length(); ) { + + int length = binary.length() - offset; + if (length > maxField) { + length = maxField; + } + + String item = binary.substring(offset, offset + length); + + binaryArray.add(item); + offset += item.length(); + } + + return binaryArray; + } + + private FieldSpec createArrayDefinition(String type, String binary) { + List binaryArray = stringToArrayString(binary); + List formatArray = + new ArrayList(Collections.nCopies(binaryArray.size(), "$S")); + + return FieldSpec.builder(String[].class, type) + .addModifiers(Modifier.PUBLIC, Modifier.FINAL, Modifier.STATIC) + .initializer("{" + String.join(",", formatArray) + "}", binaryArray.toArray()) + .build(); + } + + private FieldSpec createDefinition(String type, String binayArrayName) { + return FieldSpec.builder(String.class, type) + .addModifiers(Modifier.PUBLIC, Modifier.FINAL, Modifier.STATIC) + .initializer("String.join(\"\", " + binayArrayName + ")") + .build(); + } + + private FieldSpec createEventDefinition(String name, List parameters) { + + CodeBlock initializer = buildVariableLengthEventInitializer(name, parameters); + + return FieldSpec.builder(Event.class, buildEventDefinitionName(name)) + .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) + .initializer(initializer) + .build(); + } + + private String buildEventDefinitionName(String eventName) { + return eventName.toUpperCase() + "_EVENT"; + } + + private static boolean isOverLoadFunction( + String name, List functionDefinitions) { + int count = 0; + for (ABIDefinition functionDefinition : functionDefinitions) { + if (!functionDefinition.getType().equals("function")) { + continue; + } + + if (functionDefinition.getName().equals(name)) { + count += 1; + } + } + return count > 1; + } + + private List buildFunctionDefinitions( + TypeSpec.Builder classBuilder, List functionDefinitions) + throws ClassNotFoundException { + + List methodSpecs = new ArrayList<>(); + for (ABIDefinition functionDefinition : functionDefinitions) { + if (functionDefinition.getType().equals("function")) { + MethodSpec ms = buildFunction(functionDefinition); + methodSpecs.add(ms); + + if (!functionDefinition.isConstant()) { + MethodSpec msCallback = buildFunctionWithCallback(functionDefinition); + methodSpecs.add(msCallback); + + MethodSpec msSeq = buildFunctionSignedTransaction(functionDefinition); + methodSpecs.add(msSeq); + + boolean isOverLoad = + isOverLoadFunction(functionDefinition.getName(), functionDefinitions); + if (!functionDefinition.getInputs().isEmpty()) { + MethodSpec inputDecoder = + buildFunctionWithInputDecoder(functionDefinition, isOverLoad); + methodSpecs.add(inputDecoder); + } + + if (!functionDefinition.getOutputs().isEmpty()) { + MethodSpec outputDecoder = + buildFunctionWithOutputDecoder(functionDefinition, isOverLoad); + methodSpecs.add(outputDecoder); + } + } + } else if (functionDefinition.getType().equals("event")) { + methodSpecs.addAll(buildEventFunctions(functionDefinition, classBuilder)); + } + } + + return methodSpecs; + } + + private List buildDeployMethods( + String className, List functionDefinitions) { + boolean constructor = false; + List methodSpecs = new ArrayList<>(); + for (ABIDefinition functionDefinition : functionDefinitions) { + if (functionDefinition.getType().equals("constructor")) { + constructor = true; + methodSpecs.add( + buildDeploy( + className, functionDefinition, CryptoKeyPair.class, CREDENTIAL)); + } + } + // constructor will not be specified in ABI file if its empty + if (!constructor) { + MethodSpec.Builder credentialsMethodBuilder = + getDeployMethodSpec(className, CryptoKeyPair.class, CREDENTIAL); + methodSpecs.add(buildDeployNoParams(credentialsMethodBuilder, className, CREDENTIAL)); + } + return methodSpecs; + } + + private Iterable buildFuncNameConstants(List functionDefinitions) { + List fields = new ArrayList<>(); + Set fieldNames = new HashSet<>(); + fieldNames.add(Contract.FUNC_DEPLOY); + + for (ABIDefinition functionDefinition : functionDefinitions) { + if (functionDefinition.getType().equals("function")) { + String funcName = functionDefinition.getName(); + + if (!fieldNames.contains(funcName)) { + FieldSpec field = + FieldSpec.builder( + String.class, + funcNameToConst(funcName), + Modifier.PUBLIC, + Modifier.STATIC, + Modifier.FINAL) + .initializer("$S", funcName) + .build(); + fields.add(field); + fieldNames.add(funcName); + } + } + } + return fields; + } + + private static MethodSpec buildGetBinaryMethod( + Class authType, Class cryptoType, String authName) { + MethodSpec.Builder toReturn = + MethodSpec.methodBuilder(GET_BINARY_FUNC) + .addParameter(authType, authName) + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .returns(String.class); + + toReturn.addStatement( + "return ($N.getCryptoTypeConfig() == $T.ECDSA_TYPE ? $N : $N)", + authName, + cryptoType, + BINARY_NAME, + SM_BINARY_NAME); + return toReturn.build(); + } + + private static MethodSpec buildConstructor(Class authType, String authName) { + MethodSpec.Builder toReturn = + MethodSpec.constructorBuilder() + .addModifiers(Modifier.PROTECTED) + .addParameter(String.class, CONTRACT_ADDRESS) + .addParameter(Client.class, CLIENT) + .addParameter(authType, authName) + .addStatement( + "super($N, $N, $N, $N)", + getBinaryFuncDefinition(), + CONTRACT_ADDRESS, + CLIENT, + authName); + return toReturn.build(); + } + + private MethodSpec buildDeploy( + String className, ABIDefinition functionDefinition, Class authType, String authName) { + MethodSpec.Builder methodBuilder = getDeployMethodSpec(className, authType, authName); + String inputParams = addParameters(methodBuilder, functionDefinition.getInputs()); + + if (!inputParams.isEmpty()) { + return buildDeployWithParams(methodBuilder, className, inputParams, authName); + } else { + return buildDeployNoParams(methodBuilder, className, authName); + } + } + + private static MethodSpec buildDeployWithParams( + MethodSpec.Builder methodBuilder, + String className, + String inputParams, + String authName) { + + methodBuilder + .addStatement( + "$T encodedConstructor = $T.encodeConstructor(" + "$T.<$T>asList($L)" + ")", + String.class, + FunctionEncoder.class, + Arrays.class, + Type.class, + inputParams) + .addStatement( + "return deploy(" + "$L.class, $L, $L, $L, encodedConstructor)", + className, + CLIENT, + authName, + getBinaryFuncDefinition()); + return methodBuilder.build(); + } + + private static MethodSpec buildDeployNoParams( + MethodSpec.Builder methodBuilder, String className, String authName) { + methodBuilder.addStatement( + "return deploy($L.class, $L, $L, $L, \"\")", + className, + CLIENT, + authName, + getBinaryFuncDefinition()); + return methodBuilder.build(); + } + + private static MethodSpec.Builder getDeployMethodSpec( + String className, Class authType, String authName) { + return MethodSpec.methodBuilder("deploy") + .addException(ContractException.class) + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .returns(TypeVariableName.get(className, Type.class)) + .addParameter(Client.class, CLIENT) + .addParameter(authType, authName); + } + + private static MethodSpec buildLoad(String className, Class authType, String authName) { + MethodSpec.Builder toReturn = + MethodSpec.methodBuilder("load") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .returns(TypeVariableName.get(className, Type.class)) + .addParameter(String.class, CONTRACT_ADDRESS) + .addParameter(Client.class, CLIENT) + .addParameter(authType, authName) + .addStatement( + "return new $L($L, $L, $L)", + className, + CONTRACT_ADDRESS, + CLIENT, + authName); + return toReturn.build(); + } + + private MethodSpec.Builder addParameter( + MethodSpec.Builder methodBuilder, String type, String name) { + + ParameterSpec parameterSpec = buildParameterType(type, name); + + TypeName typeName = getNativeType(parameterSpec.type); + + ParameterSpec inputParameter = ParameterSpec.builder(typeName, parameterSpec.name).build(); + + methodBuilder.addParameter(inputParameter); + + return methodBuilder; + } + + private String addParameters( + MethodSpec.Builder methodBuilder, List namedTypes) { + List inputParameterTypes = buildParameterTypes(namedTypes); + List nativeInputParameterTypes = new ArrayList<>(inputParameterTypes.size()); + for (ParameterSpec parameterSpec : inputParameterTypes) { + TypeName typeName = getNativeType(parameterSpec.type); + nativeInputParameterTypes.add( + ParameterSpec.builder(typeName, parameterSpec.name).build()); + } + methodBuilder.addParameters(nativeInputParameterTypes); + return Collection.join( + namedTypes, + ", \n", + // this results in fully qualified names being generated + this::createMappedParameterTypes); + } + + private String addParameters(List namedTypes) { + + List inputParameterTypes = buildParameterTypes(namedTypes); + + List nativeInputParameterTypes = new ArrayList<>(inputParameterTypes.size()); + for (ParameterSpec parameterSpec : inputParameterTypes) { + TypeName typeName = getNativeType(parameterSpec.type); + nativeInputParameterTypes.add( + ParameterSpec.builder(typeName, parameterSpec.name).build()); + } + + return Collection.join( + namedTypes, + ", \n", + // this results in fully qualified names being generated + this::createMappedParameterTypes); + } + + private String createMappedParameterTypes(ABIDefinition.NamedType namedType) { + + String name = namedType.getName(); + String type = namedType.getType(); + ABIDefinition.Type innerType = new ABIDefinition.Type(type); + + ParameterSpec parameterSpec = ParameterSpec.builder(buildTypeName(type), name).build(); + + if (parameterSpec.type instanceof ParameterizedTypeName) { + List typeNames = ((ParameterizedTypeName) parameterSpec.type).typeArguments; + if (typeNames.size() != 1) { + throw new UnsupportedOperationException( + "Only a single parameterized type is supported"); + } else { + String parameterSpecType = parameterSpec.type.toString(); + TypeName typeName = typeNames.get(0); + String typeMapInput = typeName + ".class"; + + if (typeName instanceof ParameterizedTypeName) { + List typeArguments = ((ParameterizedTypeName) typeName).typeArguments; + if (typeArguments.size() != 1) { + throw new UnsupportedOperationException( + "Only a single parameterized type is supported"); + } + + TypeName innerTypeName = typeArguments.get(0); + parameterSpecType = + ((ParameterizedTypeName) parameterSpec.type).rawType.toString(); + + typeMapInput = + ((ParameterizedTypeName) typeName).rawType + + ".class, " + + innerTypeName + + ".class"; + } + + if (innerType.isDynamicList()) { // dynamic array + return parameterSpec.name + + ".isEmpty()?org.fisco.bcos.sdk.abi.datatypes.DynamicArray.empty" + + "(\"" + + type + + "\"):" + + "new " + + parameterSpecType + + "(\n" + + " org.fisco.bcos.sdk.abi.Utils.typeMap(" + + parameterSpec.name + + ", " + + typeMapInput + + "))"; + } else { // static array + return "new " + + parameterSpecType + + "(\n" + + " org.fisco.bcos.sdk.abi.Utils.typeMap(" + + parameterSpec.name + + ", " + + typeMapInput + + "))"; + } + } + } else { + return "new " + parameterSpec.type + "(" + parameterSpec.name + ")"; + } + } + + private TypeName getWrapperRawType(TypeName typeName) { + if (typeName instanceof ParameterizedTypeName) { + return ClassName.get(List.class); + } + return getNativeType(typeName); + } + + protected static TypeName getNativeType(TypeName typeName) { + + if (typeName instanceof ParameterizedTypeName) { + return getNativeType((ParameterizedTypeName) typeName); + } + + String simpleName = ((ClassName) typeName).simpleName(); + + if (simpleName.startsWith(Address.class.getSimpleName())) { + return TypeName.get(String.class); + } else if (simpleName.startsWith("Uint")) { + return TypeName.get(BigInteger.class); + } else if (simpleName.startsWith("Int")) { + return TypeName.get(BigInteger.class); + } else if (simpleName.startsWith(Utf8String.class.getSimpleName())) { + return TypeName.get(String.class); + } else if (simpleName.startsWith("Bytes")) { + return TypeName.get(byte[].class); + } else if (simpleName.startsWith(DynamicBytes.class.getSimpleName())) { + return TypeName.get(byte[].class); + } else if (simpleName.startsWith(Bool.class.getSimpleName())) { + return TypeName.get(Boolean.class); // boolean cannot be a parameterized type + } else { + throw new UnsupportedOperationException( + "Unsupported type: " + typeName + ", no native type mapping exists."); + } + } + + protected static TypeName getNativeType(ParameterizedTypeName parameterizedTypeName) { + List typeNames = parameterizedTypeName.typeArguments; + List nativeTypeNames = new ArrayList<>(typeNames.size()); + for (TypeName enclosedTypeName : typeNames) { + nativeTypeNames.add(getNativeType(enclosedTypeName)); + } + return ParameterizedTypeName.get( + ClassName.get(List.class), + nativeTypeNames.toArray(new TypeName[nativeTypeNames.size()])); + } + + protected static TypeName getEventNativeType(TypeName typeName) { + if (typeName instanceof ParameterizedTypeName) { + return TypeName.get(byte[].class); + } + + String simpleName = ((ClassName) typeName).simpleName(); + if ("Utf8String".equals(simpleName)) { + return TypeName.get(byte[].class); + } else { + return getNativeType(typeName); + } + } + + private ParameterSpec buildParameterType(String type, String name) { + + return ParameterSpec.builder(buildTypeName(type), name).build(); + } + + protected static List buildParameterTypes( + List namedTypes) { + + List result = new ArrayList<>(namedTypes.size()); + for (int i = 0; i < namedTypes.size(); i++) { + ABIDefinition.NamedType namedType = namedTypes.get(i); + String name = createValidParamName(namedType.getName(), i); + String type = namedTypes.get(i).getType(); + namedType.setName(name); + result.add(ParameterSpec.builder(buildTypeName(type), name).build()); + } + return result; + } + + /** + * Public Solidity arrays and maps require an unnamed input parameter - multiple if they require + * a struct type. + * + * @param name parameter name + * @param idx parameter index + * @return non-empty parameter name + */ + protected static String createValidParamName(String name, int idx) { + if (name.equals("")) { + return "param" + idx; + } else { + return name; + } + } + + protected static List buildTypeNames(List namedTypes) { + List result = new ArrayList<>(namedTypes.size()); + for (ABIDefinition.NamedType namedType : namedTypes) { + result.add(buildTypeName(namedType.getType())); + } + return result; + } + + private MethodSpec buildFunction(ABIDefinition functionDefinition) + throws ClassNotFoundException { + String functionName = functionDefinition.getName(); + + if (!SourceVersion.isName(functionName)) { + functionName = "_" + functionName; + } + + MethodSpec.Builder methodBuilder = + MethodSpec.methodBuilder(functionName).addModifiers(Modifier.PUBLIC); + + String inputParams = addParameters(methodBuilder, functionDefinition.getInputs()); + + List outputParameterTypes = buildTypeNames(functionDefinition.getOutputs()); + if (functionDefinition.isConstant()) { + buildConstantFunction( + functionDefinition, methodBuilder, outputParameterTypes, inputParams); + } else { + buildTransactionFunction(functionDefinition, methodBuilder, inputParams); + } + + return methodBuilder.build(); + } + + private MethodSpec buildFunctionSignedTransaction(ABIDefinition functionDefinition) + throws ClassNotFoundException { + String functionName = "getSignedTransactionFor"; + functionName += StringUtils.capitaliseFirstLetter(functionDefinition.getName()); + + if (!SourceVersion.isName(functionName)) { + functionName = "_" + functionName; + } + + MethodSpec.Builder methodBuilder = + MethodSpec.methodBuilder(functionName).addModifiers(Modifier.PUBLIC); + + String inputParams = addParameters(methodBuilder, functionDefinition.getInputs()); + + buildTransactionFunctionSeq(functionDefinition, methodBuilder, inputParams); + + return methodBuilder.build(); + } + + private MethodSpec buildFunctionWithCallback(ABIDefinition functionDefinition) + throws ClassNotFoundException { + String functionName = functionDefinition.getName(); + + MethodSpec.Builder methodBuilder = + MethodSpec.methodBuilder(functionName).addModifiers(Modifier.PUBLIC); + + List outputParameterTypes = buildTypeNames(functionDefinition.getOutputs()); + + if (functionDefinition.isConstant()) { + String inputParams = addParameters(methodBuilder, functionDefinition.getInputs()); + buildConstantFunction( + functionDefinition, methodBuilder, outputParameterTypes, inputParams); + } else { + String inputParams = addParameters(methodBuilder, functionDefinition.getInputs()); + methodBuilder.addParameter(TransactionCallback.class, "callback"); + buildTransactionFunctionWithCallback(functionDefinition, methodBuilder, inputParams); + } + + return methodBuilder.build(); + } + + public static String getInputOutputFunctionName( + ABIDefinition functionDefinition, boolean isOverLoad) { + if (!isOverLoad) { + return functionDefinition.getName(); + } + + List nameTypes = functionDefinition.getInputs(); + String name = functionDefinition.getName(); + for (int i = 0; i < nameTypes.size(); i++) { + ABIDefinition.Type type = nameTypes.get(i).newType(); + name += StringUtils.capitaliseFirstLetter(type.getRawType()); + if (!type.isList()) { + continue; + } + // parse the array or the struct + List depths = type.getDimensions(); + for (int j = 0; j < depths.size(); j++) { + name += type.getRawType(); + if (0 != depths.get(j)) { + name += String.valueOf(depths.get(j)); + } + } + } + logger.debug(" name: {}, nameTypes: {}", name, nameTypes); + return name; + } + + private MethodSpec buildFunctionWithInputDecoder( + ABIDefinition functionDefinition, boolean isOverLoad) throws ClassNotFoundException { + + String functionName = getInputOutputFunctionName(functionDefinition, isOverLoad); + + MethodSpec.Builder methodBuilder = + MethodSpec.methodBuilder( + "get" + StringUtils.capitaliseFirstLetter(functionName) + "Input") + .addModifiers(Modifier.PUBLIC) + .addParameter(TransactionReceipt.class, "transactionReceipt"); + + List returnTypes = + buildReturnTypes(buildTypeNames(functionDefinition.getInputs())); + + ParameterizedTypeName parameterizedTupleType = + ParameterizedTypeName.get( + ClassName.get( + "org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated", + "Tuple" + returnTypes.size()), + returnTypes.toArray(new TypeName[returnTypes.size()])); + + methodBuilder.returns(parameterizedTupleType); + methodBuilder.addStatement("String data = transactionReceipt.getInput().substring(10)"); + + buildVariableLengthReturnFunctionConstructor( + methodBuilder, + functionDefinition.getName(), + "", + buildTypeNames(functionDefinition.getInputs())); + + methodBuilder.addStatement( + "$T results = $T.decode(data, function.getOutputParameters())", + List.class, + FunctionReturnDecoder.class); + + buildTupleResultContainer0( + methodBuilder, + parameterizedTupleType, + buildTypeNames(functionDefinition.getInputs())); + + return methodBuilder.build(); + } + + private MethodSpec buildFunctionWithOutputDecoder( + ABIDefinition functionDefinition, boolean isOverLoad) throws ClassNotFoundException { + + String functionName = getInputOutputFunctionName(functionDefinition, isOverLoad); + + MethodSpec.Builder methodBuilder = + MethodSpec.methodBuilder( + "get" + StringUtils.capitaliseFirstLetter(functionName) + "Output") + .addModifiers(Modifier.PUBLIC) + .addParameter(TransactionReceipt.class, "transactionReceipt"); + + List returnTypes = + buildReturnTypes(buildTypeNames(functionDefinition.getOutputs())); + + ParameterizedTypeName parameterizedTupleType = + ParameterizedTypeName.get( + ClassName.get( + "org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated", + "Tuple" + returnTypes.size()), + returnTypes.toArray(new TypeName[returnTypes.size()])); + + methodBuilder.returns(parameterizedTupleType); + methodBuilder.addStatement("String data = transactionReceipt.getOutput()"); + + buildVariableLengthReturnFunctionConstructor( + methodBuilder, + functionDefinition.getName(), + "", + buildTypeNames(functionDefinition.getOutputs())); + + methodBuilder.addStatement( + "$T results = $T.decode(data, function.getOutputParameters())", + List.class, + FunctionReturnDecoder.class); + + buildTupleResultContainer0( + methodBuilder, + parameterizedTupleType, + buildTypeNames(functionDefinition.getOutputs())); + + return methodBuilder.build(); + } + + private void buildConstantFunction( + ABIDefinition functionDefinition, + MethodSpec.Builder methodBuilder, + List outputParameterTypes, + String inputParams) + throws ClassNotFoundException { + + String functionName = functionDefinition.getName(); + methodBuilder.addException(ContractException.class); + if (outputParameterTypes.isEmpty()) { + methodBuilder.addStatement( + "throw new RuntimeException" + + "(\"cannot call constant function with void return type\")"); + } else if (outputParameterTypes.size() == 1) { + + TypeName typeName = outputParameterTypes.get(0); + TypeName nativeReturnTypeName; + nativeReturnTypeName = getWrapperRawType(typeName); + + methodBuilder.returns(nativeReturnTypeName); + + methodBuilder.addStatement( + "final $T function = " + + "new $T($N, \n$T.<$T>asList($L), " + + "\n$T.<$T>asList(new $T<$T>() {}))", + Function.class, + Function.class, + funcNameToConst(functionName), + Arrays.class, + Type.class, + inputParams, + Arrays.class, + TypeReference.class, + TypeReference.class, + typeName); + + if (nativeReturnTypeName.equals(ClassName.get(List.class))) { + // We return list. So all the list elements should + // also be converted to native types + TypeName listType = ParameterizedTypeName.get(List.class, Type.class); + + CodeBlock.Builder callCode = CodeBlock.builder(); + callCode.addStatement( + "$T result = " + + "($T) executeCallWithSingleValueReturn(function, $T.class)", + listType, + listType, + nativeReturnTypeName); + callCode.addStatement("return convertToNative(result)"); + methodBuilder.returns(nativeReturnTypeName).addCode(callCode.build()); + } else { + methodBuilder.addStatement( + "return executeCallWithSingleValueReturn(function, $T.class)", + nativeReturnTypeName); + } + } else { + List returnTypes = buildReturnTypes(outputParameterTypes); + + ParameterizedTypeName parameterizedTupleType = + ParameterizedTypeName.get( + ClassName.get( + "org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated", + "Tuple" + returnTypes.size()), + returnTypes.toArray(new TypeName[returnTypes.size()])); + + methodBuilder.returns(parameterizedTupleType); + + buildVariableLengthReturnFunctionConstructor( + methodBuilder, functionName, inputParams, outputParameterTypes); + + buildTupleResultContainer(methodBuilder, parameterizedTupleType, outputParameterTypes); + } + } + + private void buildTransactionFunction( + ABIDefinition functionDefinition, MethodSpec.Builder methodBuilder, String inputParams) + throws ClassNotFoundException { + + String functionName = functionDefinition.getName(); + + methodBuilder.returns(TypeName.get(TransactionReceipt.class)); + + methodBuilder.addStatement( + "final $T function = new $T(\n$N, \n$T.<$T>asList($L), \n$T" + + ".<$T>emptyList())", + Function.class, + Function.class, + funcNameToConst(functionName), + Arrays.class, + Type.class, + inputParams, + Collections.class, + TypeReference.class); + methodBuilder.addStatement("return executeTransaction(function)"); + } + + private void buildTransactionFunctionWithCallback( + ABIDefinition functionDefinition, MethodSpec.Builder methodBuilder, String inputParams) + throws ClassNotFoundException { + String functionName = functionDefinition.getName(); + + methodBuilder.returns(TypeName.VOID); + + methodBuilder.addStatement( + "final $T function = new $T(\n$N, \n$T.<$T>asList($L), \n$T" + + ".<$T>emptyList())", + Function.class, + Function.class, + funcNameToConst(functionName), + Arrays.class, + Type.class, + inputParams, + Collections.class, + TypeReference.class); + methodBuilder.addStatement("asyncExecuteTransaction(function, callback)"); + } + + private void buildTransactionFunctionSeq( + ABIDefinition functionDefinition, MethodSpec.Builder methodBuilder, String inputParams) + throws ClassNotFoundException { + String functionName = functionDefinition.getName(); + + TypeName returnType = TypeName.get(String.class); + methodBuilder.returns(returnType); + + methodBuilder.addStatement( + "final $T function = new $T(\n$N, \n$T.<$T>asList($L), \n$T" + + ".<$T>emptyList())", + Function.class, + Function.class, + funcNameToConst(functionName), + Arrays.class, + Type.class, + inputParams, + Collections.class, + TypeReference.class); + + methodBuilder.addStatement("return createSignedTransaction(function)"); + } + + private TypeSpec buildEventResponseObject( + String className, + List indexedParameters, + List nonIndexedParameters) { + + TypeSpec.Builder builder = + TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC, Modifier.STATIC); + + builder.addField(TransactionReceipt.Logs.class, "log", Modifier.PUBLIC); + for (NamedTypeName namedType : indexedParameters) { + TypeName typeName = getEventNativeType(namedType.typeName); + builder.addField(typeName, namedType.getName(), Modifier.PUBLIC); + } + + for (NamedTypeName namedType : nonIndexedParameters) { + TypeName typeName = getNativeType(namedType.typeName); + builder.addField(typeName, namedType.getName(), Modifier.PUBLIC); + } + + return builder.build(); + } + + private MethodSpec buildSubscribeEventFunction(String eventName) throws ClassNotFoundException { + + String generatedFunctionName = + "subscribe" + StringUtils.capitaliseFirstLetter(eventName) + "Event"; + + MethodSpec.Builder getEventMethodBuilder = + MethodSpec.methodBuilder(generatedFunctionName) + .addModifiers(Modifier.PUBLIC) + .addParameter(String.class, FROM_BLOCK) + .addParameter(String.class, TO_BLOCK); + + addParameter(getEventMethodBuilder, "string[]", OTHER_TOPICS); + getEventMethodBuilder.addParameter(EventCallback.class, CALLBACK_VALUE); + getEventMethodBuilder.addStatement( + "String topic0 = $N.encode(" + buildEventDefinitionName(eventName) + ")", + EVENT_ENCODER); + + getEventMethodBuilder.addStatement( + "subscribeEvent(ABI,BINARY" + + "," + + "topic0" + + "," + + FROM_BLOCK + + "," + + TO_BLOCK + + "," + + OTHER_TOPICS + + "," + + CALLBACK_VALUE + + ")"); + + return getEventMethodBuilder.build(); + } + + private MethodSpec buildDefaultSubscribeEventLog(String eventName) { + + String generatedFunctionName = + "subscribe" + StringUtils.capitaliseFirstLetter(eventName) + "Event"; + + MethodSpec.Builder getEventMethodBuilder = + MethodSpec.methodBuilder(generatedFunctionName) + .addModifiers(Modifier.PUBLIC) + .addParameter(EventCallback.class, CALLBACK_VALUE); + + getEventMethodBuilder.addStatement( + "String topic0 = $N.encode(" + buildEventDefinitionName(eventName) + ")", + EVENT_ENCODER); + + getEventMethodBuilder.addStatement( + "subscribeEvent(ABI,BINARY" + ",topic0" + "," + CALLBACK_VALUE + ")"); + + return getEventMethodBuilder.build(); + } + + private MethodSpec buildEventTransactionReceiptFunction( + String responseClassName, + String functionName, + List indexedParameters, + List nonIndexedParameters) { + + ParameterizedTypeName parameterizedTypeName = + ParameterizedTypeName.get( + ClassName.get(List.class), ClassName.get("", responseClassName)); + + String generatedFunctionName = + "get" + StringUtils.capitaliseFirstLetter(functionName) + "Events"; + MethodSpec.Builder transactionMethodBuilder = + MethodSpec.methodBuilder(generatedFunctionName) + .addModifiers(Modifier.PUBLIC) + .addParameter(TransactionReceipt.class, "transactionReceipt") + .returns(parameterizedTypeName); + + transactionMethodBuilder + .addStatement( + "$T valueList = extractEventParametersWithLog(" + + buildEventDefinitionName(functionName) + + ", " + + "transactionReceipt)", + ParameterizedTypeName.get(List.class, Contract.EventValuesWithLog.class)) + .addStatement( + "$1T responses = new $1T(valueList.size())", + ParameterizedTypeName.get( + ClassName.get(ArrayList.class), + ClassName.get("", responseClassName))) + .beginControlFlow( + "for ($T eventValues : valueList)", Contract.EventValuesWithLog.class) + .addStatement("$1T typedResponse = new $1T()", ClassName.get("", responseClassName)) + .addCode( + buildTypedResponse( + "typedResponse", indexedParameters, nonIndexedParameters, false)) + .addStatement("responses.add(typedResponse)") + .endControlFlow(); + + transactionMethodBuilder.addStatement("return responses"); + return transactionMethodBuilder.build(); + } + + private List buildEventFunctions( + ABIDefinition functionDefinition, TypeSpec.Builder classBuilder) + throws ClassNotFoundException { + String functionName = functionDefinition.getName(); + List inputs = functionDefinition.getInputs(); + String responseClassName = + StringUtils.capitaliseFirstLetter(functionName) + "EventResponse"; + + List parameters = new ArrayList<>(); + List indexedParameters = new ArrayList<>(); + List nonIndexedParameters = new ArrayList<>(); + + Integer index = 0; + Set eventParamNameFilter = new HashSet<>(); + for (ABIDefinition.NamedType namedType : inputs) { + if (namedType.getName() != null && !namedType.getName().equals("")) { + eventParamNameFilter.add(namedType.getName()); + } + } + for (ABIDefinition.NamedType namedType : inputs) { + if (namedType.getName() == null || namedType.getName().equals("")) { + String paramName = functionName + "Param" + index; + while (eventParamNameFilter.contains(paramName)) { + index++; + paramName = functionName + "Param" + index; + } + eventParamNameFilter.add(paramName); + namedType.setName(paramName); + } + NamedTypeName parameter = + new NamedTypeName( + namedType.getName(), + buildTypeName(namedType.getType()), + namedType.isIndexed()); + if (namedType.isIndexed()) { + indexedParameters.add(parameter); + } else { + nonIndexedParameters.add(parameter); + } + parameters.add(parameter); + } + + classBuilder.addField(createEventDefinition(functionName, parameters)); + + classBuilder.addType( + buildEventResponseObject( + responseClassName, indexedParameters, nonIndexedParameters)); + + List methods = new ArrayList<>(); + methods.add( + buildEventTransactionReceiptFunction( + responseClassName, functionName, indexedParameters, nonIndexedParameters)); + + methods.add(buildSubscribeEventFunction(functionName)); + methods.add(buildDefaultSubscribeEventLog(functionName)); + + return methods; + } + + private CodeBlock buildTypedResponse( + String objectName, + List indexedParameters, + List nonIndexedParameters, + boolean flowable) { + String nativeConversion; + + nativeConversion = ".getValue()"; + + CodeBlock.Builder builder = CodeBlock.builder(); + if (flowable) { + builder.addStatement("$L.log = log", objectName); + } else { + builder.addStatement("$L.log = eventValues.getLog()", objectName); + } + for (int i = 0; i < indexedParameters.size(); i++) { + builder.addStatement( + "$L.$L = ($T) eventValues.getIndexedValues().get($L)" + nativeConversion, + objectName, + indexedParameters.get(i).getName(), + getEventNativeType(indexedParameters.get(i).getTypeName()), + i); + } + + for (int i = 0; i < nonIndexedParameters.size(); i++) { + builder.addStatement( + "$L.$L = ($T) eventValues.getNonIndexedValues().get($L)" + nativeConversion, + objectName, + nonIndexedParameters.get(i).getName(), + getNativeType(nonIndexedParameters.get(i).getTypeName()), + i); + } + return builder.build(); + } + + protected static TypeName buildTypeName(String typeDeclaration) { + String type = trimStorageDeclaration(typeDeclaration); + Matcher matcher = pattern.matcher(type); + if (matcher.find()) { + Class baseType = AbiTypes.getType(matcher.group(1)); + String firstArrayDimension = matcher.group(2); + String secondArrayDimension = matcher.group(3); + + TypeName typeName; + + if ("".equals(firstArrayDimension)) { + typeName = ParameterizedTypeName.get(DynamicArray.class, baseType); + } else { + Class rawType = getStaticArrayTypeReferenceClass(firstArrayDimension); + typeName = ParameterizedTypeName.get(rawType, baseType); + } + + if (secondArrayDimension != null) { + if ("".equals(secondArrayDimension)) { + return ParameterizedTypeName.get(ClassName.get(DynamicArray.class), typeName); + } else { + Class rawType = getStaticArrayTypeReferenceClass(secondArrayDimension); + return ParameterizedTypeName.get(ClassName.get(rawType), typeName); + } + } + return typeName; + } else { + Class cls = AbiTypes.getType(type); + return ClassName.get(cls); + } + } + + private static Class getStaticArrayTypeReferenceClass(String type) { + try { + return Class.forName("org.fisco.bcos.sdk.abi.datatypes.generated.StaticArray" + type); + } catch (ClassNotFoundException e) { + // Unfortunately we can't encode it's length as a type if it's > 32. + return StaticArray.class; + } + } + + private static String trimStorageDeclaration(String type) { + if (type.endsWith(" storage") || type.endsWith(" memory")) { + return type.split(" ")[0]; + } else { + return type; + } + } + + private List buildReturnTypes(List outputParameterTypes) { + List result = new ArrayList<>(outputParameterTypes.size()); + for (TypeName typeName : outputParameterTypes) { + result.add(getNativeType(typeName)); + } + return result; + } + + private static void buildVariableLengthReturnFunctionConstructor( + MethodSpec.Builder methodBuilder, + String functionName, + String inputParameters, + List outputParameterTypes) { + + List objects = new ArrayList<>(); + objects.add(Function.class); + objects.add(Function.class); + objects.add(funcNameToConst(functionName)); + + objects.add(Arrays.class); + objects.add(Type.class); + objects.add(inputParameters); + + objects.add(Arrays.class); + objects.add(TypeReference.class); + for (TypeName outputParameterType : outputParameterTypes) { + objects.add(TypeReference.class); + objects.add(outputParameterType); + } + + String asListParams = + Collection.join(outputParameterTypes, ", ", typeName -> "new $T<$T>() {}"); + + methodBuilder.addStatement( + "final $T function = new $T($N, \n$T.<$T>asList($L), \n$T" + + ".<$T>asList(" + + asListParams + + "))", + objects.toArray()); + } + + private void buildTupleResultContainer( + MethodSpec.Builder methodBuilder, + ParameterizedTypeName tupleType, + List outputParameterTypes) { + + List typeArguments = tupleType.typeArguments; + + CodeBlock.Builder tupleConstructor = CodeBlock.builder(); + tupleConstructor + .addStatement( + "$T results = executeCallWithMultipleValueReturn(function)", + ParameterizedTypeName.get(List.class, Type.class)) + .add("return new $T(", tupleType) + .add("$>$>"); + + String resultStringSimple = "\n($T) results.get($L)"; + resultStringSimple += ".getValue()"; + + String resultStringNativeList = "\nconvertToNative(($T) results.get($L).getValue())"; + + int size = typeArguments.size(); + ClassName classList = ClassName.get(List.class); + + for (int i = 0; i < size; i++) { + TypeName param = outputParameterTypes.get(i); + TypeName convertTo = typeArguments.get(i); + + String resultString = resultStringSimple; + + // If we use native java types we need to convert + // elements of arrays to native java types too + if (param instanceof ParameterizedTypeName) { + ParameterizedTypeName oldContainer = (ParameterizedTypeName) param; + ParameterizedTypeName newContainer = (ParameterizedTypeName) convertTo; + if (newContainer.rawType.compareTo(classList) == 0 + && newContainer.typeArguments.size() == 1) { + convertTo = + ParameterizedTypeName.get(classList, oldContainer.typeArguments.get(0)); + resultString = resultStringNativeList; + } + } + + tupleConstructor.add(resultString, convertTo, i); + tupleConstructor.add(i < size - 1 ? ", " : ");\n"); + } + tupleConstructor.add("$<$<"); + methodBuilder.returns(tupleType).addCode(tupleConstructor.build()); + } + + private void buildTupleResultContainer0( + MethodSpec.Builder methodBuilder, + ParameterizedTypeName tupleType, + List outputParameterTypes) { + + List typeArguments = tupleType.typeArguments; + + CodeBlock.Builder codeBuilder = CodeBlock.builder(); + + String resultStringSimple = "\n($T) results.get($L)"; + resultStringSimple += ".getValue()"; + + String resultStringNativeList = "\nconvertToNative(($T) results.get($L).getValue())"; + + int size = typeArguments.size(); + ClassName classList = ClassName.get(List.class); + + for (int i = 0; i < size; i++) { + TypeName param = outputParameterTypes.get(i); + TypeName convertTo = typeArguments.get(i); + + String resultString = resultStringSimple; + + // If we use native java types we need to convert + // elements of arrays to native java types too + if (param instanceof ParameterizedTypeName) { + ParameterizedTypeName oldContainer = (ParameterizedTypeName) param; + ParameterizedTypeName newContainer = (ParameterizedTypeName) convertTo; + if (newContainer.rawType.compareTo(classList) == 0 + && newContainer.typeArguments.size() == 1) { + convertTo = + ParameterizedTypeName.get(classList, oldContainer.typeArguments.get(0)); + resultString = resultStringNativeList; + } + } + + codeBuilder.add(resultString, convertTo, i); + codeBuilder.add(i < size - 1 ? ", " : "\n"); + } + + methodBuilder.addStatement("return new $T(\n$L)", tupleType, codeBuilder.build()); + } + + private static CodeBlock buildVariableLengthEventInitializer( + String eventName, List parameterTypes) { + + List objects = new ArrayList<>(); + objects.add(Event.class); + objects.add(eventName); + + objects.add(Arrays.class); + objects.add(TypeReference.class); + for (NamedTypeName parameterType : parameterTypes) { + objects.add(TypeReference.class); + objects.add(parameterType.getTypeName()); + } + + String asListParams = + parameterTypes + .stream() + .map( + type -> { + if (type.isIndexed()) { + return "new $T<$T>(true) {}"; + } else { + return "new $T<$T>() {}"; + } + }) + .collect(Collectors.joining(", ")); + + return CodeBlock.builder() + .addStatement( + "new $T($S, \n" + "$T.<$T>asList(" + asListParams + "))", + objects.toArray()) + .build(); + } + + private static String funcNameToConst(String funcName) { + return FUNC_NAME_PREFIX + funcName.toUpperCase(); + } + + private static class NamedTypeName { + private final TypeName typeName; + private final String name; + private final boolean indexed; + + NamedTypeName(String name, TypeName typeName, boolean indexed) { + this.name = name; + this.typeName = typeName; + this.indexed = indexed; + } + + public String getName() { + return name; + } + + public TypeName getTypeName() { + return typeName; + } + + public boolean isIndexed() { + return indexed; + } + } + + private static String getBinaryFuncDefinition() { + return GET_BINARY_FUNC + "(client.getCryptoSuite())"; + } +} diff --git a/sdk-codegen/src/main/java/org/fisco/bcos/sdk/codegen/exceptions/CodeGenException.java b/sdk-codegen/src/main/java/org/fisco/bcos/sdk/codegen/exceptions/CodeGenException.java new file mode 100644 index 000000000..ff4f33b63 --- /dev/null +++ b/sdk-codegen/src/main/java/org/fisco/bcos/sdk/codegen/exceptions/CodeGenException.java @@ -0,0 +1,25 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.codegen.exceptions; + +/** Exceptioned when calling hash. */ +public class CodeGenException extends Exception { + public CodeGenException(String message) { + super(message); + } + + public CodeGenException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/sdk-core/build.gradle b/sdk-core/build.gradle new file mode 100644 index 000000000..2d77a2885 --- /dev/null +++ b/sdk-core/build.gradle @@ -0,0 +1,53 @@ +// Apply the java-library plugin to add support for Java Library +plugins { + id 'java' +} +dependencies { + compile ("org.apache.commons:commons-lang3:${commonsLang3Version}") + compile ("io.netty:netty-all:${nettyVersion}") + compile ("org.fisco-bcos:netty-sm-ssl-context:${nettySMSSLContextVersion}") + compile ("com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}") + compile ("com.moandjiezana.toml:toml4j:${toml4jVersion}") +} +uploadArchives { + repositories { + mavenDeployer { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + + repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { + authentication(userName: ossrhUsername, password: ossrhPassword) + } + + snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { + authentication(userName: ossrhUsername, password: ossrhPassword) + } + + pom.project { + name project.name + packaging 'jar' + description = 'fisco-bcos java-sdk' + url = 'http://www.fisco-bcos.org' + + scm { + connection = 'https://github.com/FISCO-BCOS/java-sdk.git' + url = 'https://github.com/FISCO-BCOS/java-sdk.git' + } + + licenses { + license { + name = 'The Apache License, Version 2.0' + url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + + developers { + developer { + id = 'zhangsan' + name = 'zhangsan' + email = 'zhangsan@example.com' + } + } + } + } + } +} diff --git a/sdk-core/model/MessageTest.java b/sdk-core/model/MessageTest.java new file mode 100644 index 000000000..5bc67a1e5 --- /dev/null +++ b/sdk-core/model/MessageTest.java @@ -0,0 +1,75 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.test.model; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import java.util.Arrays; +import org.fisco.bcos.sdk.model.Message; +import org.fisco.bcos.sdk.model.MsgType; +import org.fisco.bcos.sdk.utils.ChannelUtils; +import org.junit.Assert; +import org.junit.Test; + +public class MessageTest { + @Test + public void testMessageEncodeDecode() { + String data = "getBlockByNumber"; + // Note: the seq must be 32 bytes + checkAndTestMessage( + (short) MsgType.AMOP_CLIENT_TOPICS.ordinal(), + ChannelUtils.newSeq(), + 0, + data.getBytes()); + + data = "test@12sd3*"; + checkAndTestMessage((short) 0x1010, ChannelUtils.newSeq(), 0, data.getBytes()); + + data = "test\\sdf000 sd"; + checkAndTestMessage( + (short) MsgType.EVENT_LOG_PUSH.ordinal(), + ChannelUtils.newSeq(), + 0, + data.getBytes()); + + // test json string + data = + "'{\"jsonrpc\":\"2.0\",\"method\":\"getPendingTxSize\",\"params\":[65535],\"id\":1}'"; + checkAndTestMessage( + (short) MsgType.CHANNEL_RPC_REQUEST.ordinal(), + ChannelUtils.newSeq(), + 0, + data.getBytes()); + } + + private void checkAndTestMessage(short msgType, String seq, Integer result, byte[] data) { + Message message = new Message(); + message.setSeq(seq); + message.setResult(result); + message.setType(msgType); + message.setData(data); + + ByteBuf encodedData = Unpooled.buffer(1000); + message.encode(encodedData); + + // decode the byteBuf into message object + Message decodedMessage = new Message(); + decodedMessage.decode(encodedData); + + Assert.assertEquals(message.getType(), decodedMessage.getType()); + Assert.assertEquals(message.getSeq(), decodedMessage.getSeq()); + Assert.assertEquals(message.getResult(), decodedMessage.getResult()); + Assert.assertTrue(Arrays.equals(message.getData(), decodedMessage.getData())); + } +} diff --git a/sdk-core/model/TransactionStatusTest.java b/sdk-core/model/TransactionStatusTest.java new file mode 100644 index 000000000..8e0a8a6f7 --- /dev/null +++ b/sdk-core/model/TransactionStatusTest.java @@ -0,0 +1,187 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.test.model; + +import org.fisco.bcos.sdk.model.RetCode; +import org.fisco.bcos.sdk.model.TransactionReceiptStatus; +import org.junit.Assert; +import org.junit.Test; + +public class TransactionStatusTest { + @Test + public void testGetStatusMessage() { + testGetStatus( + TransactionReceiptStatus.Success.getCode(), + TransactionReceiptStatus.Success.getCode(), + TransactionReceiptStatus.Success.getMessage()); + testGetStatus( + TransactionReceiptStatus.Unknown.getCode(), + TransactionReceiptStatus.Unknown.getCode(), + TransactionReceiptStatus.Unknown.getMessage()); + testGetStatus( + TransactionReceiptStatus.BadRLP.getCode(), + TransactionReceiptStatus.BadRLP.getCode(), + TransactionReceiptStatus.BadRLP.getMessage()); + testGetStatus( + TransactionReceiptStatus.InvalidFormat.getCode(), + TransactionReceiptStatus.InvalidFormat.getCode(), + TransactionReceiptStatus.InvalidFormat.getMessage()); + testGetStatus( + TransactionReceiptStatus.OutOfGasIntrinsic.getCode(), + TransactionReceiptStatus.OutOfGasIntrinsic.getCode(), + TransactionReceiptStatus.OutOfGasIntrinsic.getMessage()); + testGetStatus( + TransactionReceiptStatus.InvalidSignature.getCode(), + TransactionReceiptStatus.InvalidSignature.getCode(), + TransactionReceiptStatus.InvalidSignature.getMessage()); + testGetStatus( + TransactionReceiptStatus.InvalidNonce.getCode(), + TransactionReceiptStatus.InvalidNonce.getCode(), + TransactionReceiptStatus.InvalidNonce.getMessage()); + testGetStatus( + TransactionReceiptStatus.NotEnoughCash.getCode(), + TransactionReceiptStatus.NotEnoughCash.getCode(), + TransactionReceiptStatus.NotEnoughCash.getMessage()); + testGetStatus( + TransactionReceiptStatus.OutOfGasBase.getCode(), + TransactionReceiptStatus.OutOfGasBase.getCode(), + TransactionReceiptStatus.OutOfGasBase.getMessage()); + testGetStatus( + TransactionReceiptStatus.BlockGasLimitReached.getCode(), + TransactionReceiptStatus.BlockGasLimitReached.getCode(), + TransactionReceiptStatus.BlockGasLimitReached.getMessage()); + testGetStatus( + TransactionReceiptStatus.BadInstruction.getCode(), + TransactionReceiptStatus.BadInstruction.getCode(), + TransactionReceiptStatus.BadInstruction.getMessage()); + testGetStatus( + TransactionReceiptStatus.BadJumpDestination.getCode(), + TransactionReceiptStatus.BadJumpDestination.getCode(), + TransactionReceiptStatus.BadJumpDestination.getMessage()); + testGetStatus( + TransactionReceiptStatus.OutOfGas.getCode(), + TransactionReceiptStatus.OutOfGas.getCode(), + TransactionReceiptStatus.OutOfGas.getMessage()); + testGetStatus( + TransactionReceiptStatus.OutOfStack.getCode(), + TransactionReceiptStatus.OutOfStack.getCode(), + TransactionReceiptStatus.OutOfStack.getMessage()); + testGetStatus( + TransactionReceiptStatus.StackUnderflow.getCode(), + TransactionReceiptStatus.StackUnderflow.getCode(), + TransactionReceiptStatus.StackUnderflow.getMessage()); + testGetStatus( + TransactionReceiptStatus.NonceCheckFail.getCode(), + TransactionReceiptStatus.NonceCheckFail.getCode(), + TransactionReceiptStatus.NonceCheckFail.getMessage()); + testGetStatus( + TransactionReceiptStatus.BlockLimitCheckFail.getCode(), + TransactionReceiptStatus.BlockLimitCheckFail.getCode(), + TransactionReceiptStatus.BlockLimitCheckFail.getMessage()); + testGetStatus( + TransactionReceiptStatus.FilterCheckFail.getCode(), + TransactionReceiptStatus.FilterCheckFail.getCode(), + TransactionReceiptStatus.FilterCheckFail.getMessage()); + testGetStatus( + TransactionReceiptStatus.NoDeployPermission.getCode(), + TransactionReceiptStatus.NoDeployPermission.getCode(), + TransactionReceiptStatus.NoDeployPermission.getMessage()); + testGetStatus( + TransactionReceiptStatus.NoCallPermission.getCode(), + TransactionReceiptStatus.NoCallPermission.getCode(), + TransactionReceiptStatus.NoCallPermission.getMessage()); + testGetStatus( + TransactionReceiptStatus.NoTxPermission.getCode(), + TransactionReceiptStatus.NoTxPermission.getCode(), + TransactionReceiptStatus.NoTxPermission.getMessage()); + testGetStatus( + TransactionReceiptStatus.PrecompiledError.getCode(), + TransactionReceiptStatus.PrecompiledError.getCode(), + TransactionReceiptStatus.PrecompiledError.getMessage()); + testGetStatus( + TransactionReceiptStatus.RevertInstruction.getCode(), + TransactionReceiptStatus.RevertInstruction.getCode(), + TransactionReceiptStatus.RevertInstruction.getMessage()); + testGetStatus( + TransactionReceiptStatus.InvalidZeroSignatureFormat.getCode(), + TransactionReceiptStatus.InvalidZeroSignatureFormat.getCode(), + TransactionReceiptStatus.InvalidZeroSignatureFormat.getMessage()); + testGetStatus( + TransactionReceiptStatus.AddressAlreadyUsed.getCode(), + TransactionReceiptStatus.AddressAlreadyUsed.getCode(), + TransactionReceiptStatus.AddressAlreadyUsed.getMessage()); + testGetStatus( + TransactionReceiptStatus.PermissionDenied.getCode(), + TransactionReceiptStatus.PermissionDenied.getCode(), + TransactionReceiptStatus.PermissionDenied.getMessage()); + testGetStatus( + TransactionReceiptStatus.CallAddressError.getCode(), + TransactionReceiptStatus.CallAddressError.getCode(), + TransactionReceiptStatus.CallAddressError.getMessage()); + testGetStatus( + TransactionReceiptStatus.GasOverflow.getCode(), + TransactionReceiptStatus.GasOverflow.getCode(), + TransactionReceiptStatus.GasOverflow.getMessage()); + testGetStatus( + TransactionReceiptStatus.TxPoolIsFull.getCode(), + TransactionReceiptStatus.TxPoolIsFull.getCode(), + TransactionReceiptStatus.TxPoolIsFull.getMessage()); + testGetStatus( + TransactionReceiptStatus.TransactionRefused.getCode(), + TransactionReceiptStatus.TransactionRefused.getCode(), + TransactionReceiptStatus.TransactionRefused.getMessage()); + testGetStatus( + TransactionReceiptStatus.AccountFrozen.getCode(), + TransactionReceiptStatus.AccountFrozen.getCode(), + TransactionReceiptStatus.AccountFrozen.getMessage()); + testGetStatus( + TransactionReceiptStatus.AlreadyKnown.getCode(), + TransactionReceiptStatus.AlreadyKnown.getCode(), + TransactionReceiptStatus.AlreadyKnown.getMessage()); + testGetStatus( + TransactionReceiptStatus.ContractFrozen.getCode(), + TransactionReceiptStatus.ContractFrozen.getCode(), + TransactionReceiptStatus.ContractFrozen.getMessage()); + testGetStatus( + TransactionReceiptStatus.AlreadyInChain.getCode(), + TransactionReceiptStatus.AlreadyInChain.getCode(), + TransactionReceiptStatus.AlreadyInChain.getMessage()); + testGetStatus( + TransactionReceiptStatus.InvalidChainId.getCode(), + TransactionReceiptStatus.InvalidChainId.getCode(), + TransactionReceiptStatus.InvalidChainId.getMessage()); + testGetStatus( + TransactionReceiptStatus.InvalidGroupId.getCode(), + TransactionReceiptStatus.InvalidGroupId.getCode(), + TransactionReceiptStatus.InvalidGroupId.getMessage()); + testGetStatus( + TransactionReceiptStatus.RequestNotBelongToTheGroup.getCode(), + TransactionReceiptStatus.RequestNotBelongToTheGroup.getCode(), + TransactionReceiptStatus.RequestNotBelongToTheGroup.getMessage()); + testGetStatus( + TransactionReceiptStatus.MalformedTx.getCode(), + TransactionReceiptStatus.MalformedTx.getCode(), + TransactionReceiptStatus.MalformedTx.getMessage()); + testGetStatus( + TransactionReceiptStatus.OverGroupMemoryLimit.getCode(), + TransactionReceiptStatus.OverGroupMemoryLimit.getCode(), + TransactionReceiptStatus.OverGroupMemoryLimit.getMessage()); + } + + private void testGetStatus(int status, int expectedCode, String expectedMessage) { + RetCode retCode = TransactionReceiptStatus.getStatusMessage(String.valueOf(status), ""); + Assert.assertEquals(expectedCode, retCode.getCode()); + Assert.assertTrue(retCode.getMessage().equals(expectedMessage)); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/Channel.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/Channel.java new file mode 100644 index 000000000..9a317123e --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/Channel.java @@ -0,0 +1,185 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.channel; + +import java.util.List; +import java.util.concurrent.ExecutorService; +import org.fisco.bcos.sdk.channel.model.Options; +import org.fisco.bcos.sdk.config.ConfigOption; +import org.fisco.bcos.sdk.config.exceptions.ConfigException; +import org.fisco.bcos.sdk.model.Message; +import org.fisco.bcos.sdk.model.MsgType; +import org.fisco.bcos.sdk.model.Response; +import org.fisco.bcos.sdk.network.ConnectionInfo; +import org.fisco.bcos.sdk.network.MsgHandler; +import org.fisco.bcos.sdk.network.Network; + +/** + * The channel module interface. + * + * @author Maggie + */ +public interface Channel { + /** + * Init channel module + * + * @param configOption config file path. + * @return a channel instance + * @throws ConfigException the configuration exception + */ + static Channel build(ConfigOption configOption) throws ConfigException { + return new ChannelImp(configOption); + } + + Network getNetwork(); + + void start(); + + void stop(); + + /** + * Add a message handler to handle specific type messages. When one message comes the handler + * will be notified, handler.onMessage(ChannleHandlerContext ctx, Message msg) called. + * + * @param type the type of message + * @param handler the message handler + */ + void addMessageHandler(MsgType type, MsgHandler handler); + + /** + * Add a connect handler, when one connect success, call handler.onConnect(ChannleHandlerContext + * ctx)is called + * + * @param handler the connect handler + */ + void addConnectHandler(MsgHandler handler); + + /** + * Add a establish handler, when the SDK establishes a connection with the node, call the + * handler + * + * @param handler the establish handler + */ + void addEstablishHandler(MsgHandler handler); + + /** + * Add a disconnect handler, when one connection disconnect, + * handler.onDisconnect(ChannleHandlerContext ctx) is called + * + * @param handler disconnect handler + */ + void addDisconnectHandler(MsgHandler handler); + + /** + * Send a message to the given group, only send + * + * @param out Message to be sent + * @param groupId ID of the group receiving the message packet + */ + void broadcastToGroup(Message out, String groupId); + + /** + * Broadcast to all peer, only send + * + * @param out Message to be sent + */ + void broadcast(Message out); + + /** + * Synchronize interface, send a message to the given peer, and get the response + * + * @param out Message to be sent + * @param peerIpPort Remote ip:port information + * @return Remote reply + */ + Response sendToPeer(Message out, String peerIpPort); + + /** + * Synchronize interface with timeout, send a message to the given peer, and get the response + * + * @param out Message to be sent + * @param peerIpPort Remote ip:port information + * @param options Include timeout + * @return Remote reply + */ + Response sendToPeerWithTimeOut(Message out, String peerIpPort, Options options); + + /** + * Synchronize interface with timeout, randomly select nodes to send messages + * + * @param out Message to be sent + * @param options Include timeout + * @return Remote reply + */ + Response sendToRandomWithTimeOut(Message out, Options options); + + /** + * Synchronize interface with timeout, send message to peer select by client`s rule + * + * @param out Message to be sent + * @param rule Rule set by client + * @param options Include timeout + * @return Remote reply + */ + Response sendToPeerByRuleWithTimeOut(Message out, PeerSelectRule rule, Options options); + + /** + * Asynchronous interface, send message to peer + * + * @param out Message to be sent + * @param peerIpPort Remote ip:port information + * @param callback Response callback + * @param options Include timeout + */ + void asyncSendToPeer( + Message out, String peerIpPort, ResponseCallback callback, Options options); + + /** + * Asynchronous interface, send to an random peer + * + * @param out Message to be sent + * @param callback Response callback + * @param options Include timeout + */ + void asyncSendToRandom(Message out, ResponseCallback callback, Options options); + + /** + * Asynchronous interface, send message to peer select by client`s rule + * + * @param out Message to be sent + * @param rule Rule set by client + * @param callback Response callback + * @param options Include timeout + */ + void asyncSendToPeerByRule( + Message out, PeerSelectRule rule, ResponseCallback callback, Options options); + + /** + * Get connection information + * + * @return List of connection information + */ + List getConnectionInfo(); + + /** + * Get available peer information + * + * @return List of available peer + */ + List getAvailablePeer(); + + void setThreadPool(ExecutorService threadPool); +} 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 new file mode 100644 index 000000000..57a709447 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/ChannelImp.java @@ -0,0 +1,439 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.channel; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.netty.channel.ChannelException; +import io.netty.channel.ChannelHandlerContext; +import io.netty.util.HashedWheelTimer; +import io.netty.util.Timeout; +import io.netty.util.Timer; +import io.netty.util.TimerTask; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import org.fisco.bcos.sdk.channel.model.ChannelMessageError; +import org.fisco.bcos.sdk.channel.model.ChannelPrococolExceiption; +import org.fisco.bcos.sdk.channel.model.HeartBeatParser; +import org.fisco.bcos.sdk.channel.model.NodeHeartbeat; +import org.fisco.bcos.sdk.channel.model.Options; +import org.fisco.bcos.sdk.config.ConfigOption; +import org.fisco.bcos.sdk.config.exceptions.ConfigException; +import org.fisco.bcos.sdk.model.Message; +import org.fisco.bcos.sdk.model.MsgType; +import org.fisco.bcos.sdk.model.Response; +import org.fisco.bcos.sdk.network.ConnectionInfo; +import org.fisco.bcos.sdk.network.MsgHandler; +import org.fisco.bcos.sdk.network.Network; +import org.fisco.bcos.sdk.network.NetworkException; +import org.fisco.bcos.sdk.network.NetworkImp; +import org.fisco.bcos.sdk.utils.ChannelUtils; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; +import org.fisco.bcos.sdk.utils.ThreadPoolService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * An implementation of channel. + * + * @author chaychen + */ +public class ChannelImp implements Channel { + + private static Logger logger = LoggerFactory.getLogger(ChannelImp.class); + private Integer connectSeconds = 30; + private Integer connectSleepPerMillis = 30; + private boolean running = false; + + private ChannelMsgHandler msgHandler; + private Network network; + private Map> groupId2PeerIpPortList; // upper module settings are required + private Timer timeoutHandler = new HashedWheelTimer(); + private long heartBeatDelay = (long) 2000; + private ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1); + + public ChannelImp(ConfigOption configOption) throws ConfigException { + msgHandler = new ChannelMsgHandler(); + network = new NetworkImp(configOption, msgHandler); + } + + @Override + public Network getNetwork() { + return this.network; + } + + @Override + public void start() { + try { + if (running) { + logger.warn("The channel has already been started!"); + } + network.start(); + checkConnectionsToStartPeriodTask(); + running = true; + 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); + } + } + + private void checkConnectionsToStartPeriodTask() { + try { + int sleepTime = 0; + while (true) { + if (getAvailablePeer().size() > 0 || sleepTime > connectSeconds * 1000) { + break; + } else { + Thread.sleep(connectSleepPerMillis); + sleepTime += connectSleepPerMillis; + } + } + + List peers = getAvailablePeer(); + String connectionInfoStr = ""; + for (String peer : peers) { + connectionInfoStr += peer + ", "; + } + + String baseMessage = + " nodes: " + + connectionInfoStr + + "java version: " + + System.getProperty("java.version") + + " ,java vendor: " + + System.getProperty("java.vm.vendor"); + + if (getAvailablePeer().size() == 0) { + String errorMessage = " Failed to connect to " + baseMessage; + logger.error(errorMessage); + throw new Exception(errorMessage); + } + + logger.info(" Connect to " + baseMessage); + + startPeriodTask(); + } catch (InterruptedException e) { + logger.warn(" thread interrupted exception: ", e); + Thread.currentThread().interrupt(); + } catch (Exception e) { + logger.error(" service init failed, error message: {}, error: ", e.getMessage(), e); + } + } + + private void startPeriodTask() { + /** periodically send heartbeat message to all connected node, default period : 2s */ + scheduledExecutorService.scheduleAtFixedRate( + () -> broadcastHeartbeat(), 0, heartBeatDelay, TimeUnit.MILLISECONDS); + } + + @Override + public void stop() { + if (!running) { + logger.warn("The channel has already been stopped!"); + } + logger.debug("stop channel..."); + timeoutHandler.stop(); + ThreadPoolService.stopThreadPool(scheduledExecutorService); + network.stop(); + Thread.currentThread().interrupt(); + running = false; + logger.debug("stop channel succ..."); + } + + @Override + public void addConnectHandler(MsgHandler handler) { + msgHandler.addConnectHandler(handler); + } + + @Override + public void addEstablishHandler(MsgHandler handler) { + msgHandler.addEstablishHandler(handler); + } + + @Override + public void addMessageHandler(MsgType type, MsgHandler handler) { + msgHandler.addMessageHandler(type, handler); + } + + @Override + public void addDisconnectHandler(MsgHandler handler) { + msgHandler.addDisconnectHandler(handler); + } + + public void setGroupId2PeerIpPortList(Map> groupId2PeerIpPortList) { + this.groupId2PeerIpPortList = groupId2PeerIpPortList; + } + + @Override + public void broadcastToGroup(Message out, String groupId) { + List peerIpPortList = groupId2PeerIpPortList.get(groupId); + for (String peerIpPort : peerIpPortList) { + if (msgHandler.getAvailablePeer().containsKey(peerIpPort)) { + sendToPeer(out, peerIpPort); + } + } + } + + @Override + public void broadcast(Message out) { + msgHandler + .getAvailablePeer() + .forEach( + (peer, ctx) -> { + ctx.writeAndFlush(out); + logger.trace("send message to {} success ", peer); + }); + } + + @Override + public Response sendToPeer(Message out, String peerIpPort) { + Options options = new Options(); + options.setTimeout(10000); + return sendToPeerWithTimeOut(out, peerIpPort, options); + } + + class Callback extends ResponseCallback { + public transient Response retResponse; + public transient Semaphore semaphore = new Semaphore(1, true); + + Callback() { + try { + semaphore.acquire(1); + } catch (InterruptedException e) { + logger.error("error :", e); + Thread.currentThread().interrupt(); + } + } + + @Override + public void onTimeout() { + super.onTimeout(); + semaphore.release(); + } + + @Override + public void onResponse(Response response) { + retResponse = response; + if (retResponse != null && retResponse.getContent() != null) { + logger.trace("response: {}", retResponse.getContent()); + } else { + logger.error("response is null"); + } + + semaphore.release(); + } + } + + public void waitResponse(Callback callback, Options options) { + try { + callback.semaphore.acquire(1); + } catch (InterruptedException e) { + logger.error("waitResponse exception, error info: {}", e.getMessage()); + Thread.currentThread().interrupt(); + } + } + + @Override + public Response sendToPeerWithTimeOut(Message out, String peerIpPort, Options options) { + Callback callback = new Callback(); + asyncSendToPeer(out, peerIpPort, callback, options); + waitResponse(callback, options); + return callback.retResponse; + } + + @Override + public Response sendToRandomWithTimeOut(Message out, Options options) { + Callback callback = new Callback(); + asyncSendToRandom(out, callback, options); + waitResponse(callback, options); + return callback.retResponse; + } + + @Override + public Response sendToPeerByRuleWithTimeOut(Message out, PeerSelectRule rule, Options options) { + Callback callback = new Callback(); + asyncSendToPeerByRule(out, rule, callback, options); + waitResponse(callback, options); + return callback.retResponse; + } + + @Override + public void asyncSendToPeer( + Message out, String peerIpPort, ResponseCallback callback, Options options) { + ChannelHandlerContext ctx = null; + if (msgHandler.getAvailablePeer() != null) { + ctx = msgHandler.getAvailablePeer().get(peerIpPort); + } + if (ctx != null) { + if (callback == null) { + ctx.writeAndFlush(out); + return; + } + msgHandler.addSeq2CallBack(out.getSeq(), callback); + if (options.getTimeout() > 0) { + callback.setTimeout( + timeoutHandler.newTimeout( + new TimerTask() { + @Override + public void run(Timeout timeout) { + // handle timer + callback.onTimeout(); + msgHandler.removeSeq(out.getSeq()); + } + }, + options.getTimeout(), + TimeUnit.MILLISECONDS)); + } + ctx.writeAndFlush(out); + logger.trace("send message {} to {} success ", out.getSeq(), peerIpPort); + } else { + logger.warn("send message with seq {} to {} failed ", out.getSeq(), peerIpPort); + Response response = new Response(); + response.setErrorCode(ChannelMessageError.CONNECTION_INVALID.getError()); + response.setErrorMessage( + "Send message " + + peerIpPort + + " failed for connect failed, current available peers: " + + getAvailablePeer().toString()); + response.setMessageID(out.getSeq()); + if (callback != null) { + callback.onResponse(response); + } + } + } + + @Override + public void asyncSendToRandom(Message out, ResponseCallback callback, Options options) { + List peerList = getAvailablePeer(); + int random = (int) (Math.random() * (peerList.size())); + String peerIpPort = peerList.get(random); + logger.trace("send message to random peer {} ", peerIpPort); + asyncSendToPeer(out, peerIpPort, callback, options); + } + + @Override + public void asyncSendToPeerByRule( + Message out, PeerSelectRule rule, ResponseCallback callback, Options options) { + String target = rule.select(getConnectionInfo()); + asyncSendToPeer(out, target, callback, options); + } + + @Override + public List getConnectionInfo() { + return network.getConnectionInfo(); + } + + @Override + public List getAvailablePeer() { + List peerList = new ArrayList<>(); + msgHandler + .getAvailablePeer() + .forEach( + (peer, ctx) -> { + peerList.add(peer); + }); + return peerList; + } + + private void broadcastHeartbeat() { + try { + msgHandler + .getAvailablePeer() + .forEach( + (peer, ctx) -> { + sendHeartbeatMessage(ctx); + logger.trace("broadcastHeartbeat to {} success ", peer); + }); + } catch (Exception e) { + logger.error("broadcastHeartbeat failed, error info: {}", e.getMessage()); + } + } + + public void sendHeartbeatMessage(ChannelHandlerContext ctx) { + String seq = ChannelUtils.newSeq(); + Message message = new Message(); + + try { + message.setSeq(seq); + message.setResult(0); + message.setType(Short.valueOf((short) MsgType.CLIENT_HEARTBEAT.getType())); + HeartBeatParser heartBeatParser = + new HeartBeatParser(ChannelVersionNegotiation.getProtocolVersion(ctx)); + message.setData(heartBeatParser.encode("0")); + logger.trace( + "encodeHeartbeatToMessage, seq: {}, content: {}, messageType: {}", + message.getSeq(), + heartBeatParser.toString(), + message.getType()); + } catch (JsonProcessingException e) { + logger.error( + "sendHeartbeatMessage failed for decode the message exception, errorMessage: {}", + e.getMessage()); + return; + } + + ResponseCallback callback = + new ResponseCallback() { + @Override + public void onResponse(Response response) { + Boolean disconnect = true; + try { + if (response.getErrorCode() != 0) { + logger.error( + " channel protocol heartbeat request failed, code: {}, message: {}", + response.getErrorCode(), + response.getErrorMessage()); + throw new ChannelPrococolExceiption( + " channel protocol heartbeat request failed, code: " + + response.getErrorCode() + + ", message: " + + response.getErrorMessage()); + } + + NodeHeartbeat nodeHeartbeat = + ObjectMapperFactory.getObjectMapper() + .readValue(response.getContent(), NodeHeartbeat.class); + int heartBeat = nodeHeartbeat.getHeartBeat(); + logger.trace(" heartbeat packet, heartbeat is {} ", heartBeat); + disconnect = false; + } catch (Exception e) { + logger.error( + " channel protocol heartbeat failed, exception: {}", + e.getMessage()); + } + if (disconnect) { + String host = ChannelVersionNegotiation.getPeerHost(ctx); + network.removeConnection(host); + } + } + }; + + ctx.writeAndFlush(message); + msgHandler.addSeq2CallBack(seq, callback); + } + + @Override + public void setThreadPool(ExecutorService threadPool) { + network.setMsgHandleThreadPool(threadPool); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/ChannelMsgHandler.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/ChannelMsgHandler.java new file mode 100644 index 000000000..14bc3b843 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/ChannelMsgHandler.java @@ -0,0 +1,342 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.channel; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.netty.channel.ChannelHandlerContext; +import io.netty.util.AttributeKey; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import org.fisco.bcos.sdk.channel.model.ChannelHandshake; +import org.fisco.bcos.sdk.channel.model.ChannelMessageError; +import org.fisco.bcos.sdk.channel.model.ChannelPrococolExceiption; +import org.fisco.bcos.sdk.channel.model.ChannelProtocol; +import org.fisco.bcos.sdk.channel.model.ChannelRequest; +import org.fisco.bcos.sdk.channel.model.EnumChannelProtocolVersion; +import org.fisco.bcos.sdk.channel.model.EnumNodeVersion; +import org.fisco.bcos.sdk.channel.model.EnumSocketChannelAttributeKey; +import org.fisco.bcos.sdk.model.Message; +import org.fisco.bcos.sdk.model.MsgType; +import org.fisco.bcos.sdk.model.NodeVersion; +import org.fisco.bcos.sdk.model.Response; +import org.fisco.bcos.sdk.network.MsgHandler; +import org.fisco.bcos.sdk.utils.ChannelUtils; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * An implementation of channel. + * + * @author chaychen + */ +public class ChannelMsgHandler implements MsgHandler { + + private static Logger logger = LoggerFactory.getLogger(ChannelImp.class); + private final ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(); + + private List msgConnectHandlerList = new CopyOnWriteArrayList(); + private List msgDisconnectHandleList = new CopyOnWriteArrayList(); + private Map msgHandlers = new ConcurrentHashMap<>(); + private List msgEstablishHandlerList = new CopyOnWriteArrayList(); + + private Map seq2Callback = new ConcurrentHashMap<>(); + private Map availablePeer = new ConcurrentHashMap<>(); + + public Map getAvailablePeer() { + return availablePeer; + } + + public void addConnectHandler(MsgHandler handler) { + msgConnectHandlerList.add(handler); + } + + public void addEstablishHandler(MsgHandler handler) { + msgEstablishHandlerList.add(handler); + } + + public void addMessageHandler(MsgType type, MsgHandler handler) { + msgHandlers.put(type.getType(), handler); + } + + public void addDisconnectHandler(MsgHandler handler) { + msgDisconnectHandleList.add(handler); + } + + public void addSeq2CallBack(String seq, ResponseCallback callback) { + seq2Callback.put(seq, callback); + } + + public void removeSeq(String seq) { + seq2Callback.remove(seq); + } + + private void addAvailablePeer(String host, ChannelHandlerContext ctx) { + availablePeer.put(host, ctx); + for (MsgHandler msgHandler : msgEstablishHandlerList) { + msgHandler.onConnect(ctx); + } + } + + private void removeAvailablePeers(String host) { + if (availablePeer.containsKey(host)) { + availablePeer.remove(host); + } + } + + private ResponseCallback getAndRemoveSeq(String seq) { + ResponseCallback callback = seq2Callback.get(seq); + seq2Callback.remove(seq); + return callback; + } + + @Override + public void onConnect(ChannelHandlerContext ctx) { + logger.debug( + "onConnect in ChannelMsgHandler called, host : {}", + ChannelVersionNegotiation.getPeerHost(ctx)); + queryNodeVersion(ctx); + for (MsgHandler msgHandler : msgConnectHandlerList) { + msgHandler.onConnect(ctx); + } + } + + @Override + public void onMessage(ChannelHandlerContext ctx, Message msg) { + logger.trace( + "onMessage in ChannelMsgHandler called, host : {}, seq : {}, msgType : {}", + ChannelVersionNegotiation.getPeerHost(ctx), + msg.getSeq(), + (int) msg.getType()); + ResponseCallback callback = getAndRemoveSeq(msg.getSeq()); + if (callback != null) { + callback.cancelTimeout(); + logger.trace( + " receive response, seq: {}, result: {}, content: {}", + msg.getSeq(), + msg.getResult(), + new String(msg.getData())); + + Response response = new Response(); + if (msg.getResult() != 0) { + response.setErrorMessage("Response error"); + } + response.setErrorCode(msg.getResult()); + response.setMessageID(msg.getSeq()); + response.setContentBytes(msg.getData()); + response.setCtx(ctx); + callback.onResponse(response); + } else { + logger.trace( + " receive response with invalid seq, type: {}, result: {}, content: {}", + (int) msg.getType(), + msg.getResult(), + new String(msg.getData())); + MsgHandler msgHandler = msgHandlers.get(msg.getType().intValue()); + if (msgHandler != null) { + msgHandler.onMessage(ctx, msg); + } + } + } + + @Override + public void onDisconnect(ChannelHandlerContext ctx) { + String host = ChannelVersionNegotiation.getPeerHost(ctx); + logger.debug("onDisconnect in ChannelMsgHandler called, host : {}", host); + for (MsgHandler handle : msgDisconnectHandleList) { + handle.onDisconnect(ctx); + } + removeAvailablePeers(host); + } + + private void queryNodeVersion(ChannelHandlerContext ctx) { + ChannelRequest request = new ChannelRequest("getClientVersion", Arrays.asList()); + String seq = ChannelUtils.newSeq(); + Message message = new Message(); + try { + byte[] payload = objectMapper.writeValueAsBytes(request); + message.setSeq(seq); + message.setResult(0); + message.setType((short) MsgType.CHANNEL_RPC_REQUEST.getType()); + message.setData(payload); + logger.trace( + "encodeRequestToMessage, seq: {}, method: {}, messageType: {}", + message.getSeq(), + request.getMethod(), + message.getType()); + } catch (JsonProcessingException e) { + logger.error( + "encodeRequestToMessage failed for decode the message exception, errorMessage: {}", + e.getMessage()); + } + + ResponseCallback callback = + new ResponseCallback() { + @Override + public void onResponse(Response response) { + Boolean disconnect = true; + try { + if (response.getErrorCode() + == ChannelMessageError.MESSAGE_TIMEOUT.getError()) { + // The node version number is below 2.1.0 when request timeout + ChannelVersionNegotiation.setProtocolVersion( + ctx, + EnumChannelProtocolVersion.VERSION_1, + "below-2.1.0-timeout"); + + logger.info( + " query node version timeout, content: {}", + response.getContent()); + return; + } else if (response.getErrorCode() != 0) { + logger.error( + " node version response, code: {}, message: {}", + response.getErrorCode(), + response.getErrorMessage()); + + throw new ChannelPrococolExceiption( + " query node version failed, code: " + + response.getErrorCode() + + ", message: " + + response.getErrorMessage()); + } + + NodeVersion nodeVersion = + objectMapper.readValue( + response.getContent(), NodeVersion.class); + logger.info( + " node: {}, content: {}", + nodeVersion.getResult(), + response.getContent()); + + if (EnumNodeVersion.channelProtocolHandleShakeSupport( + nodeVersion.getResult().getSupportedVersion())) { + // node support channel protocol handshake, start it + logger.info(" support channel handshake node"); + queryChannelProtocolVersion(ctx); + } else { // default channel protocol + logger.info(" not support channel handshake set default"); + ChannelVersionNegotiation.setProtocolVersion( + ctx, + EnumChannelProtocolVersion.VERSION_1, + nodeVersion.getResult().getSupportedVersion()); + addPeerHost(ctx); + } + disconnect = false; + } catch (Exception e) { + logger.error(" query node version failed, message: {}", e.getMessage()); + } + + if (disconnect) { + ctx.disconnect(); + ctx.close(); + } + } + }; + + ctx.writeAndFlush(message); + addSeq2CallBack(seq, callback); + } + + private void queryChannelProtocolVersion(ChannelHandlerContext ctx) + throws ChannelPrococolExceiption { + final String host = ChannelVersionNegotiation.getPeerHost(ctx); + String seq = ChannelUtils.newSeq(); + Message message = new Message(); + + try { + ChannelHandshake channelHandshake = new ChannelHandshake(); + byte[] payload = objectMapper.writeValueAsBytes(channelHandshake); + message.setSeq(seq); + message.setResult(0); + message.setType(Short.valueOf((short) MsgType.CLIENT_HANDSHAKE.getType())); + message.setData(payload); + logger.trace( + "encodeChannelHandshakeToMessage, seq: {}, data: {}, messageType: {}", + message.getSeq(), + channelHandshake.toString(), + message.getType()); + } catch (JsonProcessingException e) { + logger.error( + "queryChannelProtocolVersion failed for decode the message exception, errorMessage: {}", + e.getMessage()); + throw new ChannelPrococolExceiption(e.getMessage()); + } + + ResponseCallback callback = + new ResponseCallback() { + @Override + public void onResponse(Response response) { + Boolean disconnect = true; + try { + if (response.getErrorCode() != 0) { + logger.error( + " channel protocol handshake request failed, code: {}, message: {}", + response.getErrorCode(), + response.getErrorMessage()); + throw new ChannelPrococolExceiption( + " channel protocol handshake request failed, code: " + + response.getErrorCode() + + ", message: " + + response.getErrorMessage()); + } + + ChannelProtocol channelProtocol = + objectMapper.readValue( + response.getContent(), ChannelProtocol.class); + EnumChannelProtocolVersion enumChannelProtocolVersion = + EnumChannelProtocolVersion.toEnum( + channelProtocol.getProtocol()); + channelProtocol.setEnumProtocol(enumChannelProtocolVersion); + logger.info( + " channel protocol handshake success, set socket channel protocol, host: {}, channel protocol: {}", + host, + channelProtocol); + + ctx.channel() + .attr( + AttributeKey.valueOf( + EnumSocketChannelAttributeKey + .CHANNEL_PROTOCOL_KEY.getKey())) + .set(channelProtocol); + disconnect = false; + } catch (Exception e) { + logger.error( + " channel protocol handshake failed, exception: {}", + e.getMessage()); + } + if (disconnect) { + ctx.disconnect(); + ctx.close(); + } else { + addPeerHost(ctx); + } + } + }; + + ctx.writeAndFlush(message); + addSeq2CallBack(seq, callback); + } + + private void addPeerHost(ChannelHandlerContext ctx) { + String host = ChannelVersionNegotiation.getPeerHost(ctx); + addAvailablePeer(host, ctx); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/ChannelVersionNegotiation.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/ChannelVersionNegotiation.java new file mode 100644 index 000000000..71303bfaf --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/ChannelVersionNegotiation.java @@ -0,0 +1,66 @@ +package org.fisco.bcos.sdk.channel; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.socket.SocketChannel; +import io.netty.util.AttributeKey; +import org.fisco.bcos.sdk.channel.model.ChannelProtocol; +import org.fisco.bcos.sdk.channel.model.EnumChannelProtocolVersion; +import org.fisco.bcos.sdk.channel.model.EnumSocketChannelAttributeKey; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ChannelVersionNegotiation { + + private static Logger logger = LoggerFactory.getLogger(ChannelVersionNegotiation.class); + + public static void setProtocolVersion( + ChannelHandlerContext ctx, EnumChannelProtocolVersion version, String nodeVersion) { + ChannelProtocol channelProtocol = new ChannelProtocol(); + channelProtocol.setProtocol(version.getVersionNumber()); + channelProtocol.setNodeVersion(nodeVersion); + channelProtocol.setEnumProtocol(version); + ctx.channel() + .attr( + AttributeKey.valueOf( + EnumSocketChannelAttributeKey.CHANNEL_PROTOCOL_KEY.getKey())) + .set(channelProtocol); + } + + public static void setCtxAttibuteValue(ChannelHandlerContext ctx, String key, String value) { + + AttributeKey attributeKey = AttributeKey.valueOf(key); + ctx.channel().attr(attributeKey).set(value); + } + + public static EnumChannelProtocolVersion getProtocolVersion(ChannelHandlerContext ctx) { + + String host = getPeerHost(ctx); + AttributeKey attributeKey = + AttributeKey.valueOf(EnumSocketChannelAttributeKey.CHANNEL_PROTOCOL_KEY.getKey()); + if (ctx.channel().hasAttr(attributeKey)) { + ChannelProtocol channelProtocol = ctx.channel().attr(attributeKey).get(); + if (null != channelProtocol) { + return channelProtocol.getEnumProtocol(); + } else { + logger.warn(" channel has attr but get null, host: {}", host); + } + } else { + logger.warn(" channel has not attr, host: {}", host); + } + + return null; + } + + public static String getPeerHost(ChannelHandlerContext ctx) { + + SocketChannel socketChannel = (SocketChannel) ctx.channel(); + String hostAddress = socketChannel.remoteAddress().getAddress().getHostAddress(); + int port = socketChannel.remoteAddress().getPort(); + return hostAddress + ":" + port; + } + + public static boolean isChannelAvailable(ChannelHandlerContext ctx) { + + return (null != ctx) && ctx.channel().isActive() && (null != getProtocolVersion(ctx)); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/PeerSelectRule.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/PeerSelectRule.java new file mode 100644 index 000000000..416626453 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/PeerSelectRule.java @@ -0,0 +1,29 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.channel; + +import java.util.List; +import org.fisco.bcos.sdk.network.ConnectionInfo; + +public interface PeerSelectRule { + /** + * PeerSelectRule Customize a rule to select a peer to send message to + * + * @param conns the list of connection info + * @return the selected peer + */ + String select(List conns); +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/ResponseCallback.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/ResponseCallback.java new file mode 100644 index 000000000..d6cb5a73e --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/ResponseCallback.java @@ -0,0 +1,71 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.channel; + +import io.netty.util.Timeout; +import org.fisco.bcos.sdk.channel.model.ChannelMessageError; +import org.fisco.bcos.sdk.model.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** ResponseCallback is to define a callback to handle response from node. */ +public abstract class ResponseCallback { + + private static Logger logger = LoggerFactory.getLogger(ResponseCallback.class); + + private Timeout timeout; + + /** + * OnResponse + * + * @param response the response from node + */ + public abstract void onResponse(Response response); + + public void onTimeout() { + logger.error("Processing message timeout:{}"); + cancelTimeout(); + Response response = new Response(); + response.setErrorCode(ChannelMessageError.MESSAGE_TIMEOUT.getError()); + response.setErrorMessage("Processing message timeout"); + + response.setContent(""); + + onResponse(response); + } + + public void cancelTimeout() { + if (getTimeout() != null && !getTimeout().isCancelled()) { + getTimeout().cancel(); + } + } + + public void onError(String errorMessage) { + cancelTimeout(); + Response response = new Response(); + response.setErrorCode(ChannelMessageError.INTERNAL_MESSAGE_HANDLE_FAILED.getError()); + response.setErrorMessage(errorMessage); + onResponse(response); + } + + public Timeout getTimeout() { + return timeout; + } + + public void setTimeout(Timeout timeout) { + this.timeout = timeout; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/ChannelHandshake.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/ChannelHandshake.java new file mode 100644 index 000000000..735fb676e --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/ChannelHandshake.java @@ -0,0 +1,44 @@ +package org.fisco.bcos.sdk.channel.model; + +public class ChannelHandshake { + private int maximumSupport = EnumChannelProtocolVersion.getMaximumProtocol().getVersionNumber(); + + private int minimumSupport = EnumChannelProtocolVersion.getMinimumProtocol().getVersionNumber(); + + private String clientType = "java-sdk"; + + public int getMaximumSupport() { + return maximumSupport; + } + + public void setMaximumSupport(int maximumSupport) { + this.maximumSupport = maximumSupport; + } + + public int getMinimumSupport() { + return minimumSupport; + } + + public void setMinimumSupport(int minimumSupport) { + this.minimumSupport = minimumSupport; + } + + public String getClientType() { + return clientType; + } + + public void setClientType(String clientType) { + this.clientType = clientType; + } + + @Override + public String toString() { + return "ChannelHandshake [maximumSupport=" + + maximumSupport + + ", minimumSupport=" + + minimumSupport + + ", clientType=" + + clientType + + "]"; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/ChannelMessageError.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/ChannelMessageError.java new file mode 100644 index 000000000..be1a815a0 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/ChannelMessageError.java @@ -0,0 +1,27 @@ +package org.fisco.bcos.sdk.channel.model; + +public enum ChannelMessageError { + NODES_UNREACHABLE(99), // node unreachable + MESSAGE_SEND_EXCEPTION(100), // send failed after N times retry + MESSAGE_TIMEOUT(102), // timeout + REJECT_AMOP_REQ_FOR_OVER_BANDWIDTHLIMIT( + 103), // the AMOP_requests or the AMOP_multicast_requests have been rejected due to over + // bandwidth limit + MESSAGE_DECODE_ERROR(105), // decode error + INTERNAL_MESSAGE_HANDLE_FAILED(-5000), + CONNECTION_INVALID(-5001); + + private int error; + + private ChannelMessageError(int error) { + this.setError(error); + } + + public int getError() { + return error; + } + + public void setError(int error) { + this.error = error; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/ChannelPrococolExceiption.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/ChannelPrococolExceiption.java new file mode 100644 index 000000000..3db434fe8 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/ChannelPrococolExceiption.java @@ -0,0 +1,8 @@ +package org.fisco.bcos.sdk.channel.model; + +public class ChannelPrococolExceiption extends Exception { + + public ChannelPrococolExceiption(String message) { + super(message); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/ChannelProtocol.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/ChannelProtocol.java new file mode 100644 index 000000000..bf9ec95a4 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/ChannelProtocol.java @@ -0,0 +1,47 @@ +package org.fisco.bcos.sdk.channel.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class ChannelProtocol { + private int protocol; + + private String nodeVersion; + + @JsonIgnore private EnumChannelProtocolVersion EnumProtocol; + + public String getNodeVersion() { + return nodeVersion; + } + + public void setNodeVersion(String nodeVersion) { + this.nodeVersion = nodeVersion; + } + + public int getProtocol() { + return protocol; + } + + public void setProtocol(int protocol) { + this.protocol = protocol; + } + + @JsonIgnore + public EnumChannelProtocolVersion getEnumProtocol() { + return EnumProtocol; + } + + public void setEnumProtocol(EnumChannelProtocolVersion enumProtocol) { + EnumProtocol = enumProtocol; + } + + @Override + public String toString() { + return "ChannelProtocol [protocol=" + + protocol + + ", nodeVersion=" + + nodeVersion + + ", EnumProtocol=" + + EnumProtocol + + "]"; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/ChannelRequest.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/ChannelRequest.java new file mode 100644 index 000000000..370dcec5b --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/ChannelRequest.java @@ -0,0 +1,53 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.channel.model; + +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +public class ChannelRequest { + // for set the json id + private static AtomicLong nextIdGetter = new AtomicLong(0); + // the jsonrpc version, default is 2.0 + private String jsonrpc = "2.0"; + // rpc method + private String method; + // params for the rpc interface + private List params; + // the json rpc request id + private long id; + + public ChannelRequest(String method, List params) { + this.method = method; + this.params = params; + this.id = nextIdGetter.getAndIncrement(); + } + + // getter and setter for the class members + public String getJsonrpc() { + return this.jsonrpc; + } + + public String getMethod() { + return this.method; + } + + public long getId() { + return this.id; + } + + public List getParams() { + return this.params; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/EnumChannelProtocolVersion.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/EnumChannelProtocolVersion.java new file mode 100644 index 000000000..96729c41a --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/EnumChannelProtocolVersion.java @@ -0,0 +1,53 @@ +package org.fisco.bcos.sdk.channel.model; + +public enum EnumChannelProtocolVersion { + VERSION_1(1), // default version + VERSION_2(2), + VERSION_3(3); + + private int versionNumber; + + private EnumChannelProtocolVersion(int versionNumber) { + this.setVersionNumber(versionNumber); + } + + public int getVersionNumber() { + return versionNumber; + } + + public void setVersionNumber(int versionNumber) { + this.versionNumber = versionNumber; + } + + public static EnumChannelProtocolVersion getMinimumProtocol() { + // get minimum version number supported + EnumChannelProtocolVersion[] versions = EnumChannelProtocolVersion.values(); + if (0 == versions.length) { + return EnumChannelProtocolVersion.VERSION_1; + } + + return versions[0]; + } + + public static EnumChannelProtocolVersion getMaximumProtocol() { + // get highest version number supported + EnumChannelProtocolVersion[] versions = EnumChannelProtocolVersion.values(); + if (0 == versions.length) { + return EnumChannelProtocolVersion.VERSION_1; + } + + return versions[versions.length - 1]; + } + + public static EnumChannelProtocolVersion toEnum(int v) throws ChannelPrococolExceiption { + + for (EnumChannelProtocolVersion enumVersion : EnumChannelProtocolVersion.values()) { + if (enumVersion.getVersionNumber() == v) { + return enumVersion; + } + } + + throw new ChannelPrococolExceiption( + " not support channel protocol, version " + String.valueOf(v)); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/EnumNodeVersion.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/EnumNodeVersion.java new file mode 100644 index 000000000..f35575c28 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/EnumNodeVersion.java @@ -0,0 +1,116 @@ +package org.fisco.bcos.sdk.channel.model; + +public enum EnumNodeVersion { + BCOS_2_0_0_RC1("2.0.0-rc1"), + BCOS_2_0_0("2.0.0"), + BCOS_2_1_0("2.1.0"); + + private String version; + + private EnumNodeVersion(String version) { + this.version = version; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + // the object of node version + public class Version { + private int major; + private int minor; + private int patch; + private String ext; + + @Override + public String toString() { + return "Version [major=" + + major + + ", minor=" + + minor + + ", patch=" + + patch + + ", ext=" + + ext + + "]"; + } + + public String toVersionString() { + return this.getMajor() + "." + this.getMinor(); + } + + public int getMajor() { + return major; + } + + public void setMajor(int major) { + this.major = major; + } + + public int getMinor() { + return minor; + } + + public void setMinor(int minor) { + this.minor = minor; + } + + public int getPatch() { + return patch; + } + + public void setPatch(int patch) { + this.patch = patch; + } + + public String getExt() { + return ext; + } + + public void setExt(String ext) { + this.ext = ext; + } + } + + public static Version getClassVersion(String version) throws ChannelPrococolExceiption { + try { + // node version str format : "a.b.c" or "a.b.c-rcx" or gm version + if (version.endsWith("gm")) { + version = version.substring(0, version.indexOf("gm")); + } + String[] s0 = version.trim().split("-"); + + Version v = EnumNodeVersion.BCOS_2_0_0.new Version(); + if (s0.length > 1) { + v.setExt(s0[1]); + } + + // + String[] s1 = s0[0].split("\\."); + if (s1.length >= 3) { + v.setMajor(Integer.parseInt(s1[0].trim())); + v.setMinor(Integer.parseInt(s1[1].trim())); + v.setPatch(Integer.parseInt(s1[2].trim())); + } else { // invaid format + throw new ChannelPrococolExceiption( + " invalid node version format, version: " + version); + } + + return v; + } catch (Exception e) { + throw new ChannelPrococolExceiption( + " invalid node version format, version: " + version); + } + } + + public static boolean channelProtocolHandleShakeSupport(String version) + throws ChannelPrococolExceiption { + Version v = getClassVersion(version); + // 2.1.0 and above + return (v.getMajor() == 2) && (v.getMinor() >= 1); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/EnumSocketChannelAttributeKey.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/EnumSocketChannelAttributeKey.java new file mode 100644 index 000000000..e6c4ef400 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/EnumSocketChannelAttributeKey.java @@ -0,0 +1,19 @@ +package org.fisco.bcos.sdk.channel.model; + +public enum EnumSocketChannelAttributeKey { + CHANNEL_PROTOCOL_KEY("CHANNEL_PROTOCOL_KEY"); + + private String key; + + EnumSocketChannelAttributeKey(String key) { + this.key = key; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/HeartBeatParser.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/HeartBeatParser.java new file mode 100644 index 000000000..ae4e59343 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/HeartBeatParser.java @@ -0,0 +1,68 @@ +package org.fisco.bcos.sdk.channel.model; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import java.io.IOException; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; + +public class HeartBeatParser { + + public EnumChannelProtocolVersion version; + + public HeartBeatParser(EnumChannelProtocolVersion version) { + this.version = version; + } + + public EnumChannelProtocolVersion getVersion() { + return version; + } + + public void setVersion(EnumChannelProtocolVersion version) { + this.version = version; + } + + public byte[] encode(String value) throws JsonProcessingException { + + byte[] result = null; + + switch (getVersion()) { + case VERSION_1: + { + result = value.getBytes(); + } + break; + default: + { + NodeHeartbeat nodeHeartbeat = new NodeHeartbeat(); + nodeHeartbeat.setHeartBeat(Integer.parseInt(value)); + result = ObjectMapperFactory.getObjectMapper().writeValueAsBytes(nodeHeartbeat); + } + break; + } + + return result; + } + + public NodeHeartbeat decode(String data) + throws JsonParseException, JsonMappingException, IOException { + NodeHeartbeat nodeHeartbeat = new NodeHeartbeat(); + + switch (getVersion()) { + case VERSION_1: + { + nodeHeartbeat.setHeartBeat(Integer.parseInt(data)); + } + break; + default: + { + nodeHeartbeat = + ObjectMapperFactory.getObjectMapper() + .readValue(data, NodeHeartbeat.class); + } + break; + } + + return nodeHeartbeat; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/NodeHeartbeat.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/NodeHeartbeat.java new file mode 100644 index 000000000..d3b3e10c4 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/NodeHeartbeat.java @@ -0,0 +1,18 @@ +package org.fisco.bcos.sdk.channel.model; + +public class NodeHeartbeat { + public int heartBeat; + + public int getHeartBeat() { + return heartBeat; + } + + public void setHeartBeat(int HeartBeat) { + this.heartBeat = HeartBeat; + } + + @Override + public String toString() { + return "NodeHeartbeat [heartBeat=" + heartBeat + "]"; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/Options.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/Options.java new file mode 100644 index 000000000..f30fb8103 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/channel/model/Options.java @@ -0,0 +1,13 @@ +package org.fisco.bcos.sdk.channel.model; + +public class Options { + public long timeout = 0; + + public long getTimeout() { + return timeout; + } + + public void setTimeout(long timeout) { + this.timeout = timeout; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/config/Config.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/Config.java new file mode 100644 index 000000000..bcc034de9 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/Config.java @@ -0,0 +1,52 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.config; + +import com.moandjiezana.toml.Toml; +import java.io.File; +import org.fisco.bcos.sdk.config.exceptions.ConfigException; +import org.fisco.bcos.sdk.config.model.ConfigProperty; +import org.fisco.bcos.sdk.model.CryptoType; + +/** + * Config is to load config file and verify. + * + * @author Maggie + */ +public class Config { + public static ConfigOption load(String tomlConfigFile) throws ConfigException { + // default load ECDSA config + return load(tomlConfigFile, CryptoType.ECDSA_TYPE); + } + /** + * @param tomlConfigFile the toml configuration file path + * @param cryptoType the type of crypto function + * @return ConfigOption the configuration object + * @throws ConfigException the configuration exception + */ + public static ConfigOption load(String tomlConfigFile, int cryptoType) throws ConfigException { + // Load a toml config file to an java object + File configFile = new File(tomlConfigFile); + try { + ConfigProperty configProperty = new Toml().read(configFile).to(ConfigProperty.class); + ConfigOption configOption = new ConfigOption(configProperty, cryptoType); + return configOption; + } catch (Exception e) { + throw new ConfigException( + "parse Config " + tomlConfigFile + " failed, error info: " + e.getMessage(), e); + } + } +} 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 new file mode 100644 index 000000000..1d3123830 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/ConfigOption.java @@ -0,0 +1,104 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.config; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.fisco.bcos.sdk.config.exceptions.ConfigException; +import org.fisco.bcos.sdk.config.model.AccountConfig; +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.NetworkConfig; +import org.fisco.bcos.sdk.config.model.ThreadPoolConfig; +import org.fisco.bcos.sdk.model.CryptoType; + +/** + * ConfigOption is the java object of the config file. + * + * @author Maggie + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class ConfigOption { + private CryptoMaterialConfig cryptoMaterialConfig; + private AccountConfig accountConfig; + private AmopConfig amopConfig; + private NetworkConfig networkConfig; + private ThreadPoolConfig threadPoolConfig; + private ConfigProperty configProperty; + + public ConfigOption(ConfigProperty configProperty) throws ConfigException { + this(configProperty, CryptoType.ECDSA_TYPE); + } + + public ConfigOption(ConfigProperty configProperty, int cryptoType) throws ConfigException { + // load cryptoMaterialConfig + cryptoMaterialConfig = new CryptoMaterialConfig(configProperty, cryptoType); + // load accountConfig + accountConfig = new AccountConfig(configProperty); + // load AmopConfig + amopConfig = new AmopConfig(configProperty); + // load networkConfig + networkConfig = new NetworkConfig(configProperty); + // load threadPoolConfig + threadPoolConfig = new ThreadPoolConfig(configProperty); + // init configProperty + this.configProperty = configProperty; + } + + public void reloadConfig(int cryptoType) throws ConfigException { + cryptoMaterialConfig = new CryptoMaterialConfig(configProperty, cryptoType); + } + + public CryptoMaterialConfig getCryptoMaterialConfig() { + return cryptoMaterialConfig; + } + + public void setCryptoMaterialConfig(CryptoMaterialConfig cryptoMaterialConfig) { + this.cryptoMaterialConfig = cryptoMaterialConfig; + } + + public AccountConfig getAccountConfig() { + return accountConfig; + } + + public void setAccountConfig(AccountConfig accountConfig) { + this.accountConfig = accountConfig; + } + + public AmopConfig getAmopConfig() { + return amopConfig; + } + + public void setAmopConfig(AmopConfig amopConfig) { + this.amopConfig = amopConfig; + } + + public NetworkConfig getNetworkConfig() { + return networkConfig; + } + + public void setNetworkConfig(NetworkConfig networkConfig) { + this.networkConfig = networkConfig; + } + + public ThreadPoolConfig getThreadPoolConfig() { + return threadPoolConfig; + } + + public void setThreadPoolConfig(ThreadPoolConfig threadPoolConfig) { + this.threadPoolConfig = threadPoolConfig; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/config/exceptions/ConfigException.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/exceptions/ConfigException.java new file mode 100644 index 000000000..622a1aabf --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/exceptions/ConfigException.java @@ -0,0 +1,30 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.config.exceptions; + +public class ConfigException extends Exception { + public ConfigException(String message) { + super(message); + } + + public ConfigException(Throwable cause) { + super(cause); + } + + public ConfigException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/AccountConfig.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/AccountConfig.java new file mode 100644 index 000000000..303ffae2c --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/AccountConfig.java @@ -0,0 +1,143 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.config.model; + +import java.util.Objects; +import org.fisco.bcos.sdk.config.exceptions.ConfigException; + +public class AccountConfig { + private String keyStoreDir; + private String accountAddress; + private String accountFileFormat; + private String accountPassword; + private String accountFilePath; + + public AccountConfig(ConfigProperty configProperty) throws ConfigException { + this.keyStoreDir = + ConfigProperty.getValue(configProperty.getAccount(), "keyStoreDir", "account"); + this.accountAddress = + ConfigProperty.getValue(configProperty.getAccount(), "accountAddress", ""); + this.accountFileFormat = + ConfigProperty.getValue(configProperty.getAccount(), "accountFileFormat", "pem"); + this.accountPassword = ConfigProperty.getValue(configProperty.getAccount(), "password", ""); + this.accountFilePath = + ConfigProperty.getValue(configProperty.getAccount(), "accountFilePath", ""); + checkAccountConfig(); + } + + private void checkAccountConfig() throws ConfigException { + if (this.accountAddress.equals("")) { + return; + } + // check account format + if ("pem".compareToIgnoreCase(accountFileFormat) != 0 + && "p12".compareToIgnoreCase(accountFileFormat) != 0) { + throw new ConfigException( + "load account failed, only support pem and p12 account file format, current configurated account file format is " + + accountFileFormat); + } + } + + public String getAccountFilePath() { + return accountFilePath; + } + + public void setAccountFilePath(String accountFilePath) { + this.accountFilePath = accountFilePath; + } + + public String getKeyStoreDir() { + return keyStoreDir; + } + + public void setKeyStoreDir(String keyStoreDir) { + this.keyStoreDir = keyStoreDir; + } + + public String getAccountAddress() { + return accountAddress; + } + + public void setAccountAddress(String accountAddress) { + this.accountAddress = accountAddress; + } + + public String getAccountFileFormat() { + return accountFileFormat; + } + + public void setAccountFileFormat(String accountFileFormat) { + this.accountFileFormat = accountFileFormat; + } + + public String getAccountPassword() { + return accountPassword; + } + + public void setAccountPassword(String accountPassword) { + this.accountPassword = accountPassword; + } + + @Override + public String toString() { + return "AccountConfig{" + + "keyStoreDir='" + + keyStoreDir + + '\'' + + ", accountAddress='" + + accountAddress + + '\'' + + ", accountFileFormat='" + + accountFileFormat + + '\'' + + ", accountPassword='" + + accountPassword + + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AccountConfig that = (AccountConfig) o; + return Objects.equals(keyStoreDir, that.keyStoreDir) + && Objects.equals(accountAddress, that.accountAddress) + && Objects.equals(accountFileFormat, that.accountFileFormat) + && Objects.equals(accountPassword, that.accountPassword); + } + + @Override + public int hashCode() { + return Objects.hash(keyStoreDir, accountAddress, accountFileFormat, accountPassword); + } + + public void clearAccount() { + this.accountFilePath = ""; + this.accountAddress = ""; + this.accountPassword = ""; + } + + public boolean isAccountConfigured() { + if (accountFilePath != null && !accountFilePath.equals("")) { + return true; + } + if (accountAddress != null && !accountAddress.equals("")) { + return true; + } + return false; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/AmopConfig.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/AmopConfig.java new file mode 100644 index 000000000..7eed990ee --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/AmopConfig.java @@ -0,0 +1,68 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.config.model; + +import java.io.File; +import java.util.List; +import org.fisco.bcos.sdk.config.exceptions.ConfigException; + +public class AmopConfig { + // AMOP topic related config + private List amopTopicConfig; + + public AmopConfig(ConfigProperty configProperty) throws ConfigException { + this.amopTopicConfig = configProperty.getAmop(); + if (amopTopicConfig == null) { + return; + } + // Check Amop configure + // checkFileExist(); + + } + + private void checkFileExist() throws ConfigException { + for (AmopTopic topic : amopTopicConfig) { + if (null != topic.getPrivateKey()) { + File privateKeyFile = new File(topic.getPrivateKey()); + if (!privateKeyFile.exists()) { + throw new ConfigException( + "Invalid configuration, " + topic.getPrivateKey() + " file not exist"); + } + } else if (null != topic.getPublicKeys()) { + for (String pubKey : topic.getPublicKeys()) { + File pubKeyFile = new File(pubKey); + if (!pubKeyFile.exists()) { + throw new ConfigException( + "Invalid configuration, " + pubKey + " file not exist"); + } + } + } else { + throw new ConfigException( + "Amop private topic is not configured right, please check your config file. Topic name " + + topic.getTopicName() + + ", neither private key nor public key list configured."); + } + } + } + + public List getAmopTopicConfig() { + return amopTopicConfig; + } + + public void setAmopTopicConfig(List amopTopicConfig) { + this.amopTopicConfig = amopTopicConfig; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/AmopTopic.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/AmopTopic.java new file mode 100644 index 000000000..927bb9fa8 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/AmopTopic.java @@ -0,0 +1,71 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.config.model; + +import java.util.List; + +public class AmopTopic { + public String topicName; + public List publicKeys; + public String privateKey; + public String password; + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public List getPublicKeys() { + return publicKeys; + } + + public void setPublicKeys(List publicKeys) { + this.publicKeys = publicKeys; + } + + public String getPrivateKey() { + return privateKey; + } + + public void setPrivateKey(String privateKey) { + this.privateKey = privateKey; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + @Override + public String toString() { + return "AmopTopic{" + + "topicName='" + + topicName + + '\'' + + ", publicKeys=" + + publicKeys + + ", privateKey='" + + privateKey + + '\'' + + '}'; + } +} 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 new file mode 100644 index 000000000..8f8c828c5 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/ConfigProperty.java @@ -0,0 +1,82 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.config.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.List; +import java.util.Map; + +/** + * ConfigOption is the java object of the config file. + * + * @author Maggie + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class ConfigProperty { + public Map cryptoMaterial; + public Map network; + public List amop; + public Map account; + + public Map threadPool; + + public Map getCryptoMaterial() { + return cryptoMaterial; + } + + public void setCryptoMaterial(Map cryptoMaterial) { + this.cryptoMaterial = cryptoMaterial; + } + + public Map getNetwork() { + return network; + } + + public void setNetwork(Map network) { + this.network = network; + } + + public List getAmop() { + return amop; + } + + public void setAmop(List amop) { + this.amop = amop; + } + + public Map getAccount() { + return account; + } + + public void setAccount(Map account) { + this.account = account; + } + + public Map getThreadPool() { + return threadPool; + } + + public void setThreadPool(Map threadPool) { + this.threadPool = threadPool; + } + + public static String getValue(Map config, String key, String defaultValue) { + if (config == null || config.get(key) == null) { + return defaultValue; + } + return (String) config.get(key); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/CryptoMaterialConfig.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/CryptoMaterialConfig.java new file mode 100644 index 000000000..166f628cb --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/CryptoMaterialConfig.java @@ -0,0 +1,161 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.config.model; + +import java.io.File; +import java.util.Map; +import org.fisco.bcos.sdk.config.exceptions.ConfigException; +import org.fisco.bcos.sdk.model.CryptoType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CryptoMaterialConfig { + private static Logger logger = LoggerFactory.getLogger(CryptoMaterialConfig.class); + private String certPath = "conf"; + private String caCertPath; + private String sdkCertPath; + private String sdkPrivateKeyPath; + private String enSSLCertPath; + private String enSSLPrivateKeyPath; + private int sslCryptoType; + + protected CryptoMaterialConfig() {} + + public CryptoMaterialConfig(ConfigProperty configProperty, int cryptoType) + throws ConfigException { + this.sslCryptoType = cryptoType; + Map cryptoMaterialProperty = configProperty.getCryptoMaterial(); + this.certPath = ConfigProperty.getValue(cryptoMaterialProperty, "certPath", this.certPath); + CryptoMaterialConfig defaultCryptoMaterialConfig = + getDefaultCaCertPath(cryptoType, this.certPath); + this.caCertPath = + ConfigProperty.getValue( + cryptoMaterialProperty, + "caCert", + defaultCryptoMaterialConfig.getCaCertPath()); + this.sdkCertPath = + ConfigProperty.getValue( + cryptoMaterialProperty, + "sslCert", + defaultCryptoMaterialConfig.getSdkCertPath()); + this.sdkPrivateKeyPath = + ConfigProperty.getValue( + cryptoMaterialProperty, + "sslKey", + defaultCryptoMaterialConfig.getSdkPrivateKeyPath()); + this.enSSLCertPath = + ConfigProperty.getValue( + cryptoMaterialProperty, + "enSslCert", + defaultCryptoMaterialConfig.getEnSSLCertPath()); + this.enSSLPrivateKeyPath = + ConfigProperty.getValue( + cryptoMaterialProperty, + "enSslKey", + defaultCryptoMaterialConfig.getEnSSLPrivateKeyPath()); + logger.debug( + "Load cryptoMaterial, caCertPath: {}, sdkCertPath: {}, sdkPrivateKeyPath:{}, enSSLCertPath: {}, enSSLPrivateKeyPath:{}", + this.getCaCertPath(), + this.getSdkCertPath(), + this.getSdkPrivateKeyPath(), + this.getEnSSLCertPath(), + this.getEnSSLPrivateKeyPath()); + } + + public CryptoMaterialConfig getDefaultCaCertPath(int cryptoType, String certPath) + throws ConfigException { + CryptoMaterialConfig cryptoMaterialConfig = new CryptoMaterialConfig(); + cryptoMaterialConfig.setCertPath(certPath); + String smDir = "gm"; + if (cryptoType == CryptoType.ECDSA_TYPE) { + cryptoMaterialConfig.setCaCertPath(certPath + File.separator + "ca.crt"); + cryptoMaterialConfig.setSdkCertPath(certPath + File.separator + "sdk.crt"); + cryptoMaterialConfig.setSdkPrivateKeyPath(certPath + File.separator + "sdk.key"); + } else if (cryptoType == CryptoType.SM_TYPE) { + cryptoMaterialConfig.setCaCertPath( + certPath + File.separator + smDir + File.separator + "gmca.crt"); + cryptoMaterialConfig.setSdkCertPath( + certPath + File.separator + smDir + File.separator + "gmsdk.crt"); + cryptoMaterialConfig.setSdkPrivateKeyPath( + certPath + File.separator + smDir + File.separator + "gmsdk.key"); + cryptoMaterialConfig.setEnSSLCertPath( + certPath + File.separator + smDir + File.separator + "gmensdk.crt"); + cryptoMaterialConfig.setEnSSLPrivateKeyPath( + certPath + File.separator + smDir + File.separator + "gmensdk.key"); + } else { + throw new ConfigException( + "load CryptoMaterialConfig failed, only support ecdsa and sm now, expected 0 or 1, but provided " + + cryptoType); + } + return cryptoMaterialConfig; + } + + public String getCertPath() { + return certPath; + } + + public void setCertPath(String certPath) { + this.certPath = certPath; + } + + public String getCaCertPath() { + return caCertPath; + } + + public void setCaCertPath(String caCertPath) { + this.caCertPath = caCertPath; + } + + public String getSdkCertPath() { + return sdkCertPath; + } + + public void setSdkCertPath(String sdkCertPath) { + this.sdkCertPath = sdkCertPath; + } + + public String getSdkPrivateKeyPath() { + return sdkPrivateKeyPath; + } + + public void setSdkPrivateKeyPath(String sdkPrivateKeyPath) { + this.sdkPrivateKeyPath = sdkPrivateKeyPath; + } + + public String getEnSSLCertPath() { + return enSSLCertPath; + } + + public void setEnSSLCertPath(String enSSLCertPath) { + this.enSSLCertPath = enSSLCertPath; + } + + public String getEnSSLPrivateKeyPath() { + return enSSLPrivateKeyPath; + } + + public void setEnSSLPrivateKeyPath(String enSSLPrivateKeyPath) { + this.enSSLPrivateKeyPath = enSSLPrivateKeyPath; + } + + public int getSslCryptoType() { + return sslCryptoType; + } + + public void setSslCryptoType(int sslCryptoType) { + this.sslCryptoType = sslCryptoType; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/NetworkConfig.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/NetworkConfig.java new file mode 100644 index 000000000..1b8aa4469 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/NetworkConfig.java @@ -0,0 +1,69 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.config.model; + +import io.netty.util.NetUtil; +import java.util.List; +import java.util.Map; +import org.fisco.bcos.sdk.config.exceptions.ConfigException; +import org.fisco.bcos.sdk.utils.Host; + +public class NetworkConfig { + private List peers; + + public NetworkConfig(ConfigProperty configProperty) throws ConfigException { + Map networkProperty = configProperty.getNetwork(); + if (networkProperty != null) { + peers = (List) networkProperty.get("peers"); + } + checkPeers(peers); + } + + private void checkPeers(List peers) throws ConfigException { + if (peers == null || peers.size() == 0) { + throw new ConfigException( + "Invalid configuration, peers not configured, please config peers in yaml config file."); + } + for (String peer : peers) { + int index = peer.lastIndexOf(':'); + if (index == -1) { + throw new ConfigException( + " Invalid configuration, the peer value should in IP:Port format(eg: 127.0.0.1:1111), value: " + + peer); + } + String IP = peer.substring(0, index); + String port = peer.substring(index + 1); + + if (!(NetUtil.isValidIpV4Address(IP) || NetUtil.isValidIpV6Address(IP))) { + throw new ConfigException( + " Invalid configuration, invalid IP string format, value: " + IP); + } + + if (!Host.validPort(port)) { + throw new ConfigException( + " Invalid configuration, tcp port should from 1 to 65535, value: " + port); + } + } + } + + public List getPeers() { + return peers; + } + + public void setPeers(List peers) { + this.peers = peers; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/ThreadPoolConfig.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/ThreadPoolConfig.java new file mode 100644 index 000000000..aa73c1e61 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/config/model/ThreadPoolConfig.java @@ -0,0 +1,83 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.config.model; + +import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ThreadPoolConfig { + private static final Logger logger = LoggerFactory.getLogger(ThreadPoolConfig.class); + public static String DEFAULT_MAX_BLOCKING_QUEUE_SIZE = "102400"; + private Integer channelProcessorThreadSize; + private Integer receiptProcessorThreadSize; + private Integer maxBlockingQueueSize; + + public ThreadPoolConfig(ConfigProperty configProperty) { + Map threadPoolConfig = configProperty.getThreadPool(); + String cpuNum = String.valueOf(Runtime.getRuntime().availableProcessors()); + String channelProcessorThread = + ConfigProperty.getValue(threadPoolConfig, "channelProcessorThreadSize", cpuNum); + String receiptProcessorThread = + ConfigProperty.getValue(threadPoolConfig, "receiptProcessorThreadSize", cpuNum); + channelProcessorThreadSize = Integer.valueOf(channelProcessorThread); + receiptProcessorThreadSize = Integer.valueOf(receiptProcessorThread); + if (channelProcessorThreadSize.intValue() <= 0) { + channelProcessorThreadSize = Runtime.getRuntime().availableProcessors(); + } + if (receiptProcessorThreadSize.intValue() <= 0) { + receiptProcessorThreadSize = Runtime.getRuntime().availableProcessors(); + } + maxBlockingQueueSize = + Integer.valueOf( + ConfigProperty.getValue( + threadPoolConfig, + "maxBlockingQueueSize", + DEFAULT_MAX_BLOCKING_QUEUE_SIZE)); + if (maxBlockingQueueSize.intValue() <= 0) { + maxBlockingQueueSize = Integer.valueOf(DEFAULT_MAX_BLOCKING_QUEUE_SIZE); + } + logger.debug( + "Init ThreadPoolConfig, channelProcessorThreadSize: {}, receiptProcessorThreadSize: {}, maxBlockingQueueSize: {}", + channelProcessorThreadSize, + receiptProcessorThreadSize, + maxBlockingQueueSize); + } + + public Integer getChannelProcessorThreadSize() { + return channelProcessorThreadSize; + } + + public void setChannelProcessorThreadSize(Integer channelProcessorThreadSize) { + this.channelProcessorThreadSize = channelProcessorThreadSize; + } + + public Integer getReceiptProcessorThreadSize() { + return receiptProcessorThreadSize; + } + + public void setReceiptProcessorThreadSize(Integer receiptProcessorThreadSize) { + this.receiptProcessorThreadSize = receiptProcessorThreadSize; + } + + public Integer getMaxBlockingQueueSize() { + return maxBlockingQueueSize; + } + + public void setMaxBlockingQueueSize(Integer maxBlockingQueueSize) { + this.maxBlockingQueueSize = maxBlockingQueueSize; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/model/AmopMsg.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/AmopMsg.java new file mode 100644 index 000000000..aae276663 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/AmopMsg.java @@ -0,0 +1,100 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.model; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import java.io.UnsupportedEncodingException; + +public class AmopMsg extends Message { + private static final long serialVersionUID = -7276897518418560354L; + private String topic; + + public AmopMsg() { + result = 0; + } + + public AmopMsg(Message msg) { + length = msg.getLength(); + type = msg.getType(); + seq = msg.getSeq(); + result = msg.getResult(); + } + + public void decodeAmopBody(byte[] in) { + ByteBuf amopBody = Unpooled.wrappedBuffer(in); + if (result == 0) { + Short topicLength = amopBody.readUnsignedByte(); + byte[] topicBytes = new byte[topicLength - 1]; + amopBody.readBytes(topicBytes, 0, topicLength - 1); + topic = new String(topicBytes); + /*data = new byte[length - Message.HEADER_LENGTH - topicLength]; + amopBody.readBytes(data, 0, length - Message.HEADER_LENGTH - topicLength);*/ + data = new byte[in.length - topicLength]; + amopBody.readBytes(data, 0, in.length - topicLength); + } + } + + public Message getMessage() { + Message msg = new Message(); + msg.setResult(this.result); + msg.setType(this.type); + msg.setSeq(this.seq); + + byte[] msgData = new byte[length - Message.HEADER_LENGTH + 1 + topic.getBytes().length]; + ByteBuf out = Unpooled.buffer(); + writeExtra(out); + out.readBytes(msgData, 0, length - Message.HEADER_LENGTH + 1 + topic.getBytes().length); + msg.setData(msgData); + return msg; + } + + @Override + public void encode(ByteBuf encodedData) { + writeHeader(encodedData); + writeExtra(encodedData); + } + + @Override + public void writeHeader(ByteBuf out) { + // total length + try { + length = Message.HEADER_LENGTH + 1 + topic.getBytes("utf-8").length + data.length; + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(" topic string to utf8 failed, topic: " + topic); + } + super.writeHeader(out); + } + + public void writeExtra(ByteBuf out) { + try { + out.writeByte(1 + topic.getBytes("utf-8").length); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(" topic string to utf8 failed, topic: " + topic); + } + out.writeBytes(topic.getBytes()); + + out.writeBytes(data); + } + + public String getTopic() { + return topic; + } + + public void setTopic(String toTopic) { + this.topic = toTopic; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/model/ConstantConfig.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/ConstantConfig.java new file mode 100644 index 000000000..6a85cf145 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/ConstantConfig.java @@ -0,0 +1,21 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.model; + +public class ConstantConfig { + public static final String CONFIG_FILE_NAME = "config.toml"; + public static final Integer MIN_GROUPID = 1; + public static final Integer MAX_GROUPID = 32767; +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/model/CryptoType.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/CryptoType.java new file mode 100644 index 000000000..bb3c804d5 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/CryptoType.java @@ -0,0 +1,21 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.model; + +public class CryptoType { + public static final int ECDSA_TYPE = 0; + public static final int SM_TYPE = 1; +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/model/EventLog.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/EventLog.java new file mode 100644 index 000000000..266b9dca6 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/EventLog.java @@ -0,0 +1,261 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import java.math.BigInteger; +import java.util.List; +import org.fisco.bcos.sdk.utils.Numeric; + +public class EventLog { + private boolean removed; + private String logIndex; + private String transactionIndex; + private String transactionHash; + private String blockHash; + private String blockNumber; + private String address; + private String data; + private String type; + private List topics; + + public EventLog() {} + + public EventLog( + boolean removed, + String logIndex, + String transactionIndex, + String transactionHash, + String blockHash, + String blockNumber, + String address, + String data, + String type, + List topics) { + this.removed = removed; + this.logIndex = logIndex; + this.transactionIndex = transactionIndex; + this.transactionHash = transactionHash; + this.blockHash = blockHash; + this.blockNumber = blockNumber; + this.address = address; + this.data = data; + this.type = type; + this.topics = topics; + } + + public EventLog(String data, List topics) { + this.data = data; + this.topics = topics; + } + + @JsonIgnore + public boolean isRemoved() { + return removed; + } + + public void setRemoved(boolean removed) { + this.removed = removed; + } + + public BigInteger getLogIndex() { + return convert(logIndex); + } + + @JsonIgnore + public String getLogIndexRaw() { + return logIndex; + } + + public void setLogIndex(String logIndex) { + this.logIndex = logIndex; + } + + public BigInteger getTransactionIndex() { + return convert(transactionIndex); + } + + @JsonIgnore + public String getTransactionIndexRaw() { + return transactionIndex; + } + + public void setTransactionIndex(String transactionIndex) { + this.transactionIndex = transactionIndex; + } + + public String getTransactionHash() { + return transactionHash; + } + + public void setTransactionHash(String transactionHash) { + this.transactionHash = transactionHash; + } + + public String getBlockHash() { + return blockHash; + } + + public void setBlockHash(String blockHash) { + this.blockHash = blockHash; + } + + public BigInteger getBlockNumber() { + return convert(blockNumber); + } + + @JsonIgnore + public String getBlockNumberRaw() { + return blockNumber; + } + + public void setBlockNumber(String blockNumber) { + this.blockNumber = blockNumber; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + @JsonIgnore + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public List getTopics() { + return topics; + } + + public void setTopics(List topics) { + this.topics = topics; + } + + private BigInteger convert(String value) { + if (value != null) { + return Numeric.decodeQuantity(value); + } else { + return null; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof EventLog)) { + return false; + } + + EventLog log = (EventLog) o; + + if (isRemoved() != log.isRemoved()) { + return false; + } + if (getLogIndexRaw() != null + ? !getLogIndexRaw().equals(log.getLogIndexRaw()) + : log.getLogIndexRaw() != null) { + return false; + } + if (getTransactionIndexRaw() != null + ? !getTransactionIndexRaw().equals(log.getTransactionIndexRaw()) + : log.getTransactionIndexRaw() != null) { + return false; + } + if (getTransactionHash() != null + ? !getTransactionHash().equals(log.getTransactionHash()) + : log.getTransactionHash() != null) { + return false; + } + if (getBlockHash() != null + ? !getBlockHash().equals(log.getBlockHash()) + : log.getBlockHash() != null) { + return false; + } + if (getBlockNumberRaw() != null + ? !getBlockNumberRaw().equals(log.getBlockNumberRaw()) + : log.getBlockNumberRaw() != null) { + return false; + } + if (getAddress() != null + ? !getAddress().equals(log.getAddress()) + : log.getAddress() != null) { + return false; + } + if (getData() != null ? !getData().equals(log.getData()) : log.getData() != null) { + return false; + } + if (getType() != null ? !getType().equals(log.getType()) : log.getType() != null) { + return false; + } + return getTopics() != null ? getTopics().equals(log.getTopics()) : log.getTopics() == null; + } + + @Override + public int hashCode() { + int result = (isRemoved() ? 1 : 0); + result = 31 * result + (getLogIndexRaw() != null ? getLogIndexRaw().hashCode() : 0); + result = + 31 * result + + (getTransactionIndexRaw() != null + ? getTransactionIndexRaw().hashCode() + : 0); + result = 31 * result + (getTransactionHash() != null ? getTransactionHash().hashCode() : 0); + result = 31 * result + (getBlockHash() != null ? getBlockHash().hashCode() : 0); + result = 31 * result + (getBlockNumberRaw() != null ? getBlockNumberRaw().hashCode() : 0); + result = 31 * result + (getAddress() != null ? getAddress().hashCode() : 0); + result = 31 * result + (getData() != null ? getData().hashCode() : 0); + result = 31 * result + (getType() != null ? getType().hashCode() : 0); + result = 31 * result + (getTopics() != null ? getTopics().hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Log [logIndex=" + + logIndex + + ", transactionIndex=" + + transactionIndex + + ", transactionHash=" + + transactionHash + + ", blockHash=" + + blockHash + + ", blockNumber=" + + blockNumber + + ", address=" + + address + + ", data=" + + data + + ", topics=" + + topics + + "]"; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/model/JsonRpcResponse.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/JsonRpcResponse.java new file mode 100644 index 000000000..1cc3a22a1 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/JsonRpcResponse.java @@ -0,0 +1,137 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class JsonRpcResponse { + private long id; + private String jsonrpc; + private T result; + private Error error; + private String rawResponse; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getJsonrpc() { + return jsonrpc; + } + + public void setJsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + } + + public T getResult() { + return result; + } + + public void setResult(T result) { + this.result = result; + } + + public Error getError() { + return error; + } + + public void setError(Error error) { + this.error = error; + } + + public boolean hasError() { + return error != null; + } + + public String getRawResponse() { + return rawResponse; + } + + public void setRawResponse(String rawResponse) { + this.rawResponse = rawResponse; + } + + public static class Error { + private int code; + private String message; + private String data; + + public Error() {} + + public Error(int code, String message) { + this.code = code; + this.message = message; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Error)) { + return false; + } + + Error error = (Error) o; + + if (getCode() != error.getCode()) { + return false; + } + if (getMessage() != null + ? !getMessage().equals(error.getMessage()) + : error.getMessage() != null) { + return false; + } + return getData() != null ? getData().equals(error.getData()) : error.getData() == null; + } + + @Override + public int hashCode() { + int result = getCode(); + result = 31 * result + (getMessage() != null ? getMessage().hashCode() : 0); + result = 31 * result + (getData() != null ? getData().hashCode() : 0); + return result; + } + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/model/MerkleProofUnit.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/MerkleProofUnit.java new file mode 100644 index 000000000..5098b47a8 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/MerkleProofUnit.java @@ -0,0 +1,58 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.model; + +import java.util.List; +import java.util.Objects; + +public class MerkleProofUnit { + private List left; + private List right; + + public List getLeft() { + return left; + } + + public void setLeft(List left) { + this.left = left; + } + + public List getRight() { + return right; + } + + public void setRight(List right) { + this.right = right; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MerkleProofUnit that = (MerkleProofUnit) o; + return Objects.equals(left, that.left) && Objects.equals(right, that.right); + } + + @Override + public int hashCode() { + return Objects.hash(left, right); + } + + @Override + public String toString() { + return "MerkleProofUnit{" + "left=" + left + ", right=" + right + '}'; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/model/Message.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/Message.java new file mode 100644 index 000000000..718ae726c --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/Message.java @@ -0,0 +1,135 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.model; + +import io.netty.buffer.ByteBuf; +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import org.fisco.bcos.sdk.model.exceptions.DecodeMessageException; + +/** Messages between sdk and FISCO BCOS node. */ +public class Message implements Serializable { + private static final long serialVersionUID = -7276897518418560354L; + protected Integer length = 0; + protected Short type = 0; + protected String seq = ""; + protected Integer result = 0; + protected byte[] data; + + public static final int HEADER_LENGTH = 4 + 2 + 32 + 4; + + /** + * encode the message into ByteBuf + * + * @param encodedData the ByteBuf stores the encodedData + */ + public void encode(ByteBuf encodedData) { + writeHeader(encodedData); + writeDataToByteBuf(encodedData); + } + + /** + * decode the message from the given ByteBuf + * + * @param in the ByteBuf that needs to decoded into the message + */ + public void decode(ByteBuf in) { + readHeader(in); + readDataFromByteBuf(in); + } + + protected void readDataFromByteBuf(ByteBuf in) { + data = new byte[length - HEADER_LENGTH]; + in.readBytes(data, 0, length - HEADER_LENGTH); + } + + protected void writeDataToByteBuf(ByteBuf out) { + out.writeBytes(data); + } + + protected void readHeader(ByteBuf in) { + length = in.readInt(); + type = in.readShort(); + byte[] dst = new byte[32]; + in.readBytes(dst); + try { + seq = new String(dst, "utf-8"); + } catch (UnsupportedEncodingException e) { + throw new DecodeMessageException( + "readHeader failed, seq: " + + seq + + ", type:" + + type + + " dataLen : " + + data.length, + e); + } + result = in.readInt(); + } + + protected void writeHeader(ByteBuf out) { + // calculate the total length + if (length.equals(0)) { + length = HEADER_LENGTH + data.length; + } + + out.writeInt(length); + out.writeShort(type); + out.writeBytes(seq.getBytes(), 0, 32); + out.writeInt(result); + } + + public Integer getLength() { + return length; + } + + public void setLength(Integer length) { + this.length = length; + } + + public Short getType() { + return type; + } + + public void setType(Short type) { + this.type = type; + } + + public String getSeq() { + return seq; + } + + public void setSeq(String seq) { + this.seq = seq; + } + + public Integer getResult() { + return result; + } + + public void setResult(Integer result) { + this.result = result; + } + + public byte[] getData() { + return data; + } + + public void setData(byte[] data) { + this.data = data; + this.length = data.length + HEADER_LENGTH; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/model/MsgType.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/MsgType.java new file mode 100644 index 000000000..1c4c96e19 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/MsgType.java @@ -0,0 +1,71 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.model; + +/** Message types send from fisco bcos node. */ +public enum MsgType { + + /** + * Message types which Client module interested in. CHANNEL_RPC_REQUEST: type of rpc request + * message TRANSACTION_NOTIFY: type of transaction notify message BLOCK_NOTIFY: type of block + * notify message + */ + CHANNEL_RPC_REQUEST(0x12), + TRANSACTION_NOTIFY(0x1000), + BLOCK_NOTIFY(0x1001), + + /** + * Message types processed by Client module. CLIENT_HEARTBEAT:type of heart beat message + * CLIENT_HANDSHAKE:type of hand shake message + */ + CLIENT_HEARTBEAT(0x13), + CLIENT_HANDSHAKE(0x14), + + /** + * Message types processed by EventSubscribe module CLIENT_REGISTER_EVENT_LOG:type of event log + * filter register request and response message EVENT_LOG_PUSH:type of event log push message + */ + CLIENT_REGISTER_EVENT_LOG(0x15), + CLIENT_UNREGISTER_EVENT_LOG(0x16), + EVENT_LOG_PUSH(0x1002), + + /** + * Message types processed by AMOP module AMOP_REQUEST:type of request message from sdk + * AMOP_RESPONSE:type of response message to sdk AMOP_MULBROADCAST:type of mult broadcast + * message AMOP_CLIENT_TOPICS:type of topic request message REQUEST_TOPICCERT:type of request + * verify message UPDATE_TOPIICSTATUS:type of update status message + */ + AMOP_REQUEST(0x30), + AMOP_RESPONSE(0x31), + AMOP_MULBROADCAST(0x35), + AMOP_CLIENT_TOPICS(0x32), + REQUEST_TOPICCERT(0x37), + UPDATE_TOPIICSTATUS(0x38); + + private int type; + + private MsgType(int type) { + this.setType(type); + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/model/NodeVersion.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/NodeVersion.java new file mode 100644 index 000000000..9964c2d49 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/NodeVersion.java @@ -0,0 +1,158 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Objects; + +/** getNodeVersion. */ +public class NodeVersion extends JsonRpcResponse { + public ClientVersion getNodeVersion() { + return getResult(); + } + + public static class ClientVersion { + @JsonProperty("FISCO-BCOS Version") + private String version; + + @JsonProperty("Supported Version") + private String supportedVersion; + + @JsonProperty("Chain Id") + private String chainId; + + @JsonProperty("Build Time") + private String buildTime; + + @JsonProperty("Build Type") + private String buildType; + + @JsonProperty("Git Branch") + private String gitBranch; + + @JsonProperty("Git Commit Hash") + private String gitCommitHash; + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getSupportedVersion() { + return supportedVersion; + } + + public void setSupportedVersion(String supportedVersion) { + this.supportedVersion = supportedVersion; + } + + public String getChainId() { + return chainId; + } + + public void setChainId(String chainId) { + this.chainId = chainId; + } + + public String getBuildTime() { + return buildTime; + } + + public void setBuildTime(String buildTime) { + this.buildTime = buildTime; + } + + public String getBuildType() { + return buildType; + } + + public void setBuildType(String buildType) { + this.buildType = buildType; + } + + public String getGitBranch() { + return gitBranch; + } + + public void setGitBranch(String gitBranch) { + this.gitBranch = gitBranch; + } + + public String getGitCommitHash() { + return gitCommitHash; + } + + public void setGitCommitHash(String gitCommitHash) { + this.gitCommitHash = gitCommitHash; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ClientVersion that = (ClientVersion) o; + return Objects.equals(version, that.version) + && Objects.equals(supportedVersion, that.supportedVersion) + && Objects.equals(chainId, that.chainId) + && Objects.equals(buildTime, that.buildTime) + && Objects.equals(buildType, that.buildType) + && Objects.equals(gitBranch, that.gitBranch) + && Objects.equals(gitCommitHash, that.gitCommitHash); + } + + @Override + public int hashCode() { + return Objects.hash( + version, + supportedVersion, + chainId, + buildTime, + buildType, + gitBranch, + gitCommitHash); + } + + @Override + public String toString() { + return "ClientVersion{" + + "version='" + + version + + '\'' + + ", supportedVersion='" + + supportedVersion + + '\'' + + ", chainId='" + + chainId + + '\'' + + ", buildTime='" + + buildTime + + '\'' + + ", buildType='" + + buildType + + '\'' + + ", gitBranch='" + + gitBranch + + '\'' + + ", gitCommitHash='" + + gitCommitHash + + '\'' + + '}'; + } + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/model/PrecompiledConstant.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/PrecompiledConstant.java new file mode 100644 index 000000000..77f198328 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/PrecompiledConstant.java @@ -0,0 +1,40 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.model; + +public class PrecompiledConstant { + // constant value + public static final int CNS_MAX_VERSION_LENGTH = 40; + public static final int TABLE_KEY_MAX_LENGTH = 255; + public static final int TABLE_FIELD_NAME_MAX_LENGTH = 64; + public static final int USER_TABLE_NAME_MAX_LENGTH = 48; + public static final int TABLE_VALUE_FIELD_MAX_LENGTH = 1024; + public static final int TABLE_KEY_VALUE_MAX_LENGTH = 255; + public static final int USER_TABLE_FIELD_VALUE_MAX_LENGTH = 16 * 1024 * 1024 - 1; + + public static final String SYS_TABLE = "_sys_tables_"; + public static final String SYS_TABLE_ACCESS = "_sys_table_access_"; + public static final String SYS_CONSENSUS = "_sys_consensus_"; + public static final String SYS_CNS = "_sys_cns_"; + public static final String SYS_CONFIG = "_sys_config_"; + + // user table prefix + public static final String USER_TABLE_PREFIX = "_user_"; + public static final String USER_TABLE_PREFIX_2_2_0_VERSION = "u_"; + + public static final String KEY_FIELD_NAME = "key_field"; + public static final String VALUE_FIELD_NAME = "value_field"; + public static final String TABLE_NAME_FIELD = "table_name"; +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/model/PrecompiledRetCode.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/PrecompiledRetCode.java new file mode 100644 index 000000000..46a1af9fe --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/PrecompiledRetCode.java @@ -0,0 +1,200 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.model; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +public class PrecompiledRetCode { + // ChainGovernancePrecompiled -52099 ~ -52000 + public static final RetCode CODE_CURRENT_VALUE_IS_EXPECTED_VALUE = + new RetCode(-52012, "The current value is expected"); + public static final RetCode CODE_ACCOUNT_FROZEN = new RetCode(-52011, "The account is frozen"); + public static final RetCode CODE_ACCOUNT_ALREADY_AVAILABLE = + new RetCode(-52010, "The account is already available"); + public static final RetCode CODE_INVALID_ACCOUNT_ADDRESS = + new RetCode(-52009, "Invalid account address"); + public static final RetCode CODE_ACCOUNT_NOT_EXIST = new RetCode(-52008, "Account not exist"); + public static final RetCode CODE_OPERATOR_NOT_EXIST = + new RetCode(-52007, "The operator not exist"); + public static final RetCode CODE_OPERATOR_EXIST = + new RetCode(-52006, "The operator already exist"); + public static final RetCode CODE_COMMITTEE_MEMBER_CANNOT_BE_OPERATOR = + new RetCode(-52005, "The committee member cannot be operator"); + public static final RetCode CODE_OPERATOR_CANNOT_BE_COMMITTEE_MEMBER = + new RetCode(-52004, "The operator cannot be committee member"); + public static final RetCode CODE_INVALID_THRESHOLD = + new RetCode(-52003, "Invalid threshold, threshold should from 0 to 99"); + public static final RetCode CODE_INVALID_REQUEST_PERMISSION_DENIED = + new RetCode(-52002, "Invalid request for permission deny"); + public static final RetCode CODE_COMMITTEE_MEMBER_NOT_EXIST = + new RetCode(-52001, "The committee member not exist"); + public static final RetCode CODE_COMMITTEE_MEMBER_EXIST = + new RetCode(-52000, "The committee member already exist"); + + // ContractLifeCyclePrecompiled -51999 ~ -51900 + public static final RetCode CODE_INVALID_NO_AUTHORIZED = + new RetCode(-51905, "Have no permission to access the contract table"); + public static final RetCode CODE_INVALID_TABLE_NOT_EXIST = + new RetCode(-51904, "The queried contract address doesn't exist"); + public static final RetCode CODE_INVALID_CONTRACT_ADDRESS = + new RetCode(-51903, "The contract address is invalid"); + public static final RetCode CODE_INVALID_CONTRACT_REPEAT_AUTHORIZATION = + new RetCode(-51902, "The contract has been granted authorization with same user"); + public static final RetCode CODE_INVALID_CONTRACT_AVAILABLE = + new RetCode(-51901, "The contract is available"); + public static final RetCode CODE_INVALID_CONTRACT_FEOZEN = + new RetCode(-51900, "The contract has been frozen"); + + // RingSigPrecompiled -51899 ~ -51800 + public static final RetCode VERIFY_RING_SIG_FAILED = + new RetCode(-51800, "Verify ring signature failed"); + + // GroupSigPrecompiled -51799 ~ -51700 + public static final RetCode VERIFY_GROUP_SIG_FAILED = + new RetCode(-51700, "Verify group signature failed"); + + // PaillierPrecompiled -51699 ~ -51600 + public static final RetCode CODE_INVALID_CIPHERS = + new RetCode(-51600, "Execute PaillierAdd failed"); + + // CRUDPrecompiled -51599 ~ -51500 + public static final RetCode CODE_CONDITION_OPERATION_UNDEFINED = + new RetCode(-51502, "Undefined function of Condition Precompiled"); + public static final RetCode CODE_PARSE_CONDITION_ERROR = + new RetCode(-51501, "Parse the input of Condition Precompiled failed"); + public static final RetCode CODE_PARSE_ENTRY_ERROR = + new RetCode(-51500, "Parse the inpput of the Entriy Precompiled failed"); + + // SystemConfigPrecompiled -51399 ~ -51300 + public static final RetCode CODE_INVALID_CONFIGURATION_VALUES = + new RetCode(-51300, "Invalid configuration entry"); + + // CNSPrecompiled -51299 ~ -51200 + public static final RetCode CODE_VERSION_LENGTH_OVERFLOW = + new RetCode(-51201, "The version string length exceeds the maximum limit"); + public static final RetCode CODE_ADDRESS_AND_VERSION_EXIST = + new RetCode(-51200, "The contract name and version already exist"); + + // ConsensusPrecompiled -51199 ~ -51100 + public static final RetCode CODE_LAST_SEALER = + new RetCode(-51101, "The last sealer cannot be removed"); + public static final RetCode CODE_INVALID_NODEID = new RetCode(-51100, "Invalid node ID"); + + // PermissionPrecompiled -51099 ~ -51000 + public static final RetCode CODE_COMMITTEE_PERMISSION = + new RetCode( + -51004, + "The committee permission control by ChainGovernancePrecompiled are recommended"); + public static final RetCode CODE_CONTRACT_NOT_EXIST = + new RetCode(-51003, "The contract is not exist"); + public static final RetCode CODE_TABLE_NAME_OVERFLOW = + new RetCode(-51002, "The table name string length exceeds the maximum limit"); + public static final RetCode CODE_TABLE_AND_ADDRESS_NOT_EXIST = + new RetCode(-51001, "The table name and address not exist"); + public static final RetCode CODE_TABLE_AND_ADDRESS_EXIST = + new RetCode(-51000, "The table name and address already exist"); + + // Common error code among all precompiled contracts -50199 ~ -50100 + public static final RetCode CODE_ADDRESS_INVALID = + new RetCode(-50102, "Invalid address format"); + public static final RetCode CODE_UNKNOWN_FUNCTION_CALL = + new RetCode(-50101, "Undefined function"); + public static final RetCode CODE_TABLE_NOT_EXIST = + new RetCode(-50100, "Open table failed, please check the existence of the table"); + + // correct return code great or equal 0 + public static final RetCode CODE_SUCCESS = new RetCode(0, "Success"); + + public static final RetCode CODE_NO_AUTHORIZED = new RetCode(-50000, "Permission denied"); + public static final RetCode CODE_TABLE_NAME_ALREADY_EXIST = + new RetCode(-50001, "The table already exist"); + public static final RetCode CODE_TABLE_NAME_LENGTH_OVERFLOW = + new RetCode( + -50002, + "The table name length exceeds the limit " + + PrecompiledConstant.USER_TABLE_NAME_MAX_LENGTH); + public static final RetCode CODE_TABLE_FILED_LENGTH_OVERFLOW = + new RetCode( + -50003, + "The table field name exceeds the limit " + + PrecompiledConstant.TABLE_FIELD_NAME_MAX_LENGTH); + public static final RetCode CODE_TABLE_FILED_TOTALLENGTH_OVERFLOW = + new RetCode( + -50004, + "The length of all the fields name exceeds the limit " + + PrecompiledConstant.TABLE_VALUE_FIELD_MAX_LENGTH); + public static final RetCode CODE_TABLE_KEYVALUE_LENGTH_OVERFLOW = + new RetCode( + -50005, + "The value exceeds the limit, key max length is " + + PrecompiledConstant.TABLE_KEY_VALUE_MAX_LENGTH + + ", field value max length is " + + PrecompiledConstant.TABLE_VALUE_FIELD_MAX_LENGTH); + public static final RetCode CODE_TABLE_FIELDVALUE_LENGTH_OVERFLOW = + new RetCode( + -50006, + "The field value exceeds the limit " + + PrecompiledConstant.TABLE_VALUE_FIELD_MAX_LENGTH); + public static final RetCode CODE_TABLE_DUMPLICATE_FIELD = + new RetCode(-50007, "The table contains duplicated field"); + public static final RetCode CODE_TABLE_INVALIDATE_FIELD = + new RetCode(-50008, "Invalid table name or field name"); + + // internal error(for example: params check failed, etc.): -29999~-20000 + public static final String MUST_EXIST_IN_NODE_LIST = + "The operated node must be in the list returned by getNodeIDList"; + public static final String ALREADY_EXISTS_IN_SEALER_LIST = + "The node already exists in the sealerList"; + public static final String ALREADY_EXISTS_IN_OBSERVER_LIST = + "The node already exists in the observerList"; + + public static final String ALREADY_REMOVED_FROM_THE_GROUP = + "The node already has been removed from the group"; + + public static final String OVER_CONTRACT_VERSION_LEN_LIMIT = + "The length of contract version over the limit, must be smaller than " + + PrecompiledConstant.CNS_MAX_VERSION_LENGTH; + + public static final String OVER_TABLE_KEY_LENGTH_LIMIT = + "The length of the table key exceeds the maximum limit " + + PrecompiledConstant.TABLE_KEY_MAX_LENGTH; + + protected static Map codeToMessage = new HashMap<>(); + + static { + Field[] fields = PrecompiledRetCode.class.getDeclaredFields(); + for (Field field : fields) { + if (field.getType().equals(RetCode.class)) { + try { + RetCode constantRetCode = (RetCode) field.get(null); + codeToMessage.put(constantRetCode.getCode(), constantRetCode); + } catch (IllegalAccessException e) { + continue; + } + } + } + } + + private PrecompiledRetCode() {} + + public static RetCode getPrecompiledResponse(int responseCode, String message) { + if (codeToMessage.containsKey(responseCode)) { + return codeToMessage.get(responseCode); + } + return new RetCode(responseCode, message); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/model/Response.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/Response.java new file mode 100644 index 000000000..160e2b18d --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/Response.java @@ -0,0 +1,78 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.model; + +import io.netty.channel.ChannelHandlerContext; +import java.nio.charset.StandardCharsets; + +public class Response { + private Integer errorCode; + private String errorMessage; + private String messageID; + private byte[] content; + private ChannelHandlerContext ctx; + + public Integer getErrorCode() { + return errorCode; + } + + public void setErrorCode(Integer errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public String getMessageID() { + return messageID; + } + + public void setMessageID(String messageID) { + this.messageID = messageID; + } + + public String getContent() { + if (content != null) { + return new String(content, StandardCharsets.UTF_8); + } + return null; + } + + public void setContent(String content) { + this.content = content.getBytes(); + } + + public void setContentBytes(byte[] content) { + this.content = content; + } + + public byte[] getContentBytes() { + return this.content; + } + + public ChannelHandlerContext getCtx() { + return ctx; + } + + public void setCtx(ChannelHandlerContext ctx) { + this.ctx = ctx; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/model/RetCode.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/RetCode.java new file mode 100644 index 000000000..838439a48 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/RetCode.java @@ -0,0 +1,72 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.model; + +import java.util.Objects; + +public class RetCode { + private TransactionReceipt transactionReceipt; + public int code; + private String message; + + public RetCode() {} + + public RetCode(int code, String message) { + this.code = code; + this.message = message; + } + + public TransactionReceipt getTransactionReceipt() { + return transactionReceipt; + } + + public void setTransactionReceipt(TransactionReceipt transactionReceipt) { + this.transactionReceipt = transactionReceipt; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMessage() { + return this.message; + } + + public void setMessage(String message) { + this.message = message; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + RetCode retCode = (RetCode) o; + return code == retCode.code && Objects.equals(message, retCode.message); + } + + @Override + public int hashCode() { + return Objects.hash(code, message); + } + + @Override + public String toString() { + return "{" + "\"code\":" + code + ", \"msg\":\"" + message + "\"}"; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/model/TransactionReceipt.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/TransactionReceipt.java new file mode 100644 index 000000000..25e4e69dd --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/TransactionReceipt.java @@ -0,0 +1,352 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.model; + +import java.util.List; +import java.util.Objects; + +public class TransactionReceipt { + private String transactionHash; + private String transactionIndex; + private String root; + private String blockNumber; + private String blockHash; + private String from; + private String to; + private String gasUsed; + private String contractAddress; + private List logs; + private String logsBloom; + private String status; + private String input; + private String output; + private List txProof; + private List receiptProof; + private String message; + + public boolean isStatusOK() { + return status.equals("0x0") || status.equals("0"); + } + + public static class Logs { + private String address; + private List topics; + private String data; + private String blockNumber; + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public List getTopics() { + return topics; + } + + public void setTopics(List topics) { + this.topics = topics; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public String getBlockNumber() { + return blockNumber; + } + + public void setBlockNumber(String blockNumber) { + this.blockNumber = blockNumber; + } + + public EventLog toEventLog() { + EventLog eventLog = new EventLog(); + eventLog.setAddress(this.address); + eventLog.setTopics(this.topics); + eventLog.setData(this.data); + eventLog.setBlockNumber(this.blockNumber); + return eventLog; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Logs logs = (Logs) o; + return Objects.equals(address, logs.address) + && Objects.equals(topics, logs.topics) + && Objects.equals(data, logs.data); + } + + @Override + public int hashCode() { + return Objects.hash(address, topics, data); + } + + @Override + public String toString() { + return "Logs{" + + "address='" + + address + + '\'' + + ", topics=" + + topics + + ", data='" + + data + + '\'' + + '}'; + } + } + + public List getReceiptProof() { + return receiptProof; + } + + public void setReceiptProof(List receiptProof) { + this.receiptProof = receiptProof; + } + + public String getTransactionHash() { + return transactionHash; + } + + public void setTransactionHash(String transactionHash) { + this.transactionHash = transactionHash; + } + + public String getTransactionIndex() { + return transactionIndex; + } + + public void setTransactionIndex(String transactionIndex) { + this.transactionIndex = transactionIndex; + } + + public String getRoot() { + return root; + } + + public void setRoot(String root) { + this.root = root; + } + + public String getBlockNumber() { + return blockNumber; + } + + public void setBlockNumber(String blockNumber) { + this.blockNumber = blockNumber; + } + + public String getBlockHash() { + return blockHash; + } + + public void setBlockHash(String blockHash) { + this.blockHash = blockHash; + } + + public String getFrom() { + return from; + } + + public void setFrom(String from) { + this.from = from; + } + + public String getTo() { + return to; + } + + public void setTo(String to) { + this.to = to; + } + + public String getGasUsed() { + return gasUsed; + } + + public void setGasUsed(String gasUsed) { + this.gasUsed = gasUsed; + } + + public String getContractAddress() { + return contractAddress; + } + + public void setContractAddress(String contractAddress) { + this.contractAddress = contractAddress; + } + + public List getLogs() { + return logs; + } + + public void setLogs(List logs) { + this.logs = logs; + } + + public String getLogsBloom() { + return logsBloom; + } + + public void setLogsBloom(String logsBloom) { + this.logsBloom = logsBloom; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getInput() { + return input; + } + + public void setInput(String input) { + this.input = input; + } + + public String getOutput() { + return output; + } + + public void setOutput(String output) { + this.output = output; + } + + public List getTxProof() { + return txProof; + } + + public void setTxProof(List txProof) { + this.txProof = txProof; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TransactionReceipt that = (TransactionReceipt) o; + return Objects.equals(transactionHash, that.transactionHash) + && Objects.equals(transactionIndex, that.transactionIndex) + && Objects.equals(root, that.root) + && Objects.equals(blockNumber, that.blockNumber) + && Objects.equals(blockHash, that.blockHash) + && Objects.equals(from, that.from) + && Objects.equals(to, that.to) + && Objects.equals(gasUsed, that.gasUsed) + && Objects.equals(contractAddress, that.contractAddress) + && Objects.equals(logs, that.logs) + && Objects.equals(logsBloom, that.logsBloom) + && Objects.equals(status, that.status) + && Objects.equals(input, that.input) + && Objects.equals(output, that.output) + && Objects.equals(txProof, that.txProof) + && Objects.equals(receiptProof, that.receiptProof); + } + + @Override + public int hashCode() { + return Objects.hash( + transactionHash, + transactionIndex, + root, + blockNumber, + blockHash, + from, + to, + gasUsed, + contractAddress, + logs, + logsBloom, + status, + input, + output, + txProof, + receiptProof); + } + + @Override + public String toString() { + return "TransactionReceipt{" + + "transactionHash='" + + transactionHash + + '\'' + + ", transactionIndex='" + + transactionIndex + + '\'' + + ", root='" + + root + + '\'' + + ", blockNumber='" + + blockNumber + + '\'' + + ", blockHash='" + + blockHash + + '\'' + + ", from='" + + from + + '\'' + + ", to='" + + to + + '\'' + + ", gasUsed='" + + gasUsed + + '\'' + + ", contractAddress='" + + contractAddress + + '\'' + + ", logs=" + + logs + + ", logsBloom='" + + logsBloom + + '\'' + + ", status='" + + status + + '\'' + + ", input='" + + input + + '\'' + + ", output='" + + output + + '\'' + + ", txProof=" + + txProof + + ", receiptProof=" + + receiptProof + + '}'; + } + + /** @return the message */ + public String getMessage() { + return message; + } + + /** @param message the message to set */ + public void setMessage(String message) { + this.message = message; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/model/TransactionReceiptStatus.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/TransactionReceiptStatus.java new file mode 100644 index 000000000..aac10f90e --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/TransactionReceiptStatus.java @@ -0,0 +1,91 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.model; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import org.fisco.bcos.sdk.utils.Numeric; + +public class TransactionReceiptStatus { + public static final RetCode Success = new RetCode(0, "Success"); + public static final RetCode Unknown = new RetCode(1, "Unknown"); + public static final RetCode BadRLP = new RetCode(2, "Bad RLP"); + public static final RetCode InvalidFormat = new RetCode(3, "Invalid format"); + public static final RetCode OutOfGasIntrinsic = + new RetCode(4, "The contract to deploy is too long(or input data is too long)"); + public static final RetCode InvalidSignature = new RetCode(5, "Invalid signature"); + public static final RetCode InvalidNonce = new RetCode(6, "Invalid nonce"); + public static final RetCode NotEnoughCash = new RetCode(7, "Not enough cash"); + public static final RetCode OutOfGasBase = new RetCode(8, "Input data is too long"); + public static final RetCode BlockGasLimitReached = new RetCode(9, "Block gas limit reached"); + public static final RetCode BadInstruction = new RetCode(10, "Bad instruction"); + public static final RetCode BadJumpDestination = new RetCode(11, "Bad jump destination"); + public static final RetCode OutOfGas = new RetCode(12, "Out-of-gas during EVM execution"); + public static final RetCode OutOfStack = new RetCode(13, "Out of stack"); + public static final RetCode StackUnderflow = new RetCode(14, "Stack underflow"); + public static final RetCode NonceCheckFail = new RetCode(15, "Nonce check fail"); + public static final RetCode BlockLimitCheckFail = new RetCode(16, "Block limit check fail"); + public static final RetCode FilterCheckFail = new RetCode(17, "Filter check fail"); + public static final RetCode NoDeployPermission = new RetCode(18, "No deploy permission"); + public static final RetCode NoCallPermission = new RetCode(19, "No call permission"); + public static final RetCode NoTxPermission = new RetCode(20, "No tx permission"); + public static final RetCode PrecompiledError = new RetCode(21, "Precompiled error"); + public static final RetCode RevertInstruction = new RetCode(22, "Revert instruction"); + public static final RetCode InvalidZeroSignatureFormat = + new RetCode(23, "Invalid zero signature format"); + public static final RetCode AddressAlreadyUsed = new RetCode(24, "Address already used"); + public static final RetCode PermissionDenied = new RetCode(25, "Permission denied"); + public static final RetCode CallAddressError = new RetCode(26, "Call address error"); + public static final RetCode GasOverflow = new RetCode(27, "Gas overflow"); + public static final RetCode TxPoolIsFull = new RetCode(28, "Transaction pool is full"); + public static final RetCode TransactionRefused = new RetCode(29, "Transaction refused"); + public static final RetCode ContractFrozen = new RetCode(30, "The contract has been frozen"); + public static final RetCode AccountFrozen = new RetCode(31, "The account has been frozen"); + public static final RetCode AlreadyKnown = new RetCode(10000, "Transaction already known"); + public static final RetCode AlreadyInChain = new RetCode(10001, "Transaction already in chain"); + public static final RetCode InvalidChainId = new RetCode(10002, "Invalid chain id"); + public static final RetCode InvalidGroupId = new RetCode(10003, "Invalid group id"); + public static final RetCode RequestNotBelongToTheGroup = + new RetCode(10004, "The request doesn't belong to the group"); + public static final RetCode MalformedTx = new RetCode(10005, "Malformed transaction"); + public static final RetCode OverGroupMemoryLimit = + new RetCode(10006, "Exceeded the group transaction pool capacity limit"); + public static final RetCode TimeOut = new RetCode(50001, "Transaction receipt timeout"); + + protected static Map codeToRetCode = new HashMap<>(); + + static { + Field[] fields = TransactionReceiptStatus.class.getDeclaredFields(); + for (Field field : fields) { + if (field.getType().equals(RetCode.class)) { + try { + RetCode constantRetCode = (RetCode) field.get(null); + codeToRetCode.put(constantRetCode.getCode(), constantRetCode); + } catch (IllegalAccessException e) { + continue; + } + } + } + } + + public static RetCode getStatusMessage(String status, String message) { + int statusCode = Numeric.decodeQuantity(status).intValue(); + if (codeToRetCode.containsKey(statusCode)) { + return codeToRetCode.get(statusCode); + } + return new RetCode(statusCode, message); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/model/callback/TransactionCallback.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/callback/TransactionCallback.java new file mode 100644 index 000000000..006548baa --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/callback/TransactionCallback.java @@ -0,0 +1,72 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.model.callback; + +import io.netty.util.Timeout; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.TransactionReceiptStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class TransactionCallback { + private static Logger logger = LoggerFactory.getLogger(TransactionCallback.class); + private Timeout timeoutHandler; + public static Integer DEFAULT_TRANS_TIMEOUT = 30 * 1000; + private Integer timeout = DEFAULT_TRANS_TIMEOUT; + + public abstract void onResponse(TransactionReceipt receipt); + + public void onError(int errorCode, String errorMessage) { + cancelTimeout(); + logger.error( + "transaction exception, errorCode: {}, errorMessage: {}", errorCode, errorMessage); + TransactionReceipt receipt = new TransactionReceipt(); + receipt.setStatus(String.valueOf(errorCode)); + receipt.setMessage(errorMessage); + onResponse(receipt); + } + + public void cancelTimeout() { + if (getTimeoutHandler() != null && !getTimeoutHandler().isCancelled()) { + getTimeoutHandler().cancel(); + } + } + + public void onTimeout() { + cancelTimeout(); + logger.warn("transactionSuc timeout"); + TransactionReceipt receipt = new TransactionReceipt(); + receipt.setStatus(String.valueOf(TransactionReceiptStatus.TimeOut.getCode())); + receipt.setMessage(TransactionReceiptStatus.TimeOut.getMessage()); + onResponse(receipt); + } + + public Timeout getTimeoutHandler() { + return timeoutHandler; + } + + public void setTimeoutHandler(Timeout timeoutHandler) { + this.timeoutHandler = timeoutHandler; + } + + public void setTimeout(Integer timeout) { + this.timeout = timeout; + } + + public Integer getTimeout() { + return this.timeout; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/model/exceptions/DecodeMessageException.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/exceptions/DecodeMessageException.java new file mode 100644 index 000000000..7f842a64d --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/model/exceptions/DecodeMessageException.java @@ -0,0 +1,30 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.model.exceptions; + +/** Exception thrown if an attempt is made to decode invalid data, or some other failure occurs. */ +public class DecodeMessageException extends IllegalStateException { + private final Throwable cause; + + public DecodeMessageException(String msg, Throwable cause) { + super(msg); + + this.cause = cause; + } + + @Override + public final synchronized Throwable getCause() { + return cause; + } +} 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 new file mode 100644 index 000000000..35842fea0 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/ChannelHandler.java @@ -0,0 +1,167 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.network; + +import io.netty.channel.ChannelHandler.Sharable; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.ssl.SslCloseCompletionEvent; +import io.netty.handler.ssl.SslHandshakeCompletionEvent; +import io.netty.handler.timeout.IdleStateEvent; +import java.util.Objects; +import java.util.concurrent.ExecutorService; +import org.fisco.bcos.sdk.model.Message; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Channel handler process inbound message. */ +@Sharable +public class ChannelHandler extends SimpleChannelInboundHandler { + private static Logger logger = LoggerFactory.getLogger(ChannelHandler.class); + private MsgHandler msgHandler; + private ConnectionManager connectionManager; + private ExecutorService msgHandleThreadPool; + + public void setMsgHandleThreadPool(ExecutorService msgHandleThreadPool) { + this.msgHandleThreadPool = msgHandleThreadPool; + } + + public ChannelHandler(ConnectionManager connManager, MsgHandler msgHandler) { + this.msgHandler = msgHandler; + this.connectionManager = connManager; + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + String host = ((SocketChannel) ctx.channel()).remoteAddress().getAddress().getHostAddress(); + Integer port = ((SocketChannel) ctx.channel()).remoteAddress().getPort(); + if (evt instanceof IdleStateEvent) { + final IdleStateEvent e = (IdleStateEvent) evt; + switch (e.state()) { + case READER_IDLE: + case WRITER_IDLE: + case ALL_IDLE: + logger.error( + " idle state event:{} connect{}:{} long time Inactive, disconnect", + e.state(), + host, + port); + channelInactive(ctx); + ctx.disconnect(); + ctx.close(); + break; + default: + break; + } + } else if (evt instanceof SslHandshakeCompletionEvent) { + SslHandshakeCompletionEvent e = (SslHandshakeCompletionEvent) evt; + if (e.isSuccess()) { + logger.info( + " handshake success, host: {}, port: {}, ctx: {}", + host, + port, + System.identityHashCode(ctx)); + ChannelHandlerContext oldCtx = + connectionManager.addConnectionContext(host, port, ctx); + msgHandler.onConnect(ctx); + + if (Objects.nonNull(oldCtx)) { + oldCtx.close(); + oldCtx.disconnect(); + + logger.warn( + " disconnect old connection, host: {}, port: {}, ctx: {}", + host, + port, + System.identityHashCode(ctx)); + } + } else { + logger.error( + " handshake failed, host: {}, port: {}, message: {}, cause: {} ", + host, + port, + e.cause().getMessage(), + e.cause()); + + ctx.disconnect(); + ctx.close(); + } + + } else if (evt instanceof SslCloseCompletionEvent) { + logger.info( + " ssl close completion event, host: {}, port: {}, ctx: {} ", + host, + port, + System.identityHashCode(ctx)); + } else { + logger.info( + " userEventTriggered event, host: {}, port: {}, evt: {}, ctx: {} ", + host, + port, + evt, + System.identityHashCode(ctx)); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + try { + // lost the connection, get ip info + String host = + ((SocketChannel) ctx.channel()).remoteAddress().getAddress().getHostAddress(); + Integer port = ((SocketChannel) ctx.channel()).remoteAddress().getPort(); + + logger.debug( + " channelInactive, disconnect " + + host + + ":" + + String.valueOf(port) + + " ," + + String.valueOf(ctx.channel().isActive())); + + connectionManager.removeConnectionContext(host, port, ctx); + msgHandler.onDisconnect(ctx); + + } catch (Exception e) { + logger.error("error ", e); + } + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + final ChannelHandlerContext ctxF = ctx; + final Message in = (Message) msg; + + if (msgHandleThreadPool == null) { + msgHandler.onMessage(ctxF, in); + } else { + msgHandleThreadPool.execute( + new Runnable() { + @Override + public void run() { + msgHandler.onMessage(ctxF, in); + } + }); + } + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, Message msg) { + final ChannelHandlerContext ctxF = ctx; + msgHandler.onMessage(ctxF, msg); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/network/ConnectionInfo.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/ConnectionInfo.java new file mode 100644 index 000000000..e9285dd7a --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/ConnectionInfo.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.network; + +import org.fisco.bcos.sdk.utils.Host; + +/** Connection information. */ +public class ConnectionInfo { + + public ConnectionInfo(String peerIpPort) { + String IP = Host.getIpFromString(peerIpPort); + String port = Host.getPortFromString(peerIpPort); + this.ip = IP; + this.port = Integer.parseInt(port); + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public Integer getPort() { + return port; + } + + public void setPort(Integer port) { + this.port = port; + } + + public String getEndPoint() { + return ip + ":" + port; + } + + private String ip = ""; + private Integer port = 0; + + @Override + public String toString() { + return "ConnectionInfo{" + "host='" + ip + '\'' + ", port=" + port + '}'; + } +} 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 new file mode 100644 index 000000000..61f138da4 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/ConnectionManager.java @@ -0,0 +1,435 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.network; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import io.netty.handler.ssl.SMSslClientContextFactory; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.handler.ssl.SslHandler; +import io.netty.handler.ssl.SslProvider; +import io.netty.handler.timeout.IdleStateHandler; +import io.netty.util.concurrent.Future; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Security; +import java.security.cert.CertificateException; +import java.security.spec.InvalidKeySpecException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import javax.net.ssl.SSLException; +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.ThreadPoolService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Maintain peer connections. Start a schedule to reconnect failed peers. + * + * @author Maggie + */ +public class ConnectionManager { + private static Logger logger = LoggerFactory.getLogger(ConnectionManager.class); + private ChannelHandler channelHandler; + private List connectionInfoList = new CopyOnWriteArrayList<>(); + private Map availableConnections = new ConcurrentHashMap<>(); + private EventLoopGroup workerGroup; + private Boolean running = false; + private Bootstrap bootstrap = new Bootstrap(); + private ScheduledExecutorService reconnSchedule = new ScheduledThreadPoolExecutor(1); + + public ConnectionManager(ConfigOption configOption, MsgHandler msgHandler) { + for (String peerIpPort : configOption.getNetworkConfig().getPeers()) { + connectionInfoList.add(new ConnectionInfo(peerIpPort)); + } + channelHandler = new ChannelHandler(this, msgHandler); + logger.info(" all connections: {}", connectionInfoList); + } + + public void startConnect(ConfigOption configOption) throws NetworkException { + if (running) { + logger.debug("running"); + return; + } + logger.debug(" start connect. "); + /** init netty * */ + initNetty(configOption); + running = true; + + /** try connection */ + List connChannelFuture = new ArrayList(); + for (ConnectionInfo connect : connectionInfoList) { + ChannelFuture channelFuture = bootstrap.connect(connect.getIp(), connect.getPort()); + connChannelFuture.add(channelFuture); + } + + /** check connection result */ + boolean atLeastOneConnectSuccess = false; + List errorMessageList = new ArrayList<>(); + for (int i = 0; i < connectionInfoList.size(); i++) { + ConnectionInfo connInfo = connectionInfoList.get(i); + ChannelFuture connectFuture = connChannelFuture.get(i); + if (checkConnectionResult(connInfo, connectFuture, errorMessageList)) { + atLeastOneConnectSuccess = true; + } + } + + /** check available connection */ + if (!atLeastOneConnectSuccess) { + logger.error(" all connections have failed, {} ", errorMessageList); + String errorMessageString = ""; + for (RetCode errorRetCode : errorMessageList) { + 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, + NetworkException.SSL_HANDSHAKE_FAILED); + } + } + throw new NetworkException( + " Failed to connect to all the nodes! errorMessage: \n" + errorMessageString, + NetworkException.CONNECT_FAILED); + } + logger.debug(" start connect end. "); + } + + public void startReconnectSchedule() { + logger.debug(" start reconnect schedule"); + reconnSchedule.scheduleAtFixedRate( + () -> reconnect(), + TimeoutConfig.reconnectDelay, + TimeoutConfig.reconnectDelay, + TimeUnit.MILLISECONDS); + } + + public void stopReconnectSchedule() { + ThreadPoolService.stopThreadPool(reconnSchedule); + } + + public void stopNetty() { + if (running) { + if (workerGroup != null) { + workerGroup.shutdownGracefully(); + } + running = false; + } + } + + private void reconnect() { + // Get connection which need reconnect + List needReconnect = new ArrayList<>(); + int aliveConnectionCount = 0; + for (ConnectionInfo connectionInfo : connectionInfoList) { + ChannelHandlerContext ctx = availableConnections.get(connectionInfo.getEndPoint()); + if (Objects.isNull(ctx) || !ctx.channel().isActive()) { + needReconnect.add(connectionInfo); + } else { + aliveConnectionCount++; + } + } + logger.trace(" Keep alive nodes count: {}", aliveConnectionCount); + + // Reconnect + for (ConnectionInfo connectionInfo : needReconnect) { + ChannelFuture connectFuture = + bootstrap.connect(connectionInfo.getIp(), connectionInfo.getPort()); + List errorMessageList = new ArrayList<>(); + if (checkConnectionResult(connectionInfo, connectFuture, errorMessageList)) { + logger.trace( + " reconnect to {}:{} success", + connectionInfo.getIp(), + connectionInfo.getPort()); + } else { + logger.error( + " reconnect to {}:{}, error: {}", + connectionInfo.getIp(), + connectionInfo.getPort(), + errorMessageList); + } + } + } + + public void setMsgHandleThreadPool(ExecutorService msgHandleThreadPool) { + channelHandler.setMsgHandleThreadPool(msgHandleThreadPool); + } + + public List getConnectionInfoList() { + return connectionInfoList; + } + + public Map getAvailableConnections() { + return availableConnections; + } + + public ChannelHandlerContext getConnectionCtx(String peer) { + return availableConnections.get(peer); + } + + private SslContext initSslContext(ConfigOption configOption) throws NetworkException { + try { + Security.setProperty("jdk.disabled.namedCurves", ""); + // Get file, file existence is already checked when check config file. + FileInputStream caCert = + new FileInputStream( + new File(configOption.getCryptoMaterialConfig().getCaCertPath())); + FileInputStream sslCert = + new FileInputStream( + new File(configOption.getCryptoMaterialConfig().getSdkCertPath())); + FileInputStream sslKey = + new FileInputStream( + new File( + configOption.getCryptoMaterialConfig().getSdkPrivateKeyPath())); + + // Init SslContext + logger.info(" build ECDSA ssl context with configured certificates "); + SslContext sslCtx = + SslContextBuilder.forClient() + .trustManager(caCert) + .keyManager(sslCert, sslKey) + .sslProvider(SslProvider.OPENSSL) + // .sslProvider(SslProvider.JDK) + .build(); + return sslCtx; + } catch (FileNotFoundException | SSLException e) { + logger.error( + "initSslContext failed, caCert: {}, sslCert: {}, sslKey: {}, error: {}, e: {}", + configOption.getCryptoMaterialConfig().getCaCertPath(), + configOption.getCryptoMaterialConfig().getSdkCertPath(), + configOption.getCryptoMaterialConfig().getSdkPrivateKeyPath(), + e.getMessage(), + e); + throw new NetworkException( + "SSL context init failed, please make sure your cert and key files are properly configured. error info: " + + e.getMessage(), + NetworkException.INIT_CONTEXT_FAILED); + } catch (IllegalArgumentException e) { + logger.error("initSslContext failed, error: {}, e: {}", e.getMessage(), e); + throw new NetworkException( + "SSL context init failed, error info: " + e.getMessage(), + NetworkException.INIT_CONTEXT_FAILED); + } + } + + private SslContext initSMSslContext(ConfigOption configOption) throws NetworkException { + try { + // Get file, file existence is already checked when check config file. + FileInputStream caCert = + new FileInputStream( + new File(configOption.getCryptoMaterialConfig().getCaCertPath())); + FileInputStream sslCert = + new FileInputStream( + new File(configOption.getCryptoMaterialConfig().getSdkCertPath())); + FileInputStream sslKey = + new FileInputStream( + new File( + configOption.getCryptoMaterialConfig().getSdkPrivateKeyPath())); + FileInputStream enCert = + new FileInputStream( + new File(configOption.getCryptoMaterialConfig().getEnSSLCertPath())); + FileInputStream enKey = + new FileInputStream( + new File( + configOption + .getCryptoMaterialConfig() + .getEnSSLPrivateKeyPath())); + + // Init SslContext + logger.info(" build SM ssl context with configured certificates "); + return SMSslClientContextFactory.build(caCert, enCert, enKey, sslCert, sslKey); + } catch (IOException + | CertificateException + | NoSuchAlgorithmException + | InvalidKeySpecException + | NoSuchProviderException e) { + logger.error( + "initSMSslContext failed, caCert:{}, sslCert: {}, sslKey: {}, enCert: {}, enKey: {}, error: {}, e: {}", + configOption.getCryptoMaterialConfig().getCaCertPath(), + configOption.getCryptoMaterialConfig().getSdkCertPath(), + configOption.getCryptoMaterialConfig().getSdkPrivateKeyPath(), + configOption.getCryptoMaterialConfig().getEnSSLCertPath(), + configOption.getCryptoMaterialConfig().getEnSSLPrivateKeyPath(), + e.getMessage(), + e); + throw new NetworkException( + "SSL context init failed, please make sure your cert and key files are properly configured. error info: " + + e.getMessage(), + e); + } + } + + private void initNetty(ConfigOption configOption) throws NetworkException { + workerGroup = new NioEventLoopGroup(); + bootstrap.group(workerGroup); + bootstrap.channel(NioSocketChannel.class); + bootstrap.option(ChannelOption.SO_KEEPALIVE, true); + // set connection timeout + bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, (int) TimeoutConfig.connectTimeout); + int sslCryptoType = configOption.getCryptoMaterialConfig().getSslCryptoType(); + SslContext sslContext = + (sslCryptoType == CryptoType.ECDSA_TYPE + ? initSslContext(configOption) + : initSMSslContext(configOption)); + SslContext finalSslContext = sslContext; + ChannelInitializer initializer = + new ChannelInitializer() { + + @Override + protected void initChannel(SocketChannel ch) throws Exception { + /* + * Each connection is fetched from the socketChannel + */ + SslHandler sslHandler = finalSslContext.newHandler(ch.alloc()); + sslHandler.setHandshakeTimeoutMillis(TimeoutConfig.sslHandShakeTimeout); + ch.pipeline() + .addLast( + sslHandler, + new LengthFieldBasedFrameDecoder( + Integer.MAX_VALUE, 0, 4, -4, 0), + new IdleStateHandler( + TimeoutConfig.idleTimeout, + TimeoutConfig.idleTimeout, + TimeoutConfig.idleTimeout, + TimeUnit.MILLISECONDS), + new MessageEncoder(), + new MessageDecoder(), + channelHandler); + } + }; + bootstrap.handler(initializer); + } + + private boolean checkConnectionResult( + ConnectionInfo connInfo, ChannelFuture connectFuture, List errorMessageList) { + connectFuture.awaitUninterruptibly(); + if (!connectFuture.isSuccess()) { + /** connect failed. */ + if (Objects.isNull(connectFuture.cause())) { + logger.error("connect to {}:{} failed. ", connInfo.getIp(), connInfo.getPort()); + } else { + logger.error( + "connect to {}:{} failed. {}", + connInfo.getIp(), + connInfo.getPort(), + connectFuture.cause().getMessage()); + } + errorMessageList.add( + new RetCode( + NetworkException.CONNECT_FAILED, + "connect to " + + connInfo.getIp() + + ":" + + connInfo.getPort() + + " failed")); + return false; + } else { + /** connect success, check ssl handshake result. */ + SslHandler sslhandler = connectFuture.channel().pipeline().get(SslHandler.class); + String checkerMessage = + "! Please check the certificate and ensure that the SDK and the node are in the same agency!"; + if (Objects.isNull(sslhandler)) { + String sslHandshakeFailedMessage = + " ssl handshake failed:/" + + connInfo.getIp() + + ":" + + connInfo.getPort() + + checkerMessage; + logger.error(sslHandshakeFailedMessage); + errorMessageList.add( + new RetCode( + NetworkException.SSL_HANDSHAKE_FAILED, sslHandshakeFailedMessage)); + return false; + } + + Future sshHandshakeFuture = + sslhandler.handshakeFuture().awaitUninterruptibly(); + if (sshHandshakeFuture.isSuccess()) { + logger.trace(" ssl handshake success {}:{}", connInfo.getIp(), connInfo.getPort()); + return true; + } else { + String sslHandshakeFailedMessage = + " ssl handshake failed:/" + + connInfo.getIp() + + ":" + + connInfo.getPort() + + checkerMessage; + logger.error(sslHandshakeFailedMessage); + errorMessageList.add( + new RetCode( + NetworkException.SSL_HANDSHAKE_FAILED, sslHandshakeFailedMessage)); + return false; + } + } + } + + protected ChannelHandlerContext addConnectionContext( + String ip, int port, ChannelHandlerContext ctx) { + String endpoint = ip + ":" + port; + return availableConnections.put(endpoint, ctx); + } + + protected void removeConnectionContext(String ip, int port, ChannelHandlerContext ctx) { + String endpoint = ip + ":" + port; + if (Objects.isNull(availableConnections.get(endpoint))) { + return; + } + Boolean result = availableConnections.remove(endpoint, ctx); + if (logger.isDebugEnabled()) { + logger.debug( + " result: {}, host: {}, port: {}, ctx: {}", + result, + ip, + port, + System.identityHashCode(ctx)); + } + } + + protected void removeConnection(String peerIpPort) { + for (ConnectionInfo conn : connectionInfoList) { + String ipPort = conn.getIp() + ":" + conn.getPort(); + if (ipPort.equals(peerIpPort)) { + connectionInfoList.remove(conn); + return; + } + } + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/network/MessageDecoder.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/MessageDecoder.java new file mode 100644 index 000000000..7f4722dfa --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/MessageDecoder.java @@ -0,0 +1,32 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.network; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; +import java.util.List; +import org.fisco.bcos.sdk.model.Message; + +public class MessageDecoder extends ByteToMessageDecoder { + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) + throws Exception { + Message msg = new Message(); + msg.decode(in); + out.add(msg); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/network/MessageEncoder.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/MessageEncoder.java new file mode 100644 index 000000000..50e719fbe --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/MessageEncoder.java @@ -0,0 +1,28 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.network; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; +import org.fisco.bcos.sdk.model.Message; + +public class MessageEncoder extends MessageToByteEncoder { + @Override + protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception { + msg.encode(out); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/network/MsgHandler.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/MsgHandler.java new file mode 100644 index 000000000..8b04b22f0 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/MsgHandler.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.network; + +import io.netty.channel.ChannelHandlerContext; +import org.fisco.bcos.sdk.model.Message; + +/** + * Message handler interface Each module which would like to get notified by the "network" module + * should implement this interface. + */ +public interface MsgHandler { + + /** + * OnConnect action. Called when connect success. + * + * @param ctx ChannelHandlerContext of the connection from netty + */ + void onConnect(ChannelHandlerContext ctx); + + /** + * OnMessage action. Called when one message comes from the network. + * + * @param ctx ChannelHandlerContext of the connection from netty + * @param msg Message from the network + */ + void onMessage(ChannelHandlerContext ctx, Message msg); + + /** + * OnDisconnect action Called when one connection disconnect. + * + * @param ctx ChannelHandlerContext of the connection from netty + */ + void onDisconnect(ChannelHandlerContext ctx); +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/network/Network.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/Network.java new file mode 100644 index 000000000..4bb30ba89 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/Network.java @@ -0,0 +1,97 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.network; + +import io.netty.channel.ChannelHandlerContext; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import org.fisco.bcos.sdk.config.ConfigOption; +import org.fisco.bcos.sdk.config.exceptions.ConfigException; +import org.fisco.bcos.sdk.model.Message; + +/** Network interface Modules interact with the network module through this interface. */ +public interface Network { + /** + * Init network module + * + * @param configOption the path of the yaml config file + * @param handler message handler + * @return a Network implementation instance + * @throws ConfigException the configuration exception + */ + static Network build(ConfigOption configOption, MsgHandler handler) throws ConfigException { + return new NetworkImp(configOption, handler); + } + + ConfigOption getConfigOption(); + + int getSslCryptoType(); + + /** + * Broadcast message + * + * @param out the message to broadcast + */ + void broadcast(Message out); + + /** + * Send to peer + * + * @param out the sent message + * @param peerIpPort the node to receive the message + * @throws NetworkException the network exception + */ + void sendToPeer(Message out, String peerIpPort) throws NetworkException; + + /** + * Get connection information + * + * @return list of connection information + */ + List getConnectionInfo(); + + /** + * Start connect peers + * + * @throws NetworkException start the network exceptioned + */ + void start() throws NetworkException; + + /** + * Get available connection context + * + * @return the map between the peer endpoint and the channelHandlerContext + */ + Map getAvailableConnections(); + + /** + * Remove the connection if version negotiation failed + * + * @param peerIpPort the peer connection to be removed + */ + void removeConnection(String peerIpPort); + + /** + * Set thread pool + * + * @param threadPool the threadpool to handle the network message + */ + void setMsgHandleThreadPool(ExecutorService threadPool); + + /** Exit gracefully */ + void stop(); +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/network/NetworkException.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/NetworkException.java new file mode 100644 index 000000000..768820b45 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/NetworkException.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.network; + +/** + * Network exception + * + * @author Maggie + */ +public class NetworkException extends Exception { + public static final int SSL_HANDSHAKE_FAILED = 1; + public static final int CONNECT_FAILED = 2; + public static final int INIT_CONTEXT_FAILED = 3; + private int errorCode = 0; + + public NetworkException(String message, int errorCode) { + super(message); + this.errorCode = errorCode; + } + + public NetworkException(String message) { + super(message); + } + + public NetworkException(Throwable cause) { + super(cause); + } + + public NetworkException(String message, Throwable cause) { + super(message, cause); + } + + public int getErrorCode() { + return errorCode; + } +} 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 new file mode 100644 index 000000000..35c4f7ea5 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/NetworkImp.java @@ -0,0 +1,224 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.network; + +import io.netty.channel.ChannelHandlerContext; +import java.io.File; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ExecutorService; +import org.fisco.bcos.sdk.config.ConfigOption; +import org.fisco.bcos.sdk.config.exceptions.ConfigException; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.Message; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * An implementation of Network + * + * @author Maggie + */ +public class NetworkImp implements Network { + private static Logger logger = LoggerFactory.getLogger(NetworkImp.class); + private ConnectionManager connManager; + private ConfigOption configOption; + private MsgHandler handler; + + public NetworkImp(ConfigOption configOption, MsgHandler handler) throws ConfigException { + this.configOption = configOption; + this.handler = handler; + connManager = new ConnectionManager(configOption, handler); + } + + @Override + public ConfigOption getConfigOption() { + return configOption; + } + + @Override + public int getSslCryptoType() { + return configOption.getCryptoMaterialConfig().getSslCryptoType(); + } + + @Override + public void broadcast(Message out) { + Map conns = connManager.getAvailableConnections(); + conns.forEach( + (peer, ctx) -> { + ctx.writeAndFlush(out); + logger.trace("send message to {} success ", peer); + }); + } + + @Override + public void sendToPeer(Message out, String peerIpPort) throws NetworkException { + ChannelHandlerContext ctx = connManager.getConnectionCtx(peerIpPort); + if (Objects.isNull(ctx)) { + ctx.writeAndFlush(out); + logger.trace("send message to {} success ", peerIpPort); + } else { + logger.warn("send message to {} failed ", peerIpPort); + throw new NetworkException("Peer not available. Peer: " + peerIpPort); + } + } + + @Override + public List getConnectionInfo() { + return connManager.getConnectionInfoList(); + } + + private class CheckCertExistenceResult { + private boolean checkPassed = true; + private String errorMessage = ""; + + public boolean isCheckPassed() { + return checkPassed; + } + + public void setCheckPassed(boolean checkPassed) { + this.checkPassed = checkPassed; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + } + + private CheckCertExistenceResult checkCertExistence(boolean isSM) { + + CheckCertExistenceResult result = new CheckCertExistenceResult(); + result.setCheckPassed(true); + String errorMessage = ""; + errorMessage = errorMessage + "Please make sure "; + if (!new File(configOption.getCryptoMaterialConfig().getCaCertPath()).exists()) { + result.setCheckPassed(false); + errorMessage = + errorMessage + configOption.getCryptoMaterialConfig().getCaCertPath() + " "; + } + if (!new File(configOption.getCryptoMaterialConfig().getSdkCertPath()).exists()) { + result.setCheckPassed(false); + errorMessage = + errorMessage + configOption.getCryptoMaterialConfig().getSdkCertPath() + " "; + } + if (!new File(configOption.getCryptoMaterialConfig().getSdkPrivateKeyPath()).exists()) { + result.setCheckPassed(false); + errorMessage = + errorMessage + + configOption.getCryptoMaterialConfig().getSdkPrivateKeyPath() + + " "; + } + if (!isSM) { + errorMessage = errorMessage + "exists!"; + result.setErrorMessage(errorMessage); + return result; + } + if (!new File(configOption.getCryptoMaterialConfig().getEnSSLCertPath()).exists()) { + errorMessage = + errorMessage + configOption.getCryptoMaterialConfig().getEnSSLCertPath() + " "; + result.setCheckPassed(false); + } + if (!new File(configOption.getCryptoMaterialConfig().getEnSSLPrivateKeyPath()).exists()) { + errorMessage = + errorMessage + + configOption.getCryptoMaterialConfig().getEnSSLPrivateKeyPath() + + " "; + result.setCheckPassed(false); + } + errorMessage = errorMessage + "exist!"; + result.setErrorMessage(errorMessage); + return result; + } + + @Override + public void start() throws NetworkException { + boolean tryEcdsaConnect = false; + CheckCertExistenceResult result = null; + try { + try { + result = checkCertExistence(false); + if (result.isCheckPassed()) { + logger.debug("start connManager with ECDSA sslContext"); + connManager.startConnect(configOption); + connManager.startReconnectSchedule(); + tryEcdsaConnect = true; + return; + } + } catch (NetworkException e) { + tryEcdsaConnect = true; + configOption.reloadConfig(CryptoType.SM_TYPE); + result = checkCertExistence(true); + if (e.getErrorCode() == NetworkException.CONNECT_FAILED + || !result.isCheckPassed()) { + throw e; + } + 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"); + configOption.reloadConfig(CryptoType.SM_TYPE); + result = checkCertExistence(true); + if (!result.isCheckPassed()) { + if (tryEcdsaConnect) { + throw new NetworkException("Certificate not exist:" + result.getErrorMessage()); + } else { + throw new NetworkException( + "Not providing all the certificates to connect to the node! Please provide the certificates to connect with the block-chain."); + } + } + if (tryEcdsaConnect) { + // create a new connectionManager to connect the node with the SM sslContext + connManager = new ConnectionManager(configOption, handler); + } + connManager.startConnect(configOption); + connManager.startReconnectSchedule(); + } catch (ConfigException e) { + throw new NetworkException( + "start connManager with the SM algorithm failed, error info: " + e.getMessage(), + e); + } + } + + @Override + public Map getAvailableConnections() { + return connManager.getAvailableConnections(); + } + + @Override + public void removeConnection(String peerIpPort) { + connManager.removeConnection(peerIpPort); + } + + @Override + public void setMsgHandleThreadPool(ExecutorService threadPool) { + connManager.setMsgHandleThreadPool(threadPool); + } + + @Override + public void stop() { + logger.debug("stop Network..."); + connManager.stopReconnectSchedule(); + connManager.stopNetty(); + return; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/network/TimeoutConfig.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/TimeoutConfig.java new file mode 100644 index 000000000..5f5d3cfbd --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/network/TimeoutConfig.java @@ -0,0 +1,23 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.network; + +public class TimeoutConfig { + public static long idleTimeout = (long) 10000; + public static long reconnectDelay = (long) 20000; + public static long connectTimeout = (long) 10000; + public static long sslHandShakeTimeout = (long) 10000; +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/rlp/RlpDecoder.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/rlp/RlpDecoder.java new file mode 100644 index 000000000..39ac1206d --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/rlp/RlpDecoder.java @@ -0,0 +1,179 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.rlp; + +import java.util.ArrayList; +import org.fisco.bcos.sdk.utils.exceptions.DecoderException; + +/** Recursive Length Prefix (RLP) decoder. */ +public final class RlpDecoder { + /** + * [0x80] If a string is 0-55 bytes long, the RLP encoding consists of a single byte with value + * 0x80 plus the length of the string followed by the string. The range of the first byte is + * thus [0x80, 0xb7]. + */ + public static int OFFSET_SHORT_STRING = 0x80; + + /** + * [0xb7] If a string is more than 55 bytes long, the RLP encoding consists of a single byte + * with value 0xb7 plus the length of the length of the string in binary form, followed by the + * length of the string, followed by the string. For example, a length-1024 string would be + * encoded as \xb9\x04\x00 followed by the string. The range of the first byte is thus [0xb8, + * 0xbf]. + */ + public static int OFFSET_LONG_STRING = 0xb7; + + /** + * [0xc0] If the total payload of a list (i.e. the combined length of all its items) is 0-55 + * bytes long, the RLP encoding consists of a single byte with value 0xc0 plus the length of the + * list followed by the concatenation of the RLP encodings of the items. The range of the first + * byte is thus [0xc0, 0xf7]. + */ + public static int OFFSET_SHORT_LIST = 0xc0; + + /** + * [0xf7] If the total payload of a list is more than 55 bytes long, the RLP encoding consists + * of a single byte with value 0xf7 plus the length of the length of the list in binary form, + * followed by the length of the list, followed by the concatenation of the RLP encodings of the + * items. The range of the first byte is thus [0xf8, 0xff]. + */ + public static int OFFSET_LONG_LIST = 0xf7; + + private RlpDecoder() { + throw new IllegalStateException("Utility class"); + } + /** + * Parse wire byte[] message into RLP elements. + * + * @param rlpEncoded - RLP encoded byte-array + * @return recursive RLP structure + */ + public static RlpList decode(byte[] rlpEncoded) { + RlpList rlpList = new RlpList(new ArrayList<>()); + traverse(rlpEncoded, 0, rlpEncoded.length, rlpList); + return rlpList; + } + + private static void traverse(byte[] data, int startPos, int endPos, RlpList rlpList) { + try { + if (data == null || data.length == 0) { + return; + } + + while (startPos < endPos) { + + int prefix = data[startPos] & 0xff; + + if (prefix < OFFSET_SHORT_STRING) { + + // 1. the data is a string if the range of the + // first byte(i.e. prefix) is [0x00, 0x7f], + // and the string is the first byte itself exactly; + + byte[] rlpData = {(byte) prefix}; + rlpList.getValues().add(RlpString.create(rlpData)); + startPos += 1; + + } else if (prefix == OFFSET_SHORT_STRING) { + + // null + rlpList.getValues().add(RlpString.create(new byte[0])); + startPos += 1; + + } else if (prefix > OFFSET_SHORT_STRING && prefix <= OFFSET_LONG_STRING) { + + // 2. the data is a string if the range of the + // first byte is [0x80, 0xb7], and the string + // which length is equal to the first byte minus 0x80 + // follows the first byte; + + byte strLen = (byte) (prefix - OFFSET_SHORT_STRING); + + byte[] rlpData = new byte[strLen]; + System.arraycopy(data, startPos + 1, rlpData, 0, strLen); + + rlpList.getValues().add(RlpString.create(rlpData)); + startPos += 1 + strLen; + + } else if (prefix > OFFSET_LONG_STRING && prefix < OFFSET_SHORT_LIST) { + + // 3. the data is a string if the range of the + // first byte is [0xb8, 0xbf], and the length of the + // string which length in bytes is equal to the + // first byte minus 0xb7 follows the first byte, + // and the string follows the length of the string; + + byte lenOfStrLen = (byte) (prefix - OFFSET_LONG_STRING); + int strLen = calcLength(lenOfStrLen, data, startPos); + + // now we can parse an item for data[1]..data[length] + byte[] rlpData = new byte[strLen]; + System.arraycopy(data, startPos + lenOfStrLen + 1, rlpData, 0, strLen); + + rlpList.getValues().add(RlpString.create(rlpData)); + startPos += lenOfStrLen + strLen + 1; + + } else if (prefix >= OFFSET_SHORT_LIST && prefix <= OFFSET_LONG_LIST) { + + // 4. the data is a list if the range of the + // first byte is [0xc0, 0xf7], and the concatenation of + // the RLP encodings of all items of the list which the + // total payload is equal to the first byte minus 0xc0 follows the first byte; + + byte listLen = (byte) (prefix - OFFSET_SHORT_LIST); + + RlpList newLevelList = new RlpList(new ArrayList<>()); + traverse(data, startPos + 1, startPos + listLen + 1, newLevelList); + rlpList.getValues().add(newLevelList); + + startPos += 1 + listLen; + + } else if (prefix > OFFSET_LONG_LIST) { + + // 5. the data is a list if the range of the + // first byte is [0xf8, 0xff], and the total payload of the + // list which length is equal to the + // first byte minus 0xf7 follows the first byte, + // and the concatenation of the RLP encodings of all items of + // the list follows the total payload of the list; + + byte lenOfListLen = (byte) (prefix - OFFSET_LONG_LIST); + int listLen = calcLength(lenOfListLen, data, startPos); + + RlpList newLevelList = new RlpList(new ArrayList<>()); + traverse( + data, + startPos + lenOfListLen + 1, + startPos + lenOfListLen + listLen + 1, + newLevelList); + rlpList.getValues().add(newLevelList); + + startPos += lenOfListLen + listLen + 1; + } + } + } catch (Exception e) { + throw new DecoderException("RLP wrong encoding", e); + } + } + + private static int calcLength(int lengthOfLength, byte[] data, int pos) { + byte pow = (byte) (lengthOfLength - 1); + int length = 0; + for (int i = 1; i <= lengthOfLength; ++i) { + length += (data[pos + i] & 0xff) << (8 * pow); + pow--; + } + return length; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/rlp/RlpEncoder.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/rlp/RlpEncoder.java new file mode 100644 index 000000000..1e016b5e3 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/rlp/RlpEncoder.java @@ -0,0 +1,103 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.rlp; + +import static org.fisco.bcos.sdk.rlp.RlpDecoder.OFFSET_SHORT_LIST; +import static org.fisco.bcos.sdk.rlp.RlpDecoder.OFFSET_SHORT_STRING; + +import java.util.Arrays; +import java.util.List; + +/** Recursive Length Prefix (RLP) encoder. */ +public final class RlpEncoder { + + private RlpEncoder() { + throw new IllegalStateException("Utility class"); + } + + public static byte[] encode(RlpType value) { + if (value instanceof RlpString) { + return encodeString((RlpString) value); + } else { + return encodeList((RlpList) value); + } + } + + private static byte[] encode(byte[] bytesValue, int offset) { + if (bytesValue.length == 1 + && offset == OFFSET_SHORT_STRING + && bytesValue[0] >= (byte) 0x00 + && bytesValue[0] <= (byte) 0x7f) { + return bytesValue; + } else if (bytesValue.length <= 55) { + byte[] result = new byte[bytesValue.length + 1]; + result[0] = (byte) (offset + bytesValue.length); + System.arraycopy(bytesValue, 0, result, 1, bytesValue.length); + return result; + } else { + byte[] encodedStringLength = toMinimalByteArray(bytesValue.length); + byte[] result = new byte[bytesValue.length + encodedStringLength.length + 1]; + + result[0] = (byte) ((offset + 0x37) + encodedStringLength.length); + System.arraycopy(encodedStringLength, 0, result, 1, encodedStringLength.length); + System.arraycopy( + bytesValue, 0, result, encodedStringLength.length + 1, bytesValue.length); + return result; + } + } + + private static byte[] encodeString(RlpString value) { + return encode(value.getBytes(), OFFSET_SHORT_STRING); + } + + private static byte[] toMinimalByteArray(int value) { + byte[] encoded = toByteArray(value); + + for (int i = 0; i < encoded.length; i++) { + if (encoded[i] != 0) { + return Arrays.copyOfRange(encoded, i, encoded.length); + } + } + + return new byte[] {}; + } + + private static byte[] toByteArray(int value) { + return new byte[] { + (byte) ((value >> 24) & 0xff), + (byte) ((value >> 16) & 0xff), + (byte) ((value >> 8) & 0xff), + (byte) (value & 0xff) + }; + } + + private static byte[] encodeList(RlpList value) { + List values = value.getValues(); + if (values.isEmpty()) { + return encode(new byte[] {}, OFFSET_SHORT_LIST); + } else { + byte[] result = new byte[0]; + for (RlpType entry : values) { + result = concat(result, encode(entry)); + } + return encode(result, OFFSET_SHORT_LIST); + } + } + + private static byte[] concat(byte[] b1, byte[] b2) { + byte[] result = Arrays.copyOf(b1, b1.length + b2.length); + System.arraycopy(b2, 0, result, b1.length, b2.length); + return result; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/rlp/RlpList.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/rlp/RlpList.java new file mode 100644 index 000000000..ec6b0aa1f --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/rlp/RlpList.java @@ -0,0 +1,34 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.rlp; + +import java.util.Arrays; +import java.util.List; + +/** RLP list type. */ +public class RlpList implements RlpType { + private final List values; + + public RlpList(RlpType... values) { + this.values = Arrays.asList(values); + } + + public RlpList(List values) { + this.values = values; + } + + public List getValues() { + return values; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/rlp/RlpString.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/rlp/RlpString.java new file mode 100644 index 000000000..eebede928 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/rlp/RlpString.java @@ -0,0 +1,94 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.rlp; + +import java.math.BigInteger; +import java.util.Arrays; +import org.fisco.bcos.sdk.utils.Numeric; + +/** RLP string type. */ +public final class RlpString implements RlpType { + private static final byte[] EMPTY = new byte[] {}; + + public final byte[] value; + + private RlpString(byte[] value) { + this.value = value; + } + + public final byte[] getBytes() { + return value; + } + + public BigInteger asPositiveBigInteger() { + if (value.length == 0) { + return BigInteger.ZERO; + } + return new BigInteger(1, value); + } + + public String asString() { + return Numeric.toHexString(value); + } + + public static RlpString create(byte[] value) { + return new RlpString(value); + } + + public static RlpString create(byte value) { + return new RlpString(new byte[] {value}); + } + + public static RlpString create(BigInteger value) { + // RLP encoding only supports positive integer values + int valueSigNum = value.signum(); + if (valueSigNum < 1) { + return new RlpString(EMPTY); + } else { + byte[] bytes = value.toByteArray(); + if (bytes[0] == 0) { // remove leading zero + return new RlpString(Arrays.copyOfRange(bytes, 1, bytes.length)); + } else { + return new RlpString(bytes); + } + } + } + + public static RlpString create(long value) { + return create(BigInteger.valueOf(value)); + } + + public static RlpString create(String value) { + return new RlpString(value.getBytes()); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + RlpString rlpString = (RlpString) o; + + return Arrays.equals(value, rlpString.value); + } + + @Override + public int hashCode() { + return Arrays.hashCode(value); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/rlp/RlpType.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/rlp/RlpType.java new file mode 100644 index 000000000..d5dea0e74 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/rlp/RlpType.java @@ -0,0 +1,17 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.rlp; + +/** Base RLP type. */ +public interface RlpType {} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/AddressUtils.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/AddressUtils.java new file mode 100644 index 000000000..7386f2993 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/AddressUtils.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.utils; + +public class AddressUtils { + public static final int ADDRESS_SIZE = 160; + public static final int ADDRESS_LENGTH_IN_HEX = ADDRESS_SIZE >> 2; + + public static boolean isValidAddress(String address) { + String addressNoPrefix = Numeric.cleanHexPrefix(address); + return addressNoPrefix.length() == ADDRESS_LENGTH_IN_HEX; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/ByteUtils.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/ByteUtils.java new file mode 100644 index 000000000..06fc2fe18 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/ByteUtils.java @@ -0,0 +1,762 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.utils; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class ByteUtils { + + public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; + public static final byte[] ZERO_BYTE_ARRAY = new byte[] {0}; + + /** + * Creates a copy of bytes and appends b to the end of it + * + * @param bytes the original bytes + * @param b the appended byte + * @return a appended bytes @ + */ + public static byte[] appendByte(byte[] bytes, byte b) { + byte[] result = Arrays.copyOf(bytes, bytes.length + 1); + result[result.length - 1] = b; + return result; + } + + /** + * The regular {@link BigInteger#toByteArray()} method isn't quite what we often need: it + * appends a leading zero to indicate that the number is positive and may need padding. + * + * @param b the integer to format into a byte array + * @param numBytes the desired size of the resulting byte array + * @return numBytes byte long array. + */ + public static byte[] bigIntegerToBytes(BigInteger b, int numBytes) { + if (b == null) { + return null; + } + byte[] bytes = new byte[numBytes]; + byte[] biBytes = b.toByteArray(); + int start = (biBytes.length == numBytes + 1) ? 1 : 0; + int length = Math.min(biBytes.length, numBytes); + System.arraycopy(biBytes, start, bytes, numBytes - length, length); + return bytes; + } + + public static byte[] bigIntegerToBytes(BigInteger value) { + if (value == null) { + return null; + } + + byte[] data = value.toByteArray(); + + if (data.length != 1 && data[0] == 0) { + byte[] tmp = new byte[data.length - 1]; + System.arraycopy(data, 1, tmp, 0, tmp.length); + data = tmp; + } + return data; + } + + public static byte[] bigIntegerToBytesSigned(BigInteger b, int numBytes) { + if (b == null) { + return null; + } + byte[] bytes = new byte[numBytes]; + Arrays.fill(bytes, b.signum() < 0 ? (byte) 0xFF : 0x00); + byte[] biBytes = b.toByteArray(); + int start = (biBytes.length == numBytes + 1) ? 1 : 0; + int length = Math.min(biBytes.length, numBytes); + System.arraycopy(biBytes, start, bytes, numBytes - length, length); + return bytes; + } + + /** + * Cast hex encoded value from byte[] to BigInteger null is parsed like byte[0] + * + * @param bb byte array contains the values + * @return unsigned positive BigInteger value. + */ + public static BigInteger bytesToBigInteger(byte[] bb) { + return (bb == null || bb.length == 0) ? BigInteger.ZERO : new BigInteger(1, bb); + } + + /** + * Returns the amount of nibbles that match each other from 0 ... amount will never be larger + * than smallest input + * + * @param a - first input + * @param b - second input + * @return Number of bytes that match + */ + public static int matchingNibbleLength(byte[] a, byte[] b) { + int i = 0; + int length = a.length < b.length ? a.length : b.length; + while (i < length) { + if (a[i] != b[i]) { + return i; + } + i++; + } + return i; + } + + /** + * Converts a long value into a byte array. + * + * @param val - long value to convert + * @return byte[] of length 8, representing the long value + */ + public static byte[] longToBytes(long val) { + return ByteBuffer.allocate(Long.BYTES).putLong(val).array(); + } + + /** + * Converts a long value into a byte array. + * + * @param val - long value to convert + * @return decimal value with leading byte that are zeroes striped + */ + public static byte[] longToBytesNoLeadZeroes(long val) { + + // todo: improve performance by while strip numbers until (long >> 8 == 0) + if (val == 0) { + return EMPTY_BYTE_ARRAY; + } + + byte[] data = ByteBuffer.allocate(Long.BYTES).putLong(val).array(); + + return stripLeadingZeroes(data); + } + + /** + * Converts int value into a byte array. + * + * @param val - int value to convert + * @return byte[] of length 4, representing the int value + */ + public static byte[] intToBytes(int val) { + return ByteBuffer.allocate(Integer.BYTES).putInt(val).array(); + } + + /** + * Converts a int value into a byte array. + * + * @param val - int value to convert + * @return value with leading byte that are zeroes striped + */ + public static byte[] intToBytesNoLeadZeroes(int val) { + + if (val == 0) { + return EMPTY_BYTE_ARRAY; + } + + int length = 0; + + int tmpVal = val; + while (tmpVal != 0) { + tmpVal = tmpVal >>> 8; + ++length; + } + + byte[] result = new byte[length]; + + int index = result.length - 1; + while (val != 0) { + + result[index] = (byte) (val & 0xFF); + val = val >>> 8; + index -= 1; + } + + return result; + } + + /** + * Calculate packet length + * + * @param msg byte[] + * @return byte-array with 4 elements + */ + public static byte[] calcPacketLength(byte[] msg) { + int msgLen = msg.length; + return new byte[] { + (byte) ((msgLen >> 24) & 0xFF), + (byte) ((msgLen >> 16) & 0xFF), + (byte) ((msgLen >> 8) & 0xFF), + (byte) ((msgLen) & 0xFF) + }; + } + + /** + * Cast hex encoded value from byte[] to int null is parsed like byte[0] + * + *

Limited to Integer.MAX_VALUE: 2^32-1 (4 bytes) + * + * @param b array contains the values + * @return unsigned positive int value. + */ + public static int byteArrayToInt(byte[] b) { + if (b == null || b.length == 0) { + return 0; + } + return new BigInteger(1, b).intValue(); + } + + /** + * Cast hex encoded value from byte[] to long null is parsed like byte[0] + * + *

Limited to Long.MAX_VALUE: 263-1 (8 bytes) + * + * @param b array contains the values + * @return unsigned positive long value. + */ + public static long byteArrayToLong(byte[] b) { + if (b == null || b.length == 0) { + return 0; + } + return new BigInteger(1, b).longValue(); + } + + /** + * Turn nibbles to a pretty looking output string + * + *

Example. [ 1, 2, 3, 4, 5 ] becomes '\x11\x23\x45' + * + * @param nibbles - getting byte of data [ 04 ] and turning it to a '\x04' representation + * @return pretty string of nibbles + */ + public static String nibblesToPrettyString(byte[] nibbles) { + StringBuilder builder = new StringBuilder(); + for (byte nibble : nibbles) { + final String nibbleString = oneByteToHexString(nibble); + builder.append("\\x").append(nibbleString); + } + return builder.toString(); + } + + public static String oneByteToHexString(byte value) { + String retVal = Integer.toString(value & 0xFF, 16); + if (retVal.length() == 1) { + retVal = "0" + retVal; + } + return retVal; + } + + /** + * Calculate the number of bytes need to encode the number + * + * @param val - number + * @return number of min bytes used to encode the number + */ + public static int numBytes(String val) { + + BigInteger bInt = new BigInteger(val); + int bytes = 0; + + while (!bInt.equals(BigInteger.ZERO)) { + bInt = bInt.shiftRight(8); + ++bytes; + } + if (bytes == 0) { + ++bytes; + } + return bytes; + } + + /** + * @param arg - not more that 32 bits + * @return - bytes of the value pad with complete to 32 zeroes + */ + private static byte[] encodeValFor32Bits(Object arg) { + + byte[] data; + + // check if the string is numeric + if (arg.toString().trim().matches("-?\\d+(\\.\\d+)?")) { + data = new BigInteger(arg.toString().trim()).toByteArray(); + } + // check if it's hex number + else if (arg.toString().trim().matches("0[xX][0-9a-fA-F]+")) { + data = new BigInteger(arg.toString().trim().substring(2), 16).toByteArray(); + } else { + data = arg.toString().trim().getBytes(); + } + + if (data.length > 32) { + throw new RuntimeException("values can't be more than 32 byte"); + } + + byte[] val = new byte[32]; + + int j = 0; + for (int i = data.length; i > 0; --i) { + val[31 - j] = data[i - 1]; + ++j; + } + return val; + } + + /** + * encode the values and concatenate together + * + * @param args Object + * @return byte[] + */ + public static byte[] encodeDataList(Object... args) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (Object arg : args) { + byte[] val = encodeValFor32Bits(arg); + try { + baos.write(val); + } catch (IOException e) { + throw new Error("Happen something that should never happen ", e); + } + } + return baos.toByteArray(); + } + + public static int firstNonZeroByte(byte[] data) { + for (int i = 0; i < data.length; ++i) { + if (data[i] != 0) { + return i; + } + } + return -1; + } + + public static byte[] stripLeadingZeroes(byte[] data) { + + if (data == null) { + return null; + } + + final int firstNonZero = firstNonZeroByte(data); + switch (firstNonZero) { + case -1: + return ZERO_BYTE_ARRAY; + + case 0: + return data; + + default: + byte[] result = new byte[data.length - firstNonZero]; + System.arraycopy(data, firstNonZero, result, 0, data.length - firstNonZero); + + return result; + } + } + + /** + * increment byte array as a number until max is reached + * + * @param bytes byte[] + * @return boolean + */ + public static boolean increment(byte[] bytes) { + final int startIndex = 0; + int i; + for (i = bytes.length - 1; i >= startIndex; i--) { + bytes[i]++; + if (bytes[i] != 0) { + break; + } + } + // we return false when all bytes are 0 again + return (i >= startIndex || bytes[startIndex] != 0); + } + + /** + * Utility function to copy a byte array into a new byte array with given size. If the src + * length is smaller than the given size, the result will be left-padded with zeros. + * + * @param value - a BigInteger with a maximum value of 2^256-1 + * @return Byte array of given size with a copy of the src + */ + public static byte[] copyToArray(BigInteger value) { + byte[] src = ByteUtils.bigIntegerToBytes(value); + byte[] dest = ByteBuffer.allocate(32).array(); + if (src != null) { + System.arraycopy(src, 0, dest, dest.length - src.length, src.length); + } + return dest; + } + + // public static ByteArrayWrapper wrap(byte[] data) { + // return new ByteArrayWrapper(data); + // } + + public static byte[] setBit(byte[] data, int pos, int val) { + + if ((data.length * 8) - 1 < pos) { + throw new Error("outside byte array limit, pos: " + pos); + } + + int posByte = data.length - 1 - (pos) / 8; + int posBit = (pos) % 8; + byte setter = (byte) (1 << (posBit)); + byte toBeSet = data[posByte]; + byte result; + if (val == 1) { + result = (byte) (toBeSet | setter); + } else { + result = (byte) (toBeSet & ~setter); + } + + data[posByte] = result; + return data; + } + + public static int getBit(byte[] data, int pos) { + + if ((data.length * 8) - 1 < pos) { + throw new Error("outside byte array limit, pos: " + pos); + } + + int posByte = data.length - 1 - pos / 8; + int posBit = pos % 8; + byte dataByte = data[posByte]; + return Math.min(1, ((dataByte & 0xff) & (1 << (posBit)))); + } + + public static byte[] and(byte[] b1, byte[] b2) { + if (b1.length != b2.length) { + throw new RuntimeException("Array sizes differ"); + } + byte[] ret = new byte[b1.length]; + for (int i = 0; i < ret.length; i++) { + ret[i] = (byte) (b1[i] & b2[i]); + } + return ret; + } + + public static byte[] or(byte[] b1, byte[] b2) { + if (b1.length != b2.length) { + throw new RuntimeException("Array sizes differ"); + } + byte[] ret = new byte[b1.length]; + for (int i = 0; i < ret.length; i++) { + ret[i] = (byte) (b1[i] | b2[i]); + } + return ret; + } + + public static byte[] xor(byte[] b1, byte[] b2) { + if (b1.length != b2.length) { + throw new RuntimeException("Array sizes differ"); + } + byte[] ret = new byte[b1.length]; + for (int i = 0; i < ret.length; i++) { + ret[i] = (byte) (b1[i] ^ b2[i]); + } + return ret; + } + + /** + * XORs byte arrays of different lengths by aligning length of the shortest via adding zeros at + * beginning + * + * @param b1 the first byte array + * @param b2 the second byte array + * @return a byte array contains XORS of b1 and b2 + */ + public static byte[] xorAlignRight(byte[] b1, byte[] b2) { + if (b1.length > b2.length) { + byte[] b2_ = new byte[b1.length]; + System.arraycopy(b2, 0, b2_, b1.length - b2.length, b2.length); + b2 = b2_; + } else if (b2.length > b1.length) { + byte[] b1_ = new byte[b2.length]; + System.arraycopy(b1, 0, b1_, b2.length - b1.length, b1.length); + b1 = b1_; + } + + return xor(b1, b2); + } + + /** + * @param arrays - arrays to merge + * @return - merged array + */ + public static byte[] merge(byte[]... arrays) { + int count = 0; + for (byte[] array : arrays) { + count += array.length; + } + + // Create new array and copy all array contents + byte[] mergedArray = new byte[count]; + int start = 0; + for (byte[] array : arrays) { + System.arraycopy(array, 0, mergedArray, start, array.length); + start += array.length; + } + return mergedArray; + } + + public static boolean isNullOrZeroArray(byte[] array) { + return (array == null) || (array.length == 0); + } + + public static boolean isSingleZero(byte[] array) { + return (array.length == 1 && array[0] == 0); + } + + public static Set difference(Set setA, Set setB) { + + Set result = new HashSet<>(); + + for (byte[] elementA : setA) { + boolean found = false; + for (byte[] elementB : setB) { + + if (Arrays.equals(elementA, elementB)) { + found = true; + break; + } + } + if (!found) { + result.add(elementA); + } + } + + return result; + } + + public static int length(byte[]... bytes) { + int result = 0; + for (byte[] array : bytes) { + result += (array == null) ? 0 : array.length; + } + return result; + } + + public static int[] bytesToInts(byte[] arr, boolean bigEndian) { + int[] ret = new int[arr.length / 4]; + bytesToInts(arr, ret, bigEndian); + return ret; + } + + public static void bytesToInts(byte[] b, int[] arr, boolean bigEndian) { + if (!bigEndian) { + int off = 0; + for (int i = 0; i < arr.length; i++) { + int ii = b[off++] & 0x000000FF; + ii |= (b[off++] << 8) & 0x0000FF00; + ii |= (b[off++] << 16) & 0x00FF0000; + ii |= (b[off++] << 24); + arr[i] = ii; + } + } else { + int off = 0; + for (int i = 0; i < arr.length; i++) { + int ii = b[off++] << 24; + ii |= (b[off++] << 16) & 0x00FF0000; + ii |= (b[off++] << 8) & 0x0000FF00; + ii |= b[off++] & 0x000000FF; + arr[i] = ii; + } + } + } + + public static byte[] intsToBytes(int[] arr, boolean bigEndian) { + byte[] ret = new byte[arr.length * 4]; + intsToBytes(arr, ret, bigEndian); + return ret; + } + + public static void intsToBytes(int[] arr, byte[] b, boolean bigEndian) { + if (!bigEndian) { + int off = 0; + for (int i = 0; i < arr.length; i++) { + int ii = arr[i]; + b[off++] = (byte) (ii & 0xFF); + b[off++] = (byte) ((ii >> 8) & 0xFF); + b[off++] = (byte) ((ii >> 16) & 0xFF); + b[off++] = (byte) ((ii >> 24) & 0xFF); + } + } else { + int off = 0; + for (int i = 0; i < arr.length; i++) { + int ii = arr[i]; + b[off++] = (byte) ((ii >> 24) & 0xFF); + b[off++] = (byte) ((ii >> 16) & 0xFF); + b[off++] = (byte) ((ii >> 8) & 0xFF); + b[off++] = (byte) (ii & 0xFF); + } + } + } + + public static short bigEndianToShort(byte[] bs) { + return bigEndianToShort(bs, 0); + } + + public static short bigEndianToShort(byte[] bs, int off) { + int n = bs[off] << 8; + ++off; + n |= bs[off] & 0xFF; + return (short) n; + } + + public static byte[] shortToBytes(short n) { + return ByteBuffer.allocate(2).putShort(n).array(); + } + + /** + * Converts string hex representation to data bytes Accepts following hex: - with or without 0x + * prefix + * + * @param data String like '0xa5e..' or just 'a5e..' + * @return decoded bytes array + */ + public static byte[] hexStringToBytes(String data) { + if (data == null) { + return EMPTY_BYTE_ARRAY; + } + if (data.startsWith("0x")) { + data = data.substring(2); + } + if (data.length() % 2 == 1) { + data = "0" + data; + } + return Hex.decode(data); + } + + /** + * Converts string representation of host/ip to 4-bytes byte[] IPv4 + * + * @param ip the ip string of host + * @return a 4-bytes byte[] IPv4 + */ + public static byte[] hostToBytes(String ip) { + byte[] bytesIp; + try { + bytesIp = InetAddress.getByName(ip).getAddress(); + } catch (UnknownHostException e) { + bytesIp = new byte[4]; // fall back to invalid 0.0.0.0 address + } + + return bytesIp; + } + + /** + * Converts 4 bytes IPv4 IP to String representation + * + * @param bytesIp the 4 bytes IPv4 IP + * @return a String representation of the IP + */ + public static String bytesToIp(byte[] bytesIp) { + + StringBuilder sb = new StringBuilder(); + sb.append(bytesIp[0] & 0xFF); + sb.append("."); + sb.append(bytesIp[1] & 0xFF); + sb.append("."); + sb.append(bytesIp[2] & 0xFF); + sb.append("."); + sb.append(bytesIp[3] & 0xFF); + + String ip = sb.toString(); + return ip; + } + + /** + * Returns a number of zero bits preceding the highest-order ("leftmost") one-bit interpreting + * input array as a big-endian integer value + * + * @param bytes the byte array + * @return the number of leading zeros + */ + public static int numberOfLeadingZeros(byte[] bytes) { + + int i = firstNonZeroByte(bytes); + + if (i == -1) { + return bytes.length * 8; + } else { + int byteLeadingZeros = Integer.numberOfLeadingZeros((int) bytes[i] & 0xff) - 24; + return i * 8 + byteLeadingZeros; + } + } + + /** + * Parses fixed number of bytes starting from {@code offset} in {@code input} array. If {@code + * input} has not enough bytes return array will be right padded with zero bytes. I.e. if {@code + * offset} is higher than {@code input.length} then zero byte array of length {@code len} will + * be returned + * + * @param input the input bytes array + * @param offset an offset in {@code input} array to start parsing from + * @param len the length of zero byte array + * @return a fixed bytes array + */ + public static byte[] parseBytes(byte[] input, int offset, int len) { + + if (offset >= input.length || len == 0) { + return EMPTY_BYTE_ARRAY; + } + + byte[] bytes = new byte[len]; + System.arraycopy(input, offset, bytes, 0, Math.min(input.length - offset, len)); + return bytes; + } + + /** + * Parses 32-bytes word from given input. Uses {@link #parseBytes(byte[], int, int)} method, + * thus, result will be right-padded with zero bytes if there is not enough bytes in {@code + * input} + * + * @param input the input bytes array + * @param idx an index of the word starting from {@code 0} + * @return a fixed bytes array + */ + public static byte[] parseWord(byte[] input, int idx) { + return parseBytes(input, 32 * idx, 32); + } + + /** + * Parses 32-bytes word from given input. Uses {@link #parseBytes(byte[], int, int)} method, + * thus, result will be right-padded with zero bytes if there is not enough bytes in {@code + * input} + * + * @param input the input bytes array + * @param idx an index of the word starting from {@code 0} + * @param offset an offset in {@code input} array to start parsing from + * @return a fixed bytes array + */ + public static byte[] parseWord(byte[] input, int offset, int idx) { + return parseBytes(input, offset + 32 * idx, 32); + } + + public static byte[] trimLeadingBytes(byte[] bytes, byte b) { + int offset = 0; + for (; offset < bytes.length - 1; offset++) { + if (bytes[offset] != b) { + break; + } + } + return Arrays.copyOfRange(bytes, offset, bytes.length); + } + + public static byte[] trimLeadingZeroes(byte[] bytes) { + return trimLeadingBytes(bytes, (byte) 0); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/ChannelUtils.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/ChannelUtils.java new file mode 100644 index 000000000..5005b9e9d --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/ChannelUtils.java @@ -0,0 +1,25 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.utils; + +import java.util.UUID; + +/** Channel utility functions. */ +public class ChannelUtils { + + public static String newSeq() { + String seq = UUID.randomUUID().toString().replaceAll("-", ""); + return seq; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/Collection.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/Collection.java new file mode 100644 index 000000000..fdb41930a --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/Collection.java @@ -0,0 +1,60 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.utils; + +import java.util.Arrays; +import java.util.List; + +/** Utility functions for working with Collections. */ +public class Collection { + private static String[] EMPTY_STRING_ARRAY = {}; + + public static String[] tail(String[] args) { + if (args.length == 0) { + return EMPTY_STRING_ARRAY; + } else { + return Arrays.copyOfRange(args, 1, args.length); + } + } + + public static T[] create(T... args) { + return args; + } + + public static String join(List list, String separator, Function function) { + String result = ""; + for (int i = 0; i < list.size(); i++) { + result += function.apply(list.get(i)).trim(); + if (i + 1 < list.size()) { + result += separator; + } + } + return result; + } + + public static String join(List list, String separator) { + String result = ""; + for (int i = 0; i < list.size(); i++) { + result += list.get(i).trim(); + if (i + 1 < list.size()) { + result += separator; + } + } + return result; + } + + public interface Function { + S apply(R r); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/Hex.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/Hex.java new file mode 100644 index 000000000..10e19d269 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/Hex.java @@ -0,0 +1,140 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.utils; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import org.fisco.bcos.sdk.utils.exceptions.DecoderException; +import org.fisco.bcos.sdk.utils.exceptions.EncoderException; + +/** Utility class for converting hex data to bytes and back again. */ +public class Hex { + private static final HexEncoder encoder = new HexEncoder(); + + public static String toHexString(byte[] data) { + return toHexString(data, 0, data.length); + } + + public static String toHexString(byte[] data, int off, int length) { + byte[] encoded = encode(data, off, length); + return StringUtils.fromByteArray(encoded); + } + + /** + * encode the input data producing a Hex encoded byte array. + * + * @param data the input data + * @return a byte array containing the Hex encoded data. + */ + public static byte[] encode(byte[] data) { + return encode(data, 0, data.length); + } + + /** + * encode the input data producing a Hex encoded byte array. + * + * @param data the input byte array + * @param off the offset of the data to be converted + * @param length the length of the data to be converted + * @return a byte array containing the Hex encoded data. + */ + public static byte[] encode(byte[] data, int off, int length) { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + try { + encoder.encode(data, off, length, bOut); + } catch (Exception e) { + throw new EncoderException("exception encoding Hex string: " + e.getMessage(), e); + } + + return bOut.toByteArray(); + } + + /** + * Hex encode the byte data writing it to the given output stream. + * + * @param data the byte array + * @param out the output stream + * @throws IOException the I/O exception + * @return the number of bytes produced. + */ + public static int encode(byte[] data, OutputStream out) throws IOException { + return encoder.encode(data, 0, data.length, out); + } + + /** + * Hex encode the byte data writing it to the given output stream. + * + * @param data the byte array + * @param off the offset of the data to be converted + * @param length the length of the data to be converted + * @param out the output stream + * @throws IOException the I/O exception + * @return the number of bytes produced. + */ + public static int encode(byte[] data, int off, int length, OutputStream out) + throws IOException { + return encoder.encode(data, off, length, out); + } + + /** + * decode the Hex encoded input data. It is assumed the input data is valid. + * + * @param data the input byte array + * @return a byte array representing the decoded data. + */ + public static byte[] decode(byte[] data) { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + try { + encoder.decode(data, 0, data.length, bOut); + } catch (Exception e) { + throw new DecoderException("exception decoding Hex data: " + e.getMessage(), e); + } + + return bOut.toByteArray(); + } + + /** + * decode the Hex encoded String data - whitespace will be ignored. + * + * @param data the input byte array + * @return a byte array representing the decoded data. + */ + public static byte[] decode(String data) { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + try { + encoder.decode(data, bOut); + } catch (Exception e) { + throw new DecoderException("exception decoding Hex string: " + e.getMessage(), e); + } + + return bOut.toByteArray(); + } + + /** + * decode the Hex encoded String data writing it to the given output stream, whitespace + * characters will be ignored. + * + * @param data the input byte array + * @param out the output stream + * @throws IOException the I/O exception + * @return the number of bytes produced. + */ + public static int decode(String data, OutputStream out) throws IOException { + return encoder.decode(data, out); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/HexEncoder.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/HexEncoder.java new file mode 100644 index 000000000..e8a595b4b --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/HexEncoder.java @@ -0,0 +1,178 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.utils; + +import java.io.IOException; +import java.io.OutputStream; + +/** A streaming Hex encoder. */ +public class HexEncoder { + protected final byte[] encodingTable = { + (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', + (byte) '7', + (byte) '8', (byte) '9', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', + (byte) 'f' + }; + + /* + * set up the decoding table. + */ + protected final byte[] decodingTable = new byte[128]; + + protected void initialiseDecodingTable() { + for (int i = 0; i < decodingTable.length; i++) { + decodingTable[i] = (byte) 0xff; + } + + for (int i = 0; i < encodingTable.length; i++) { + decodingTable[encodingTable[i]] = (byte) i; + } + + decodingTable['A'] = decodingTable['a']; + decodingTable['B'] = decodingTable['b']; + decodingTable['C'] = decodingTable['c']; + decodingTable['D'] = decodingTable['d']; + decodingTable['E'] = decodingTable['e']; + decodingTable['F'] = decodingTable['f']; + } + + public HexEncoder() { + initialiseDecodingTable(); + } + + /** + * encode the input data producing a Hex output stream. + * + * @param data the input byte array + * @param off the offset of the data to be converted + * @param length the length of the data to be converted + * @param out the output stream + * @throws IOException the I/O exception + * @return the number of bytes produced. + */ + public int encode(byte[] data, int off, int length, OutputStream out) throws IOException { + for (int i = off; i < (off + length); i++) { + int v = data[i] & 0xff; + + out.write(encodingTable[(v >>> 4)]); + out.write(encodingTable[v & 0xf]); + } + + return length * 2; + } + + private static boolean ignore(char c) { + return c == '\n' || c == '\r' || c == '\t' || c == ' '; + } + + /** + * decode the Hex encoded byte data writing it to the given output stream, whitespace characters + * will be ignored. + * + * @param data the input byte array + * @param off the offset of the data to be converted + * @param length the length of the data to be converted + * @param out the output stream + * @throws IOException the I/O exception + * @return the number of bytes produced. + */ + public int decode(byte[] data, int off, int length, OutputStream out) throws IOException { + byte field1, field2; + int outLen = 0; + + int end = off + length; + + while (end > off) { + if (!ignore((char) data[end - 1])) { + break; + } + + end--; + } + + int i = off; + while (i < end) { + while (i < end && ignore((char) data[i])) { + i++; + } + + field1 = decodingTable[data[i++]]; + + while (i < end && ignore((char) data[i])) { + i++; + } + + field2 = decodingTable[data[i++]]; + + if ((field1 | field2) < 0) { + throw new IOException("invalid characters encountered in Hex data"); + } + + out.write((field1 << 4) | (field2 & 0xff)); + + outLen++; + } + + return outLen; + } + + /** + * decode the Hex encoded String data writing it to the given output stream, whitespace + * characters will be ignored. + * + * @param data the input byte array + * @param out the output stream + * @throws IOException the I/O exception + * @return the number of bytes produced. + */ + public int decode(String data, OutputStream out) throws IOException { + byte b1, b2; + int length = 0; + + int end = data.length(); + + while (end > 0) { + if (!ignore(data.charAt(end - 1))) { + break; + } + + end--; + } + + int i = 0; + while (i < end) { + while (i < end && ignore(data.charAt(i))) { + i++; + } + + b1 = decodingTable[data.charAt(i++)]; + + while (i < end && ignore(data.charAt(i))) { + i++; + } + + b2 = decodingTable[data.charAt(i++)]; + + if ((b1 | b2) < 0) { + throw new IOException("invalid characters encountered in Hex string"); + } + + out.write((b1 << 4) | (b2 & 0xff)); + + length++; + } + + return length; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/Host.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/Host.java new file mode 100644 index 000000000..77a959edb --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/Host.java @@ -0,0 +1,70 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.utils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** Verify host and port, and extract host or port from string. */ +public class Host { + /** + * @param IP the IP string of host + * @return true if IP valid IP string otherwise false + */ + public static boolean validIP(String IP) { + String regex = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(IP); + return matcher.matches(); + } + + /** + * @param port the port string + * @return true if port valid IP port otherwise false + */ + public static boolean validPort(String port) { + try { + Integer p = Integer.parseInt(port); + return p > 0 && p <= 65535; + } catch (Exception e) { + return false; + } + } + + /** + * Get ip from IPAndPort string + * + * @param IPAndPort the combine of IP and port string + * @return String of IP address + */ + public static String getIpFromString(String IPAndPort) { + int index = IPAndPort.lastIndexOf(':'); + String IP = IPAndPort.substring(0, index); + return IP; + } + + /** + * Get port from IPAndPort string + * + * @param IPAndPort the combine of IP and port string + * @return String of port. + */ + public static String getPortFromString(String IPAndPort) { + int index = IPAndPort.lastIndexOf(':'); + String port = IPAndPort.substring(index + 1); + return port; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/LinuxSecureRandom.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/LinuxSecureRandom.java new file mode 100644 index 000000000..d69608b13 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/LinuxSecureRandom.java @@ -0,0 +1,105 @@ +/* + * Copyright 2013 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.fisco.bcos.sdk.utils; + +import java.io.*; +import java.security.Provider; +import java.security.SecureRandomSpi; +import java.security.Security; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Implementation from BitcoinJ + * implementation + * + *

A SecureRandom implementation that is able to override the standard JVM provided + * implementation, and which simply serves random numbers by reading /dev/urandom. That is, it + * delegates to the kernel on UNIX systems and is unusable on other platforms. Attempts to manually + * set the seed are ignored. There is no difference between seed bytes and non-seed bytes, they are + * all from the same source. + */ +public class LinuxSecureRandom extends SecureRandomSpi { + private static final FileInputStream urandom; + + private static class LinuxSecureRandomProvider extends Provider { + public LinuxSecureRandomProvider() { + super( + "LinuxSecureRandom", + 1.0, + "A Linux specific random number provider that uses /dev/urandom"); + put("SecureRandom.LinuxSecureRandom", LinuxSecureRandom.class.getName()); + } + } + + private static final Logger log = LoggerFactory.getLogger(LinuxSecureRandom.class); + + static { + try { + File file = new File("/dev/urandom"); + // This stream is deliberately leaked. + urandom = new FileInputStream(file); + if (urandom.read() == -1) { + throw new RuntimeException("/dev/urandom not readable?"); + } + // Now override the default SecureRandom implementation with this one. + int position = Security.insertProviderAt(new LinuxSecureRandomProvider(), 1); + + if (position != -1) { + log.info("Secure randomness will be read from {} only.", file); + } else { + log.info("Randomness is already secure."); + } + } catch (FileNotFoundException e) { + // Should never happen. + log.error("/dev/urandom does not appear to exist or is not openable"); + throw new RuntimeException(e); + } catch (IOException e) { + log.error("/dev/urandom does not appear to be readable"); + throw new RuntimeException(e); + } + } + + private final DataInputStream dis; + + public LinuxSecureRandom() { + // DataInputStream is not thread safe, so each random object has its own. + dis = new DataInputStream(urandom); + } + + @Override + protected void engineSetSeed(byte[] bytes) { + // Ignore. + } + + @Override + protected void engineNextBytes(byte[] bytes) { + try { + dis.readFully(bytes); // This will block until all the bytes can be read. + } catch (IOException e) { + throw new RuntimeException(e); // Fatal error. Do not attempt to recover from this. + } + } + + @Override + protected byte[] engineGenerateSeed(int i) { + byte[] bits = new byte[i]; + engineNextBytes(bits); + return bits; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/Numeric.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/Numeric.java new file mode 100644 index 000000000..2c4ec7793 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/Numeric.java @@ -0,0 +1,226 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.utils; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Arrays; +import org.fisco.bcos.sdk.utils.exceptions.MessageDecodingException; +import org.fisco.bcos.sdk.utils.exceptions.MessageEncodingException; + +/** Message codec functions. */ +public final class Numeric { + + private static final String HEX_PREFIX = "0x"; + + private Numeric() {} + + public static String encodeQuantity(BigInteger value) { + if (value.signum() != -1) { + return HEX_PREFIX + value.toString(16); + } else { + throw new MessageEncodingException("Negative values are not supported"); + } + } + + public static BigInteger decodeQuantity(String value) { + if (!isValidHexQuantity(value)) { + try { + if (value == null) return new BigInteger("0"); + return new BigInteger(value); + } catch (NumberFormatException e) { + throw new MessageDecodingException("Negative ", e); + } + } else { + try { + return new BigInteger(value.substring(2), 16); + } catch (NumberFormatException e) { + throw new MessageDecodingException("value is not a hex number or a decimal number"); + } + } + } + + private static boolean isValidHexQuantity(String value) { + if (value == null) { + return false; + } + + if (value.length() < 3) { + return false; + } + return (value.startsWith(HEX_PREFIX)); + } + + public static String cleanHexPrefix(String input) { + if (containsHexPrefix(input)) { + return input.substring(2); + } else { + return input; + } + } + + public static String prependHexPrefix(String input) { + if (!containsHexPrefix(input)) { + return HEX_PREFIX + input; + } else { + return input; + } + } + + public static boolean containsHexPrefix(String input) { + return !StringUtils.isEmpty(input) + && input.length() > 1 + && input.charAt(0) == '0' + && input.charAt(1) == 'x'; + } + + public static BigInteger toBigInt(byte[] value, int offset, int length) { + return toBigInt((Arrays.copyOfRange(value, offset, offset + length))); + } + + public static BigInteger toBigInt(byte[] value) { + return new BigInteger(1, value); + } + + public static BigInteger toBigInt(String hexValue) { + String cleanValue = cleanHexPrefix(hexValue); + return toBigIntNoPrefix(cleanValue); + } + + public static BigInteger toBigIntNoPrefix(String hexValue) { + return new BigInteger(hexValue, 16); + } + + public static String toHexStringWithPrefix(BigInteger value) { + return HEX_PREFIX + value.toString(16); + } + + public static String toHexStringNoPrefix(byte[] input) { + return Hex.toHexString(input); + } + + public static String toHexStringNoPrefix(BigInteger value) { + return value.toString(16); + } + + public static String toHexStringWithPrefixZeroPadded(BigInteger value, int size) { + return toHexStringZeroPadded(value, size, true); + } + + public static String toHexStringWithPrefixSafe(BigInteger value) { + String result = toHexStringNoPrefix(value); + if (result.length() < 2) { + result = StringUtils.zeros(1) + result; + } + return HEX_PREFIX + result; + } + + public static String toHexStringNoPrefixZeroPadded(BigInteger value, int size) { + return toHexStringZeroPadded(value, size, false); + } + + private static String toHexStringZeroPadded(BigInteger value, int size, boolean withPrefix) { + String result = toHexStringNoPrefix(value); + + int length = result.length(); + if (length > size) { + throw new UnsupportedOperationException( + "Value " + result + "is larger then length " + size); + } else if (value.signum() < 0) { + throw new UnsupportedOperationException("Value cannot be negative"); + } + + if (length < size) { + result = StringUtils.zeros(size - length) + result; + } + + if (withPrefix) { + return HEX_PREFIX + result; + } else { + return result; + } + } + + public static byte[] toBytesPadded(BigInteger value, int length) { + byte[] result = new byte[length]; + byte[] bytes = value.toByteArray(); + + int bytesLength; + int srcOffset; + if (bytes[0] == 0) { + bytesLength = bytes.length - 1; + srcOffset = 1; + } else { + bytesLength = bytes.length; + srcOffset = 0; + } + + if (bytesLength > length) { + throw new RuntimeException("Input is too large to put in byte array of size " + length); + } + + int destOffset = length - bytesLength; + System.arraycopy(bytes, srcOffset, result, destOffset, bytesLength); + return result; + } + + public static byte[] hexStringToByteArray(String input) { + String cleanInput = cleanHexPrefix(input); + + int len = cleanInput.length(); + + if (len == 0) { + return new byte[] {}; + } + + byte[] data; + int startIdx; + if (len % 2 != 0) { + data = new byte[(len / 2) + 1]; + data[0] = (byte) Character.digit(cleanInput.charAt(0), 16); + startIdx = 1; + } else { + data = new byte[len / 2]; + startIdx = 0; + } + + for (int i = startIdx; i < len; i += 2) { + data[(i + 1) / 2] = + (byte) + ((Character.digit(cleanInput.charAt(i), 16) << 4) + + Character.digit(cleanInput.charAt(i + 1), 16)); + } + return data; + } + + public static String toHexString(byte[] input, int offset, int length, boolean withPrefix) { + return withPrefix + ? toHexString(Arrays.copyOfRange(input, offset, offset + length)) + : toHexStringNoPrefix(Arrays.copyOfRange(input, offset, offset + length)); + } + + public static String toHexString(byte[] input) { + StringBuilder stringBuilder = new StringBuilder(2 + input.length * 2); + stringBuilder.append("0x").append(Hex.toHexString(input)); + return stringBuilder.toString(); + } + + public static byte asByte(int m, int n) { + return (byte) ((m << 4) | n); + } + + public static boolean isIntegerValue(BigDecimal value) { + return value.signum() == 0 || value.scale() <= 0 || value.stripTrailingZeros().scale() <= 0; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/ObjectMapperFactory.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/ObjectMapperFactory.java new file mode 100644 index 000000000..b9acd985c --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/ObjectMapperFactory.java @@ -0,0 +1,45 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.utils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectReader; + +/** Factory for managing our ObjectMapper instances. */ +public class ObjectMapperFactory { + + private static final ObjectMapper DEFAULT_OBJECT_MAPPER = new ObjectMapper(); + + static { + configureObjectMapper(DEFAULT_OBJECT_MAPPER); + } + + private ObjectMapperFactory() {} + + public static ObjectMapper getObjectMapper() { + return DEFAULT_OBJECT_MAPPER; + } + + public static ObjectReader getObjectReader() { + return DEFAULT_OBJECT_MAPPER.reader(); + } + + private static ObjectMapper configureObjectMapper(ObjectMapper objectMapper) { + objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + return objectMapper; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/SecureRandomUtils.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/SecureRandomUtils.java new file mode 100644 index 000000000..2f3c1a66a --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/SecureRandomUtils.java @@ -0,0 +1,39 @@ +package org.fisco.bcos.sdk.utils; + +import java.security.SecureRandom; + +/** + * Utility class for working with SecureRandom implementation. + * + *

This is to address issues with SecureRandom on Android. For more information, refer to the + * following issue. + */ +final class SecureRandomUtils { + + private static final SecureRandom SECURE_RANDOM; + + static { + if (isAndroidRuntime()) { + new LinuxSecureRandom(); + } + SECURE_RANDOM = new SecureRandom(); + } + + static SecureRandom secureRandom() { + return SECURE_RANDOM; + } + + // Taken from BitcoinJ implementation + // https://github.com/bitcoinj/bitcoinj/blob/3cb1f6c6c589f84fe6e1fb56bf26d94cccc85429/core/src/main/java/org/bitcoinj/core/Utils.java#L573 + private static int isAndroid = -1; + + static boolean isAndroidRuntime() { + if (isAndroid == -1) { + final String runtime = System.getProperty("java.runtime.name"); + isAndroid = (runtime != null && runtime.equals("Android Runtime")) ? 1 : 0; + } + return isAndroid == 1; + } + + private SecureRandomUtils() {} +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/StringUtils.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/StringUtils.java new file mode 100644 index 000000000..72d846201 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/StringUtils.java @@ -0,0 +1,317 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.utils; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; +import java.util.Vector; + +/** String utility functions. */ +public class StringUtils { + + private StringUtils() {} + + public static String toCsv(List src) { + // return src == null ? null : String.join(", ", src.toArray(new String[0])); + return join(src, ", "); + } + + public static String join(List src, String delimiter) { + return src == null ? null : String.join(delimiter, src.toArray(new String[0])); + } + + public static String capitaliseFirstLetter(String string) { + if (string == null || string.length() == 0) { + return string; + } else { + return string.substring(0, 1).toUpperCase() + string.substring(1); + } + } + + public static String lowercaseFirstLetter(String string) { + if (string == null || string.length() == 0) { + return string; + } else { + return string.substring(0, 1).toLowerCase() + string.substring(1); + } + } + + public static String zeros(int n) { + return repeat('0', n); + } + + public static String repeat(char value, int n) { + return new String(new char[n]).replace("\0", String.valueOf(value)); + } + + public static boolean isEmpty(String s) { + return s == null || s.length() == 0; + } + + public static String fromUTF8ByteArray(byte[] bytes) { + int i = 0; + int length = 0; + + while (i < bytes.length) { + length++; + if ((bytes[i] & 0xf0) == 0xf0) { + // surrogate pair + length++; + i += 4; + } else if ((bytes[i] & 0xe0) == 0xe0) { + i += 3; + } else if ((bytes[i] & 0xc0) == 0xc0) { + i += 2; + } else { + i += 1; + } + } + + char[] cs = new char[length]; + + i = 0; + length = 0; + + while (i < bytes.length) { + char ch; + + if ((bytes[i] & 0xf0) == 0xf0) { + int codePoint = + ((bytes[i] & 0x03) << 18) + | ((bytes[i + 1] & 0x3F) << 12) + | ((bytes[i + 2] & 0x3F) << 6) + | (bytes[i + 3] & 0x3F); + int U = codePoint - 0x10000; + char W1 = (char) (0xD800 | (U >> 10)); + char W2 = (char) (0xDC00 | (U & 0x3FF)); + cs[length++] = W1; + ch = W2; + i += 4; + } else if ((bytes[i] & 0xe0) == 0xe0) { + ch = + (char) + (((bytes[i] & 0x0f) << 12) + | ((bytes[i + 1] & 0x3f) << 6) + | (bytes[i + 2] & 0x3f)); + i += 3; + } else if ((bytes[i] & 0xd0) == 0xd0) { + ch = (char) (((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f)); + i += 2; + } else if ((bytes[i] & 0xc0) == 0xc0) { + ch = (char) (((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f)); + i += 2; + } else { + ch = (char) (bytes[i] & 0xff); + i += 1; + } + + cs[length++] = ch; + } + + return new String(cs); + } + + public static byte[] toUTF8ByteArray(String string) { + return toUTF8ByteArray(string.toCharArray()); + } + + public static byte[] toUTF8ByteArray(char[] string) { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + try { + toUTF8ByteArray(string, bOut); + } catch (IOException e) { + throw new IllegalStateException("cannot encode string to byte array!"); + } + + return bOut.toByteArray(); + } + + public static void toUTF8ByteArray(char[] string, OutputStream sOut) throws IOException { + char[] c = string; + int i = 0; + + while (i < c.length) { + char ch = c[i]; + + if (ch < 0x0080) { + sOut.write(ch); + } else if (ch < 0x0800) { + sOut.write(0xc0 | (ch >> 6)); + sOut.write(0x80 | (ch & 0x3f)); + } + // surrogate pair + else if (ch >= 0xD800 && ch <= 0xDFFF) { + // in error - can only happen, if the Java String class has a + // bug. + if (i + 1 >= c.length) { + throw new IllegalStateException("invalid UTF-16 codepoint"); + } + char W1 = ch; + ch = c[++i]; + char W2 = ch; + // in error - can only happen, if the Java String class has a + // bug. + if (W1 > 0xDBFF) { + throw new IllegalStateException("invalid UTF-16 codepoint"); + } + int codePoint = (((W1 & 0x03FF) << 10) | (W2 & 0x03FF)) + 0x10000; + sOut.write(0xf0 | (codePoint >> 18)); + sOut.write(0x80 | ((codePoint >> 12) & 0x3F)); + sOut.write(0x80 | ((codePoint >> 6) & 0x3F)); + sOut.write(0x80 | (codePoint & 0x3F)); + } else { + sOut.write(0xe0 | (ch >> 12)); + sOut.write(0x80 | ((ch >> 6) & 0x3F)); + sOut.write(0x80 | (ch & 0x3F)); + } + + i++; + } + } + + /** + * A locale independent version of toUpperCase. + * + * @param string input to be converted + * @return a US Ascii uppercase version + */ + public static String toUpperCase(String string) { + boolean changed = false; + char[] chars = string.toCharArray(); + + for (int i = 0; i != chars.length; i++) { + char ch = chars[i]; + if ('a' <= ch && 'z' >= ch) { + changed = true; + chars[i] = (char) (ch - 'a' + 'A'); + } + } + + if (changed) { + return new String(chars); + } + + return string; + } + + /** + * A locale independent version of toLowerCase. + * + * @param string input to be converted + * @return a US ASCII lowercase version + */ + public static String toLowerCase(String string) { + boolean changed = false; + char[] chars = string.toCharArray(); + + for (int i = 0; i != chars.length; i++) { + char ch = chars[i]; + if ('A' <= ch && 'Z' >= ch) { + changed = true; + chars[i] = (char) (ch - 'A' + 'a'); + } + } + + if (changed) { + return new String(chars); + } + + return string; + } + + public static byte[] toByteArray(char[] chars) { + byte[] bytes = new byte[chars.length]; + + for (int i = 0; i != bytes.length; i++) { + bytes[i] = (byte) chars[i]; + } + + return bytes; + } + + public static byte[] toByteArray(String string) { + byte[] bytes = new byte[string.length()]; + + for (int i = 0; i != bytes.length; i++) { + char ch = string.charAt(i); + + bytes[i] = (byte) ch; + } + + return bytes; + } + + public static int toByteArray(String s, byte[] buf, int off) { + int count = s.length(); + for (int i = 0; i < count; ++i) { + char c = s.charAt(i); + buf[off + i] = (byte) c; + } + return count; + } + + /** + * Convert an array of 8 bit characters into a string. + * + * @param bytes 8 bit characters. + * @return resulting String. + */ + public static String fromByteArray(byte[] bytes) { + return new String(asCharArray(bytes)); + } + + /** + * Do a simple conversion of an array of 8 bit characters into a string. + * + * @param bytes 8 bit characters. + * @return resulting String. + */ + public static char[] asCharArray(byte[] bytes) { + char[] chars = new char[bytes.length]; + + for (int i = 0; i != chars.length; i++) { + chars[i] = (char) (bytes[i] & 0xff); + } + + return chars; + } + + public static String[] split(String input, char delimiter) { + Vector v = new Vector(); + boolean moreTokens = true; + String subString; + + while (moreTokens) { + int tokenLocation = input.indexOf(delimiter); + if (tokenLocation > 0) { + subString = input.substring(0, tokenLocation); + v.addElement(subString); + input = input.substring(tokenLocation + 1); + } else { + moreTokens = false; + v.addElement(input); + } + } + + String[] res = new String[v.size()]; + + for (int i = 0; i != res.length; i++) { + res[i] = (String) v.elementAt(i); + } + return res; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/ThreadPoolService.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/ThreadPoolService.java new file mode 100644 index 000000000..376ad80a6 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/ThreadPoolService.java @@ -0,0 +1,84 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.utils; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ThreadPoolService { + private static final Logger logger = LoggerFactory.getLogger(ThreadPoolService.class); + public static Integer DEFAULT_KEEP_ALIVE_TIME = 60; + private final ExecutorService threadPool; + + public ThreadPoolService(String threadName, Integer maxBlockingQueueSize) { + this(threadName, Runtime.getRuntime().availableProcessors(), maxBlockingQueueSize); + } + + public ThreadPoolService( + String threadName, Integer corePoolSize, Integer maxBlockingQueueSize) { + this(threadName, corePoolSize, corePoolSize, DEFAULT_KEEP_ALIVE_TIME, maxBlockingQueueSize); + logger.debug( + "Create ThreadPoolService, threadName: {}, corePoolSize: {}, maxBlockingQueueSize: {}", + threadName, + corePoolSize, + maxBlockingQueueSize); + } + + public ThreadPoolService( + String threadName, + Integer corePoolSize, + Integer maximumPoolSize, + Integer keepAliveTime, + Integer maxBlockingQueueSize) { + // set thread name + ThreadFactory threadFactory = + new BasicThreadFactory.Builder().namingPattern(threadName).build(); + threadPool = + new ThreadPoolExecutor( + corePoolSize, + maximumPoolSize, + keepAliveTime, + TimeUnit.SECONDS, + new LinkedBlockingQueue<>(maxBlockingQueueSize), + threadFactory, + new ThreadPoolExecutor.CallerRunsPolicy()); + } + + public ExecutorService getThreadPool() { + return threadPool; + } + + public void stop() { + stopThreadPool(threadPool); + } + + public static void stopThreadPool(ExecutorService threadPool) { + threadPool.shutdown(); + try { + while (!threadPool.isTerminated()) { + threadPool.awaitTermination(10, TimeUnit.MILLISECONDS); + } + threadPool.shutdownNow(); + } catch (InterruptedException ex) { + threadPool.shutdownNow(); + Thread.currentThread().interrupt(); + } + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/exceptions/DecoderException.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/exceptions/DecoderException.java new file mode 100644 index 000000000..2f358ba3d --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/exceptions/DecoderException.java @@ -0,0 +1,30 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.utils.exceptions; + +/** Exception thrown if an attempt is made to decode invalid data, or some other failure occurs. */ +public class DecoderException extends IllegalStateException { + private final Throwable cause; + + public DecoderException(String msg, Throwable cause) { + super(msg); + + this.cause = cause; + } + + @Override + public final synchronized Throwable getCause() { + return cause; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/exceptions/EncoderException.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/exceptions/EncoderException.java new file mode 100644 index 000000000..d9f5673ba --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/exceptions/EncoderException.java @@ -0,0 +1,30 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.utils.exceptions; + +/** Exception thrown if an attempt is made to encode invalid data, or some other failure occurs. */ +public class EncoderException extends IllegalStateException { + private final Throwable cause; + + public EncoderException(String msg, Throwable cause) { + super(msg); + + this.cause = cause; + } + + @Override + public final synchronized Throwable getCause() { + return cause; + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/exceptions/MessageDecodingException.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/exceptions/MessageDecodingException.java new file mode 100644 index 000000000..06c190ef3 --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/exceptions/MessageDecodingException.java @@ -0,0 +1,25 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.utils.exceptions; + +/** Encoding exception. */ +public class MessageDecodingException extends RuntimeException { + public MessageDecodingException(String message) { + super(message); + } + + public MessageDecodingException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/exceptions/MessageEncodingException.java b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/exceptions/MessageEncodingException.java new file mode 100644 index 000000000..3b2534e1f --- /dev/null +++ b/sdk-core/src/main/java/org/fisco/bcos/sdk/utils/exceptions/MessageEncodingException.java @@ -0,0 +1,25 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.utils.exceptions; + +/** Encoding exception. */ +public class MessageEncodingException extends RuntimeException { + public MessageEncodingException(String message) { + super(message); + } + + public MessageEncodingException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/sdk-core/src/test/java/org/fisco/bcos/sdk/config/ConfigTest.java b/sdk-core/src/test/java/org/fisco/bcos/sdk/config/ConfigTest.java new file mode 100644 index 000000000..8d85b7f6a --- /dev/null +++ b/sdk-core/src/test/java/org/fisco/bcos/sdk/config/ConfigTest.java @@ -0,0 +1,46 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.config; + +import static org.junit.Assert.fail; + +import org.fisco.bcos.sdk.config.exceptions.ConfigException; +import org.fisco.bcos.sdk.model.ConstantConfig; +import org.fisco.bcos.sdk.model.CryptoType; +import org.junit.Assert; +import org.junit.Test; + +public class ConfigTest { + @Test + public void testLoadRightConfig() { + try { + ConfigOption configOption = + Config.load( + "src/test/resources/config-example.toml", + CryptoType.ECDSA_TYPE); + Assert.assertTrue(configOption.getAccountConfig() != null); + System.out.println( + "configOption.getAccountConfig: " + + configOption.getAccountConfig().getKeyStoreDir()); + // assertEquals("ecdsa", config.getAlgorithm()); + } catch (ConfigException e) { + System.out.println("testLoadRightConfig failed, error message: " + e.getMessage()); + if (!e.getMessage().contains("consumer_public_key_1.pem file not exist")) { + System.out.println("No exception is needed."); + } + } + } +} diff --git a/sdk-core/src/test/java/org/fisco/bcos/sdk/network/CodecTest.java b/sdk-core/src/test/java/org/fisco/bcos/sdk/network/CodecTest.java new file mode 100644 index 000000000..e195c8217 --- /dev/null +++ b/sdk-core/src/test/java/org/fisco/bcos/sdk/network/CodecTest.java @@ -0,0 +1,78 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.network; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import org.fisco.bcos.sdk.model.Message; +import org.fisco.bcos.sdk.model.MsgType; +import org.junit.Assert; +import org.junit.Test; + +public class CodecTest { + String seq = UUID.randomUUID().toString().replaceAll("-", ""); + + @Test + public void testMsgDecoder() { + ByteBuf in = getEventMsgByteBuf(); + MessageDecoder decoder = new MessageDecoder(); + List out = new ArrayList<>(); + try { + decoder.decode(null, in, out); + Message msg = (Message) out.get(0); + Assert.assertEquals(seq, msg.getSeq()); + Assert.assertEquals(MsgType.EVENT_LOG_PUSH.ordinal(), msg.getType().intValue()); + Assert.assertEquals("data", new String(msg.getData())); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void testMsgEncoder() { + MessageEncoder encoder = new MessageEncoder(); + ByteBuf out = Unpooled.buffer(); + try { + encoder.encode(null, getEventMsg(), out); + Assert.assertEquals(out, getEventMsgByteBuf()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private Message getEventMsg() { + Message msg = new Message(); + msg.setSeq(seq); + msg.setType((short) MsgType.EVENT_LOG_PUSH.ordinal()); + msg.setResult(0); + msg.setData("data".getBytes()); + return msg; + } + + private ByteBuf getEventMsgByteBuf() { + ByteBuf byteBuf = Unpooled.buffer(); + Message msg = new Message(); + msg.setSeq(seq); + msg.setType((short) MsgType.EVENT_LOG_PUSH.ordinal()); + msg.setResult(0); + msg.setData("data".getBytes()); + msg.encode(byteBuf); + return byteBuf; + } +} diff --git a/sdk-core/src/test/resources/config-example.toml b/sdk-core/src/test/resources/config-example.toml new file mode 100644 index 000000000..9eabf4f2f --- /dev/null +++ b/sdk-core/src/test/resources/config-example.toml @@ -0,0 +1,46 @@ +[cryptoMaterial] + +certPath = "conf" # The certification path + +# The following configurations take the certPath by default: + +# caCert = "conf/ca.crt" # CA cert file path +# sslCert = "conf/sdk.crt" # SSL cert file path +# sslKey = "conf/sdk.key" # SSL key file path +# enSslCert = "conf/gm/gmensdk.crt" # GM encryption cert file path +# enSslKey = "conf/gm/gmensdk.key" # GM ssl cert file path + +[network] +peers=["127.0.0.1:20200", "127.0.0.1:20201"] # The peer list to connect + +# Configure a private topic as a topic message sender. +# [[amop]] +# topicName = "PrivateTopic1" +# publicKeys = [ "conf/amop/consumer_public_key_1.pem" ] # Public keys of the nodes that you want to send AMOP message of this topic to. + +# Configure a private topic as a topic subscriber. +# [[amop]] +# topicName = "PrivateTopic2" +# privateKey = "conf/amop/consumer_private_key.p12" # Your private key that used to subscriber verification. +# password = "123456" + +[account] +keyStoreDir = "account" # The directory to load/store the account file, default is "account" +# accountFilePath = "" # The account file path (default load from the path specified by the keyStoreDir) +accountFileFormat = "pem" # The storage format of account file (Default is "pem", "p12" as an option) + +# accountAddress = "" # The transactions sending account address + # Default is a randomly generated account + # The randomly generated account is stored in the path specified by the keyStoreDir + +# password = "" # The password used to load the account file + +[threadPool] +# channelProcessorThreadSize = "16" # The size of the thread pool to process channel callback + # Default is the number of cpu cores + +# receiptProcessorThreadSize = "16" # The size of the thread pool to process transaction receipt notification + # Default is the number of cpu cores + +maxBlockingQueueSize = "102400" # The max blocking queue size of the thread pool + diff --git a/sdk-crypto/build.gradle b/sdk-crypto/build.gradle new file mode 100644 index 000000000..8d0c26c59 --- /dev/null +++ b/sdk-crypto/build.gradle @@ -0,0 +1,52 @@ +// Apply the java-library plugin to add support for Java Library +plugins { + id 'java' +} +dependencies { + compile project(':sdk-core') + compile ("org.bouncycastle:bcprov-jdk15on:${bcprovJDK15onVersion}") + compile ("com.webank:key-mini-toolkit:${keyMiniToolkit}") +} + +uploadArchives { + repositories { + mavenDeployer { + //beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + + repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { + authentication(userName: ossrhUsername, password: ossrhPassword) + } + + snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { + authentication(userName: ossrhUsername, password: ossrhPassword) + } + + pom.project { + name project.name + packaging 'jar' + description = 'fisco-bcos java-sdk' + url = 'http://www.fisco-bcos.org' + + scm { + connection = 'https://github.com/FISCO-BCOS/java-sdk.git' + url = 'https://github.com/FISCO-BCOS/java-sdk.git' + } + + licenses { + license { + name = 'The Apache License, Version 2.0' + url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + + developers { + developer { + id = 'zhangsan' + name = 'zhangsan' + email = 'zhangsan@example.com' + } + } + } + } + } +} diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/CryptoSuite.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/CryptoSuite.java new file mode 100644 index 000000000..d4654a510 --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/CryptoSuite.java @@ -0,0 +1,214 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto; + +import java.security.KeyPair; +import org.fisco.bcos.sdk.config.ConfigOption; +import org.fisco.bcos.sdk.config.model.AccountConfig; +import org.fisco.bcos.sdk.crypto.exceptions.LoadKeyStoreException; +import org.fisco.bcos.sdk.crypto.exceptions.UnsupportedCryptoTypeException; +import org.fisco.bcos.sdk.crypto.hash.Hash; +import org.fisco.bcos.sdk.crypto.hash.Keccak256; +import org.fisco.bcos.sdk.crypto.hash.SM3Hash; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.crypto.keypair.ECDSAKeyPair; +import org.fisco.bcos.sdk.crypto.keypair.SM2KeyPair; +import org.fisco.bcos.sdk.crypto.keystore.KeyTool; +import org.fisco.bcos.sdk.crypto.keystore.P12KeyStore; +import org.fisco.bcos.sdk.crypto.keystore.PEMKeyStore; +import org.fisco.bcos.sdk.crypto.signature.ECDSASignature; +import org.fisco.bcos.sdk.crypto.signature.SM2Signature; +import org.fisco.bcos.sdk.crypto.signature.Signature; +import org.fisco.bcos.sdk.crypto.signature.SignatureResult; +import org.fisco.bcos.sdk.model.CryptoType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CryptoSuite { + + private static Logger logger = LoggerFactory.getLogger(CryptoSuite.class); + + public final int cryptoTypeConfig; + + public final Signature signatureImpl; + public final Hash hashImpl; + private final CryptoKeyPair keyPairFactory; + private CryptoKeyPair cryptoKeyPair; + private ConfigOption config; + + public CryptoSuite(int cryptoTypeConfig, ConfigOption configOption) { + this(cryptoTypeConfig); + logger.info("init CryptoSuite, cryptoType: {}", cryptoTypeConfig); + setConfig(configOption); + // doesn't set the account name, generate the keyPair randomly + if (!configOption.getAccountConfig().isAccountConfigured()) { + createKeyPair(); + return; + } + loadAccount(configOption); + } + /** + * init the common crypto implementation according to the crypto type + * + * @param cryptoTypeConfig the crypto type config number + */ + public CryptoSuite(int cryptoTypeConfig) { + this.cryptoTypeConfig = cryptoTypeConfig; + if (this.cryptoTypeConfig == CryptoType.ECDSA_TYPE) { + this.signatureImpl = new ECDSASignature(); + this.hashImpl = new Keccak256(); + this.keyPairFactory = new ECDSAKeyPair(); + + } else if (this.cryptoTypeConfig == CryptoType.SM_TYPE) { + this.signatureImpl = new SM2Signature(); + this.hashImpl = new SM3Hash(); + this.keyPairFactory = new SM2KeyPair(); + + } else { + throw new UnsupportedCryptoTypeException( + "only support " + + CryptoType.ECDSA_TYPE + + "/" + + CryptoType.SM_TYPE + + " crypto type"); + } + // create keyPair randomly + createKeyPair(); + } + + public void loadAccount(String accountFileFormat, String accountFilePath, String password) { + KeyTool keyTool = null; + if (accountFileFormat.compareToIgnoreCase("p12") == 0) { + keyTool = new P12KeyStore(accountFilePath, password); + } else if (accountFileFormat.compareToIgnoreCase("pem") == 0) { + keyTool = new PEMKeyStore(accountFilePath); + } else { + throw new LoadKeyStoreException( + "unsupported account file format : " + + accountFileFormat + + ", current supported are p12 and pem"); + } + logger.debug("Load account from {}", accountFilePath); + createKeyPair(keyTool.getKeyPair()); + } + + private void loadAccount(ConfigOption configOption) { + AccountConfig accountConfig = configOption.getAccountConfig(); + String accountFilePath = accountConfig.getAccountFilePath(); + if (accountFilePath == null || accountFilePath.equals("")) { + if (accountConfig.getAccountFileFormat().compareToIgnoreCase("p12") == 0) { + accountFilePath = + keyPairFactory.getP12KeyStoreFilePath(accountConfig.getAccountAddress()); + } else if (accountConfig.getAccountFileFormat().compareToIgnoreCase("pem") == 0) { + accountFilePath = + keyPairFactory.getPemKeyStoreFilePath(accountConfig.getAccountAddress()); + } + } + loadAccount( + accountConfig.getAccountFileFormat(), + accountFilePath, + accountConfig.getAccountPassword()); + } + + public void setConfig(ConfigOption config) { + this.config = config; + this.keyPairFactory.setConfig(config); + } + + public int getCryptoTypeConfig() { + return cryptoTypeConfig; + } + + public Signature getSignatureImpl() { + return signatureImpl; + } + + public Hash getHashImpl() { + return hashImpl; + } + + public String hash(final String inputData) { + return hashImpl.hash(inputData); + } + + public byte[] hash(final byte[] inputBytes) { + return hashImpl.hash(inputBytes); + } + + public SignatureResult sign(final byte[] message, final CryptoKeyPair keyPair) { + return signatureImpl.sign(message, keyPair); + } + + public SignatureResult sign(final String message, final CryptoKeyPair keyPair) { + return signatureImpl.sign(message, keyPair); + } + + // for AMOP topic verify, generate signature + public String sign(KeyTool keyTool, String message) { + CryptoKeyPair cryptoKeyPair = this.keyPairFactory.createKeyPair(keyTool.getKeyPair()); + return signatureImpl.signWithStringSignature(message, cryptoKeyPair); + } + + // for AMOP topic verify, verify the signature + public boolean verify(KeyTool keyTool, String message, String signature) { + return verify(keyTool.getHexedPublicKey(), message, signature); + } + + public boolean verify(KeyTool keyTool, byte[] message, byte[] signature) { + return verify(keyTool.getHexedPublicKey(), message, signature); + } + + public boolean verify(final String publicKey, final String message, final String signature) { + return signatureImpl.verify(publicKey, message, signature); + } + + public boolean verify(final String publicKey, final byte[] message, final byte[] signature) { + return signatureImpl.verify(publicKey, message, signature); + } + + public CryptoKeyPair createKeyPair() { + this.cryptoKeyPair = this.keyPairFactory.generateKeyPair(); + this.cryptoKeyPair.setConfig(config); + return this.cryptoKeyPair; + } + + public CryptoKeyPair createKeyPair(KeyPair keyPair) { + this.cryptoKeyPair = this.keyPairFactory.createKeyPair(keyPair); + this.cryptoKeyPair.setConfig(config); + return this.cryptoKeyPair; + } + + public CryptoKeyPair createKeyPair(String hexedPrivateKey) { + this.cryptoKeyPair = this.keyPairFactory.createKeyPair(hexedPrivateKey); + this.cryptoKeyPair.setConfig(config); + return this.cryptoKeyPair; + } + + public void setCryptoKeyPair(CryptoKeyPair cryptoKeyPair) { + this.cryptoKeyPair = cryptoKeyPair; + this.cryptoKeyPair.setConfig(config); + } + + public CryptoKeyPair getCryptoKeyPair() { + return this.cryptoKeyPair; + } + + public ConfigOption getConfig() { + return this.config; + } + + public CryptoKeyPair getKeyPairFactory() { + return this.keyPairFactory; + } +} diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/exceptions/HashException.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/exceptions/HashException.java new file mode 100644 index 000000000..dc1172fb4 --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/exceptions/HashException.java @@ -0,0 +1,25 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.exceptions; + +/** Exceptioned when calling hash. */ +public class HashException extends RuntimeException { + public HashException(String message) { + super(message); + } + + public HashException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/exceptions/KeyPairException.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/exceptions/KeyPairException.java new file mode 100644 index 000000000..9f56dafb2 --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/exceptions/KeyPairException.java @@ -0,0 +1,25 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.exceptions; + +/** Exceptioned when calling hash. */ +public class KeyPairException extends RuntimeException { + public KeyPairException(String message) { + super(message); + } + + public KeyPairException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/exceptions/LoadKeyStoreException.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/exceptions/LoadKeyStoreException.java new file mode 100644 index 000000000..078400fa9 --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/exceptions/LoadKeyStoreException.java @@ -0,0 +1,25 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.exceptions; + +/** Exceptioned when calling KeyManager. */ +public class LoadKeyStoreException extends RuntimeException { + public LoadKeyStoreException(String message) { + super(message); + } + + public LoadKeyStoreException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/exceptions/SaveKeyStoreException.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/exceptions/SaveKeyStoreException.java new file mode 100644 index 000000000..f6f579ca6 --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/exceptions/SaveKeyStoreException.java @@ -0,0 +1,25 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.exceptions; + +/** Exceptioned when save the CryptoKeyPair into p12 or pem */ +public class SaveKeyStoreException extends RuntimeException { + public SaveKeyStoreException(String message) { + super(message); + } + + public SaveKeyStoreException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/exceptions/SignatureException.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/exceptions/SignatureException.java new file mode 100644 index 000000000..e97ec8d58 --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/exceptions/SignatureException.java @@ -0,0 +1,25 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.exceptions; + +/** Exceptioned when calling signature related functions. */ +public class SignatureException extends RuntimeException { + public SignatureException(String message) { + super(message); + } + + public SignatureException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/exceptions/UnsupportedCryptoTypeException.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/exceptions/UnsupportedCryptoTypeException.java new file mode 100644 index 000000000..c41f9b103 --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/exceptions/UnsupportedCryptoTypeException.java @@ -0,0 +1,25 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.exceptions; + +/** Exceptioned when calling CryptoSuite. */ +public class UnsupportedCryptoTypeException extends RuntimeException { + public UnsupportedCryptoTypeException(String message) { + super(message); + } + + public UnsupportedCryptoTypeException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/hash/Hash.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/hash/Hash.java new file mode 100644 index 000000000..c8f6b6648 --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/hash/Hash.java @@ -0,0 +1,22 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** interface for hash calculation */ +package org.fisco.bcos.sdk.crypto.hash; + +public interface Hash { + String hash(final String inputData); + + byte[] hash(final byte[] inputBytes); +} diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/hash/Keccak256.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/hash/Keccak256.java new file mode 100644 index 000000000..a5643120f --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/hash/Keccak256.java @@ -0,0 +1,43 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.hash; + +import com.webank.wedpr.crypto.CryptoResult; +import com.webank.wedpr.crypto.NativeInterface; +import org.fisco.bcos.sdk.crypto.exceptions.HashException; +import org.fisco.bcos.sdk.utils.Hex; + +public class Keccak256 implements Hash { + + @Override + public String hash(final String inputData) { + return calculateHash(inputData.getBytes()); + } + + @Override + public byte[] hash(final byte[] inputBytes) { + return Hex.decode(calculateHash(inputBytes)); + } + + private String calculateHash(final byte[] inputBytes) { + // Note: the exceptions should be handled by the caller + CryptoResult hashResult = NativeInterface.keccak256(Hex.toHexString(inputBytes)); + if (hashResult.wedprErrorMessage != null && !hashResult.wedprErrorMessage.isEmpty()) { + throw new HashException( + "Calculate hash with keccak256 failed! error message:" + + hashResult.wedprErrorMessage); + } + return hashResult.hash; + } +} diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/hash/SM3Hash.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/hash/SM3Hash.java new file mode 100644 index 000000000..cbc596b40 --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/hash/SM3Hash.java @@ -0,0 +1,43 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.hash; + +import com.webank.wedpr.crypto.CryptoResult; +import com.webank.wedpr.crypto.NativeInterface; +import org.fisco.bcos.sdk.crypto.exceptions.HashException; +import org.fisco.bcos.sdk.utils.Hex; + +public class SM3Hash implements Hash { + @Override + public String hash(final String inputData) { + return calcualteHash(inputData.getBytes()); + } + + @Override + public byte[] hash(final byte[] inputBytes) { + // Considering inefficient string conversion, this interface is not recommended + return Hex.decode(calcualteHash(inputBytes)); + } + + private String calcualteHash(final byte[] inputBytes) { + CryptoResult hashResult = NativeInterface.sm3(Hex.toHexString(inputBytes)); + // call sm3 failed + if (hashResult.wedprErrorMessage != null && !hashResult.wedprErrorMessage.isEmpty()) { + throw new HashException( + "calculate hash with sm3 failed, error message:" + + hashResult.wedprErrorMessage); + } + return hashResult.hash; + } +} 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 new file mode 100644 index 000000000..b06bcb249 --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keypair/CryptoKeyPair.java @@ -0,0 +1,258 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.keypair; + +import com.webank.wedpr.crypto.CryptoResult; +import java.io.File; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.Arrays; +import org.fisco.bcos.sdk.config.ConfigOption; +import org.fisco.bcos.sdk.crypto.exceptions.KeyPairException; +import org.fisco.bcos.sdk.crypto.hash.Hash; +import org.fisco.bcos.sdk.crypto.keystore.KeyTool; +import org.fisco.bcos.sdk.crypto.keystore.P12KeyStore; +import org.fisco.bcos.sdk.crypto.keystore.PEMKeyStore; +import org.fisco.bcos.sdk.utils.Hex; +import org.fisco.bcos.sdk.utils.Numeric; +import org.fisco.bcos.sdk.utils.StringUtils; +import org.fisco.bcos.sdk.utils.exceptions.DecoderException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class CryptoKeyPair { + protected static Logger logger = LoggerFactory.getLogger(CryptoKeyPair.class); + public static final int ADDRESS_SIZE = 160; + public static final int ADDRESS_LENGTH_IN_HEX = ADDRESS_SIZE >> 2; + + public static final int PUBLIC_KEY_SIZE = 64; + public static final int PUBLIC_KEY_LENGTH_IN_HEX = PUBLIC_KEY_SIZE << 1; + + public static final String ECDSA_CURVE_NAME = "secp256k1"; + public static final String SM2_CURVE_NAME = "sm2p256v1"; + public static final String PEM_FILE_POSTFIX = ".pem"; + public static final String P12_FILE_POSTFIX = ".p12"; + public static final String GM_ACCOUNT_SUBDIR = "gm"; + public static final String ECDSA_ACCOUNT_SUBDIR = "ecdsa"; + + protected static final String ECDSA_SIGNATURE_ALGORITHM = "SHA256WITHECDSA"; + protected static final String SM_SIGNATURE_ALGORITHM = "1.2.156.10197.1.501"; + + protected String hexPrivateKey; + protected String hexPublicKey; + public KeyPair keyPair; + + protected Hash hashImpl; + // Curve name corresponding to the KeyPair + protected String curveName; + protected String keyStoreSubDir = ""; + + protected ConfigOption config; + // The path to save the account pem file corresponding to the CryptoKeyPair + protected String pemKeyStoreFilePath = ""; + // The path to save the account p12 file + protected String p12KeyStoreFilePath = ""; + protected String signatureAlgorithm; + + public CryptoKeyPair() {} + + /** + * init CryptoKeyPair from the keyPair + * + * @param keyPair the original keyPair + */ + public CryptoKeyPair(KeyPair keyPair) { + this.keyPair = keyPair; + // init privateKey/publicKey from the keyPair + this.hexPrivateKey = KeyTool.getHexedPrivateKey(keyPair.getPrivate()); + this.hexPublicKey = KeyTool.getHexedPublicKey(keyPair.getPublic()); + } + /** + * get CryptoKeyPair information from CryptoResult + * + * @param nativeResult + */ + CryptoKeyPair(final CryptoResult nativeResult) { + this.hexPrivateKey = nativeResult.privteKey; + this.hexPublicKey = nativeResult.publicKey; + } + + public void setConfig(ConfigOption config) { + this.config = config; + } + + public String getHexPrivateKey() { + return hexPrivateKey; + } + + public String getHexPublicKey() { + return hexPublicKey; + } + + public KeyPair getKeyPair() { + return this.keyPair; + } + + /** + * generate keyPair randomly + * + * @return the generated keyPair + */ + public abstract CryptoKeyPair generateKeyPair(); + + public abstract CryptoKeyPair createKeyPair(KeyPair keyPair); + + public CryptoKeyPair createKeyPair(BigInteger privateKeyValue) { + PrivateKey privateKey = KeyTool.convertHexedStringToPrivateKey(privateKeyValue, curveName); + PublicKey publicKey = KeyTool.getPublicKeyFromPrivateKey(privateKey); + KeyPair keyPair = new KeyPair(publicKey, privateKey); + return createKeyPair(keyPair); + } + + public CryptoKeyPair createKeyPair(String hexPrivateKey) { + PrivateKey privateKey = KeyTool.convertHexedStringToPrivateKey(hexPrivateKey, curveName); + PublicKey publicKey = KeyTool.getPublicKeyFromPrivateKey(privateKey); + KeyPair keyPair = new KeyPair(publicKey, privateKey); + return createKeyPair(keyPair); + } + + protected String getPublicKeyNoPrefix(String publicKeyStr) { + String publicKeyNoPrefix = Numeric.cleanHexPrefix(publicKeyStr); + // Hexadecimal public key length is less than 128, add 0 in front + if (publicKeyNoPrefix.length() < PUBLIC_KEY_LENGTH_IN_HEX) { + publicKeyNoPrefix = + StringUtils.zeros(PUBLIC_KEY_LENGTH_IN_HEX - publicKeyNoPrefix.length()) + + publicKeyNoPrefix; + } + return publicKeyNoPrefix; + } + /** + * get the address according to the public key + * + * @return the hexed address calculated from the publicKey + */ + 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)); + } + /** + * calculate the address according to the given public key + * + * @param publicKey the Hexed publicKey that need to calculate address + * @return the account address + */ + public String getAddress(String publicKey) { + try { + String publicKeyNoPrefix = getPublicKeyNoPrefix(publicKey); + // calculate hash for the public key + String publicKeyHash = Hex.toHexString(hashImpl.hash(Hex.decode(publicKeyNoPrefix))); + // right most 160 bits + return "0x" + publicKeyHash.substring(publicKeyHash.length() - ADDRESS_LENGTH_IN_HEX); + } catch (DecoderException e) { + throw new KeyPairException( + "getAddress for " + + publicKey + + "failed, the publicKey param must be hex string, error message: " + + e.getMessage(), + e); + } + } + + public byte[] getAddress(byte[] publicKey) { + byte[] hash = hashImpl.hash(publicKey); + return Arrays.copyOfRange(hash, hash.length - 20, hash.length); // right most 160 bits + } + + public byte[] getAddress(BigInteger publicKey) { + byte[] publicKeyBytes = Numeric.toBytesPadded(publicKey, PUBLIC_KEY_SIZE); + return getAddress(publicKeyBytes); + } + + public void storeKeyPairWithPem(String keyStoreFilePath) { + PEMKeyStore.storeKeyPairWithPemFormat(this.hexPrivateKey, keyStoreFilePath, curveName); + } + + public void storeKeyPairWithPemFormat() { + String pemKeyStoreFilePath = getPemKeyStoreFilePath(); + File file = new File(pemKeyStoreFilePath); + if (file.exists()) { + return; + } + File parentFile = file.getParentFile(); + if (!parentFile.exists()) { + parentFile.mkdirs(); + } + logger.debug("store account {} to pem file: {}", getAddress(), pemKeyStoreFilePath); + storeKeyPairWithPem(pemKeyStoreFilePath); + } + + public void storeKeyPairWithP12(String p12FilePath, String password) { + P12KeyStore.storeKeyPairWithP12Format( + this.hexPrivateKey, password, p12FilePath, curveName, signatureAlgorithm); + } + + public void storeKeyPairWithP12Format(String password) { + String p12KeyStoreFilePath = getP12KeyStoreFilePath(); + File file = new File(p12KeyStoreFilePath); + if (file.exists()) { + return; + } + File parentFile = file.getParentFile(); + if (!parentFile.exists()) { + parentFile.mkdirs(); + } + logger.debug("store account {} to p12 file: {}", getAddress(), p12KeyStoreFilePath); + storeKeyPairWithP12(p12KeyStoreFilePath, password); + } + + public String getKeyStoreSubDir() { + return this.keyStoreSubDir; + } + + public String getPemKeyStoreFilePath() { + if (!pemKeyStoreFilePath.equals("")) { + return pemKeyStoreFilePath; + } + pemKeyStoreFilePath = getPemKeyStoreFilePath(getAddress()); + return pemKeyStoreFilePath; + } + + public String getPemKeyStoreFilePath(String address) { + return getKeyStoreFilePath(address, PEM_FILE_POSTFIX); + } + + public String getP12KeyStoreFilePath(String address) { + return getKeyStoreFilePath(address, P12_FILE_POSTFIX); + } + + public String getP12KeyStoreFilePath() { + if (!p12KeyStoreFilePath.equals("")) { + return p12KeyStoreFilePath; + } + p12KeyStoreFilePath = getP12KeyStoreFilePath(getAddress()); + return p12KeyStoreFilePath; + } + + protected String getKeyStoreFilePath(String address, String postFix) { + String keyStoreFileDir = "account"; + if (config != null) { + keyStoreFileDir = config.getAccountConfig().getKeyStoreDir(); + } + keyStoreFileDir = keyStoreFileDir + File.separator + keyStoreSubDir + File.separator; + return keyStoreFileDir + address + postFix; + } +} diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keypair/ECDSAKeyPair.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keypair/ECDSAKeyPair.java new file mode 100644 index 000000000..3dcffbaa4 --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keypair/ECDSAKeyPair.java @@ -0,0 +1,57 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.keypair; + +import com.webank.wedpr.crypto.CryptoResult; +import com.webank.wedpr.crypto.NativeInterface; +import java.security.KeyPair; +import org.fisco.bcos.sdk.crypto.hash.Keccak256; + +public class ECDSAKeyPair extends CryptoKeyPair { + public ECDSAKeyPair() { + initECDSAKeyPair(); + } + + public ECDSAKeyPair(KeyPair javaKeyPair) { + super(javaKeyPair); + initECDSAKeyPair(); + } + + protected ECDSAKeyPair(final CryptoResult ecKeyPairInfo) { + super(ecKeyPairInfo); + initECDSAKeyPair(); + } + + private void initECDSAKeyPair() { + this.hashImpl = new Keccak256(); + this.curveName = CryptoKeyPair.ECDSA_CURVE_NAME; + this.keyStoreSubDir = ECDSA_ACCOUNT_SUBDIR; + this.signatureAlgorithm = ECDSA_SIGNATURE_ALGORITHM; + } + + /** + * generate keyPair randomly + * + * @return the generated keyPair + */ + @Override + public CryptoKeyPair generateKeyPair() { + return new ECDSAKeyPair(NativeInterface.secp256k1keyPair()); + } + + @Override + public CryptoKeyPair createKeyPair(KeyPair javaKeyPair) { + return new ECDSAKeyPair(javaKeyPair); + } +} diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keypair/SM2KeyPair.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keypair/SM2KeyPair.java new file mode 100644 index 000000000..1c2752a4b --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keypair/SM2KeyPair.java @@ -0,0 +1,57 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.keypair; + +import com.webank.wedpr.crypto.CryptoResult; +import com.webank.wedpr.crypto.NativeInterface; +import java.security.KeyPair; +import org.fisco.bcos.sdk.crypto.hash.SM3Hash; + +public class SM2KeyPair extends CryptoKeyPair { + public SM2KeyPair() { + initSM2KeyPairObject(); + } + + public SM2KeyPair(KeyPair javaKeyPair) { + super(javaKeyPair); + initSM2KeyPairObject(); + } + + protected SM2KeyPair(CryptoResult sm2keyPairInfo) { + super(sm2keyPairInfo); + initSM2KeyPairObject(); + } + + private void initSM2KeyPairObject() { + this.keyStoreSubDir = GM_ACCOUNT_SUBDIR; + this.hashImpl = new SM3Hash(); + this.curveName = CryptoKeyPair.SM2_CURVE_NAME; + this.signatureAlgorithm = SM_SIGNATURE_ALGORITHM; + } + + /** + * generate keyPair randomly + * + * @return the generated keyPair + */ + @Override + public CryptoKeyPair generateKeyPair() { + return new SM2KeyPair(NativeInterface.sm2keyPair()); + } + + @Override + public CryptoKeyPair createKeyPair(KeyPair javaKeyPair) { + return new SM2KeyPair(javaKeyPair); + } +} 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 new file mode 100644 index 000000000..5ceeb5fd2 --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keystore/KeyTool.java @@ -0,0 +1,294 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.keystore; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; +import java.security.interfaces.ECPrivateKey; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.util.Arrays; +import java.util.Collections; +import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; +import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; +import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; +import org.bouncycastle.jce.ECNamedCurveTable; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; +import org.bouncycastle.jce.spec.ECNamedCurveSpec; +import org.bouncycastle.jce.spec.ECPrivateKeySpec; +import org.bouncycastle.util.io.pem.PemObject; +import org.bouncycastle.util.io.pem.PemWriter; +import org.fisco.bcos.sdk.crypto.exceptions.LoadKeyStoreException; +import org.fisco.bcos.sdk.utils.Numeric; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class KeyTool { + protected static Logger logger = LoggerFactory.getLogger(KeyTool.class); + + protected final String keyStoreFile; + protected final String password; + protected KeyStore keyStore; + private String hexedPublicKey = ""; + + /** + * constructor for the P12: with password + * + * @param keyStoreFile the path of the keystore file + * @param password password to read the keystore file + */ + public KeyTool(final String keyStoreFile, final String password) { + this.keyStoreFile = keyStoreFile; + this.password = password; + initSecurity(); + load(); + } + + /** + * constructor for PEM without password + * + * @param keyStoreFile the path of the keystore file + */ + public KeyTool(final String keyStoreFile) { + this(keyStoreFile, null); + } + + protected abstract PrivateKey getPrivateKey(); + + private static void initSecurity() { + Security.setProperty("crypto.policy", "unlimited"); + Security.addProvider(new BouncyCastleProvider()); + } + + public final String getKeyStoreFile() { + return this.keyStoreFile; + } + + /** + * get keyPair loaded from the keyStore file + * + * @return the keyPair + */ + public KeyPair getKeyPair() { + PrivateKey privateKey = getPrivateKey(); + PublicKey publicKey = getPublicKeyFromPrivateKey(); + return new KeyPair(publicKey, privateKey); + } + + protected abstract PublicKey getPublicKey(); + + 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)); + } + + public String getHexedPublicKey() { + if (!"".equals(hexedPublicKey)) { + return this.hexedPublicKey; + } + this.hexedPublicKey = getHexedPublicKey(getPublicKey()); + return this.hexedPublicKey; + } + + public static String getHexedPrivateKey(PrivateKey privateKey) { + return Numeric.toHexStringNoPrefixZeroPadded(((BCECPrivateKey) privateKey).getD(), 64); + } + + /** + * convert hexed string into PrivateKey type storePublicKeyWithPem + * + * @param hexedPrivateKey the hexed privateKey + * @param curveName the curve name + * @return the converted privateKey + * @throws LoadKeyStoreException convert exception, return exception information + */ + public static PrivateKey convertHexedStringToPrivateKey( + String hexedPrivateKey, String curveName) throws LoadKeyStoreException { + BigInteger privateKeyValue = new BigInteger(hexedPrivateKey, 16); + return convertHexedStringToPrivateKey(privateKeyValue, curveName); + } + + public static PrivateKey convertHexedStringToPrivateKey(BigInteger privateKey, String curveName) + throws LoadKeyStoreException { + try { + Security.setProperty("crypto.policy", "unlimited"); + Security.addProvider(new BouncyCastleProvider()); + org.bouncycastle.jce.spec.ECParameterSpec ecParameterSpec = + ECNamedCurveTable.getParameterSpec(curveName); + ECPrivateKeySpec privateKeySpec = new ECPrivateKeySpec(privateKey, ecParameterSpec); + KeyFactory keyFactory = + KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME); + // get private key + return keyFactory.generatePrivate(privateKeySpec); + } catch (NoSuchProviderException | InvalidKeySpecException | NoSuchAlgorithmException e) { + throw new LoadKeyStoreException( + "covert private key into PrivateKey type failed, " + + " error information: " + + e.getMessage(), + e); + } + } + + public static void storePublicKeyWithPem(PrivateKey privateKey, String privateKeyFilePath) + throws IOException { + String publicKeyPath = privateKeyFilePath + ".pub"; + PemWriter writer = new PemWriter(new FileWriter(publicKeyPath)); + PublicKey publicKey = getPublicKeyFromPrivateKey(privateKey); + writer.writeObject(new PemObject("PUBLIC KEY", publicKey.getEncoded())); + writer.flush(); + writer.close(); + } + + protected abstract void load(InputStream in); + + /** load information from the keyStoreFile */ + protected void load() { + try { + InputStream keyStoreFileInputStream = new FileInputStream(keyStoreFile); + this.load(keyStoreFileInputStream); + } catch (FileNotFoundException | org.bouncycastle.util.encoders.DecoderException e) { + String errorMessage = + "load keys from " + + keyStoreFile + + " failed for FileNotFoundException, error message:" + + e.getMessage(); + logger.error(errorMessage); + throw new LoadKeyStoreException(errorMessage, e); + } + } + + private static Method getMethod( + Class ec5UtilClass, String methodName, Class... parameterTypes) { + try { + return ec5UtilClass.getDeclaredMethod(methodName, parameterTypes); + } catch (NoSuchMethodException e) { + logger.warn("get method for EC5Util failed, method name: {}", methodName); + return null; + } + } + + private static org.bouncycastle.jce.spec.ECParameterSpec convertToECParamSpec( + ECParameterSpec _ecParams) throws LoadKeyStoreException { + try { + Class ec5UtilClass = EC5Util.class; + String methodName = "convertSpec"; + Object ecParamSpec = null; + Object ec5utilObject = ec5UtilClass.newInstance(); + Method methodDeclare = getMethod(ec5UtilClass, methodName, ECParameterSpec.class); + if (methodDeclare != null) { + ecParamSpec = methodDeclare.invoke(ec5utilObject, _ecParams); + + } else { + methodDeclare = + getMethod(ec5UtilClass, methodName, ECParameterSpec.class, boolean.class); + if (methodDeclare != null) { + ecParamSpec = methodDeclare.invoke(ec5utilObject, _ecParams, false); + } + } + if (ecParamSpec != null) { + return (org.bouncycastle.jce.spec.ECParameterSpec) ecParamSpec; + } + logger.error( + "convertToECParamSpec exception for {} not found, supported methodList: {}", + methodName, + (ec5UtilClass.getMethods() != null + ? ec5UtilClass.getMethods().toString() + : " none")); + throw new LoadKeyStoreException( + "convertToECParamSpec exception for " + + methodName + + " not found! Please check the version of bcprov-jdk15on!"); + } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { + logger.error( + "convertToECParamSpec exception, error: {}, e: {}", + e.getMessage(), + e.getStackTrace().toString()); + throw new LoadKeyStoreException("convertToECParamSpec exception for " + e.getMessage()); + } + } + + protected PublicKey getPublicKeyFromPrivateKey() { + return getPublicKeyFromPrivateKey(getPrivateKey()); + } + + public static PublicKey getPublicKeyFromPrivateKey(PrivateKey privateKey) + throws LoadKeyStoreException { + try { + initSecurity(); + ECPrivateKey ecPrivateKey = (ECPrivateKey) privateKey; + ECParameterSpec params = ecPrivateKey.getParams(); + + org.bouncycastle.jce.spec.ECParameterSpec bcSpec = convertToECParamSpec(params); + org.bouncycastle.math.ec.ECPoint q = bcSpec.getG().multiply(ecPrivateKey.getS()); + org.bouncycastle.math.ec.ECPoint bcW = + bcSpec.getCurve().decodePoint(q.getEncoded(false)); + ECPoint w = + new ECPoint( + bcW.getAffineXCoord().toBigInteger(), + bcW.getAffineYCoord().toBigInteger()); + ECPublicKeySpec keySpec = new ECPublicKeySpec(w, tryFindNamedCurveSpec(params)); + return (PublicKey) + KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME) + .generatePublic(keySpec); + } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException e) { + String errorMessage = + "get publicKey from given the private key failed, error message:" + + e.getMessage(); + logger.error(errorMessage); + throw new LoadKeyStoreException(errorMessage, e); + } + } + + @SuppressWarnings("unchecked") + private static ECParameterSpec tryFindNamedCurveSpec(ECParameterSpec params) + throws LoadKeyStoreException { + org.bouncycastle.jce.spec.ECParameterSpec bcSpec = convertToECParamSpec(params); + for (Object name : Collections.list(ECNamedCurveTable.getNames())) { + ECNamedCurveParameterSpec bcNamedSpec = + ECNamedCurveTable.getParameterSpec((String) name); + if (bcNamedSpec.getN().equals(bcSpec.getN()) + && bcNamedSpec.getH().equals(bcSpec.getH()) + && bcNamedSpec.getCurve().equals(bcSpec.getCurve()) + && bcNamedSpec.getG().equals(bcSpec.getG())) { + return new ECNamedCurveSpec( + bcNamedSpec.getName(), + bcNamedSpec.getCurve(), + bcNamedSpec.getG(), + bcNamedSpec.getN(), + bcNamedSpec.getH(), + bcNamedSpec.getSeed()); + } + } + return params; + } +} diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keystore/P12KeyStore.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keystore/P12KeyStore.java new file mode 100644 index 000000000..b4c77aaa0 --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keystore/P12KeyStore.java @@ -0,0 +1,181 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.keystore; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SignatureException; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Calendar; +import org.bouncycastle.jce.X509Principal; +import org.bouncycastle.x509.X509V3CertificateGenerator; +import org.fisco.bcos.sdk.crypto.exceptions.LoadKeyStoreException; +import org.fisco.bcos.sdk.crypto.exceptions.SaveKeyStoreException; + +public class P12KeyStore extends KeyTool { + private static final String NAME = "key"; + private KeyStore keyStore; + + public P12KeyStore(final String keyStoreFile, final String password) { + super(keyStoreFile, password); + } + + @Override + public PublicKey getPublicKey() { + try { + Certificate certificate = keyStore.getCertificate(NAME); + return certificate.getPublicKey(); + } catch (KeyStoreException e) { + throw new LoadKeyStoreException( + "getPublicKey from p12 file " + + keyStoreFile + + " failed, error message: " + + e.getMessage(), + e); + } + } + + /** + * load keyPair from the given input stream + * + * @param in the input stream that should used to load keyPair + */ + protected void load(InputStream in) { + try { + keyStore = KeyStore.getInstance("PKCS12", "BC"); + String password = ""; + if (this.password != null) { + password = this.password; + } + keyStore.load(in, password.toCharArray()); + + } catch (IOException + | CertificateException + | NoSuchAlgorithmException + | NoSuchProviderException + | KeyStoreException e) { + String errorMessage = + "load keys from p12 file " + + keyStoreFile + + " failed, error message:" + + e.getMessage(); + logger.error(errorMessage); + throw new LoadKeyStoreException(errorMessage, e); + } + } + + /** + * get private key from the keyStore + * + * @return the private key + */ + protected PrivateKey getPrivateKey() { + try { + return (PrivateKey) keyStore.getKey(NAME, password.toCharArray()); + } catch (UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException e) { + String errorMessage = + "get private key from " + + keyStoreFile + + " failed for UnrecoverableKeyException, error message" + + e.getMessage(); + logger.error(errorMessage); + throw new LoadKeyStoreException(errorMessage, e); + } + } + + public static void storeKeyPairWithP12Format( + String hexedPrivateKey, + String password, + String privateKeyFilePath, + String curveName, + String signatureAlgorithm) + throws SaveKeyStoreException { + try { + PrivateKey privateKey = convertHexedStringToPrivateKey(hexedPrivateKey, curveName); + // save the private key + KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC"); + // load to init the keyStore + keyStore.load(null, password.toCharArray()); + KeyPair keyPair = new KeyPair(getPublicKeyFromPrivateKey(privateKey), privateKey); + // Since KeyStore setEntry must set the certificate chain, a self-signed certificate is + // generated + Certificate[] certChain = new Certificate[1]; + certChain[0] = generateSelfSignedCertificate(keyPair, signatureAlgorithm); + keyStore.setKeyEntry(NAME, privateKey, password.toCharArray(), certChain); + keyStore.store(new FileOutputStream(privateKeyFilePath), password.toCharArray()); + // store the public key + storePublicKeyWithPem(privateKey, privateKeyFilePath); + } catch (IOException + | KeyStoreException + | NoSuchProviderException + | NoSuchAlgorithmException + | CertificateException + | LoadKeyStoreException + | InvalidKeyException + | SignatureException e) { + throw new SaveKeyStoreException( + "save private key into " + + privateKeyFilePath + + " failed, error information: " + + e.getMessage(), + e); + } + } + + /** + * generate self-signed certificate + * + * @param keyPair the keyPair used to generated the certificate + * @param signatureAlgorithm the signature algorithm of the cert + * @throws NoSuchAlgorithmException no such algorithm exception + * @throws CertificateEncodingException error occurs when encoding certificate + * @throws NoSuchProviderException no such provider exception + * @throws InvalidKeyException invalid key exception + * @throws SignatureException generic signature exception + * @return the generated self-signed certificate object + */ + public static X509Certificate generateSelfSignedCertificate( + KeyPair keyPair, String signatureAlgorithm) + throws NoSuchAlgorithmException, CertificateEncodingException, NoSuchProviderException, + InvalidKeyException, SignatureException { + X509V3CertificateGenerator cert = new X509V3CertificateGenerator(); + cert.setSerialNumber(BigInteger.valueOf(1)); // or generate a random number + cert.setSubjectDN(new X509Principal("CN=localhost")); // see examples to add O,OU etc + cert.setIssuerDN(new X509Principal("CN=localhost")); // same since it is self-signed + cert.setPublicKey(keyPair.getPublic()); + Calendar notBefore = Calendar.getInstance(); + Calendar notAfter = Calendar.getInstance(); + notBefore.add(Calendar.YEAR, 100); + cert.setNotBefore(notBefore.getTime()); + cert.setNotAfter(notAfter.getTime()); + cert.setSignatureAlgorithm(signatureAlgorithm); + cert.setPublicKey(keyPair.getPublic()); + PrivateKey signingKey = keyPair.getPrivate(); + return cert.generate(signingKey, "BC"); + } +} diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keystore/PEMKeyStore.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keystore/PEMKeyStore.java new file mode 100644 index 000000000..b2d475a03 --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/keystore/PEMKeyStore.java @@ -0,0 +1,117 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.keystore; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.io.pem.PemObject; +import org.bouncycastle.util.io.pem.PemReader; +import org.bouncycastle.util.io.pem.PemWriter; +import org.fisco.bcos.sdk.crypto.exceptions.LoadKeyStoreException; +import org.fisco.bcos.sdk.crypto.exceptions.SaveKeyStoreException; + +public class PEMKeyStore extends KeyTool { + public static final String PRIVATE_KEY = "PRIVATE KEY"; + private PemObject pem; + + public PEMKeyStore(final String keyStoreFile) { + super(keyStoreFile); + } + + @Override + protected PublicKey getPublicKey() { + try { + X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(pem.getContent()); + KeyFactory keyFactory = + KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME); + return keyFactory.generatePublic(encodedKeySpec); + } catch (InvalidKeySpecException | NoSuchProviderException | NoSuchAlgorithmException e) { + throw new LoadKeyStoreException( + "getPublicKey from pem file " + + keyStoreFile + + " failed, error message: " + + e.getMessage(), + e); + } + } + + public static void storeKeyPairWithPemFormat( + String hexedPrivateKey, String privateKeyFilePath, String curveName) + throws SaveKeyStoreException { + try { + PrivateKey privateKey = convertHexedStringToPrivateKey(hexedPrivateKey, curveName); + // save the private key + PemWriter writer = new PemWriter(new FileWriter(privateKeyFilePath)); + writer.writeObject(new PemObject(PRIVATE_KEY, privateKey.getEncoded())); + writer.flush(); + writer.close(); + storePublicKeyWithPem(privateKey, privateKeyFilePath); + } catch (IOException | LoadKeyStoreException e) { + throw new SaveKeyStoreException( + "save keys into " + + privateKeyFilePath + + " failed, error information: " + + e.getMessage(), + e); + } + } + + protected void load(InputStream in) { + try { + PemReader pemReader = new PemReader(new InputStreamReader(in)); + pem = pemReader.readPemObject(); + pemReader.close(); + } catch (IOException e) { + String errorMessage = + "load key info from the pem file " + + keyStoreFile + + " failed, error message:" + + e.getMessage(); + logger.error(errorMessage); + throw new LoadKeyStoreException(errorMessage, e); + } + if (pem == null) { + logger.error("The file " + keyStoreFile + " does not represent a pem account."); + throw new LoadKeyStoreException("The file does not represent a pem account."); + } + } + + protected PrivateKey getPrivateKey() { + try { + PKCS8EncodedKeySpec encodedKeySpec = new PKCS8EncodedKeySpec(pem.getContent()); + KeyFactory keyFacotry = + KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME); + return keyFacotry.generatePrivate(encodedKeySpec); + } catch (InvalidKeySpecException | NoSuchProviderException | NoSuchAlgorithmException e) { + String errorMessage = + "getPrivateKey from pem file " + + keyStoreFile + + " failed, error message:" + + e.getMessage(); + logger.error(errorMessage); + throw new LoadKeyStoreException(errorMessage, e); + } + } +} diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/ECDSASignature.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/ECDSASignature.java new file mode 100644 index 000000000..2560fed75 --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/ECDSASignature.java @@ -0,0 +1,63 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.signature; + +import com.webank.wedpr.crypto.CryptoResult; +import com.webank.wedpr.crypto.NativeInterface; +import org.fisco.bcos.sdk.crypto.exceptions.SignatureException; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.utils.Hex; + +public class ECDSASignature implements Signature { + @Override + public SignatureResult sign(final String message, final CryptoKeyPair keyPair) { + // convert signature string to SignatureResult struct + return new ECDSASignatureResult(signWithStringSignature(message, keyPair)); + } + + @Override + public SignatureResult sign(final byte[] message, final CryptoKeyPair keyPair) { + return sign(new String(message), keyPair); + } + + @Override + public String signWithStringSignature(final String message, final CryptoKeyPair keyPair) { + CryptoResult signatureResult = + NativeInterface.secp256k1Sign(keyPair.getHexPrivateKey(), message); + // call secp256k1Sign failed + if (signatureResult.wedprErrorMessage != null + && !signatureResult.wedprErrorMessage.isEmpty()) { + throw new SignatureException( + "Sign with secp256k1 failed:" + signatureResult.wedprErrorMessage); + } + // convert signature string to SignatureResult struct + return signatureResult.signature; + } + + @Override + public boolean verify(final String publicKey, final String message, final String signature) { + CryptoResult verifyResult = NativeInterface.secp256k1verify(publicKey, message, signature); + // call secp256k1verify failed + if (verifyResult.wedprErrorMessage != null && !verifyResult.wedprErrorMessage.isEmpty()) { + throw new SignatureException( + "Verify with secp256k1 failed:" + verifyResult.wedprErrorMessage); + } + return verifyResult.result; + } + + @Override + public boolean verify(final String publicKey, final byte[] message, final byte[] signature) { + return verify(publicKey, Hex.toHexString(message), Hex.toHexString(signature)); + } +} diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/ECDSASignatureResult.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/ECDSASignatureResult.java new file mode 100644 index 000000000..adbf1a0fb --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/ECDSASignatureResult.java @@ -0,0 +1,66 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.signature; + +import java.util.ArrayList; +import java.util.List; +import org.fisco.bcos.sdk.crypto.exceptions.SignatureException; +import org.fisco.bcos.sdk.rlp.RlpString; +import org.fisco.bcos.sdk.rlp.RlpType; +import org.fisco.bcos.sdk.utils.Hex; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ECDSASignatureResult extends SignatureResult { + protected static Logger logger = LoggerFactory.getLogger(SignatureResult.class); + protected byte v; + protected static int VBASE = 27; + + public ECDSASignatureResult(byte v, byte[] r, byte[] s) { + super(r, s); + this.v = v; + } + + public ECDSASignatureResult(final String signatureResult) { + super(signatureResult); + if (this.signatureBytes.length != 65) { + throw new SignatureException( + "Invalid signature for invalid length " + this.signatureBytes.length); + } + this.v = this.signatureBytes[64]; + } + + /** + * covert signatureResult into String + * + * @return the signature string with [r, s, v] + */ + @Override + public String convertToString() { + byte[] SignatureBytes = new byte[65]; + System.arraycopy(this.r, 0, SignatureBytes, 0, 32); + System.arraycopy(this.s, 0, SignatureBytes, 32, 32); + SignatureBytes[64] = this.v; + return Hex.toHexString(SignatureBytes); + } + + @Override + public List encode() { + List encodeResult = new ArrayList<>(); + int encodedV = this.v + VBASE; + encodeResult.add(RlpString.create((byte) encodedV)); + super.encodeCommonField(encodeResult); + return encodeResult; + } +} 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 new file mode 100644 index 000000000..d413527de --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/SM2Signature.java @@ -0,0 +1,61 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.signature; + +import com.webank.wedpr.crypto.CryptoResult; +import com.webank.wedpr.crypto.NativeInterface; +import org.fisco.bcos.sdk.crypto.exceptions.SignatureException; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.utils.Hex; + +public class SM2Signature implements Signature { + @Override + public SignatureResult sign(final String message, final CryptoKeyPair keyPair) { + return new SM2SignatureResult( + keyPair.getHexPublicKey(), signWithStringSignature(message, keyPair)); + } + + @Override + public SignatureResult sign(final byte[] message, final CryptoKeyPair keyPair) { + return sign(new String(message), keyPair); + } + + @Override + public String signWithStringSignature(final String message, final CryptoKeyPair keyPair) { + CryptoResult signatureResult = + NativeInterface.sm2SignWithPub( + keyPair.getHexPrivateKey(), keyPair.getHexPublicKey(), message); + if (signatureResult.wedprErrorMessage != null + && !signatureResult.wedprErrorMessage.isEmpty()) { + throw new SignatureException( + "Sign with sm2 failed:" + signatureResult.wedprErrorMessage); + } + return signatureResult.signature; + } + + @Override + public boolean verify(final String publicKey, final String message, final String signature) { + CryptoResult verifyResult = NativeInterface.sm2verify(publicKey, message, signature); + if (verifyResult.wedprErrorMessage != null && !verifyResult.wedprErrorMessage.isEmpty()) { + throw new SignatureException( + "Verify with sm2 failed:" + verifyResult.wedprErrorMessage); + } + return verifyResult.result; + } + + @Override + public boolean verify(final String publicKey, final byte[] message, final byte[] signature) { + return verify(publicKey, Hex.toHexString(message), Hex.toHexString(signature)); + } +} 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 new file mode 100644 index 000000000..ddedba6b2 --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/SM2SignatureResult.java @@ -0,0 +1,55 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.signature; + +import java.util.ArrayList; +import java.util.List; +import org.fisco.bcos.sdk.rlp.RlpString; +import org.fisco.bcos.sdk.rlp.RlpType; +import org.fisco.bcos.sdk.utils.Hex; + +public class SM2SignatureResult extends SignatureResult { + protected final byte[] pub; + + public SM2SignatureResult(final String hexPublicKey, final String signatureString) { + super(signatureString); + this.pub = Hex.decode(hexPublicKey.substring(2)); + } + + public SM2SignatureResult(byte[] pub, byte[] r, byte[] s) { + super(r, s); + this.pub = pub; + } + + /** + * covert signatureResult into String + * + * @return the signature string with [r, s] + */ + @Override + public String convertToString() { + byte[] SignatureBytes = new byte[64]; + System.arraycopy(this.r, 0, SignatureBytes, 0, 32); + System.arraycopy(this.s, 0, SignatureBytes, 32, 32); + return Hex.toHexString(SignatureBytes); + } + + @Override + public List encode() { + List encodeResult = new ArrayList<>(); + encodeResult.add(RlpString.create(this.pub)); + super.encodeCommonField(encodeResult); + return encodeResult; + } +} diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/Signature.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/Signature.java new file mode 100644 index 000000000..83b1e060e --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/Signature.java @@ -0,0 +1,45 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** interface for sign/verify functions */ +package org.fisco.bcos.sdk.crypto.signature; + +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; + +public interface Signature { + /** + * sign message with the given keyPair + * + * @param message the message to be signed, must be hash value + * @param keyPair the keyPair used to generate the signature + * @return the signature result + */ + SignatureResult sign(final byte[] message, final CryptoKeyPair keyPair); + + SignatureResult sign(final String message, final CryptoKeyPair keyPair); + + String signWithStringSignature(final String message, final CryptoKeyPair keyPair); + + /** + * verify signature + * + * @param publicKey the publickey + * @param message the message, must be hash value + * @param signature the signature to be verified + * @return true/false + */ + boolean verify(final String publicKey, final String message, final String signature); + + boolean verify(final String publicKey, final byte[] message, final byte[] signature); +} diff --git a/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/SignatureResult.java b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/SignatureResult.java new file mode 100644 index 000000000..74a65d2d9 --- /dev/null +++ b/sdk-crypto/src/main/java/org/fisco/bcos/sdk/crypto/signature/SignatureResult.java @@ -0,0 +1,85 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.signature; + +import java.util.List; +import org.fisco.bcos.sdk.crypto.exceptions.SignatureException; +import org.fisco.bcos.sdk.rlp.RlpString; +import org.fisco.bcos.sdk.rlp.RlpType; +import org.fisco.bcos.sdk.utils.ByteUtils; +import org.fisco.bcos.sdk.utils.Hex; + +public abstract class SignatureResult { + protected final byte[] r; + protected final byte[] s; + protected byte[] signatureBytes; + + SignatureResult(final byte[] r, final byte[] s) { + this.r = r; + this.s = s; + } + + /** + * Recover v, r, s from signature string The first 32 bytes are r, and the 32 bytes after r are + * s + * + * @param signatureString the signatureString + */ + SignatureResult(final String signatureString) { + this.signatureBytes = Hex.decode(signatureString); + // at least 64 bytes + if (this.signatureBytes.length < 64) { + throw new SignatureException( + "Invalid signature: " + + signatureString + + ", signatureString len: " + + signatureString.length() + + ", signatureBytes size:" + + signatureBytes.length); + } + // get R + this.r = new byte[32]; + System.arraycopy(this.signatureBytes, 0, this.r, 0, 32); + // get S + this.s = new byte[32]; + System.arraycopy(this.signatureBytes, 32, this.s, 0, 32); + } + + public byte[] getR() { + return r; + } + + public byte[] getS() { + return s; + } + + protected void encodeCommonField(List encodeResult) { + encodeResult.add(RlpString.create(ByteUtils.trimLeadingZeroes(this.getR()))); + encodeResult.add(RlpString.create(ByteUtils.trimLeadingZeroes(this.getS()))); + } + + /** + * covert signatureResult into String + * + * @return signatureResult in string form can be used as a verify parameter + */ + public abstract String convertToString(); + + /** + * encode the signatureResult into rlp-list + * + * @return the encoded rlp-list with r, s, v( or pub) + */ + public abstract List encode(); +} diff --git a/sdk-crypto/src/test/java/org/fisco/bcos/sdk/crypto/HashTest.java b/sdk-crypto/src/test/java/org/fisco/bcos/sdk/crypto/HashTest.java new file mode 100644 index 000000000..664410890 --- /dev/null +++ b/sdk-crypto/src/test/java/org/fisco/bcos/sdk/crypto/HashTest.java @@ -0,0 +1,136 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto; + +import org.fisco.bcos.sdk.crypto.exceptions.UnsupportedCryptoTypeException; +import org.fisco.bcos.sdk.crypto.hash.Hash; +import org.fisco.bcos.sdk.crypto.hash.Keccak256; +import org.fisco.bcos.sdk.crypto.hash.SM3Hash; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.utils.Hex; +import org.junit.Assert; +import org.junit.Test; + +public class HashTest { + @Test + public void testCryptoSuiteForSMHash() { + CryptoSuite cryptoSuite = new CryptoSuite(CryptoType.SM_TYPE); + // check sm3 hash for "abcde" + checkHashWithCryptoSuite( + cryptoSuite, + "abcde", + "afe4ccac5ab7d52bcae36373676215368baf52d3905e1fecbe369cc120e97628"); + + // check sm3 hash for "hello" + checkHashWithCryptoSuite( + cryptoSuite, + "hello", + "becbbfaae6548b8bf0cfcad5a27183cd1be6093b1cceccc303d9c61d0a645268"); + + // check sm3 hash for empty string + checkHashWithCryptoSuite( + cryptoSuite, + "", + "1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b"); + } + + @Test + public void testCryptoSuiteForKeccak256Hash() { + CryptoSuite cryptoSuite = new CryptoSuite(CryptoType.ECDSA_TYPE); + // check keccak256 for "abcde" + checkHashWithCryptoSuite( + cryptoSuite, + "abcde", + "6377c7e66081cb65e473c1b95db5195a27d04a7108b468890224bedbe1a8a6eb"); + + // check keccak256 for "hello" + checkHashWithCryptoSuite( + cryptoSuite, + "hello", + "1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"); + + // check keccak256 for empty string + checkHashWithCryptoSuite( + cryptoSuite, + "", + "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); + } + + @Test(expected = UnsupportedCryptoTypeException.class) + public void testUnsupportedCryptoType() { + new CryptoSuite(3); + } + + @Test + public void testKeccak256() { + Hash hasher = new Keccak256(); + testKeccak256(hasher); + } + + @Test + public void testSM3() { + Hash sm3Hasher = new SM3Hash(); + testSM3(sm3Hasher); + } + + private void testKeccak256(Hash hasher) { + + // check keccak256 for "abcde" + checkHash( + hasher, + "abcde", + "6377c7e66081cb65e473c1b95db5195a27d04a7108b468890224bedbe1a8a6eb"); + + // check keccak256 for "hello" + checkHash( + hasher, + "hello", + "1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"); + + // check keccak256 for empty string + checkHash(hasher, "", "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); + } + + private void testSM3(Hash hasher) { + // check sm3 hash for "abcde" + checkHash( + hasher, + "abcde", + "afe4ccac5ab7d52bcae36373676215368baf52d3905e1fecbe369cc120e97628"); + + // check sm3 hash for "hello" + checkHash( + hasher, + "hello", + "becbbfaae6548b8bf0cfcad5a27183cd1be6093b1cceccc303d9c61d0a645268"); + + // check sm3 hash for empty string + checkHash(hasher, "", "1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b"); + } + + private void checkHash(Hash hasher, String message, String expectedHash) { + String calculatedHash = hasher.hash(message); + Assert.assertEquals(true, calculatedHash.equals(expectedHash)); + byte[] calculatedHashBytes = hasher.hash(message.getBytes()); + Assert.assertEquals(true, Hex.toHexString(calculatedHashBytes).equals(expectedHash)); + } + + private void checkHashWithCryptoSuite( + CryptoSuite cryptoSuite, String message, String expectedHash) { + String calculatedHash = cryptoSuite.hash(message); + Assert.assertEquals(true, calculatedHash.equals(expectedHash)); + byte[] calculatedHashBytes = cryptoSuite.hash(message.getBytes()); + Assert.assertEquals(true, Hex.toHexString(calculatedHashBytes).equals(expectedHash)); + } +} 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 new file mode 100644 index 000000000..404fe67b5 --- /dev/null +++ b/sdk-crypto/src/test/java/org/fisco/bcos/sdk/crypto/KeyToolTest.java @@ -0,0 +1,180 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto; + +import java.security.KeyPair; + +import org.fisco.bcos.sdk.crypto.exceptions.LoadKeyStoreException; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.crypto.keystore.KeyTool; +import org.fisco.bcos.sdk.crypto.keystore.P12KeyStore; +import org.fisco.bcos.sdk.crypto.keystore.PEMKeyStore; +import org.fisco.bcos.sdk.model.CryptoType; +import org.junit.Assert; +import org.junit.Test; + +public class KeyToolTest { + @Test + public void testECDSALoadPEMFile() { + String keyStoreFile = "keystore/ecdsa/0x0fc3c4bb89bd90299db4c62be0174c4966286c00.pem"; + CryptoKeyPair cryptoKeyPair = + testLoadPEMFile( + keyStoreFile, + CryptoType.ECDSA_TYPE, + "0x0fc3c4bb89bd90299db4c62be0174c4966286c00"); + // check the public key and the privateKey + // Note the 04 prefix + Assert.assertEquals( + "04dbbfee4f76f5a3bc3dbc2e6127c4a1f50b7614bff4138a44a79aed3d42f67f9c7aa70570205f9b60a5888c6415b6a830012677b4415a79ccd1533fe5637861df", + cryptoKeyPair.getHexPublicKey()); + Assert.assertEquals( + "bc516b2600eec3a216f457dc14cf83a01ed22d0fc2149fc911dc2ec486fe57a3", + cryptoKeyPair.getHexPrivateKey()); + } + + @Test + public void testSMLoadPEMFile() { + String keyStoreFile = "keystore/gm/0x40b3558746e8f9a47a474774e8c4a9e67d4e3174.pem"; + CryptoKeyPair cryptoKeyPair = + testLoadPEMFile( + keyStoreFile, + CryptoType.SM_TYPE, + "0x40b3558746e8f9a47a474774e8c4a9e67d4e3174"); + Assert.assertEquals( + "043b72cd28244c856d3d89b67d1c5ff22e1f26835bafcd63e9a4ad3424a2a57f2b759149f46c696df08b9d9473686675fc6dade744d0c82bdc5598d759e015fd96", + cryptoKeyPair.getHexPublicKey()); + Assert.assertEquals( + "901744c34e2adffc9fd7fb12e8cba2d88a79aaf54be9b4e11660153287489f13", + cryptoKeyPair.getHexPrivateKey()); + } + + @Test(expected = LoadKeyStoreException.class) + public void testECDSALoadInvalidPEMFile() { + String keyStoreFile = "keystore/ecdsa/invalid.pem"; + testLoadPEMFile( + keyStoreFile, CryptoType.ECDSA_TYPE, "0x0fc3c4bb89bd90299db4c62be0174c4966286c00"); + } + + @Test(expected = LoadKeyStoreException.class) + public void testSMLoadInvalidPEMFile() { + String keyStoreFile = "keystore/gm/invalid.pem"; + testLoadPEMFile( + keyStoreFile, CryptoType.SM_TYPE, "0x40b3558746e8f9a47a474774e8c4a9e67d4e3174"); + } + + @Test + public void testLoadECDSAP12File() { + String keyStoreFile = "keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.p12"; + CryptoKeyPair cryptoKeyPair = + testLoadP12File( + keyStoreFile, + CryptoType.ECDSA_TYPE, + "123456", + "0x45e14c53197adbcb719d915fb93342c25600faaf"); + Assert.assertEquals( + "04d7b9e00f56d3f79305359fa2d7db166021e73086bdcd2e7a28d6ed27345e1f2ddecf85db7438e8457fd474ef9c4ceb89abb7d5fa60a22f2902ec26dca52ad5e5", + cryptoKeyPair.getHexPublicKey()); + Assert.assertEquals( + "c0c8b4d96aa4aefaeeafa157789d528b6010f65059dee796d8757e1171bbcd2c", + cryptoKeyPair.getHexPrivateKey()); + } + + @Test + public void testLoadSMP12File() { + String keyStoreFile = "keystore/gm/0x6f68461309925093236df82b51df630a55d32377.p12"; + CryptoKeyPair cryptoKeyPair = + testLoadP12File( + keyStoreFile, + CryptoType.SM_TYPE, + "abcd123", + "0x6f68461309925093236df82b51df630a55d32377"); + Assert.assertEquals( + "04a809a0176dc24432490697b6ed74995a6716a122a0fa5c73429a259cd73f14995934522288f226a049bbbb803d78f296289bee8fb4f5d7821514e731a57c9f2f", + cryptoKeyPair.getHexPublicKey()); + Assert.assertEquals( + "d0cbcdfea24e206688ce6c1a63171a24d9e1e0cf5331151ed5406e07fdb38256", + cryptoKeyPair.getHexPrivateKey()); + } + + @Test(expected = LoadKeyStoreException.class) + public void testInvalidECDSAP12Case() { + // error password + String keyStoreFile = "keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.p12"; + testLoadP12File( + keyStoreFile, + CryptoType.ECDSA_TYPE, + "13456", + "0x45e14c53197adbcb719d915fb93342c25600faaf"); + } + + @Test(expected = LoadKeyStoreException.class) + public void testInvalidSMP12Case() { + String keyStoreFile = "keystore/gm/0x6f68461309925093236df82b51df630a55d32377.p12"; + testLoadP12File( + keyStoreFile, + CryptoType.SM_TYPE, + "abcd12e", + "0x6f68461309925093236df82b51df630a55d32377"); + } + + @Test(expected = LoadKeyStoreException.class) + public void testInvalidP12FileForECDSA() { + String keyStoreFile = "keystore/ecdsa/invalid.p12"; + testLoadP12File( + keyStoreFile, + CryptoType.ECDSA_TYPE, + "abcd123", + "0x6f68461309925093236df82b51df630a55d32377"); + } + + @Test(expected = LoadKeyStoreException.class) + public void testInvalidP12FileForSM() { + String keyStoreFile = "keystore/gm/invalid.p12"; + testLoadP12File( + keyStoreFile, + CryptoType.SM_TYPE, + "123456", + "0x45e14c53197adbcb719d915fb93342c25600faaf"); + } + + private String getFilePath(String fileName) { + return getClass().getClassLoader().getResource(fileName).getPath(); + } + + private CryptoKeyPair testLoadPEMFile( + String pemFileName, int cryptoType, String expectedAccount) { + // get KeyPair from the pem + KeyTool pem = new PEMKeyStore(getFilePath(pemFileName)); + KeyPair keyPair = pem.getKeyPair(); + return testSignature(keyPair, cryptoType, expectedAccount); + } + + private CryptoKeyPair testLoadP12File( + String p12FileName, int cryptoType, String password, String expectedAccount) { + KeyTool p12 = new P12KeyStore(getFilePath(p12FileName), password); + KeyPair keyPair = p12.getKeyPair(); + return testSignature(keyPair, cryptoType, expectedAccount); + } + + private CryptoKeyPair testSignature(KeyPair keyPair, int cryptoType, String expectedAccount) { + CryptoSuite cryptoSuite = new CryptoSuite(cryptoType); + CryptoKeyPair cryptoKeyPair = cryptoSuite.createKeyPair(keyPair); + // check account + Assert.assertEquals(expectedAccount, cryptoKeyPair.getAddress()); + // test signature + SignatureTest signatureTest = new SignatureTest(); + signatureTest.testSignature(cryptoSuite, cryptoKeyPair); + return cryptoKeyPair; + } +} 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 new file mode 100644 index 000000000..55ba16734 --- /dev/null +++ b/sdk-crypto/src/test/java/org/fisco/bcos/sdk/crypto/SignatureTest.java @@ -0,0 +1,449 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto; + +import java.io.File; +import java.math.BigInteger; +import org.fisco.bcos.sdk.config.Config; +import org.fisco.bcos.sdk.config.ConfigOption; +import org.fisco.bcos.sdk.config.exceptions.ConfigException; +import org.fisco.bcos.sdk.crypto.exceptions.KeyPairException; +import org.fisco.bcos.sdk.crypto.hash.Hash; +import org.fisco.bcos.sdk.crypto.hash.Keccak256; +import org.fisco.bcos.sdk.crypto.hash.SM3Hash; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.crypto.keypair.ECDSAKeyPair; +import org.fisco.bcos.sdk.crypto.keypair.SM2KeyPair; +import org.fisco.bcos.sdk.crypto.keystore.KeyTool; +import org.fisco.bcos.sdk.crypto.keystore.P12KeyStore; +import org.fisco.bcos.sdk.crypto.keystore.PEMKeyStore; +import org.fisco.bcos.sdk.crypto.signature.ECDSASignature; +import org.fisco.bcos.sdk.crypto.signature.SM2Signature; +import org.fisco.bcos.sdk.crypto.signature.Signature; +import org.fisco.bcos.sdk.crypto.signature.SignatureResult; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.utils.Hex; +import org.junit.Assert; +import org.junit.Test; + +public class SignatureTest { + private static final String configFile = + SignatureTest.class + .getClassLoader() + .getResource("config-example.toml") + .getPath(); + + @Test + public void testCryptoSuiteForECDSA() { + CryptoSuite cryptoSuite = new CryptoSuite(CryptoType.ECDSA_TYPE); + // generate keyPair + CryptoKeyPair keyPair = cryptoSuite.createKeyPair(); + // test signature + testSignature(cryptoSuite, keyPair); + + // load KeyPair from the given privateKey + String privateKeyStr = + "47300381232944006945664493109832654111051142806262820216166278362539860431476"; + String publicKeyStr = + "2179819159336280954262570523402774481036769289289277534998346117714415641803934346338726829054711133487295949018624582253372411779380507548447040213240521"; + String hexedPublicKey = new BigInteger(publicKeyStr).toString(16); + BigInteger privateKey = new BigInteger(privateKeyStr); + keyPair = cryptoSuite.getKeyPairFactory().createKeyPair(privateKey); + // check publicKey + System.out.println("hexedPublicKey: " + hexedPublicKey); + System.out.println("keyPair.getHexPublicKey(): " + keyPair.getHexPublicKey()); + Assert.assertEquals(hexedPublicKey, keyPair.getHexPublicKey().substring(2)); + testSignature(cryptoSuite, keyPair); + + String hexedPrivateKeyStr = "bcec428d5205abe0f0cc8a734083908d9eb8563e31f943d760786edf42ad67dd"; + keyPair = cryptoSuite.getKeyPairFactory().createKeyPair(hexedPrivateKeyStr); + testSignature(cryptoSuite, keyPair); + } + + @Test + public void testCryptoSuiteForSM2() { + CryptoSuite cryptoSuite = new CryptoSuite(CryptoType.SM_TYPE); + // generate keyPair + CryptoKeyPair keyPair = cryptoSuite.createKeyPair(); + // test signature + testSignature(cryptoSuite, keyPair); + } + + @Test + public void testECDSASignature() { + Signature ecdsaSignature = new ECDSASignature(); + CryptoKeyPair keyPair = (new ECDSAKeyPair()).generateKeyPair(); + Hash hasher = new Keccak256(); + testSignature(hasher, ecdsaSignature, keyPair); + } + + @Test + public void testSM2Signature() { + Signature sm2Signature = new SM2Signature(); + CryptoKeyPair keyPair = (new SM2KeyPair()).generateKeyPair(); + Hash hasher = new SM3Hash(); + testSignature(hasher, sm2Signature, keyPair); + } + + @Test + public void testValidGetAddressForECDSA() { + CryptoKeyPair keyPair = (new ECDSAKeyPair()).generateKeyPair(); + String hexPublicKey = + "77a8f8d2f786f079bd661e774da3a9f430c76b9acbcd71f9976bff7456bb136a80cb97335cc929a531791970f8ce10c0ca6ffb391e9ef241a48cbd8f3db1a82e"; + String expectedHash = "0xdeaa5343178c2be2cb5e9b13000ed951e302c15d"; + + String hexPublicKey2 = "00000"; + String expectedHash2 = "0x3f17f1962b36e491b30a40b2405849e597ba5fb5"; + testValidGetAddressForKeyPair( + keyPair, hexPublicKey, expectedHash, hexPublicKey2, expectedHash2); + + // create keyPair with cryptoSuite + CryptoSuite cryptoSuite = new CryptoSuite(CryptoType.ECDSA_TYPE); + keyPair = cryptoSuite.createKeyPair(); + testValidGetAddressForKeyPair( + keyPair, hexPublicKey, expectedHash, hexPublicKey2, expectedHash2); + + // test getAddress with generated KeyPair + keyPair.getAddress(); + } + + @Test + public void testValidGetAddressForSM() { + CryptoKeyPair keyPair = (new SM2KeyPair()).generateKeyPair(); + String hexPublicKey = + "77a8f8d2f786f079bd661e774da3a9f430c76b9acbcd71f9976bff7456bb136a80cb97335cc929a531791970f8ce10c0ca6ffb391e9ef241a48cbd8f3db1a82e"; + String expectedHash = "0x4b99a949a24f3dc8dc54b02d51ec0ae4c8bb7018"; + + String hexPublicKey2 = "00000"; + String expectedHash2 = "0x0ec7f82b659cc8c6b753f26d4e9ec85bc91c231e"; + testValidGetAddressForKeyPair( + keyPair, hexPublicKey, expectedHash, hexPublicKey2, expectedHash2); + + // create keyPair with cryptoSuite + CryptoSuite cryptoSuite = new CryptoSuite(CryptoType.SM_TYPE); + keyPair = cryptoSuite.createKeyPair(); + testValidGetAddressForKeyPair( + keyPair, hexPublicKey, expectedHash, hexPublicKey2, expectedHash2); + + // test getAddress with generated keyPair + keyPair.getAddress(); + } + + private void testValidGetAddressForKeyPair( + CryptoKeyPair keyPair, + String hexPublicKey, + String expectedHash, + String hexPublicKey2, + String expectedHash2) { + // case1: input public key is hexed string, without 0x prefix + testKeyPair(keyPair, hexPublicKey, expectedHash); + + // case2: input public key is bytes, without 0x prefix + byte[] publicKeyBytes = Hex.decode(hexPublicKey); + testKeyPair(keyPair, publicKeyBytes, expectedHash); + + // case3: input public key is hexed string, with 0x prefix + String hexPublicKeyWithPrefix = "0x" + hexPublicKey; + testKeyPair(keyPair, hexPublicKeyWithPrefix, expectedHash); + + // case4: input public key is bytes, with 0x prefix + publicKeyBytes = Hex.decode(hexPublicKey); + testKeyPair(keyPair, publicKeyBytes, expectedHash); + + // case5: input public key is bigInteger + BigInteger publicKeyValue = new BigInteger(hexPublicKey, 16); + testKeyPair(keyPair, publicKeyValue, expectedHash); + + // case6: input is 0 + testKeyPair(keyPair, hexPublicKey2, expectedHash2); + testKeyPair(keyPair, hexPublicKey2 + "00000", expectedHash2); + testKeyPair(keyPair, new BigInteger("0", 16), expectedHash2); + } + + private void testKeyPair(CryptoKeyPair keyPair, String publicKey, String expectedAddress) { + Assert.assertEquals(expectedAddress, keyPair.getAddress(publicKey)); + } + + private void testKeyPair(CryptoKeyPair keyPair, BigInteger publicKey, String expectedAddress) { + Assert.assertEquals(expectedAddress, "0x" + Hex.toHexString(keyPair.getAddress(publicKey))); + } + + private void testKeyPair(CryptoKeyPair keyPair, byte[] publicKey, String expectedAddress) { + Assert.assertEquals(expectedAddress, "0x" + Hex.toHexString(keyPair.getAddress(publicKey))); + } + + @Test(expected = KeyPairException.class) + public void testInvalidCaseForSM2KeyPair() { + CryptoKeyPair keyPair = (new SM2KeyPair()).generateKeyPair(); + testInvalidPublicKey(keyPair); + } + + @Test(expected = KeyPairException.class) + public void testInvalidCaseForECDSAKeyPair() { + CryptoKeyPair keyPair = (new ECDSAKeyPair()).generateKeyPair(); + testInvalidPublicKey(keyPair); + } + + @Test(expected = KeyPairException.class) + public void testInvalidCaseForECDSACryptoSuite() { + CryptoSuite cryptoSuite = new CryptoSuite(CryptoType.ECDSA_TYPE); + CryptoKeyPair keyPair = cryptoSuite.createKeyPair(); + testInvalidPublicKey(keyPair); + } + + @Test(expected = KeyPairException.class) + public void testInvalidCaseForSM2CryptoSuite() { + CryptoSuite cryptoSuite = new CryptoSuite(CryptoType.SM_TYPE); + CryptoKeyPair keyPair = cryptoSuite.createKeyPair(); + testInvalidPublicKey(keyPair); + } + + private void testInvalidPublicKey(CryptoKeyPair keyPair) { + // input is invalid hex string + keyPair.getAddress("123xyz"); + } + + public void testSignature(Hash hasher, Signature signature, CryptoKeyPair keyPair) { + String message = "abcde"; + + // check valid case + for (int i = 0; i < 10; i++) { + message = hasher.hash("abcd----" + Integer.toString(i)); + // sign + SignatureResult signResult = signature.sign(message, keyPair); + // verify + Assert.assertTrue( + signature.verify( + keyPair.getHexPublicKey(), message, signResult.convertToString())); + signResult = signature.sign(message.getBytes(), keyPair); + Assert.assertTrue( + signature.verify( + keyPair.getHexPublicKey(), message, signResult.convertToString())); + } + + // check invalid case + for (int i = 0; i < 10; i++) { + message = hasher.hash("abcd----" + Integer.toString(i)); + String invaidMessage = hasher.hash("abcd---" + Integer.toString(i + 1)); + // sign + SignatureResult signResult = signature.sign(message, keyPair); + // verify + Assert.assertEquals( + false, + signature.verify( + keyPair.getHexPublicKey(), + invaidMessage, + signResult.convertToString())); + signResult = signature.sign(message.getBytes(), keyPair); + Assert.assertEquals( + false, + signature.verify( + keyPair.getHexPublicKey(), + invaidMessage, + signResult.convertToString())); + } + } + + public void testSignature(CryptoSuite signature, CryptoKeyPair keyPair) { + String message = "abcde"; + // check valid case + for (int i = 0; i < 10; i++) { + // Note: the message must be hash + message = signature.hash("abcd----" + Integer.toString(i)); + // sign + SignatureResult signResult = signature.sign(message, keyPair); + // verify + Assert.assertTrue( + signature.verify( + keyPair.getHexPublicKey(), message, signResult.convertToString())); + signResult = signature.sign(message.getBytes(), keyPair); + Assert.assertTrue( + signature.verify( + keyPair.getHexPublicKey(), message, signResult.convertToString())); + } + + // check invalid case + for (int i = 0; i < 10; i++) { + message = signature.hash("abcd----" + Integer.toString(i)); + String invaidMessage = signature.hash("abcd---" + Integer.toString(i + 1)); + // sign + SignatureResult signResult = signature.sign(message, keyPair); + // verify + Assert.assertEquals( + false, + signature.verify( + keyPair.getHexPublicKey(), + invaidMessage, + signResult.convertToString())); + signResult = signature.sign(message.getBytes(), keyPair); + Assert.assertEquals( + false, + signature.verify( + keyPair.getHexPublicKey(), + invaidMessage, + signResult.convertToString())); + } + } + + @Test + public void testSignAndVerifyWithKeyManager() { + String publicKeyPem = + "keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.public.pem"; + KeyTool verifykeyTool = + new PEMKeyStore(getClass().getClassLoader().getResource(publicKeyPem).getPath()); + + String keyPairPem = "keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.p12"; + KeyTool signKeyTool = + new P12KeyStore( + getClass().getClassLoader().getResource(keyPairPem).getPath(), "123456"); + CryptoSuite cryptoSuite = new CryptoSuite(CryptoType.ECDSA_TYPE); + // sign and verify message with keyManager + for (int i = 0; i < 10; i++) { + String message = cryptoSuite.hash("abcd----" + Integer.toString(i)); + String signature = cryptoSuite.sign(signKeyTool, message); + Assert.assertTrue(cryptoSuite.verify(verifykeyTool, message, signature)); + String invalidMessage = cryptoSuite.hash("abcde----" + Integer.toString(i)); + Assert.assertTrue(!cryptoSuite.verify(verifykeyTool, invalidMessage, signature)); + } + } + + public String getKeyStoreFilePath( + CryptoSuite cryptoSuite, ConfigOption configOption, String postFix) { + return configOption.getAccountConfig().getKeyStoreDir() + + File.separator + + cryptoSuite.getCryptoKeyPair().getKeyStoreSubDir() + + File.separator + + cryptoSuite.getCryptoKeyPair().getAddress() + + postFix; + } + + @Test + public void testSMLoadAndStoreKeyPairWithPEM() throws ConfigException { + testLoadAndStoreKeyPairWithPEM(CryptoType.SM_TYPE); + } + + @Test + public void testECDSALoadAndStoreKeyPairWithPEM() throws ConfigException { + testLoadAndStoreKeyPairWithPEM(CryptoType.ECDSA_TYPE); + } + + @Test + public void testSMLoadAndStoreKeyPairWithP12() throws ConfigException { + testLoadAndStoreKeyPairWithP12(CryptoType.SM_TYPE); + } + + @Test + public void testECDSALoadAndStoreKeyPairWithP12() throws ConfigException { + testLoadAndStoreKeyPairWithP12(CryptoType.ECDSA_TYPE); + } + + public void testLoadAndStoreKeyPairWithPEM(int cryptoType) throws ConfigException { + ConfigOption configOption = Config.load(configFile, CryptoType.ECDSA_TYPE); + CryptoSuite cryptoSuite = new CryptoSuite(cryptoType); + cryptoSuite.getCryptoKeyPair().setConfig(configOption); + cryptoSuite.getCryptoKeyPair().storeKeyPairWithPemFormat(); + CryptoKeyPair orgKeyPair = cryptoSuite.getCryptoKeyPair(); + + // get pem file path + String pemFilePath = + getKeyStoreFilePath(cryptoSuite, configOption, CryptoKeyPair.PEM_FILE_POSTFIX); + // load pem file + KeyTool pemManager = new PEMKeyStore(pemFilePath); + CryptoKeyPair decodedCryptoKeyPair = cryptoSuite.createKeyPair(pemManager.getKeyPair()); + + System.out.println("PEM orgKeyPair pub: " + orgKeyPair.getHexPublicKey()); + System.out.println("PEM decodedKeyPair pub: " + decodedCryptoKeyPair.getHexPublicKey()); + + System.out.println("PEM orgKeyPair pri: " + orgKeyPair.getHexPrivateKey()); + System.out.println("PEM decodedKeyPair pr: " + decodedCryptoKeyPair.getHexPrivateKey()); + + // test sign and verify message with + String publicPemPath = pemFilePath + ".pub"; + KeyTool verifyKeyTool = new PEMKeyStore(publicPemPath); + + checkSignAndVerifyWithKeyManager( + pemManager, decodedCryptoKeyPair, verifyKeyTool, cryptoSuite); + } + + public void testLoadAndStoreKeyPairWithP12(int cryptoType) throws ConfigException { + ConfigOption configOption = Config.load(configFile, CryptoType.ECDSA_TYPE); + CryptoSuite cryptoSuite = new CryptoSuite(cryptoType); + cryptoSuite.getCryptoKeyPair().setConfig(configOption); + String password = "123"; + cryptoSuite.getCryptoKeyPair().storeKeyPairWithP12Format(password); + CryptoKeyPair orgKeyPair = cryptoSuite.getCryptoKeyPair(); + + // get p12 file path + String p12FilePath = + getKeyStoreFilePath(cryptoSuite, configOption, CryptoKeyPair.P12_FILE_POSTFIX); + // load p12 file + KeyTool p12Manager = new P12KeyStore(p12FilePath, password); + CryptoKeyPair decodedCryptoKeyPair = cryptoSuite.createKeyPair(p12Manager.getKeyPair()); + // check the keyPair + System.out.println("P12 orgKeyPair pub: " + orgKeyPair.getHexPublicKey()); + System.out.println("P12 decodedKeyPair pub: " + decodedCryptoKeyPair.getHexPublicKey()); + + 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())); + + // test sign and verify message with + String publicP12Path = p12FilePath + ".pub"; + KeyTool verifyKeyTool = new PEMKeyStore(publicP12Path); + checkSignAndVerifyWithKeyManager( + p12Manager, decodedCryptoKeyPair, verifyKeyTool, cryptoSuite); + } + + private void checkSignAndVerifyWithKeyManager( + KeyTool pemManager, + CryptoKeyPair cryptoKeyPair, + KeyTool verifyKeyTool, + CryptoSuite cryptoSuite) { + // sign and verify message with cryptoKeyPair + for (int i = 0; i < 10; i++) { + String message = cryptoSuite.hash("abcd----" + Integer.toString(i)); + SignatureResult signature = cryptoSuite.sign(message, cryptoKeyPair); + Assert.assertTrue( + cryptoSuite.verify( + cryptoKeyPair.getHexPublicKey(), message, signature.convertToString())); + + Assert.assertTrue( + cryptoSuite.verify( + cryptoKeyPair.getHexPublicKey(), + Hex.decode(message), + Hex.decode(signature.convertToString()))); + + String invalidMessage = cryptoSuite.hash("abcde----" + Integer.toString(i)); + Assert.assertTrue( + !cryptoSuite.verify( + cryptoKeyPair.getHexPublicKey(), + invalidMessage, + signature.convertToString())); + } + for (int i = 0; i < 10; i++) { + String message = cryptoSuite.hash("abcd----" + Integer.toString(i)); + String signature = cryptoSuite.sign(pemManager, message); + Assert.assertTrue(cryptoSuite.verify(verifyKeyTool, message, signature)); + Assert.assertTrue( + cryptoSuite.verify( + verifyKeyTool, Hex.decode(message), Hex.decode(signature))); + String invalidMessage = cryptoSuite.hash("abcde----" + Integer.toString(i)); + Assert.assertTrue(!cryptoSuite.verify(verifyKeyTool, invalidMessage, signature)); + } + } +} diff --git a/sdk-crypto/src/test/resources/amop/config-publisher-for-test.toml b/sdk-crypto/src/test/resources/amop/config-publisher-for-test.toml new file mode 100644 index 000000000..ceb34741a --- /dev/null +++ b/sdk-crypto/src/test/resources/amop/config-publisher-for-test.toml @@ -0,0 +1,44 @@ +# This is a config file for amop test + +[cryptoMaterial] +certPath = "conf" +# CA cert file path +# caCert = "conf/ca.crt" +# SSL cert file path +# sslCert = "conf/sdk.crt" +# SSL key file path +# sslKey = "conf/sdk.key" +# enSslCert = "conf/gm/gmensdk.crt" +# enSslKey = "conf/gm/gmensdk.key" + +[network] +# The peer list to connect +peers=["127.0.0.1:20200", "127.0.0.1:20201"] + +# Configure a "need verify AMOP topic" as a topic message sender. +[[amop]] +topicName = "privTopic" +# Public keys of the nodes that you want to send AMOP message of this topic to. +publicKeys = [ "conf/amop/consumer_public_key_1.pem"] + + +[account] +# The directory where the account private key file is placed in +keyStoreDir = "account" +# The account file path(Default load account from keyStoreDir directory when accountFilePath is not configured) +# accountFilePath = "" +# The storage format of the account, support pem and p12, default is pem +accountFileFormat = "pem" +# The address of the account used to send transactions +# When it's empty, use a randomly generated account to send transactions, +# and the randomly generated account information is stored in tmp sub-directory of keyStoreDir +# accountAddress = "" +# The password used to load the account private key file +# password = "" + +[threadPool] +# The size of the thread pool used to process the callback of the channel +channelProcessorThreadSize = "16" +# The size of the thread pool used to process the transaction receipt notification +receiptProcessorThreadSize = "16" + diff --git a/sdk-crypto/src/test/resources/amop/config-subscriber-for-test.toml b/sdk-crypto/src/test/resources/amop/config-subscriber-for-test.toml new file mode 100644 index 000000000..1ffd63fdd --- /dev/null +++ b/sdk-crypto/src/test/resources/amop/config-subscriber-for-test.toml @@ -0,0 +1,46 @@ +# This is a config file for amop test + +[cryptoMaterial] +certPath = "conf" +# CA cert file path +# caCert = "conf/ca.crt" +# SSL cert file path +# sslCert = "conf/sdk.crt" +# SSL key file path +# sslKey = "conf/sdk.key" +# enSslCert = "conf/gm/gmensdk.crt" +# enSslKey = "conf/gm/gmensdk.key" + +[network] +# The peer list to connect +peers=["127.0.0.1:20202", "127.0.0.1:20203"] + +# Configure a private topic as a topic message sender. +[[amop]] +topicName = "privTopic" +# Your private key that used to subscriber verification. +privateKey = "conf/amop/consumer_private_key.p12" +password = "123456" + + +[account] +# The directory where the account private key file is placed in +keyStoreDir = "account" +# The account file path(Default load account from keyStoreDir directory when accountFilePath is not configured) +# accountFilePath = "" +# The storage format of the account, support pem and p12, default is pem +accountFileFormat = "pem" +# The address of the account used to send transactions +# When it's empty, use a randomly generated account to send transactions, +# and the randomly generated account information is stored in tmp sub-directory of keyStoreDir +# accountAddress = "" +# The password used to load the account private key file +# password = "" + + +[threadPool] +# The size of the thread pool used to process the callback of the channel +channelProcessorThreadSize = "16" +# The size of the thread pool used to process the transaction receipt notification +receiptProcessorThreadSize = "16" + diff --git a/sdk-crypto/src/test/resources/amop/consumer_private_key.p12 b/sdk-crypto/src/test/resources/amop/consumer_private_key.p12 new file mode 100644 index 000000000..09388e9a7 Binary files /dev/null and b/sdk-crypto/src/test/resources/amop/consumer_private_key.p12 differ diff --git a/sdk-crypto/src/test/resources/amop/consumer_public_key_1.pem b/sdk-crypto/src/test/resources/amop/consumer_public_key_1.pem new file mode 100644 index 000000000..0b6ef051e --- /dev/null +++ b/sdk-crypto/src/test/resources/amop/consumer_public_key_1.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE17ngD1bT95MFNZ+i19sWYCHnMIa9zS56 +KNbtJzReHy3ez4XbdDjoRX/UdO+cTOuJq7fV+mCiLykC7CbcpSrV5Q== +-----END PUBLIC KEY----- diff --git a/sdk-crypto/src/test/resources/applicationContext-sample.xml b/sdk-crypto/src/test/resources/applicationContext-sample.xml new file mode 100644 index 000000000..a4684aec2 --- /dev/null +++ b/sdk-crypto/src/test/resources/applicationContext-sample.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + 127.0.0.1:20200 + 127.0.0.1:20201 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk-crypto/src/test/resources/config-example.toml b/sdk-crypto/src/test/resources/config-example.toml new file mode 100644 index 000000000..9eabf4f2f --- /dev/null +++ b/sdk-crypto/src/test/resources/config-example.toml @@ -0,0 +1,46 @@ +[cryptoMaterial] + +certPath = "conf" # The certification path + +# The following configurations take the certPath by default: + +# caCert = "conf/ca.crt" # CA cert file path +# sslCert = "conf/sdk.crt" # SSL cert file path +# sslKey = "conf/sdk.key" # SSL key file path +# enSslCert = "conf/gm/gmensdk.crt" # GM encryption cert file path +# enSslKey = "conf/gm/gmensdk.key" # GM ssl cert file path + +[network] +peers=["127.0.0.1:20200", "127.0.0.1:20201"] # The peer list to connect + +# Configure a private topic as a topic message sender. +# [[amop]] +# topicName = "PrivateTopic1" +# publicKeys = [ "conf/amop/consumer_public_key_1.pem" ] # Public keys of the nodes that you want to send AMOP message of this topic to. + +# Configure a private topic as a topic subscriber. +# [[amop]] +# topicName = "PrivateTopic2" +# privateKey = "conf/amop/consumer_private_key.p12" # Your private key that used to subscriber verification. +# password = "123456" + +[account] +keyStoreDir = "account" # The directory to load/store the account file, default is "account" +# accountFilePath = "" # The account file path (default load from the path specified by the keyStoreDir) +accountFileFormat = "pem" # The storage format of account file (Default is "pem", "p12" as an option) + +# accountAddress = "" # The transactions sending account address + # Default is a randomly generated account + # The randomly generated account is stored in the path specified by the keyStoreDir + +# password = "" # The password used to load the account file + +[threadPool] +# channelProcessorThreadSize = "16" # The size of the thread pool to process channel callback + # Default is the number of cpu cores + +# receiptProcessorThreadSize = "16" # The size of the thread pool to process transaction receipt notification + # Default is the number of cpu cores + +maxBlockingQueueSize = "102400" # The max blocking queue size of the thread pool + diff --git a/sdk-crypto/src/test/resources/config.toml b/sdk-crypto/src/test/resources/config.toml new file mode 100644 index 000000000..9eabf4f2f --- /dev/null +++ b/sdk-crypto/src/test/resources/config.toml @@ -0,0 +1,46 @@ +[cryptoMaterial] + +certPath = "conf" # The certification path + +# The following configurations take the certPath by default: + +# caCert = "conf/ca.crt" # CA cert file path +# sslCert = "conf/sdk.crt" # SSL cert file path +# sslKey = "conf/sdk.key" # SSL key file path +# enSslCert = "conf/gm/gmensdk.crt" # GM encryption cert file path +# enSslKey = "conf/gm/gmensdk.key" # GM ssl cert file path + +[network] +peers=["127.0.0.1:20200", "127.0.0.1:20201"] # The peer list to connect + +# Configure a private topic as a topic message sender. +# [[amop]] +# topicName = "PrivateTopic1" +# publicKeys = [ "conf/amop/consumer_public_key_1.pem" ] # Public keys of the nodes that you want to send AMOP message of this topic to. + +# Configure a private topic as a topic subscriber. +# [[amop]] +# topicName = "PrivateTopic2" +# privateKey = "conf/amop/consumer_private_key.p12" # Your private key that used to subscriber verification. +# password = "123456" + +[account] +keyStoreDir = "account" # The directory to load/store the account file, default is "account" +# accountFilePath = "" # The account file path (default load from the path specified by the keyStoreDir) +accountFileFormat = "pem" # The storage format of account file (Default is "pem", "p12" as an option) + +# accountAddress = "" # The transactions sending account address + # Default is a randomly generated account + # The randomly generated account is stored in the path specified by the keyStoreDir + +# password = "" # The password used to load the account file + +[threadPool] +# channelProcessorThreadSize = "16" # The size of the thread pool to process channel callback + # Default is the number of cpu cores + +# receiptProcessorThreadSize = "16" # The size of the thread pool to process transaction receipt notification + # Default is the number of cpu cores + +maxBlockingQueueSize = "102400" # The max blocking queue size of the thread pool + diff --git a/sdk-crypto/src/test/resources/config/ca.crt b/sdk-crypto/src/test/resources/config/ca.crt new file mode 100644 index 000000000..d02981796 --- /dev/null +++ b/sdk-crypto/src/test/resources/config/ca.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSzCCAjOgAwIBAgIUKsk+1UNeCOqmiha4AtNbK2HRtWUwDQYJKoZIhvcNAQEL +BQAwNTEOMAwGA1UEAwwFY2hhaW4xEzARBgNVBAoMCmZpc2NvLWJjb3MxDjAMBgNV +BAsMBWNoYWluMB4XDTIwMDcyMDA3MzY0NVoXDTMwMDcxODA3MzY0NVowNTEOMAwG +A1UEAwwFY2hhaW4xEzARBgNVBAoMCmZpc2NvLWJjb3MxDjAMBgNVBAsMBWNoYWlu +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo5zrDCq69OAtMMrHv9yb +fcV95GzEAXNxhvqR2rVcP9M5OMrhQ8TXz39GMpTHHYYy/DKKwpYykAR752FTEFbo +ky4JNMxGvO1SV3NrwY/pQyeuCyRo2Iry+sYPtxBAMg/fCRdMzSjMrZXWmnOYx2uW +4IVVtVZBJ5WFCp3R6ZTz505hZzXyxTr/5jIztmtIi29I/q88bFFQtmayj8J+qZZu +BiN5qSs9xG7GbmfxeQEFzftThK5rQ5KUBUe56jAeJbNInB1kFiIyB119wsY+QTnP +I7OCm3vQ58RMPUXk9RuT7WBE2/ORRWGu5EBCI0gOK4bNzIcfUeF+i2Yo0N0+MASN +zwIDAQABo1MwUTAdBgNVHQ4EFgQU1pXn7uKZL73JAgYhN57V8w3juGUwHwYDVR0j +BBgwFoAU1pXn7uKZL73JAgYhN57V8w3juGUwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQsFAAOCAQEAicxdWl3msjRDI/JCoL3EMRtPGa7haQbBsBPl+iS5gCXm +QWPxPSbt8WCZWYuAg786XDlrblA6gMEKwFpi1V4kVwOWYdrom2a+ljdc8OO6de2K +8ZKKYzj/LEIwPkdp0xHvo1St3vT/9qHKiM6OtpQxlbrPsHZNviJh1vuYqLxcoU2N +F6cdDv8DfVF0Xh3Q/1zjLOfS9ayuCIPHoaIm4Px9DjrwU6KG1BwJCdO/do5sopYS +PPL3IekgpkMKFlCm6jKYLEPuj3hSMkZipnYlrfe231pwOjo1aDkH5ud5rvUx6uUy ++6hms09chOK+Bx5LMclyNd/MX7YCmwPnxllkQvT3AA== +-----END CERTIFICATE----- diff --git a/sdk-crypto/src/test/resources/config/sdk.crt b/sdk-crypto/src/test/resources/config/sdk.crt new file mode 100644 index 000000000..267207fc4 --- /dev/null +++ b/sdk-crypto/src/test/resources/config/sdk.crt @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIICQjCCASqgAwIBAgIURDhyND2WYBEQPWE+TFUHbI3T+14wDQYJKoZIhvcNAQEL +BQAwNzEPMA0GA1UEAwwGYWdlbmN5MRMwEQYDVQQKDApmaXNjby1iY29zMQ8wDQYD +VQQLDAZhZ2VuY3kwHhcNMjAwNzIwMDczNjQ2WhcNMzAwNzE4MDczNjQ2WjAxMQww +CgYDVQQDDANzZGsxEzARBgNVBAoMCmZpc2NvLWJjb3MxDDAKBgNVBAsMA3NkazBW +MBAGByqGSM49AgEGBSuBBAAKA0IABAakRi6hjdXt3Eh3XNdS0IxMqOIQMYPk1ixf +DhR/KM6ODDbXp+PNelp7J/2zxjW9gv8ll25dG/Wzg4Pl8EUJVj6jGjAYMAkGA1Ud +EwQCMAAwCwYDVR0PBAQDAgXgMA0GCSqGSIb3DQEBCwUAA4IBAQAmByQEn4c+OP2v +iJe3Z7RW8l8+InsXWBebEbiAhOImGAQ2XfLAmR+lhVQ7A7iInnKmEBK7oNn9vgcG +NiXarKAHsEE6LV7uqAZYVX7+Xp8u/DD7utE3+tw++k0ysxzxLlsW47yhU04nw2wf +IJoWsEGvkpnMDo2soLV3RPSWzBKUudSCtYdH9xP5j1umBElnPfTx0Jw2CQZS21cK +7NPI23aU7CDRsKO4MNdrhddBzDyWlOtoGkiFrBxBL26Wk2BPkc/v9ip/g7Tw+1Og +awky+4T4RGPIxmsrwVzrqrbl/efMMcmeG4CrbiWuE/9nHtLbM+ZVnPXTYB5U2Wot +NNi033ff +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDCjCCAfKgAwIBAgIUBnXphpxPBgeogKUldLgxFq1rbe8wDQYJKoZIhvcNAQEL +BQAwNTEOMAwGA1UEAwwFY2hhaW4xEzARBgNVBAoMCmZpc2NvLWJjb3MxDjAMBgNV +BAsMBWNoYWluMB4XDTIwMDcyMDA3MzY0NVoXDTMwMDcxODA3MzY0NVowNzEPMA0G +A1UEAwwGYWdlbmN5MRMwEQYDVQQKDApmaXNjby1iY29zMQ8wDQYDVQQLDAZhZ2Vu +Y3kwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDcarpuKChCkoQAJGFT +30L9WbFmCnS9szy1FfnzoPs7h5qJBuyTOFGgtnQOfuUd1g7ZDoAtf5tfAxhXlCyl +YlE8epuDmRJQBZAC2NSdC6IaBVNjgX7QotJ8FW5ylFmlIt8OkOjB+/k7jL7yTjIc +R+mTUr3Qn1DG9kQ9bg+XjyoqDQ5FVx2TywwmzuptRnUBXgoVH/69AQKLpC/LQE61 +dnVbnobrq2u6inwX3kfAoWm41rmn2gksQpSHqQFgTIVqaCpIrXq/gmNWwNZT0PqY +yqiOGe0+V5Nz7Jfj96vTRsLjVnzrp8XmP035nGA4tZiw0B+HfgN1WPtm7cqeP0Vj +XTgZAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAF/R +xpld6ETAHPowbFxdGtAL0QZ/lPn4trFNAZrKveM1TlZef1AxrG1wzLrVqsBNANXv +Nhsxk71yGDc8RAhiOIAosjQI7EV8MoDDVl7TUPmCVN0xAe8wrGikca+9YtO0PgYQ +9vmemam/rnRr35ZJJxYwEOGqGj6FP/XsNt68ysdBFmOYtXq5EA4KVXfYYStLrPqJ +qJsqvtFCtURfWf1CJWrLsk+iVGl30a0NlDEimwOQZ8nAMSvwdoM3cyi815N+rRy5 +7idf7sbtuzKhI6vbOHFDtuvTVW7vjFvDnTpGI4+wiVBDSpxNbKmm+PbcP+bW4C2s +v2BsJbum3UlIGRBP9uA= +-----END CERTIFICATE----- diff --git a/sdk-crypto/src/test/resources/config/sdk.key b/sdk-crypto/src/test/resources/config/sdk.key new file mode 100644 index 000000000..be516180a --- /dev/null +++ b/sdk-crypto/src/test/resources/config/sdk.key @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgngMq1bsP9e0JLYTO7t+L +CKEHoEKP+6lcVU8Ml00miIWhRANCAAQGpEYuoY3V7dxId1zXUtCMTKjiEDGD5NYs +Xw4UfyjOjgw216fjzXpaeyf9s8Y1vYL/JZduXRv1s4OD5fBFCVY+ +-----END PRIVATE KEY----- diff --git a/sdk-crypto/src/test/resources/contracts/ComplexSol.sol b/sdk-crypto/src/test/resources/contracts/ComplexSol.sol new file mode 100644 index 000000000..f864e8df9 --- /dev/null +++ b/sdk-crypto/src/test/resources/contracts/ComplexSol.sol @@ -0,0 +1,70 @@ +pragma solidity ^0.4.25; +pragma experimental ABIEncoderV2; + +contract ComplexSol{ + + uint256 private _uint256V; + int public _intV; + address public _addr; + string public _s; + bytes public _bytesV; + uint256[2] _uint8SArray; + address[] public _addrDArray; + mapping(bytes => bytes[]) _bytesMapping; + + event LogIncrement(address sender, uint256 a); + event LogInit(address sender, string s); + event LogSetValues(int i, address[] a, string s); + event LogSetBytes(bytes o, bytes b); + event LogSetSArray(uint256[2] o, uint256[2] n); + + constructor(int i, string s) public { + _addr = msg.sender; + _intV = i; + _s = s; + emit LogInit(msg.sender, s); + } + + function emptyArgs() public {} + + + function incrementUint256(uint256 v) public returns(uint256){ + _uint256V = v + 1 ; + emit LogIncrement(msg.sender, v); + return _uint256V; + } + + function getUint256() public view returns(uint256){ + return _uint256V; + } + + function setValues(int i, address[] a, string s) public { + _intV = i; + _addrDArray = a; + _s = s; + emit LogSetValues(i, a, s); + } + + + function setBytes(bytes b) public returns (bytes) { + emit LogSetBytes(_bytesV, b); + _bytesV = b; + return b; + } + + function setBytesMapping(bytes[] bytesArray) public returns (bool) { + require(bytesArray.length>1, "Bytes array is less than 2"); + _bytesMapping[bytesArray[0]] = bytesArray; + return true; + } + + function getByBytes(bytes b) public view returns (bytes[]) { + return _bytesMapping[b]; + } + + function getSArray() public returns (uint256[2]){ + uint256[2] memory arr = [uint256(1),2]; + emit LogSetSArray(arr, _uint8SArray); + return arr; + } +} diff --git a/sdk-crypto/src/test/resources/contracts/HelloWorld.sol b/sdk-crypto/src/test/resources/contracts/HelloWorld.sol new file mode 100644 index 000000000..28b00ba49 --- /dev/null +++ b/sdk-crypto/src/test/resources/contracts/HelloWorld.sol @@ -0,0 +1,12 @@ +pragma solidity ^0.4.25; + +contract HelloWorld{ + string public name; + constructor() public{ + name = "Hello, World!"; + } + + function set(string n) public{ + name = n; + } +} \ No newline at end of file diff --git a/sdk-crypto/src/test/resources/ecdsa/abi/ComplexSol.abi b/sdk-crypto/src/test/resources/ecdsa/abi/ComplexSol.abi new file mode 100644 index 000000000..5cc9376b1 --- /dev/null +++ b/sdk-crypto/src/test/resources/ecdsa/abi/ComplexSol.abi @@ -0,0 +1 @@ +[{"constant":true,"inputs":[{"name":"b","type":"bytes"}],"name":"getByBytes","outputs":[{"name":"","type":"bytes[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"bytesArray","type":"bytes[]"}],"name":"setBytesMapping","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"_addrDArray","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_addr","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getUint256","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"v","type":"uint256"}],"name":"incrementUint256","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"_bytesV","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_s","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"getSArray","outputs":[{"name":"","type":"uint256[2]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"b","type":"bytes"}],"name":"setBytes","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"i","type":"int256"},{"name":"a","type":"address[]"},{"name":"s","type":"string"}],"name":"setValues","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"_intV","outputs":[{"name":"","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"emptyArgs","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"i","type":"int256"},{"name":"s","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"a","type":"uint256"}],"name":"LogIncrement","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"s","type":"string"}],"name":"LogInit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"int256"},{"indexed":false,"name":"a","type":"address[]"},{"indexed":false,"name":"s","type":"string"}],"name":"LogSetValues","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"o","type":"bytes"},{"indexed":false,"name":"b","type":"bytes"}],"name":"LogSetBytes","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"o","type":"uint256[2]"},{"indexed":false,"name":"n","type":"uint256[2]"}],"name":"LogSetSArray","type":"event"}] \ No newline at end of file diff --git a/sdk-crypto/src/test/resources/ecdsa/abi/HelloWorld.abi b/sdk-crypto/src/test/resources/ecdsa/abi/HelloWorld.abi new file mode 100644 index 000000000..68f2ce200 --- /dev/null +++ b/sdk-crypto/src/test/resources/ecdsa/abi/HelloWorld.abi @@ -0,0 +1 @@ +[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"n","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}] \ No newline at end of file diff --git a/sdk-crypto/src/test/resources/gm/abi/ComplexSol.abi b/sdk-crypto/src/test/resources/gm/abi/ComplexSol.abi new file mode 100644 index 000000000..d19f506cd --- /dev/null +++ b/sdk-crypto/src/test/resources/gm/abi/ComplexSol.abi @@ -0,0 +1 @@ +[{"constant":true,"inputs":[],"name":"_intV","outputs":[{"name":"","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"bytesArray","type":"bytes[]"}],"name":"setBytesMapping","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"i","type":"int256"},{"name":"a","type":"address[]"},{"name":"s","type":"string"}],"name":"setValues","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"b","type":"bytes"}],"name":"getByBytes","outputs":[{"name":"","type":"bytes[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_s","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_addr","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_bytesV","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"emptyArgs","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"getSArray","outputs":[{"name":"","type":"uint256[2]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getUint256","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"b","type":"bytes"}],"name":"setBytes","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"v","type":"uint256"}],"name":"incrementUint256","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"_addrDArray","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"i","type":"int256"},{"name":"s","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"a","type":"uint256"}],"name":"LogIncrement","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"s","type":"string"}],"name":"LogInit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"int256"},{"indexed":false,"name":"a","type":"address[]"},{"indexed":false,"name":"s","type":"string"}],"name":"LogSetValues","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"o","type":"bytes"},{"indexed":false,"name":"b","type":"bytes"}],"name":"LogSetBytes","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"o","type":"uint256[2]"},{"indexed":false,"name":"n","type":"uint256[2]"}],"name":"LogSetSArray","type":"event"}] \ No newline at end of file diff --git a/sdk-crypto/src/test/resources/gm/abi/HelloWorld.abi b/sdk-crypto/src/test/resources/gm/abi/HelloWorld.abi new file mode 100644 index 000000000..426703568 --- /dev/null +++ b/sdk-crypto/src/test/resources/gm/abi/HelloWorld.abi @@ -0,0 +1 @@ +[{"constant":false,"inputs":[{"name":"n","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}] \ No newline at end of file diff --git a/sdk-crypto/src/test/resources/keystore/ecdsa/0x0fc3c4bb89bd90299db4c62be0174c4966286c00.pem b/sdk-crypto/src/test/resources/keystore/ecdsa/0x0fc3c4bb89bd90299db4c62be0174c4966286c00.pem new file mode 100644 index 000000000..b448c4cd7 --- /dev/null +++ b/sdk-crypto/src/test/resources/keystore/ecdsa/0x0fc3c4bb89bd90299db4c62be0174c4966286c00.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgvFFrJgDuw6IW9FfcFM+D +oB7SLQ/CFJ/JEdwuxIb+V6OhRANCAATbv+5PdvWjvD28LmEnxKH1C3YUv/QTikSn +mu09QvZ/nHqnBXAgX5tgpYiMZBW2qDABJne0QVp5zNFTP+VjeGHf +-----END PRIVATE KEY----- diff --git a/sdk-crypto/src/test/resources/keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.p12 b/sdk-crypto/src/test/resources/keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.p12 new file mode 100644 index 000000000..09388e9a7 Binary files /dev/null and b/sdk-crypto/src/test/resources/keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.p12 differ diff --git a/sdk-crypto/src/test/resources/keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.public.pem b/sdk-crypto/src/test/resources/keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.public.pem new file mode 100644 index 000000000..0b6ef051e --- /dev/null +++ b/sdk-crypto/src/test/resources/keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.public.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE17ngD1bT95MFNZ+i19sWYCHnMIa9zS56 +KNbtJzReHy3ez4XbdDjoRX/UdO+cTOuJq7fV+mCiLykC7CbcpSrV5Q== +-----END PUBLIC KEY----- diff --git a/sdk-crypto/src/test/resources/keystore/ecdsa/invalid.p12 b/sdk-crypto/src/test/resources/keystore/ecdsa/invalid.p12 new file mode 100644 index 000000000..5e5138794 Binary files /dev/null and b/sdk-crypto/src/test/resources/keystore/ecdsa/invalid.p12 differ diff --git a/sdk-crypto/src/test/resources/keystore/ecdsa/invalid.pem b/sdk-crypto/src/test/resources/keystore/ecdsa/invalid.pem new file mode 100644 index 000000000..ecc335ea0 --- /dev/null +++ b/sdk-crypto/src/test/resources/keystore/ecdsa/invalid.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgvFFrJgDuw6IW9FfcFM+D +oB7SLQ/CFJ/JEdwuxIb+V6OhRANCAATbv+5PdvWjvD28LmEnxKH1C3YUv/QTikSn +mu09QvZ/nHqnBXAgX5tgpYiMZBW2qDABJne0QVp5zNFTP+VjeGf +-----END PRIVATE KEY----- diff --git a/sdk-crypto/src/test/resources/keystore/gm/0x40b3558746e8f9a47a474774e8c4a9e67d4e3174.pem b/sdk-crypto/src/test/resources/keystore/gm/0x40b3558746e8f9a47a474774e8c4a9e67d4e3174.pem new file mode 100644 index 000000000..f5395940b --- /dev/null +++ b/sdk-crypto/src/test/resources/keystore/gm/0x40b3558746e8f9a47a474774e8c4a9e67d4e3174.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgkBdEw04q3/yf1/sS +6Mui2Ip5qvVL6bThFmAVModInxOhRANCAAQ7cs0oJEyFbT2Jtn0cX/IuHyaDW6/N +Y+mkrTQkoqV/K3WRSfRsaW3wi52Uc2hmdfxtredE0Mgr3FWY11ngFf2W +-----END PRIVATE KEY----- diff --git a/sdk-crypto/src/test/resources/keystore/gm/0x6f68461309925093236df82b51df630a55d32377.p12 b/sdk-crypto/src/test/resources/keystore/gm/0x6f68461309925093236df82b51df630a55d32377.p12 new file mode 100644 index 000000000..367c17da1 Binary files /dev/null and b/sdk-crypto/src/test/resources/keystore/gm/0x6f68461309925093236df82b51df630a55d32377.p12 differ diff --git a/sdk-crypto/src/test/resources/keystore/gm/invalid.p12 b/sdk-crypto/src/test/resources/keystore/gm/invalid.p12 new file mode 100644 index 000000000..60862eb2f Binary files /dev/null and b/sdk-crypto/src/test/resources/keystore/gm/invalid.p12 differ diff --git a/sdk-crypto/src/test/resources/keystore/gm/invalid.pem b/sdk-crypto/src/test/resources/keystore/gm/invalid.pem new file mode 100644 index 000000000..d63a94f80 --- /dev/null +++ b/sdk-crypto/src/test/resources/keystore/gm/invalid.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgkBdEw04q3/yf1/sS +6Mui2Ip5qvVL6bThFmAVModInxOhRANCAAQ7cs0oJEyFbT2Jtn0cX/IuHyaDW6/N +Y+mkrTQkoqV/K3WRSfRsaW3wi52Uc2hmdfxtredE0Mgr3FWY11ngFf2 +-----END PRIVATE KEY----- diff --git a/sdk-crypto/src/test/resources/log4j.properties b/sdk-crypto/src/test/resources/log4j.properties new file mode 100644 index 000000000..55785c234 --- /dev/null +++ b/sdk-crypto/src/test/resources/log4j.properties @@ -0,0 +1,32 @@ +# +# Copyright 2014-2020 [fisco-dev] +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under the License +# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +# or implied. See the License for the specific language governing permissions and limitations under +# the License. +# +# + +### set log levels ### +log4j.rootLogger=DEBUG, file + +### output the log information to the file ### +log4j.appender.file=org.apache.log4j.DailyRollingFileAppender +log4j.appender.file.DatePattern='_'yyyyMMddHH'.log' +log4j.appender.file.File=./log/sdk.log +log4j.appender.file.Append=true +log4j.appender.file.filter.traceFilter=org.apache.log4j.varia.LevelRangeFilter +log4j.appender.file.layout=org.apache.log4j.PatternLayout +log4j.appender.file.layout.ConversionPattern=[%p] [%-d{yyyy-MM-dd HH:mm:ss}] %C{1}.%M(%L) | %m%n + +###output the log information to the console ### +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=[%p] [%-d{yyyy-MM-dd HH:mm:ss}] %C{1}.%M(%L) | %m%n diff --git a/sdk-demo/build.gradle b/sdk-demo/build.gradle new file mode 100644 index 000000000..9412920eb --- /dev/null +++ b/sdk-demo/build.gradle @@ -0,0 +1,11 @@ +// Apply the java-library plugin to add support for Java Library +plugins { + id 'java' +} +dependencies { + compile project(':sdk-codegen') + compile ("org.fisco-bcos:solcJ:${solcJVersion}") + compile ("com.google.guava:guava:${guavaVersion}") + compile ("org.apache.commons:commons-collections4:${commonsCollections4Version}") +} + diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/perf/AmopMsgBuilder.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/perf/AmopMsgBuilder.java new file mode 100644 index 000000000..f0b957148 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/perf/AmopMsgBuilder.java @@ -0,0 +1,47 @@ +package org.fisco.bcos.sdk.demo.amop.perf; + +import java.util.Random; +import org.fisco.bcos.sdk.amop.Amop; +import org.fisco.bcos.sdk.amop.AmopMsgOut; +import org.fisco.bcos.sdk.amop.topic.TopicType; +import org.fisco.bcos.sdk.channel.ResponseCallback; +import org.fisco.bcos.sdk.model.Response; + +public class AmopMsgBuilder { + + public void sendMsg( + AmopMsgCollector collector, Amop sender, String topic, TopicType type, int contentLen) { + AmopMsgOut out = new AmopMsgOut(); + out.setTopic(topic); + out.setType(type); + out.setTimeout(5000); + out.setContent(getRandomBytes(contentLen)); + + ResponseCallback callback = + new ResponseCallback() { + @Override + public void onResponse(Response response) { + collector.addResponse(); + if (response.getErrorCode() != 0) { + System.out.println( + "error, code:" + + response.getErrorCode() + + " msg:" + + response.getErrorMessage()); + collector.addError(); + } + } + }; + sender.sendAmopMsg(out, callback); + } + + public byte[] getRandomBytes(int len) { + Random random = new Random(); + byte[] b = new byte[len]; + for (int i = 0; i < len; i++) { + Integer is = random.nextInt(9); + b[i] = Byte.parseByte(is.toString()); + } + return b; + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/perf/AmopMsgCallback.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/perf/AmopMsgCallback.java new file mode 100644 index 000000000..d70c20810 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/perf/AmopMsgCallback.java @@ -0,0 +1,21 @@ +package org.fisco.bcos.sdk.demo.amop.perf; + +import org.fisco.bcos.sdk.amop.AmopCallback; +import org.fisco.bcos.sdk.amop.topic.AmopMsgIn; + +public class AmopMsgCallback extends AmopCallback { + private Long startTime = System.currentTimeMillis(); + + private AmopMsgCollector collector = new AmopMsgCollector(); + + public AmopMsgCollector getCollector() { + return collector; + } + + @Override + public byte[] receiveAmopMsg(AmopMsgIn msg) { + Long cost = System.currentTimeMillis() - startTime; + collector.onSubscribedTopicMsg(msg, cost); + return "Yes, I received!".getBytes(); + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/perf/AmopMsgCollector.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/perf/AmopMsgCollector.java new file mode 100644 index 000000000..53bc8b95f --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/perf/AmopMsgCollector.java @@ -0,0 +1,124 @@ +package org.fisco.bcos.sdk.demo.amop.perf; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import org.fisco.bcos.sdk.amop.topic.AmopMsgIn; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AmopMsgCollector { + private static Logger logger = LoggerFactory.getLogger(AmopMsgCollector.class); + private AtomicLong less500 = new AtomicLong(0); + private AtomicLong less1000 = new AtomicLong(0); + private AtomicLong less2000 = new AtomicLong(0); + private AtomicLong less4000 = new AtomicLong(0); + private AtomicLong less10000 = new AtomicLong(0); + private AtomicLong timeout10000 = new AtomicLong(0); + private AtomicLong totalCost = new AtomicLong(0); + + private Integer total = 0; + private AtomicInteger received = new AtomicInteger(0); + private AtomicInteger error = new AtomicInteger(0); + private AtomicInteger responsed = new AtomicInteger(0); + private Long startTimestamp = System.currentTimeMillis(); + + public Integer getTotal() { + return total; + } + + public void setTotal(Integer total) { + this.total = total; + } + + public void addResponse() { + responsed.incrementAndGet(); + if (responsed.get() >= total) { + printResult(); + } + } + + public void addError() { + error.incrementAndGet(); + } + + public void onSubscribedTopicMsg(AmopMsgIn msg, long cost) { + + // System.out.println("Subscriber receive msg :" + Hex.toHexString(msg.getContent())); + try { + if (cost < 500) { + less500.incrementAndGet(); + } else if (cost < 1000) { + less1000.incrementAndGet(); + } else if (cost < 2000) { + less2000.incrementAndGet(); + } else if (cost < 4000) { + less4000.incrementAndGet(); + } else if (cost < 10000) { + less10000.incrementAndGet(); + } else { + timeout10000.incrementAndGet(); + } + totalCost.addAndGet(cost); + received.incrementAndGet(); + } catch (Exception e) { + logger.error("error:", e); + } + } + + public void printResult() { + + System.out.println("total"); + + Long totalTime = System.currentTimeMillis() - startTimestamp; + + System.out.println("==================================================================="); + + System.out.println("Total amop msg: " + String.valueOf(total)); + System.out.println("Total time: " + String.valueOf(totalTime) + "ms"); + System.out.println("Success received: " + String.valueOf(received.get())); + System.out.println("Response error:" + String.valueOf(error.get())); + System.out.println( + "Msg per second(exclude error requests): " + + String.valueOf(received.get() / ((double) totalTime / 1000))); + System.out.println("Avg time cost: " + String.valueOf(totalCost.get() / total) + "ms"); + System.out.println("Time area:"); + System.out.println( + "0 < time < 0.5s : " + + String.valueOf(less500) + + " : " + + String.valueOf((double) less500.get() / total * 100) + + "%"); + System.out.println( + "0.5 < time < 1s : " + + String.valueOf(less1000) + + " : " + + String.valueOf((double) less1000.get() / total * 100) + + "%"); + System.out.println( + "1 < time < 2s : " + + String.valueOf(less2000) + + " : " + + String.valueOf((double) less2000.get() / total * 100) + + "%"); + System.out.println( + "2 < time < 4s : " + + String.valueOf(less4000) + + " : " + + String.valueOf((double) less4000.get() / total * 100) + + "%"); + System.out.println( + "4 < time < 10s : " + + String.valueOf(less10000) + + " : " + + String.valueOf((double) less10000.get() / total * 100) + + "%"); + System.out.println( + "10 < time : " + + String.valueOf(timeout10000) + + " : " + + String.valueOf((double) timeout10000.get() / total * 100) + + "%"); + + System.exit(0); + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/perf/PerformanceAmop.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/perf/PerformanceAmop.java new file mode 100644 index 000000000..9b6c97f23 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/perf/PerformanceAmop.java @@ -0,0 +1,93 @@ +package org.fisco.bcos.sdk.demo.amop.perf; + +import com.google.common.util.concurrent.RateLimiter; +import java.util.concurrent.atomic.AtomicInteger; +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.amop.Amop; +import org.fisco.bcos.sdk.amop.topic.TopicType; +import org.fisco.bcos.sdk.utils.ThreadPoolService; + +public class PerformanceAmop { + private static final String senderConfig = + PerformanceAmop.class + .getClassLoader() + .getResource("config-sender-for-test.toml") + .getPath(); + private static final String subscriberConfig = + PerformanceAmop.class + .getClassLoader() + .getResource("config-subscriber-for-test.toml") + .getPath(); + private static AtomicInteger sendedMsg = new AtomicInteger(0); + private static AmopMsgBuilder msgBuilder = new AmopMsgBuilder(); + + public static void main(String[] args) { + try { + Integer count = Integer.valueOf(args[0]); + Integer qps = Integer.valueOf(args[1]); + Integer msgSize = Integer.valueOf(args[2]); + + // Init subscriber + String topic = "normalTopic"; + Amop subscriber = BcosSDK.build(subscriberConfig).getAmop(); + AmopMsgCallback cb = new AmopMsgCallback(); + AmopMsgCollector collector = cb.getCollector(); + collector.setTotal(count); + subscriber.subscribeTopic(topic, cb); + subscriber.setCallback(cb); + + // Init publisher + Amop sender = BcosSDK.build(senderConfig).getAmop(); + + System.out.println("Start test"); + Thread.sleep(2000); + System.out.println("3s ..."); + Thread.sleep(1000); + System.out.println("2s ..."); + Thread.sleep(1000); + System.out.println("1s ..."); + Thread.sleep(1000); + System.out.println( + "====== PerformanceAmop Amop public topic text message performance start ======"); + RateLimiter limiter = RateLimiter.create(qps); + Integer area = count / 10; + final Integer total = count; + ThreadPoolService threadPoolService = new ThreadPoolService("PerformanceAmop", 102400); + + for (Integer i = 0; i < count; i++) { + limiter.acquire(); + threadPoolService + .getThreadPool() + .execute( + new Runnable() { + @Override + public void run() { + msgBuilder.sendMsg( + collector, + sender, + "normalTopic", + TopicType.NORMAL_TOPIC, + msgSize); + int current = sendedMsg.incrementAndGet(); + if (current >= area && ((current % area) == 0)) { + System.out.println( + "Already sended: " + + current + + "/" + + total + + " amop text message"); + } + } + }); + } + // wait to send all msg + while (sendedMsg.get() != count) { + Thread.sleep(1000); + } + threadPoolService.stop(); + } catch (Exception e) { + System.out.println( + "====== PerformanceAmop test failed, error message: " + e.getMessage()); + } + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/AmopPublisher.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/AmopPublisher.java new file mode 100644 index 000000000..b37ee9f67 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/AmopPublisher.java @@ -0,0 +1,86 @@ +package org.fisco.bcos.sdk.demo.amop.tool; + +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.amop.Amop; +import org.fisco.bcos.sdk.amop.AmopMsgOut; +import org.fisco.bcos.sdk.amop.topic.TopicType; +import org.fisco.bcos.sdk.channel.ResponseCallback; +import org.fisco.bcos.sdk.model.Response; + +public class AmopPublisher { + private static final int parameterNum = 4; + private static String publisherFile = + AmopPublisher.class + .getClassLoader() + .getResource("amop/config-publisher-for-test.toml") + .getPath(); + + /** + * @param args topicName, isBroadcast, Content(Content you want to send out), Count(how many msg + * you want to send out) + * @throws Exception AMOP publish exceptioned + */ + public static void main(String[] args) throws Exception { + if (args.length < parameterNum) { + System.out.println("param: target topic total number of request"); + return; + } + String topicName = args[0]; + Boolean isBroadcast = Boolean.valueOf(args[1]); + String content = args[2]; + Integer count = Integer.parseInt(args[3]); + BcosSDK sdk = BcosSDK.build(publisherFile); + Amop amop = sdk.getAmop(); + + System.out.println("3s ..."); + Thread.sleep(1000); + System.out.println("2s ..."); + Thread.sleep(1000); + System.out.println("1s ..."); + Thread.sleep(1000); + + System.out.println("start test"); + System.out.println("==================================================================="); + + for (Integer i = 0; i < count; ++i) { + Thread.sleep(2000); + AmopMsgOut out = new AmopMsgOut(); + out.setType(TopicType.NORMAL_TOPIC); + out.setContent(content.getBytes()); + out.setTimeout(6000); + out.setTopic(topicName); + ResponseCallback cb = + new ResponseCallback() { + @Override + public void onResponse(Response response) { + + System.out.println( + "Step 3:Get response, { errorCode:" + + response.getErrorCode() + + " error:" + + response.getErrorMessage() + + " seq:" + + response.getMessageID() + + " content:" + + new String(response.getContentBytes()) + + " }"); + } + }; + if (isBroadcast) { + amop.broadcastAmopMsg(out); + System.out.println( + "Step 1: Send out msg by broadcast, topic:" + + out.getTopic() + + " content:" + + new String(out.getContent())); + } else { + amop.sendAmopMsg(out, cb); + System.out.println( + "Step 1: Send out msg, topic:" + + out.getTopic() + + " content:" + + new String(out.getContent())); + } + } + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/AmopPublisherFile.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/AmopPublisherFile.java new file mode 100644 index 000000000..e1bf80feb --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/AmopPublisherFile.java @@ -0,0 +1,97 @@ +package org.fisco.bcos.sdk.demo.amop.tool; + +import static org.fisco.bcos.sdk.demo.amop.tool.FileToByteArrayHelper.byteCat; +import static org.fisco.bcos.sdk.demo.amop.tool.FileToByteArrayHelper.getFileByteArray; +import static org.fisco.bcos.sdk.demo.amop.tool.FileToByteArrayHelper.intToByteArray; + +import java.io.File; +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.amop.Amop; +import org.fisco.bcos.sdk.amop.AmopMsgOut; +import org.fisco.bcos.sdk.amop.topic.TopicType; +import org.fisco.bcos.sdk.channel.ResponseCallback; +import org.fisco.bcos.sdk.model.Response; + +public class AmopPublisherFile { + private static final int parameterNum = 4; + private static String publisherFile = + AmopPublisherFile.class + .getClassLoader() + .getResource("amop/config-publisher-for-test.toml") + .getPath(); + + /** + * @param args topicName, isBroadcast: true/false, fileName, count + * @throws Exception AMOP publish exceptioned + */ + public static void main(String[] args) throws Exception { + if (args.length < parameterNum) { + System.out.println("param: target topic total number of request"); + return; + } + String topicName = args[0]; + Boolean isBroadcast = Boolean.valueOf(args[1]); + String fileName = args[2]; + Integer count = Integer.parseInt(args[3]); + BcosSDK sdk = BcosSDK.build(publisherFile); + Amop amop = sdk.getAmop(); + Integer timeout = 6000; + if (args.length > 4) { + timeout = Integer.parseInt(args[4]); + } + System.out.println("3s ..."); + Thread.sleep(1000); + System.out.println("2s ..."); + Thread.sleep(1000); + System.out.println("1s ..."); + Thread.sleep(1000); + + System.out.println("start test"); + System.out.println("==================================================================="); + + int flag = -128; + byte[] byteflag = intToByteArray(flag); + int filelength = fileName.length(); + byte[] bytelength = intToByteArray(filelength); + byte[] bytefilename = fileName.getBytes(); + byte[] contentfile = getFileByteArray(new File(fileName)); + byte[] content = byteCat(byteCat(byteCat(byteflag, bytelength), bytefilename), contentfile); + + for (Integer i = 0; i < count; ++i) { + Thread.sleep(2000); + AmopMsgOut out = new AmopMsgOut(); + out.setType(TopicType.NORMAL_TOPIC); + out.setContent(content); + out.setTimeout(timeout); + out.setTopic(topicName); + ResponseCallback cb = + new ResponseCallback() { + @Override + public void onResponse(Response response) { + if (response.getErrorCode() == 102) { + System.out.println( + "Step 3: Timeout, maybe your file is too large or your gave a short timeout. Add a timeout arg, topicName, isBroadcast: true/false, fileName, count, timeout"); + } else { + System.out.println( + "Step 3:Get response, { errorCode:" + + response.getErrorCode() + + " error:" + + response.getErrorMessage() + + " seq:" + + response.getMessageID() + + " content:" + + new String(response.getContentBytes()) + + " }"); + } + } + }; + if (isBroadcast) { + amop.broadcastAmopMsg(out); + } else { + amop.sendAmopMsg(out, cb); + } + System.out.println( + "Step 1: Send out msg, topic:" + out.getTopic() + " content: file " + fileName); + } + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/AmopPublisherPrivate.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/AmopPublisherPrivate.java new file mode 100644 index 000000000..273a62a63 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/AmopPublisherPrivate.java @@ -0,0 +1,109 @@ +package org.fisco.bcos.sdk.demo.amop.tool; + +import java.util.ArrayList; +import java.util.List; +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.amop.Amop; +import org.fisco.bcos.sdk.amop.AmopMsgOut; +import org.fisco.bcos.sdk.amop.topic.TopicType; +import org.fisco.bcos.sdk.channel.ResponseCallback; +import org.fisco.bcos.sdk.crypto.keystore.KeyTool; +import org.fisco.bcos.sdk.crypto.keystore.PEMKeyStore; +import org.fisco.bcos.sdk.model.Response; + +public class AmopPublisherPrivate { + private static final int parameterNum = 6; + private static String publisherFile = + AmopPublisherPrivate.class + .getClassLoader() + .getResource("amop/config-publisher-for-test.toml") + .getPath(); + + /** + * @param args topicName, pubKey1, pubKey2, isBroadcast: true/false, content, count. if only one + * public key please fill pubKey2 with null + * @throws Exception AMOP exceptioned + */ + public static void main(String[] args) throws Exception { + if (args.length < parameterNum) { + System.out.println( + "param: opicName, pubKey1, pubKey2, isBroadcast: true/false, content, count"); + return; + } + String topicName = args[0]; + String pubkey1 = args[1]; + String pubkey2 = args[2]; + Boolean isBroadcast = Boolean.valueOf(args[3]); + String content = args[4]; + Integer count = Integer.parseInt(args[5]); + BcosSDK sdk = BcosSDK.build(publisherFile); + Amop amop = sdk.getAmop(); + + System.out.println("3s ..."); + Thread.sleep(1000); + System.out.println("2s ..."); + Thread.sleep(1000); + System.out.println("1s ..."); + Thread.sleep(1000); + + System.out.println("start test"); + System.out.println("==================================================================="); + System.out.println("set up private topic"); + List keyToolList = new ArrayList<>(); + KeyTool keyTool = new PEMKeyStore(pubkey1); + keyToolList.add(keyTool); + if (!pubkey2.equals("null")) { + KeyTool keyTool1 = new PEMKeyStore(pubkey2); + keyToolList.add(keyTool1); + } + amop.publishPrivateTopic(topicName, keyToolList); + System.out.println("wait until finish private topic verify"); + System.out.println("3s ..."); + Thread.sleep(1000); + System.out.println("2s ..."); + Thread.sleep(1000); + System.out.println("1s ..."); + Thread.sleep(1000); + + for (Integer i = 0; i < count; ++i) { + Thread.sleep(2000); + AmopMsgOut out = new AmopMsgOut(); + out.setType(TopicType.PRIVATE_TOPIC); + out.setContent(content.getBytes()); + out.setTimeout(6000); + out.setTopic(topicName); + ResponseCallback cb = + new ResponseCallback() { + @Override + public void onResponse(Response response) { + + System.out.println( + "Step 3:Get response, { errorCode:" + + response.getErrorCode() + + " error:" + + response.getErrorMessage() + + " seq:" + + response.getMessageID() + + " content:" + + new String(response.getContentBytes()) + + " }"); + } + }; + if (isBroadcast) { + amop.broadcastAmopMsg(out); + System.out.println( + "Step 1: Send out msg by broadcast, topic:" + + out.getTopic() + + " content:" + + new String(out.getContent())); + } else { + amop.sendAmopMsg(out, cb); + System.out.println( + "Step 1: Send out msg, topic:" + + out.getTopic() + + " content:" + + new String(out.getContent())); + } + } + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/AmopPublisherPrivateFile.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/AmopPublisherPrivateFile.java new file mode 100644 index 000000000..f3327bd15 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/AmopPublisherPrivateFile.java @@ -0,0 +1,122 @@ +package org.fisco.bcos.sdk.demo.amop.tool; + +import static org.fisco.bcos.sdk.demo.amop.tool.FileToByteArrayHelper.byteCat; +import static org.fisco.bcos.sdk.demo.amop.tool.FileToByteArrayHelper.getFileByteArray; +import static org.fisco.bcos.sdk.demo.amop.tool.FileToByteArrayHelper.intToByteArray; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.amop.Amop; +import org.fisco.bcos.sdk.amop.AmopMsgOut; +import org.fisco.bcos.sdk.amop.topic.TopicType; +import org.fisco.bcos.sdk.channel.ResponseCallback; +import org.fisco.bcos.sdk.crypto.keystore.KeyTool; +import org.fisco.bcos.sdk.crypto.keystore.PEMKeyStore; +import org.fisco.bcos.sdk.model.Response; + +public class AmopPublisherPrivateFile { + private static final int parameterNum = 6; + private static String publisherFile = + AmopPublisherPrivateFile.class + .getClassLoader() + .getResource("amop/config-publisher-for-test.toml") + .getPath(); + + /** + * @param args topicName, pubKey1, pubKey2, isBroadcast: true/false, fileName, count, timeout. + * if only one public key please fill pubKey2 with null + * @throws Exception the exception + */ + public static void main(String[] args) throws Exception { + if (args.length < parameterNum) { + System.out.println("param: target topic total number of request"); + return; + } + String topicName = args[0]; + String pubkey1 = args[1]; + String pubkey2 = args[2]; + Boolean isBroadcast = Boolean.valueOf(args[3]); + String fileName = args[4]; + Integer count = Integer.parseInt(args[5]); + Integer timeout = 6000; + if (args.length > 6) { + timeout = Integer.parseInt(args[6]); + } + BcosSDK sdk = BcosSDK.build(publisherFile); + Amop amop = sdk.getAmop(); + // todo setup topic + + System.out.println("3s ..."); + Thread.sleep(1000); + System.out.println("2s ..."); + Thread.sleep(1000); + System.out.println("1s ..."); + Thread.sleep(1000); + + System.out.println("start test"); + System.out.println("==================================================================="); + System.out.println("set up private topic"); + List kml = new ArrayList<>(); + KeyTool km1 = new PEMKeyStore(pubkey1); + kml.add(km1); + if (!pubkey2.equals("null")) { + KeyTool km2 = new PEMKeyStore(pubkey2); + kml.add(km2); + } + amop.publishPrivateTopic(topicName, kml); + System.out.println("wait until finish private topic verify"); + System.out.println("3s ..."); + Thread.sleep(1000); + System.out.println("2s ..."); + Thread.sleep(1000); + System.out.println("1s ..."); + Thread.sleep(1000); + + int flag = -128; + byte[] byteflag = intToByteArray(flag); + int filelength = fileName.length(); + byte[] bytelength = intToByteArray(filelength); + byte[] bytefilename = fileName.getBytes(); + byte[] contentfile = getFileByteArray(new File(fileName)); + byte[] content = byteCat(byteCat(byteCat(byteflag, bytelength), bytefilename), contentfile); + + for (Integer i = 0; i < count; ++i) { + Thread.sleep(2000); + AmopMsgOut out = new AmopMsgOut(); + out.setType(TopicType.PRIVATE_TOPIC); + out.setContent(content); + out.setTimeout(timeout); + out.setTopic(topicName); + ResponseCallback cb = + new ResponseCallback() { + @Override + public void onResponse(Response response) { + if (response.getErrorCode() == 102) { + System.out.println( + "Step 3: Timeout, maybe your file is too large or your gave a short timeout. Add a timeout arg, topicName, isBroadcast: true/false, fileName, count, timeout"); + } else { + System.out.println( + "Step 3:Get response, { errorCode:" + + response.getErrorCode() + + " error:" + + response.getErrorMessage() + + " seq:" + + response.getMessageID() + + " content:" + + new String(response.getContentBytes()) + + " }"); + } + } + }; + if (isBroadcast) { + amop.broadcastAmopMsg(out); + } else { + amop.sendAmopMsg(out, cb); + } + System.out.println( + "Step 1: Send out msg, topic:" + out.getTopic() + " content: file " + fileName); + } + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/AmopSubscriber.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/AmopSubscriber.java new file mode 100644 index 000000000..88e6b9fd8 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/AmopSubscriber.java @@ -0,0 +1,26 @@ +package org.fisco.bcos.sdk.demo.amop.tool; + +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.amop.Amop; +import org.fisco.bcos.sdk.amop.AmopCallback; + +public class AmopSubscriber { + private static String subscriberConfigFile = + AmopSubscriber.class + .getClassLoader() + .getResource("amop/config-subscriber-for-test.toml") + .getPath(); + + public static void main(String[] args) throws Exception { + if (args.length < 1) { + System.out.println("Param: topic"); + return; + } + String topic = args[0]; + BcosSDK sdk = BcosSDK.build(subscriberConfigFile); + Amop amop = sdk.getAmop(); + AmopCallback cb = new DemoAmopCallback(); + System.out.println("Start test"); + amop.subscribeTopic(topic, cb); + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/AmopSubscriberPrivate.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/AmopSubscriberPrivate.java new file mode 100644 index 000000000..380c7b740 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/AmopSubscriberPrivate.java @@ -0,0 +1,44 @@ +package org.fisco.bcos.sdk.demo.amop.tool; + +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.amop.Amop; +import org.fisco.bcos.sdk.amop.AmopCallback; +import org.fisco.bcos.sdk.crypto.keystore.KeyTool; +import org.fisco.bcos.sdk.crypto.keystore.P12KeyStore; +import org.fisco.bcos.sdk.crypto.keystore.PEMKeyStore; + +public class AmopSubscriberPrivate { + private static String subscriberConfigFile = + AmopSubscriberPrivate.class + .getClassLoader() + .getResource("amop/config-subscriber-for-test.toml") + .getPath(); + + /** + * @param args topic, privateKeyFile, password(Option) + * @throws Exception AMOP exceptioned + */ + public static void main(String[] args) throws Exception { + if (args.length < 2) { + System.out.println("Param: topic, privateKeyFile, password"); + return; + } + String topic = args[0]; + String privateKeyFile = args[1]; + BcosSDK sdk = BcosSDK.build(subscriberConfigFile); + Amop amop = sdk.getAmop(); + AmopCallback cb = new DemoAmopCallback(); + + System.out.println("Start test"); + amop.setCallback(cb); + + KeyTool km; + if (privateKeyFile.endsWith("p12")) { + String password = args[2]; + km = new P12KeyStore(privateKeyFile, password); + } else { + km = new PEMKeyStore(privateKeyFile); + } + amop.subscribePrivateTopics(topic, km, cb); + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/DemoAmopCallback.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/DemoAmopCallback.java new file mode 100644 index 000000000..2c98bf8ec --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/DemoAmopCallback.java @@ -0,0 +1,97 @@ +package org.fisco.bcos.sdk.demo.amop.tool; + +import static org.fisco.bcos.sdk.utils.ByteUtils.byteArrayToInt; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Arrays; +import org.fisco.bcos.sdk.amop.AmopCallback; +import org.fisco.bcos.sdk.amop.topic.AmopMsgIn; +import org.fisco.bcos.sdk.model.MsgType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DemoAmopCallback extends AmopCallback { + private static Logger logger = LoggerFactory.getLogger(DemoAmopCallback.class); + + @Override + public byte[] receiveAmopMsg(AmopMsgIn msg) { + if (msg.getContent().length > 8) { + byte[] content = msg.getContent(); + byte[] byteflag = subbytes(content, 0, 4); + int flag = byteArrayToInt(byteflag); + if (flag == -128) { + byte[] bytelength = subbytes(content, 4, 4); + int length = byteArrayToInt(bytelength); + byte[] bytefilename = subbytes(content, 8, length); + String filename = new String(bytefilename); + System.out.println( + "Step 2:Receive file, filename length:" + + length + + " filename binary:" + + Arrays.toString(bytefilename) + + " filename:" + + filename); + + int contentlength = content.length - 8 - filename.length(); + byte[] fileContent = subbytes(content, 8 + filename.length(), contentlength); + getFileFromBytes(fileContent, filename); + System.out.println("|---save file:" + filename + " success"); + byte[] responseData = "Yes, I received!".getBytes(); + if (msg.getType() == (short) MsgType.AMOP_REQUEST.getType()) { + System.out.println("|---response:" + new String(responseData)); + } + return responseData; + } + } + + byte[] responseData = "Yes, I received!".getBytes(); + System.out.println( + "Step 2:Receive msg, topic:" + + msg.getTopic() + + " content:" + + new String(msg.getContent())); + if (msg.getType() == (short) MsgType.AMOP_REQUEST.getType()) { + System.out.println("|---response:" + new String(responseData)); + } + return responseData; + } + + public static byte[] subbytes(byte[] src, int begin, int count) { + byte[] bs = new byte[count]; + System.arraycopy(src, begin, bs, 0, count); + return bs; + } + + public static void getFileFromBytes(byte[] b, String outputFile) { + File ret = null; + BufferedOutputStream stream = null; + FileOutputStream fstream = null; + try { + ret = new File(outputFile); + fstream = new FileOutputStream(ret); + stream = new BufferedOutputStream(fstream); + stream.write(b); + } catch (Exception e) { + logger.error(" write exception, message: {}", e.getMessage()); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + logger.error(" close exception, message: {}", e.getMessage()); + } + } + + if (fstream != null) { + try { + fstream.close(); + } catch (IOException e) { + logger.error(" close exception, message: {}", e.getMessage()); + } + } + } + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/FileToByteArrayHelper.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/FileToByteArrayHelper.java new file mode 100644 index 000000000..8398fdcb2 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/amop/tool/FileToByteArrayHelper.java @@ -0,0 +1,47 @@ +package org.fisco.bcos.sdk.demo.amop.tool; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +public class FileToByteArrayHelper { + public static byte[] getFileByteArray(File file) { + long fileSize = file.length(); + if (fileSize > Integer.MAX_VALUE) { + System.out.println("file too big..."); + return null; + } + byte[] buffer = null; + try (FileInputStream fi = new FileInputStream(file)) { + buffer = new byte[(int) fileSize]; + int offset = 0; + int numRead = 0; + while (offset < buffer.length + && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) { + offset += numRead; + } + if (offset != buffer.length) { + throw new IOException("Could not completely read file " + file.getName()); + } + } catch (Exception e) { + e.printStackTrace(); + } + return buffer; + } + + public static byte[] byteCat(byte[] data1, byte[] data2) { + byte[] data3 = new byte[data1.length + data2.length]; + System.arraycopy(data1, 0, data3, 0, data1.length); + System.arraycopy(data2, 0, data3, data1.length, data2.length); + return data3; + } + + public static byte[] intToByteArray(int i) { + byte[] result = new byte[4]; + result[0] = (byte) ((i >> 24) & 0xFF); + result[1] = (byte) ((i >> 16) & 0xFF); + result[2] = (byte) ((i >> 8) & 0xFF); + result[3] = (byte) (i & 0xFF); + return result; + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/codegen/CompileSolidityException.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/codegen/CompileSolidityException.java new file mode 100644 index 000000000..02fc40c4e --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/codegen/CompileSolidityException.java @@ -0,0 +1,25 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.demo.codegen; + +/** Exceptioned when calling hash. */ +public class CompileSolidityException extends RuntimeException { + public CompileSolidityException(String message) { + super(message); + } + + public CompileSolidityException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/codegen/DemoSolcToJava.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/codegen/DemoSolcToJava.java new file mode 100644 index 000000000..c07c34c63 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/codegen/DemoSolcToJava.java @@ -0,0 +1,164 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.demo.codegen; + +import static org.fisco.solc.compiler.SolidityCompiler.Options.ABI; +import static org.fisco.solc.compiler.SolidityCompiler.Options.BIN; +import static org.fisco.solc.compiler.SolidityCompiler.Options.INTERFACE; +import static org.fisco.solc.compiler.SolidityCompiler.Options.METADATA; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Arrays; +import org.fisco.bcos.sdk.codegen.CodeGenMain; +import org.fisco.solc.compiler.CompilationResult; +import org.fisco.solc.compiler.SolidityCompiler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DemoSolcToJava { + + private static final Logger logger = LoggerFactory.getLogger(DemoSolcToJava.class); + + public static final String SOLIDITY_PATH = "contracts/solidity/"; + public static final String JAVA_PATH = "contracts/sdk/java/"; + public static final String ABI_PATH = "contracts/sdk/abi/"; + public static final String BIN_PATH = "contracts/sdk/bin/"; + + public static void main(String[] args) { + if (args.length < 1) { + System.out.println("Please provide a package name."); + return; + } + + File solFileList = new File(SOLIDITY_PATH); + File javaPath = new File(JAVA_PATH); + if (!javaPath.exists()) { + javaPath.mkdirs(); + } + File abiPath = new File(ABI_PATH + File.separator + "sm"); + if (!abiPath.exists()) { + abiPath.mkdirs(); + } + File binPath = new File(BIN_PATH + File.separator + "sm"); + if (!binPath.exists()) { + binPath.mkdirs(); + } + String tempDirPath = javaPath.getAbsolutePath(); + try { + compileSolToJava("*", tempDirPath, args[0], solFileList, ABI_PATH, BIN_PATH); + System.out.println( + "\nCompile solidity contract files to java contract files successfully!"); + } catch (IOException | CompileSolidityException e) { + System.out.print(e.getMessage()); + logger.error(" message: {}, e: {}", e.getMessage(), e); + } + } + + private static void writeStringToFile(String destFile, String content) throws IOException { + FileOutputStream fos = new FileOutputStream(destFile); + fos.write(content.getBytes()); + fos.close(); + } + + public static void compileSolToJava( + String solName, + String tempDirPath, + String packageName, + File solFileList, + String abiDir, + String binDir) + throws IOException { + File[] solFiles = solFileList.listFiles(); + if (solFiles.length == 0) { + System.out.println("The contracts directory is empty."); + return; + } + for (File solFile : solFiles) { + if (!solFile.getName().endsWith(".sol")) { + continue; + } + if (!"*".equals(solName)) { + if (!solFile.getName().equals(solName)) { + continue; + } + if (solFile.getName().startsWith("Lib")) { + throw new IOException("Don't deploy the library: " + solFile.getName()); + } + } else { + if (solFile.getName().startsWith("Lib")) { + continue; + } + } + + String contractName = solFile.getName().split("\\.")[0]; + + /** ecdsa compile */ + SolidityCompiler.Result res = + SolidityCompiler.compile(solFile, false, true, ABI, BIN, INTERFACE, METADATA); + logger.debug( + " solidity compiler result, success: {}, output: {}", + !res.isFailed(), + res.getOutput()); + if (res.isFailed() || "".equals(res.getOutput())) { + throw new CompileSolidityException(" Compile error: " + res.getErrors()); + } + + /** sm compile */ + SolidityCompiler.Result smRes = + SolidityCompiler.compile(solFile, true, true, ABI, BIN, INTERFACE, METADATA); + logger.debug( + " sm solidity compiler result, success: {}, output: {}, error: {}", + !smRes.isFailed(), + smRes.getOutput(), + smRes.getErrors()); + if (smRes.isFailed() || "".equals(smRes.getOutput())) { + throw new CompileSolidityException(" Compile SM error: " + res.getErrors()); + } + + CompilationResult result = CompilationResult.parse(res.getOutput()); + CompilationResult smResult = CompilationResult.parse(smRes.getOutput()); + + CompilationResult.ContractMetadata meta = result.getContract(contractName); + CompilationResult.ContractMetadata smMeta = smResult.getContract(contractName); + + writeStringToFile(new File(abiDir + contractName + ".abi").getAbsolutePath(), meta.abi); + writeStringToFile(new File(binDir + contractName + ".bin").getAbsolutePath(), meta.bin); + + writeStringToFile( + new File(abiDir + "/sm/" + contractName + ".abi").getAbsolutePath(), + smMeta.abi); + writeStringToFile( + new File(binDir + "/sm/" + contractName + ".bin").getAbsolutePath(), + smMeta.bin); + + String binFile; + String abiFile; + String smBinFile; + String filename = contractName; + abiFile = abiDir + filename + ".abi"; + binFile = binDir + filename + ".bin"; + smBinFile = binDir + "/sm/" + filename + ".bin"; + CodeGenMain.main( + Arrays.asList( + "-a", abiFile, + "-b", binFile, + "-s", smBinFile, + "-p", packageName, + "-o", tempDirPath) + .toArray(new String[0])); + } + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/DagTransfer.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/DagTransfer.java new file mode 100644 index 000000000..fccf250b8 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/DagTransfer.java @@ -0,0 +1,322 @@ +package org.fisco.bcos.sdk.demo.contract; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.abi.FunctionReturnDecoder; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Uint256; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple1; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple3; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.Contract; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; + +@SuppressWarnings("unchecked") +public class DagTransfer extends Contract { + public static final String[] BINARY_ARRAY = {}; + + public static final String BINARY = String.join("", BINARY_ARRAY); + + public static final String[] SM_BINARY_ARRAY = {}; + + public static final String SM_BINARY = String.join("", SM_BINARY_ARRAY); + + public static final String[] ABI_ARRAY = { + "[{\"constant\":false,\"inputs\":[{\"name\":\"user_a\",\"type\":\"string\"},{\"name\":\"user_b\",\"type\":\"string\"},{\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"userTransfer\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"user\",\"type\":\"string\"}],\"name\":\"userBalance\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"},{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"user\",\"type\":\"string\"},{\"name\":\"balance\",\"type\":\"uint256\"}],\"name\":\"userAdd\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"user\",\"type\":\"string\"},{\"name\":\"balance\",\"type\":\"uint256\"}],\"name\":\"userSave\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"user\",\"type\":\"string\"},{\"name\":\"balance\",\"type\":\"uint256\"}],\"name\":\"userDraw\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" + }; + + public static final String ABI = String.join("", ABI_ARRAY); + + public static final String FUNC_USERTRANSFER = "userTransfer"; + + public static final String FUNC_USERBALANCE = "userBalance"; + + public static final String FUNC_USERADD = "userAdd"; + + public static final String FUNC_USERSAVE = "userSave"; + + public static final String FUNC_USERDRAW = "userDraw"; + + protected DagTransfer(String contractAddress, Client client, CryptoKeyPair credential) { + super(getBinary(client.getCryptoSuite()), contractAddress, client, credential); + } + + public static String getBinary(CryptoSuite cryptoSuite) { + return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY); + } + + public TransactionReceipt userTransfer(String user_a, String user_b, BigInteger amount) { + final Function function = + new Function( + FUNC_USERTRANSFER, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user_a), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user_b), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(amount)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void userTransfer( + String user_a, String user_b, BigInteger amount, TransactionCallback callback) { + final Function function = + new Function( + FUNC_USERTRANSFER, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user_a), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user_b), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(amount)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForUserTransfer( + String user_a, String user_b, BigInteger amount) { + final Function function = + new Function( + FUNC_USERTRANSFER, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user_a), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user_b), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(amount)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple3 getUserTransferInput( + TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_USERTRANSFER, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple3( + (String) results.get(0).getValue(), + (String) results.get(1).getValue(), + (BigInteger) results.get(2).getValue()); + } + + public Tuple1 getUserTransferOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_USERTRANSFER, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public Tuple2 userBalance(String user) throws ContractException { + final Function function = + new Function( + FUNC_USERBALANCE, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user)), + Arrays.>asList( + new TypeReference() {}, new TypeReference() {})); + List results = executeCallWithMultipleValueReturn(function); + return new Tuple2( + (BigInteger) results.get(0).getValue(), (BigInteger) results.get(1).getValue()); + } + + public TransactionReceipt userAdd(String user, BigInteger balance) { + final Function function = + new Function( + FUNC_USERADD, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(balance)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void userAdd(String user, BigInteger balance, TransactionCallback callback) { + final Function function = + new Function( + FUNC_USERADD, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(balance)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForUserAdd(String user, BigInteger balance) { + final Function function = + new Function( + FUNC_USERADD, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(balance)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple2 getUserAddInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_USERADD, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple2( + (String) results.get(0).getValue(), (BigInteger) results.get(1).getValue()); + } + + public Tuple1 getUserAddOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_USERADD, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public TransactionReceipt userSave(String user, BigInteger balance) { + final Function function = + new Function( + FUNC_USERSAVE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(balance)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void userSave(String user, BigInteger balance, TransactionCallback callback) { + final Function function = + new Function( + FUNC_USERSAVE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(balance)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForUserSave(String user, BigInteger balance) { + final Function function = + new Function( + FUNC_USERSAVE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(balance)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple2 getUserSaveInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_USERSAVE, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple2( + (String) results.get(0).getValue(), (BigInteger) results.get(1).getValue()); + } + + public Tuple1 getUserSaveOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_USERSAVE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public TransactionReceipt userDraw(String user, BigInteger balance) { + final Function function = + new Function( + FUNC_USERDRAW, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(balance)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void userDraw(String user, BigInteger balance, TransactionCallback callback) { + final Function function = + new Function( + FUNC_USERDRAW, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(balance)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForUserDraw(String user, BigInteger balance) { + final Function function = + new Function( + FUNC_USERDRAW, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(user), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(balance)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple2 getUserDrawInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_USERDRAW, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple2( + (String) results.get(0).getValue(), (BigInteger) results.get(1).getValue()); + } + + public Tuple1 getUserDrawOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_USERDRAW, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public static DagTransfer load( + String contractAddress, Client client, CryptoKeyPair credential) { + return new DagTransfer(contractAddress, client, credential); + } + + public static DagTransfer deploy(Client client, CryptoKeyPair credential) + throws ContractException { + return deploy( + DagTransfer.class, client, credential, getBinary(client.getCryptoSuite()), ""); + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/HelloWorld.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/HelloWorld.java new file mode 100644 index 000000000..8dce787d4 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/HelloWorld.java @@ -0,0 +1,108 @@ +package org.fisco.bcos.sdk.demo.contract; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.abi.FunctionReturnDecoder; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple1; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.Contract; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; + +@SuppressWarnings("unchecked") +public class HelloWorld extends Contract { + public static final String[] BINARY_ARRAY = { + "608060405234801561001057600080fd5b506040805190810160405280600d81526020017f48656c6c6f2c20576f726c6421000000000000000000000000000000000000008152506000908051906020019061005c929190610062565b50610107565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100a357805160ff19168380011785556100d1565b828001600101855582156100d1579182015b828111156100d05782518255916020019190600101906100b5565b5b5090506100de91906100e2565b5090565b61010491905b808211156101005760008160009055506001016100e8565b5090565b90565b6102d7806101166000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680634ed3885e146100515780636d4ce63c146100ba575b600080fd5b34801561005d57600080fd5b506100b8600480360381019080803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061014a565b005b3480156100c657600080fd5b506100cf610164565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561010f5780820151818401526020810190506100f4565b50505050905090810190601f16801561013c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b8060009080519060200190610160929190610206565b5050565b606060008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101fc5780601f106101d1576101008083540402835291602001916101fc565b820191906000526020600020905b8154815290600101906020018083116101df57829003601f168201915b5050505050905090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061024757805160ff1916838001178555610275565b82800160010185558215610275579182015b82811115610274578251825591602001919060010190610259565b5b5090506102829190610286565b5090565b6102a891905b808211156102a457600081600090555060010161028c565b5090565b905600a165627a7a7230582035f32cd11f4fdc4d12abab1850ea5b401f853d9ef91e913e4e82d34efa18a2210029" + }; + + public static final String BINARY = String.join("", BINARY_ARRAY); + + public static final String[] SM_BINARY_ARRAY = { + "608060405234801561001057600080fd5b506040805190810160405280600d81526020017f48656c6c6f2c20576f726c6421000000000000000000000000000000000000008152506000908051906020019061005c929190610062565b50610107565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100a357805160ff19168380011785556100d1565b828001600101855582156100d1579182015b828111156100d05782518255916020019190600101906100b5565b5b5090506100de91906100e2565b5090565b61010491905b808211156101005760008160009055506001016100e8565b5090565b90565b6102d7806101166000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063299f7f9d146100515780633590b49f146100e1575b600080fd5b34801561005d57600080fd5b5061006661014a565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100a657808201518184015260208101905061008b565b50505050905090810190601f1680156100d35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156100ed57600080fd5b50610148600480360381019080803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506101ec565b005b606060008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101e25780601f106101b7576101008083540402835291602001916101e2565b820191906000526020600020905b8154815290600101906020018083116101c557829003601f168201915b5050505050905090565b8060009080519060200190610202929190610206565b5050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061024757805160ff1916838001178555610275565b82800160010185558215610275579182015b82811115610274578251825591602001919060010190610259565b5b5090506102829190610286565b5090565b6102a891905b808211156102a457600081600090555060010161028c565b5090565b905600a165627a7a72305820ddb4a8b4c62e003ac9d6ca2396325dcea3b9441c5d2af668d4ccb883a9af271b0029" + }; + + public static final String SM_BINARY = String.join("", SM_BINARY_ARRAY); + + public static final String[] ABI_ARRAY = { + "[{\"constant\":false,\"inputs\":[{\"name\":\"n\",\"type\":\"string\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]" + }; + + public static final String ABI = String.join("", ABI_ARRAY); + + public static final String FUNC_SET = "set"; + + public static final String FUNC_GET = "get"; + + protected HelloWorld(String contractAddress, Client client, CryptoKeyPair credential) { + super(getBinary(client.getCryptoSuite()), contractAddress, client, credential); + } + + public static String getBinary(CryptoSuite cryptoSuite) { + return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY); + } + + public TransactionReceipt set(String n) { + final Function function = + new Function( + FUNC_SET, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(n)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void set(String n, TransactionCallback callback) { + final Function function = + new Function( + FUNC_SET, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(n)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForSet(String n) { + final Function function = + new Function( + FUNC_SET, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(n)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple1 getSetInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_SET, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((String) results.get(0).getValue()); + } + + public String get() throws ContractException { + final Function function = + new Function( + FUNC_GET, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + return executeCallWithSingleValueReturn(function, String.class); + } + + public static HelloWorld load(String contractAddress, Client client, CryptoKeyPair credential) { + return new HelloWorld(contractAddress, client, credential); + } + + public static HelloWorld deploy(Client client, CryptoKeyPair credential) + throws ContractException { + return deploy(HelloWorld.class, client, credential, getBinary(client.getCryptoSuite()), ""); + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/Ok.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/Ok.java new file mode 100644 index 000000000..c37257e4d --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/Ok.java @@ -0,0 +1,151 @@ +package org.fisco.bcos.sdk.demo.contract; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.abi.FunctionReturnDecoder; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.datatypes.Event; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.generated.Uint256; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple1; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.Contract; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.eventsub.EventCallback; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; + +@SuppressWarnings("unchecked") +public class Ok extends Contract { + public static final String[] BINARY_ARRAY = { + "608060405234801561001057600080fd5b5060016000800160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506402540be40060006001018190555060028060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060006002600101819055506103bf806100c26000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806366c99139146100515780636d4ce63c1461007e575b600080fd5b34801561005d57600080fd5b5061007c600480360381019080803590602001909291905050506100a9565b005b34801561008a57600080fd5b506100936102e1565b6040518082815260200191505060405180910390f35b8060006001015410806100c757506002600101548160026001015401105b156100d1576102de565b8060006001015403600060010181905550806002600101600082825401925050819055507fc77b710b83d1dc3f3fafeccd08a6c469beb873b2f0975b50d1698e46b3ee5b4c816040518082815260200191505060405180910390a160046080604051908101604052806040805190810160405280600881526020017f323031373034313300000000000000000000000000000000000000000000000081525081526020016000800160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600260000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001838152509080600181540180825580915050906001820390600052602060002090600402016000909192909190915060008201518160000190805190602001906102419291906102ee565b5060208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550606082015181600301555050505b50565b6000600260010154905090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061032f57805160ff191683800117855561035d565b8280016001018555821561035d579182015b8281111561035c578251825591602001919060010190610341565b5b50905061036a919061036e565b5090565b61039091905b8082111561038c576000816000905550600101610374565b5090565b905600a165627a7a723058208e45b63292be04a7dc7a9721084c85fff95b392534d9e9362cf84a1b75be8dc80029" + }; + + public static final String BINARY = String.join("", BINARY_ARRAY); + + public static final String[] SM_BINARY_ARRAY = { + "608060405234801561001057600080fd5b5060016000800160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506402540be40060006001018190555060028060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060006002600101819055506103bf806100c26000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063299f7f9d146100515780638fff0fc41461007c575b600080fd5b34801561005d57600080fd5b506100666100a9565b6040518082815260200191505060405180910390f35b34801561008857600080fd5b506100a7600480360381019080803590602001909291905050506100b6565b005b6000600260010154905090565b8060006001015410806100d457506002600101548160026001015401105b156100de576102eb565b8060006001015403600060010181905550806002600101600082825401925050819055507fc345610041c3c141ff9e0fbc73b34bf13842fd02e0c3cfe6541eedd6adef4b2c816040518082815260200191505060405180910390a160046080604051908101604052806040805190810160405280600881526020017f323031373034313300000000000000000000000000000000000000000000000081525081526020016000800160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600260000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018381525090806001815401808255809150509060018203906000526020600020906004020160009091929091909150600082015181600001908051906020019061024e9291906102ee565b5060208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550606082015181600301555050505b50565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061032f57805160ff191683800117855561035d565b8280016001018555821561035d579182015b8281111561035c578251825591602001919060010190610341565b5b50905061036a919061036e565b5090565b61039091905b8082111561038c576000816000905550600101610374565b5090565b905600a165627a7a72305820760c6c97c0ebf59ab2bb361d87b702ca01db177b03e7f76dc57ece4f04aa3e9d0029" + }; + + public static final String SM_BINARY = String.join("", SM_BINARY_ARRAY); + + public static final String[] ABI_ARRAY = { + "[{\"constant\":false,\"inputs\":[{\"name\":\"num\",\"type\":\"uint256\"}],\"name\":\"trans\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"num\",\"type\":\"uint256\"}],\"name\":\"TransEvent\",\"type\":\"event\"}]" + }; + + public static final String ABI = String.join("", ABI_ARRAY); + + public static final String FUNC_TRANS = "trans"; + + public static final String FUNC_GET = "get"; + + public static final Event TRANSEVENT_EVENT = + new Event( + "TransEvent", + Arrays.>asList(new TypeReference() {}));; + + protected Ok(String contractAddress, Client client, CryptoKeyPair credential) { + super(getBinary(client.getCryptoSuite()), contractAddress, client, credential); + } + + public static String getBinary(CryptoSuite cryptoSuite) { + return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY); + } + + public TransactionReceipt trans(BigInteger num) { + final Function function = + new Function( + FUNC_TRANS, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(num)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void trans(BigInteger num, TransactionCallback callback) { + final Function function = + new Function( + FUNC_TRANS, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(num)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForTrans(BigInteger num) { + final Function function = + new Function( + FUNC_TRANS, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(num)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple1 getTransInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_TRANS, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public BigInteger get() throws ContractException { + final Function function = + new Function( + FUNC_GET, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + return executeCallWithSingleValueReturn(function, BigInteger.class); + } + + public List getTransEventEvents( + TransactionReceipt transactionReceipt) { + List valueList = + extractEventParametersWithLog(TRANSEVENT_EVENT, transactionReceipt); + ArrayList responses = + new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + TransEventEventResponse typedResponse = new TransEventEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.num = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public void subscribeTransEventEvent( + String fromBlock, String toBlock, List otherTopics, EventCallback callback) { + String topic0 = eventEncoder.encode(TRANSEVENT_EVENT); + subscribeEvent(ABI, BINARY, topic0, fromBlock, toBlock, otherTopics, callback); + } + + public void subscribeTransEventEvent(EventCallback callback) { + String topic0 = eventEncoder.encode(TRANSEVENT_EVENT); + subscribeEvent(ABI, BINARY, topic0, callback); + } + + public static Ok load(String contractAddress, Client client, CryptoKeyPair credential) { + return new Ok(contractAddress, client, credential); + } + + public static Ok deploy(Client client, CryptoKeyPair credential) throws ContractException { + return deploy(Ok.class, client, credential, getBinary(client.getCryptoSuite()), ""); + } + + public static class TransEventEventResponse { + public TransactionReceipt.Logs log; + + public BigInteger num; + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/OkD.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/OkD.java new file mode 100644 index 000000000..864bb7aab --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/OkD.java @@ -0,0 +1,158 @@ +package org.fisco.bcos.sdk.demo.contract; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.abi.FunctionReturnDecoder; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.datatypes.Event; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Int256; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.Contract; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.eventsub.EventCallback; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; + +@SuppressWarnings("unchecked") +public class OkD extends Contract { + public static final String[] BINARY_ARRAY = { + "608060405234801561001057600080fd5b50600080600060016000800160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506402540be40060006001018190555060028060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600060026001018190555061100192508273ffffffffffffffffffffffffffffffffffffffff166356004b6a6040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180806020018060200180602001848103845260048152602001807f745f6f6b000000000000000000000000000000000000000000000000000000008152506020018481038352600b8152602001807f66726f6d5f6163636f7574000000000000000000000000000000000000000000815250602001848103825260218152602001807f66726f6d5f62616c616e63652c746f5f6163636f75742c746f5f62616c616e6381526020017f65000000000000000000000000000000000000000000000000000000000000008152506040019350505050602060405180830381600087803b1580156101f557600080fd5b505af1158015610209573d6000803e3d6000fd5b505050506040513d602081101561021f57600080fd5b81019080805190602001909291905050505061100192508273ffffffffffffffffffffffffffffffffffffffff1663f23f63c96040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825260048152602001807f745f6f6b00000000000000000000000000000000000000000000000000000000815250602001915050602060405180830381600087803b1580156102d657600080fd5b505af11580156102ea573d6000803e3d6000fd5b505050506040513d602081101561030057600080fd5b810190808051906020019092919050505091508173ffffffffffffffffffffffffffffffffffffffff166313db93466040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561037757600080fd5b505af115801561038b573d6000803e3d6000fd5b505050506040513d60208110156103a157600080fd5b810190808051906020019092919050505090508073ffffffffffffffffffffffffffffffffffffffff1663e942b5166040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001806020018381038352600b8152602001807f66726f6d5f6163636f7574000000000000000000000000000000000000000000815250602001838103825260038152602001807f307831000000000000000000000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b15801561048d57600080fd5b505af11580156104a1573d6000803e3d6000fd5b505050508073ffffffffffffffffffffffffffffffffffffffff1663e942b5166040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001806020018381038352600c8152602001807f66726f6d5f62616c616e636500000000000000000000000000000000000000008152506020018381038252600b8152602001807f313030303030303030303000000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b15801561057e57600080fd5b505af1158015610592573d6000803e3d6000fd5b505050508073ffffffffffffffffffffffffffffffffffffffff1663e942b5166040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808060200180602001838103835260098152602001807f746f5f6163636f75740000000000000000000000000000000000000000000000815250602001838103825260038152602001807f307832000000000000000000000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b15801561066f57600080fd5b505af1158015610683573d6000803e3d6000fd5b505050508073ffffffffffffffffffffffffffffffffffffffff1663e942b5166040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001806020018381038352600a8152602001807f746f5f62616c616e636500000000000000000000000000000000000000000000815250602001838103825260018152602001807f300000000000000000000000000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b15801561076057600080fd5b505af1158015610774573d6000803e3d6000fd5b505050505050506108228061078a6000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636d4ce63c14610051578063abe181b51461007c575b600080fd5b34801561005d57600080fd5b506100666100ef565b6040518082815260200191505060405180910390f35b34801561008857600080fd5b506100ed600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001909291905050506100fc565b005b6000600260010154905090565b60008060008084600060010154128061012057506002600101548560026001015401125b1561012a576107ee565b84600060010154036000600101819055508460026001016000828254019250508190555061100193508373ffffffffffffffffffffffffffffffffffffffff1663f23f63c96040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825260048152602001807f745f6f6b00000000000000000000000000000000000000000000000000000000815250602001915050602060405180830381600087803b1580156101f357600080fd5b505af1158015610207573d6000803e3d6000fd5b505050506040513d602081101561021d57600080fd5b810190808051906020019092919050505092508273ffffffffffffffffffffffffffffffffffffffff166313db93466040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561029457600080fd5b505af11580156102a8573d6000803e3d6000fd5b505050506040513d60208110156102be57600080fd5b810190808051906020019092919050505091508173ffffffffffffffffffffffffffffffffffffffff1663e942b516876040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001806020018381038352600b8152602001807f66726f6d5f6163636f7574000000000000000000000000000000000000000000815250602001838103825284818151815260200191508051906020019080838360005b83811015610391578082015181840152602081019050610376565b50505050905090810190601f1680156103be5780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b1580156103de57600080fd5b505af11580156103f2573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff16632ef8ba746000600101546040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180806020018381526020018281038252600c8152602001807f66726f6d5f62616c616e6365000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b1580156104a357600080fd5b505af11580156104b7573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff1663e942b5166040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808060200180602001838103835260098152602001807f746f5f6163636f75740000000000000000000000000000000000000000000000815250602001838103825260038152602001807f307832000000000000000000000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b15801561059457600080fd5b505af11580156105a8573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff16632ef8ba746002600101546040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180806020018381526020018281038252600a8152602001807f746f5f62616c616e63650000000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b15801561065957600080fd5b505af115801561066d573d6000803e3d6000fd5b505050508273ffffffffffffffffffffffffffffffffffffffff166331afac3687846040518363ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180806020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818151815260200191508051906020019080838360005b8381101561072c578082015181840152602081019050610711565b50505050905090810190601f1680156107595780820380516001836020036101000a031916815260200191505b509350505050602060405180830381600087803b15801561077957600080fd5b505af115801561078d573d6000803e3d6000fd5b505050506040513d60208110156107a357600080fd5b810190808051906020019092919050505090507f66f7705280112a4d1145399e0414adc43a2d6974b487710f417edcf7d4a39d71816040518082815260200191505060405180910390a15b5050505050505600a165627a7a72305820307df815a9c714eb36e529357cd78a05148a38f1832b64df2a805a405586ef3e0029" + }; + + public static final String BINARY = String.join("", BINARY_ARRAY); + + public static final String[] SM_BINARY_ARRAY = { + "608060405234801561001057600080fd5b50600080600060016000800160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506402540be40060006001018190555060028060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600060026001018190555061100192508273ffffffffffffffffffffffffffffffffffffffff1663c92a78016040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180806020018060200180602001848103845260048152602001807f745f6f6b000000000000000000000000000000000000000000000000000000008152506020018481038352600b8152602001807f66726f6d5f6163636f7574000000000000000000000000000000000000000000815250602001848103825260218152602001807f66726f6d5f62616c616e63652c746f5f6163636f75742c746f5f62616c616e6381526020017f65000000000000000000000000000000000000000000000000000000000000008152506040019350505050602060405180830381600087803b1580156101f557600080fd5b505af1158015610209573d6000803e3d6000fd5b505050506040513d602081101561021f57600080fd5b81019080805190602001909291905050505061100192508273ffffffffffffffffffffffffffffffffffffffff166359a48b656040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825260048152602001807f745f6f6b00000000000000000000000000000000000000000000000000000000815250602001915050602060405180830381600087803b1580156102d657600080fd5b505af11580156102ea573d6000803e3d6000fd5b505050506040513d602081101561030057600080fd5b810190808051906020019092919050505091508173ffffffffffffffffffffffffffffffffffffffff16635887ab246040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561037757600080fd5b505af115801561038b573d6000803e3d6000fd5b505050506040513d60208110156103a157600080fd5b810190808051906020019092919050505090508073ffffffffffffffffffffffffffffffffffffffff16631a391cb46040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001806020018381038352600b8152602001807f66726f6d5f6163636f7574000000000000000000000000000000000000000000815250602001838103825260038152602001807f307831000000000000000000000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b15801561048d57600080fd5b505af11580156104a1573d6000803e3d6000fd5b505050508073ffffffffffffffffffffffffffffffffffffffff16631a391cb46040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001806020018381038352600c8152602001807f66726f6d5f62616c616e636500000000000000000000000000000000000000008152506020018381038252600b8152602001807f313030303030303030303000000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b15801561057e57600080fd5b505af1158015610592573d6000803e3d6000fd5b505050508073ffffffffffffffffffffffffffffffffffffffff16631a391cb46040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808060200180602001838103835260098152602001807f746f5f6163636f75740000000000000000000000000000000000000000000000815250602001838103825260038152602001807f307832000000000000000000000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b15801561066f57600080fd5b505af1158015610683573d6000803e3d6000fd5b505050508073ffffffffffffffffffffffffffffffffffffffff16631a391cb46040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001806020018381038352600a8152602001807f746f5f62616c616e636500000000000000000000000000000000000000000000815250602001838103825260018152602001807f300000000000000000000000000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b15801561076057600080fd5b505af1158015610774573d6000803e3d6000fd5b505050505050506108228061078a6000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063299f7f9d1461005157806390749a5e1461007c575b600080fd5b34801561005d57600080fd5b506100666100ef565b6040518082815260200191505060405180910390f35b34801561008857600080fd5b506100ed600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001909291905050506100fc565b005b6000600260010154905090565b60008060008084600060010154128061012057506002600101548560026001015401125b1561012a576107ee565b84600060010154036000600101819055508460026001016000828254019250508190555061100193508373ffffffffffffffffffffffffffffffffffffffff166359a48b656040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825260048152602001807f745f6f6b00000000000000000000000000000000000000000000000000000000815250602001915050602060405180830381600087803b1580156101f357600080fd5b505af1158015610207573d6000803e3d6000fd5b505050506040513d602081101561021d57600080fd5b810190808051906020019092919050505092508273ffffffffffffffffffffffffffffffffffffffff16635887ab246040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561029457600080fd5b505af11580156102a8573d6000803e3d6000fd5b505050506040513d60208110156102be57600080fd5b810190808051906020019092919050505091508173ffffffffffffffffffffffffffffffffffffffff16631a391cb4876040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001806020018381038352600b8152602001807f66726f6d5f6163636f7574000000000000000000000000000000000000000000815250602001838103825284818151815260200191508051906020019080838360005b83811015610391578082015181840152602081019050610376565b50505050905090810190601f1680156103be5780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b1580156103de57600080fd5b505af11580156103f2573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff1663def426986000600101546040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180806020018381526020018281038252600c8152602001807f66726f6d5f62616c616e6365000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b1580156104a357600080fd5b505af11580156104b7573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff16631a391cb46040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808060200180602001838103835260098152602001807f746f5f6163636f75740000000000000000000000000000000000000000000000815250602001838103825260038152602001807f307832000000000000000000000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b15801561059457600080fd5b505af11580156105a8573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff1663def426986002600101546040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180806020018381526020018281038252600a8152602001807f746f5f62616c616e63650000000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b15801561065957600080fd5b505af115801561066d573d6000803e3d6000fd5b505050508273ffffffffffffffffffffffffffffffffffffffff16634c6f30c087846040518363ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180806020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818151815260200191508051906020019080838360005b8381101561072c578082015181840152602081019050610711565b50505050905090810190601f1680156107595780820380516001836020036101000a031916815260200191505b509350505050602060405180830381600087803b15801561077957600080fd5b505af115801561078d573d6000803e3d6000fd5b505050506040513d60208110156107a357600080fd5b810190808051906020019092919050505090507f11edf97b45aa6c006853fb598a4a9be2e678d9498feb5e6c1f389b491e12bc4a816040518082815260200191505060405180910390a15b5050505050505600a165627a7a72305820e07034d3e12dfdf1f20c39aa151a5623c7b2690d56eab36fedd1ca3fedce899d0029" + }; + + public static final String SM_BINARY = String.join("", SM_BINARY_ARRAY); + + public static final String[] ABI_ARRAY = { + "[{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from_accout\",\"type\":\"string\"},{\"name\":\"num\",\"type\":\"int256\"}],\"name\":\"trans\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"count\",\"type\":\"int256\"}],\"name\":\"insertResult\",\"type\":\"event\"}]" + }; + + public static final String ABI = String.join("", ABI_ARRAY); + + public static final String FUNC_GET = "get"; + + public static final String FUNC_TRANS = "trans"; + + public static final Event INSERTRESULT_EVENT = + new Event( + "insertResult", + Arrays.>asList(new TypeReference() {}));; + + protected OkD(String contractAddress, Client client, CryptoKeyPair credential) { + super(getBinary(client.getCryptoSuite()), contractAddress, client, credential); + } + + public static String getBinary(CryptoSuite cryptoSuite) { + return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY); + } + + public BigInteger get() throws ContractException { + final Function function = + new Function( + FUNC_GET, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + return executeCallWithSingleValueReturn(function, BigInteger.class); + } + + public TransactionReceipt trans(String from_accout, BigInteger num) { + final Function function = + new Function( + FUNC_TRANS, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(from_accout), + new org.fisco.bcos.sdk.abi.datatypes.generated.Int256(num)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void trans(String from_accout, BigInteger num, TransactionCallback callback) { + final Function function = + new Function( + FUNC_TRANS, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(from_accout), + new org.fisco.bcos.sdk.abi.datatypes.generated.Int256(num)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForTrans(String from_accout, BigInteger num) { + final Function function = + new Function( + FUNC_TRANS, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(from_accout), + new org.fisco.bcos.sdk.abi.datatypes.generated.Int256(num)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple2 getTransInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_TRANS, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple2( + (String) results.get(0).getValue(), (BigInteger) results.get(1).getValue()); + } + + public List getInsertResultEvents( + TransactionReceipt transactionReceipt) { + List valueList = + extractEventParametersWithLog(INSERTRESULT_EVENT, transactionReceipt); + ArrayList responses = + new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + InsertResultEventResponse typedResponse = new InsertResultEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.count = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public void subscribeInsertResultEvent( + String fromBlock, String toBlock, List otherTopics, EventCallback callback) { + String topic0 = eventEncoder.encode(INSERTRESULT_EVENT); + subscribeEvent(ABI, BINARY, topic0, fromBlock, toBlock, otherTopics, callback); + } + + public void subscribeInsertResultEvent(EventCallback callback) { + String topic0 = eventEncoder.encode(INSERTRESULT_EVENT); + subscribeEvent(ABI, BINARY, topic0, callback); + } + + public static OkD load(String contractAddress, Client client, CryptoKeyPair credential) { + return new OkD(contractAddress, client, credential); + } + + public static OkD deploy(Client client, CryptoKeyPair credential) throws ContractException { + return deploy(OkD.class, client, credential, getBinary(client.getCryptoSuite()), ""); + } + + public static class InsertResultEventResponse { + public TransactionReceipt.Logs log; + + public BigInteger count; + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/ParallelOk.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/ParallelOk.java new file mode 100644 index 000000000..cb0776c06 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/ParallelOk.java @@ -0,0 +1,393 @@ +package org.fisco.bcos.sdk.demo.contract; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.abi.FunctionReturnDecoder; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Uint256; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple1; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple3; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.Contract; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; + +@SuppressWarnings("unchecked") +public class ParallelOk extends Contract { + public static final String[] BINARY_ARRAY = { + "60806040526110066000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561005257600080fd5b50610aeb806100626000396000f30060806040526004361061008e576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806334a18dda1461009357806335ee5f871461010657806379fa913f146101835780638a42ebe9146101ec5780639b80b0501461025f578063bca926af14610318578063d39f70bc1461032f578063fad42f8714610346575b600080fd5b34801561009f57600080fd5b50610104600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001909291905050506103ff565b005b34801561011257600080fd5b5061016d600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610570565b6040518082815260200191505060405180910390f35b34801561018f57600080fd5b506101ea600480360381019080803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506105e5565b005b3480156101f857600080fd5b5061025d600480360381019080803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192908035906020019092919050505061074d565b005b34801561026b57600080fd5b50610316600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001909291905050506107c1565b005b34801561032457600080fd5b5061032d6108b8565b005b34801561033b57600080fd5b5061034461093a565b005b34801561035257600080fd5b506103fd600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001909291905050506109b8565b005b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630553904e3084846040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156104e25780820151818401526020810190506104c7565b50505050905090810190601f16801561050f5780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600087803b15801561053057600080fd5b505af1158015610544573d6000803e3d6000fd5b505050506040513d602081101561055a57600080fd5b8101908080519060200190929190505050505050565b60006001826040518082805190602001908083835b6020831015156105aa5780518252602082019150602081019050602083039250610585565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020549050919050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166311e3f2af30836040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b838110156106c15780820151818401526020810190506106a6565b50505050905090810190601f1680156106ee5780820380516001836020036101000a031916815260200191505b509350505050602060405180830381600087803b15801561070e57600080fd5b505af1158015610722573d6000803e3d6000fd5b505050506040513d602081101561073857600080fd5b81019080805190602001909291905050505050565b806001836040518082805190602001908083835b6020831015156107865780518252602082019150602081019050602083039250610761565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020819055505050565b806001846040518082805190602001908083835b6020831015156107fa57805182526020820191506020810190506020830392506107d5565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902060008282540392505081905550806001836040518082805190602001908083835b602083101515610873578051825260208201915060208101905060208303925061084e565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902060008282540192505081905550505050565b6108f86040805190810160405280601f81526020017f7472616e7366657228737472696e672c737472696e672c75696e74323536290081525060026103ff565b6109386040805190810160405280601381526020017f73657428737472696e672c75696e74323536290000000000000000000000000081525060016103ff565b565b6109786040805190810160405280601f81526020017f7472616e7366657228737472696e672c737472696e672c75696e7432353629008152506105e5565b6109b66040805190810160405280601381526020017f73657428737472696e672c75696e7432353629000000000000000000000000008152506105e5565b565b806001846040518082805190602001908083835b6020831015156109f157805182526020820191506020810190506020830392506109cc565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902060008282540392505081905550806001836040518082805190602001908083835b602083101515610a6a5780518252602082019150602081019050602083039250610a45565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390206000828254019250508190555060648111151515610aba57600080fd5b5050505600a165627a7a723058203df637a9f27f60ded73c5d33efa5cfcb7b3a52fab87e18249ab9cdbf5566126d0029" + }; + + public static final String BINARY = String.join("", BINARY_ARRAY); + + public static final String[] SM_BINARY_ARRAY = { + "60806040526110066000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561005257600080fd5b50610aea806100626000396000f30060806040526004361061008d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168062f0e13314610092578063612d2bff146100fb578063748e7a1b146101b457806394618e4c146101cb578063ab71bf09146101e2578063b4c653e01461029b578063cd93c25d1461030e578063f2f4ee6d1461038b575b600080fd5b34801561009e57600080fd5b506100f9600480360381019080803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506103fe565b005b34801561010757600080fd5b506101b2600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929080359060200190929190505050610566565b005b3480156101c057600080fd5b506101c961065d565b005b3480156101d757600080fd5b506101e06106db565b005b3480156101ee57600080fd5b50610299600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192908035906020019092919050505061075d565b005b3480156102a757600080fd5b5061030c600480360381019080803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929080359060200190929190505050610864565b005b34801561031a57600080fd5b50610375600480360381019080803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506109d5565b6040518082815260200191505060405180910390f35b34801561039757600080fd5b506103fc600480360381019080803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929080359060200190929190505050610a4a565b005b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663714c65bd30836040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b838110156104da5780820151818401526020810190506104bf565b50505050905090810190601f1680156105075780820380516001836020036101000a031916815260200191505b509350505050602060405180830381600087803b15801561052757600080fd5b505af115801561053b573d6000803e3d6000fd5b505050506040513d602081101561055157600080fd5b81019080805190602001909291905050505050565b806001846040518082805190602001908083835b60208310151561059f578051825260208201915060208101905060208303925061057a565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902060008282540392505081905550806001836040518082805190602001908083835b60208310151561061857805182526020820191506020810190506020830392506105f3565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902060008282540192505081905550505050565b61069b6040805190810160405280601f81526020017f7472616e7366657228737472696e672c737472696e672c75696e7432353629008152506103fe565b6106d96040805190810160405280601381526020017f73657428737472696e672c75696e7432353629000000000000000000000000008152506103fe565b565b61071b6040805190810160405280601f81526020017f7472616e7366657228737472696e672c737472696e672c75696e7432353629008152506002610864565b61075b6040805190810160405280601381526020017f73657428737472696e672c75696e7432353629000000000000000000000000008152506001610864565b565b806001846040518082805190602001908083835b6020831015156107965780518252602082019150602081019050602083039250610771565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902060008282540392505081905550806001836040518082805190602001908083835b60208310151561080f57805182526020820191506020810190506020830392506107ea565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020600082825401925050819055506064811115151561085f57600080fd5b505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dc536a623084846040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b8381101561094757808201518184015260208101905061092c565b50505050905090810190601f1680156109745780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600087803b15801561099557600080fd5b505af11580156109a9573d6000803e3d6000fd5b505050506040513d60208110156109bf57600080fd5b8101908080519060200190929190505050505050565b60006001826040518082805190602001908083835b602083101515610a0f57805182526020820191506020810190506020830392506109ea565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020549050919050565b806001836040518082805190602001908083835b602083101515610a835780518252602082019150602081019050602083039250610a5e565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390208190555050505600a165627a7a72305820bdd068ddd29d31c6bd5b2d5ba93d15eec371fccc5579888cf009ac61aa91a8190029" + }; + + public static final String SM_BINARY = String.join("", SM_BINARY_ARRAY); + + public static final String[] ABI_ARRAY = { + "[{\"constant\":false,\"inputs\":[{\"name\":\"functionName\",\"type\":\"string\"},{\"name\":\"criticalSize\",\"type\":\"uint256\"}],\"name\":\"registerParallelFunction\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"functionName\",\"type\":\"string\"}],\"name\":\"unregisterParallelFunction\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"num\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"string\"},{\"name\":\"to\",\"type\":\"string\"},{\"name\":\"num\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"enableParallel\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"disableParallel\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"string\"},{\"name\":\"to\",\"type\":\"string\"},{\"name\":\"num\",\"type\":\"uint256\"}],\"name\":\"transferWithRevert\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" + }; + + public static final String ABI = String.join("", ABI_ARRAY); + + public static final String FUNC_REGISTERPARALLELFUNCTION = "registerParallelFunction"; + + public static final String FUNC_BALANCEOF = "balanceOf"; + + public static final String FUNC_UNREGISTERPARALLELFUNCTION = "unregisterParallelFunction"; + + public static final String FUNC_SET = "set"; + + public static final String FUNC_TRANSFER = "transfer"; + + public static final String FUNC_ENABLEPARALLEL = "enableParallel"; + + public static final String FUNC_DISABLEPARALLEL = "disableParallel"; + + public static final String FUNC_TRANSFERWITHREVERT = "transferWithRevert"; + + protected ParallelOk(String contractAddress, Client client, CryptoKeyPair credential) { + super(getBinary(client.getCryptoSuite()), contractAddress, client, credential); + } + + public static String getBinary(CryptoSuite cryptoSuite) { + return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY); + } + + public TransactionReceipt registerParallelFunction( + String functionName, BigInteger criticalSize) { + final Function function = + new Function( + FUNC_REGISTERPARALLELFUNCTION, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(functionName), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256( + criticalSize)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void registerParallelFunction( + String functionName, BigInteger criticalSize, TransactionCallback callback) { + final Function function = + new Function( + FUNC_REGISTERPARALLELFUNCTION, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(functionName), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256( + criticalSize)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForRegisterParallelFunction( + String functionName, BigInteger criticalSize) { + final Function function = + new Function( + FUNC_REGISTERPARALLELFUNCTION, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(functionName), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256( + criticalSize)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple2 getRegisterParallelFunctionInput( + TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_REGISTERPARALLELFUNCTION, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple2( + (String) results.get(0).getValue(), (BigInteger) results.get(1).getValue()); + } + + public BigInteger balanceOf(String name) throws ContractException { + final Function function = + new Function( + FUNC_BALANCEOF, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name)), + Arrays.>asList(new TypeReference() {})); + return executeCallWithSingleValueReturn(function, BigInteger.class); + } + + public TransactionReceipt unregisterParallelFunction(String functionName) { + final Function function = + new Function( + FUNC_UNREGISTERPARALLELFUNCTION, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(functionName)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void unregisterParallelFunction(String functionName, TransactionCallback callback) { + final Function function = + new Function( + FUNC_UNREGISTERPARALLELFUNCTION, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(functionName)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForUnregisterParallelFunction(String functionName) { + final Function function = + new Function( + FUNC_UNREGISTERPARALLELFUNCTION, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(functionName)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple1 getUnregisterParallelFunctionInput( + TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_UNREGISTERPARALLELFUNCTION, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((String) results.get(0).getValue()); + } + + public TransactionReceipt set(String name, BigInteger num) { + final Function function = + new Function( + FUNC_SET, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(num)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void set(String name, BigInteger num, TransactionCallback callback) { + final Function function = + new Function( + FUNC_SET, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(num)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForSet(String name, BigInteger num) { + final Function function = + new Function( + FUNC_SET, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(num)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple2 getSetInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_SET, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple2( + (String) results.get(0).getValue(), (BigInteger) results.get(1).getValue()); + } + + public TransactionReceipt transfer(String from, String to, BigInteger num) { + final Function function = + new Function( + FUNC_TRANSFER, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(from), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(to), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(num)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void transfer(String from, String to, BigInteger num, TransactionCallback callback) { + final Function function = + new Function( + FUNC_TRANSFER, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(from), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(to), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(num)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForTransfer(String from, String to, BigInteger num) { + final Function function = + new Function( + FUNC_TRANSFER, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(from), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(to), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(num)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple3 getTransferInput( + TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_TRANSFER, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple3( + (String) results.get(0).getValue(), + (String) results.get(1).getValue(), + (BigInteger) results.get(2).getValue()); + } + + public TransactionReceipt enableParallel() { + final Function function = + new Function( + FUNC_ENABLEPARALLEL, + Arrays.asList(), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void enableParallel(TransactionCallback callback) { + final Function function = + new Function( + FUNC_ENABLEPARALLEL, + Arrays.asList(), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForEnableParallel() { + final Function function = + new Function( + FUNC_ENABLEPARALLEL, + Arrays.asList(), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public TransactionReceipt disableParallel() { + final Function function = + new Function( + FUNC_DISABLEPARALLEL, + Arrays.asList(), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void disableParallel(TransactionCallback callback) { + final Function function = + new Function( + FUNC_DISABLEPARALLEL, + Arrays.asList(), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForDisableParallel() { + final Function function = + new Function( + FUNC_DISABLEPARALLEL, + Arrays.asList(), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public TransactionReceipt transferWithRevert(String from, String to, BigInteger num) { + final Function function = + new Function( + FUNC_TRANSFERWITHREVERT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(from), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(to), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(num)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void transferWithRevert( + String from, String to, BigInteger num, TransactionCallback callback) { + final Function function = + new Function( + FUNC_TRANSFERWITHREVERT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(from), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(to), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(num)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForTransferWithRevert( + String from, String to, BigInteger num) { + final Function function = + new Function( + FUNC_TRANSFERWITHREVERT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(from), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(to), + new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(num)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple3 getTransferWithRevertInput( + TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_TRANSFERWITHREVERT, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple3( + (String) results.get(0).getValue(), + (String) results.get(1).getValue(), + (BigInteger) results.get(2).getValue()); + } + + public static ParallelOk load(String contractAddress, Client client, CryptoKeyPair credential) { + return new ParallelOk(contractAddress, client, credential); + } + + public static ParallelOk deploy(Client client, CryptoKeyPair credential) + throws ContractException { + return deploy(ParallelOk.class, client, credential, getBinary(client.getCryptoSuite()), ""); + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/TableTest.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/TableTest.java new file mode 100644 index 000000000..e9d418e6f --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/TableTest.java @@ -0,0 +1,509 @@ +package org.fisco.bcos.sdk.demo.contract; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.abi.FunctionReturnDecoder; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.datatypes.DynamicArray; +import org.fisco.bcos.sdk.abi.datatypes.Event; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Bytes32; +import org.fisco.bcos.sdk.abi.datatypes.generated.Int256; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple1; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple3; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.Contract; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.eventsub.EventCallback; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; + +@SuppressWarnings("unchecked") +public class TableTest extends Contract { + public static final String[] BINARY_ARRAY = { + "608060405234801561001057600080fd5b5061221f806100206000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063487a5a1014610072578063c4f41ab31461013f578063ebf3b24f146101c6578063efc81a8c14610293578063fcd7e3c1146102aa575b600080fd5b34801561007e57600080fd5b50610129600480360381019080803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929080359060200190929190803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506103f8565b6040518082815260200191505060405180910390f35b34801561014b57600080fd5b506101b0600480360381019080803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929080359060200190929190505050610aee565b6040518082815260200191505060405180910390f35b3480156101d257600080fd5b5061027d600480360381019080803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929080359060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610fe7565b6040518082815260200191505060405180910390f35b34801561029f57600080fd5b506102a8611606565b005b3480156102b657600080fd5b50610311600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050611798565b60405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b8381101561035c578082015181840152602081019050610341565b50505050905001848103835286818151815260200191508051906020019060200280838360005b8381101561039e578082015181840152602081019050610383565b50505050905001848103825285818151815260200191508051906020019060200280838360005b838110156103e05780820151818401526020810190506103c5565b50505050905001965050505050505060405180910390f35b60008060008060008061100194508473ffffffffffffffffffffffffffffffffffffffff1663f23f63c96040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825260068152602001807f745f746573740000000000000000000000000000000000000000000000000000815250602001915050602060405180830381600087803b1580156104a657600080fd5b505af11580156104ba573d6000803e3d6000fd5b505050506040513d60208110156104d057600080fd5b810190808051906020019092919050505093508373ffffffffffffffffffffffffffffffffffffffff166313db93466040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561054757600080fd5b505af115801561055b573d6000803e3d6000fd5b505050506040513d602081101561057157600080fd5b810190808051906020019092919050505092508273ffffffffffffffffffffffffffffffffffffffff1663e942b516886040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808060200180602001838103835260098152602001807f6974656d5f6e616d650000000000000000000000000000000000000000000000815250602001838103825284818151815260200191508051906020019080838360005b83811015610644578082015181840152602081019050610629565b50505050905090810190601f1680156106715780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b15801561069157600080fd5b505af11580156106a5573d6000803e3d6000fd5b505050508373ffffffffffffffffffffffffffffffffffffffff16637857d7c96040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561070d57600080fd5b505af1158015610721573d6000803e3d6000fd5b505050506040513d602081101561073757600080fd5b810190808051906020019092919050505091508173ffffffffffffffffffffffffffffffffffffffff1663cd30a1d18a6040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808060200180602001838103835260048152602001807f6e616d6500000000000000000000000000000000000000000000000000000000815250602001838103825284818151815260200191508051906020019080838360005b8381101561080a5780820151818401526020810190506107ef565b50505050905090810190601f1680156108375780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b15801561085757600080fd5b505af115801561086b573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff1663e44594b9896040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001838152602001828103825260078152602001807f6974656d5f69640000000000000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b15801561091757600080fd5b505af115801561092b573d6000803e3d6000fd5b505050508373ffffffffffffffffffffffffffffffffffffffff1663bf2b70a18a85856040518463ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180806020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828103825285818151815260200191508051906020019080838360005b83811015610a1d578082015181840152602081019050610a02565b50505050905090810190601f168015610a4a5780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600087803b158015610a6b57600080fd5b505af1158015610a7f573d6000803e3d6000fd5b505050506040513d6020811015610a9557600080fd5b810190808051906020019092919050505090507f0bdcb3b747cf033ae78b4b6e1576d2725709d03f68ad3d641b12cb72de614354816040518082815260200191505060405180910390a180955050505050509392505050565b600080600080600061100193508373ffffffffffffffffffffffffffffffffffffffff1663f23f63c96040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825260068152602001807f745f746573740000000000000000000000000000000000000000000000000000815250602001915050602060405180830381600087803b158015610b9b57600080fd5b505af1158015610baf573d6000803e3d6000fd5b505050506040513d6020811015610bc557600080fd5b810190808051906020019092919050505092508273ffffffffffffffffffffffffffffffffffffffff16637857d7c96040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015610c3c57600080fd5b505af1158015610c50573d6000803e3d6000fd5b505050506040513d6020811015610c6657600080fd5b810190808051906020019092919050505091508173ffffffffffffffffffffffffffffffffffffffff1663cd30a1d1886040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808060200180602001838103835260048152602001807f6e616d6500000000000000000000000000000000000000000000000000000000815250602001838103825284818151815260200191508051906020019080838360005b83811015610d39578082015181840152602081019050610d1e565b50505050905090810190601f168015610d665780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b158015610d8657600080fd5b505af1158015610d9a573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff1663e44594b9876040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001838152602001828103825260078152602001807f6974656d5f69640000000000000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b158015610e4657600080fd5b505af1158015610e5a573d6000803e3d6000fd5b505050508273ffffffffffffffffffffffffffffffffffffffff166328bb211788846040518363ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180806020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818151815260200191508051906020019080838360005b83811015610f19578082015181840152602081019050610efe565b50505050905090810190601f168015610f465780820380516001836020036101000a031916815260200191505b509350505050602060405180830381600087803b158015610f6657600080fd5b505af1158015610f7a573d6000803e3d6000fd5b505050506040513d6020811015610f9057600080fd5b810190808051906020019092919050505090507f896358cb98e9e8e891ae04efd1bc177efbe5cffd7eca2e784b16ed7468553e08816040518082815260200191505060405180910390a18094505050", + "505092915050565b600080600080600061100193508373ffffffffffffffffffffffffffffffffffffffff1663f23f63c96040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825260068152602001807f745f746573740000000000000000000000000000000000000000000000000000815250602001915050602060405180830381600087803b15801561109457600080fd5b505af11580156110a8573d6000803e3d6000fd5b505050506040513d60208110156110be57600080fd5b810190808051906020019092919050505092508273ffffffffffffffffffffffffffffffffffffffff166313db93466040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561113557600080fd5b505af1158015611149573d6000803e3d6000fd5b505050506040513d602081101561115f57600080fd5b810190808051906020019092919050505091508173ffffffffffffffffffffffffffffffffffffffff1663e942b516896040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808060200180602001838103835260048152602001807f6e616d6500000000000000000000000000000000000000000000000000000000815250602001838103825284818151815260200191508051906020019080838360005b83811015611232578082015181840152602081019050611217565b50505050905090810190601f16801561125f5780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b15801561127f57600080fd5b505af1158015611293573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff16632ef8ba74886040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001838152602001828103825260078152602001807f6974656d5f69640000000000000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b15801561133f57600080fd5b505af1158015611353573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff1663e942b516876040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808060200180602001838103835260098152602001807f6974656d5f6e616d650000000000000000000000000000000000000000000000815250602001838103825284818151815260200191508051906020019080838360005b838110156114175780820151818401526020810190506113fc565b50505050905090810190601f1680156114445780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b15801561146457600080fd5b505af1158015611478573d6000803e3d6000fd5b505050508273ffffffffffffffffffffffffffffffffffffffff166331afac3689846040518363ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180806020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818151815260200191508051906020019080838360005b8381101561153757808201518184015260208101905061151c565b50505050905090810190601f1680156115645780820380516001836020036101000a031916815260200191505b509350505050602060405180830381600087803b15801561158457600080fd5b505af1158015611598573d6000803e3d6000fd5b505050506040513d60208110156115ae57600080fd5b810190808051906020019092919050505090507f66f7705280112a4d1145399e0414adc43a2d6974b487710f417edcf7d4a39d71816040518082815260200191505060405180910390a1809450505050509392505050565b60008061100191508173ffffffffffffffffffffffffffffffffffffffff166356004b6a6040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180806020018060200180602001848103845260068152602001807f745f746573740000000000000000000000000000000000000000000000000000815250602001848103835260048152602001807f6e616d6500000000000000000000000000000000000000000000000000000000815250602001848103825260118152602001807f6974656d5f69642c6974656d5f6e616d650000000000000000000000000000008152506020019350505050602060405180830381600087803b15801561172057600080fd5b505af1158015611734573d6000803e3d6000fd5b505050506040513d602081101561174a57600080fd5b810190808051906020019092919050505090507fcd4779437d9d027acc605a96427bfbd3787a1402cb53a5e64cd813d5391fbc2b816040518082815260200191505060405180910390a15050565b6060806060600080600080606080606060008061100198508873ffffffffffffffffffffffffffffffffffffffff1663f23f63c96040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825260068152602001807f745f746573740000000000000000000000000000000000000000000000000000815250602001915050602060405180830381600087803b15801561185057600080fd5b505af1158015611864573d6000803e3d6000fd5b505050506040513d602081101561187a57600080fd5b810190808051906020019092919050505097508773ffffffffffffffffffffffffffffffffffffffff16637857d7c96040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156118f157600080fd5b505af1158015611905573d6000803e3d6000fd5b505050506040513d602081101561191b57600080fd5b810190808051906020019092919050505096508773ffffffffffffffffffffffffffffffffffffffff1663e8434e398e896040518363ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180806020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818151815260200191508051906020019080838360005b838110156119e95780820151818401526020810190506119ce565b50505050905090810190601f168015611a165780820380516001836020036101000a031916815260200191505b509350505050602060405180830381600087803b158015611a3657600080fd5b505af1158015611a4a573d6000803e3d6000fd5b505050506040513d6020811015611a6057600080fd5b810190808051906020019092919050505095508573ffffffffffffffffffffffffffffffffffffffff1663949d225d6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015611ad757600080fd5b505af1158015611aeb573d6000803e3d6000fd5b505050506040513d6020811015611b0157600080fd5b8101908080519060200190929190505050604051908082528060200260200182016040528015611b405781602001602082028038833980820191505090505b5094508573ffffffffffffffffffffffffffffffffffffffff1663949d225d6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015611ba757600080fd5b505af1158015611bbb573d6000803e3d6000fd5b505050506040513d6020811015611bd157600080fd5b8101908080519060200190929190505050604051908082528060200260200182016040528015611c105781602001602082028038833980820191505090505b5093508573ffffffffffffffffffffffffffffffffffffffff1663949d225d6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015611c7757600080fd5b505af1158015611c8b573d6000803e3d6000fd5b505050506040513d6020811015611ca157600080fd5b8101908080519060200190929190505050604051908082528060200260200182016040528015611ce05781602001602082028038833980820191505090505b509250600091505b8573ffffffffffffffffffffffffffffffffffffffff1663949d225d6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015611d4c57600080fd5b505af1158015611d60573d6000803e3d6000fd5b505050506040513d6020811015611d7657600080fd5b81019080805190602001909291905050508212156121da578573ffffffffffffffffffffffffffffffffffffffff1663846719e0836040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b158015611dfd57600080fd5b505af1158015611e11573d6000803e3d6000fd5b505050506040513d6020811015611e2757600080fd5b810190808051906020019092919050505090508073ffffffffffffffffffffffffffffffffffffffff166327314f796040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825260048152602001807f6e616d6500000000000000000000000000000000000000000000000000000000815250602001915050602060405180830381600087803b158015611eda57600080fd5b505af1158015611eee573d6000803e3d6000fd5b505050506040513d6020811015611f0457600080fd5b81019080805190602001909291905050508583815181101515611f2357fe5b9060200190602002019060001916908160001916815250508073ffffffffffffffffffffffffffffffffffffffff1663fda69fae6040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825260078152602001807f6974656d5f696400000000000000000000000000000000000000000000000000815250602001915050602060405180830381600087803b158015611fdb57600080fd5b505af115", + "8015611fef573d6000803e3d6000fd5b505050506040513d602081101561200557600080fd5b8101908080519060200190929190505050848381518110151561202457fe5b90602001906020020181815250508073ffffffffffffffffffffffffffffffffffffffff166327314f796040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825260098152602001807f6974656d5f6e616d650000000000000000000000000000000000000000000000815250602001915050602060405180830381600087803b1580156120d257600080fd5b505af11580156120e6573d6000803e3d6000fd5b505050506040513d60208110156120fc57600080fd5b8101908080519060200190929190505050838381518110151561211b57fe5b9060200190602002019060001916908160001916815250507fc65cd2adf133adee2ddcfab8b165c2f1f7b185c4389b0789a11112483efb1c84858381518110151561216257fe5b90602001906020020151858481518110151561217a57fe5b90602001906020020151858581518110151561219257fe5b906020019060200201516040518084600019166000191681526020018381526020018260001916600019168152602001935050505060405180910390a1816001019150611ce8565b8484849b509b509b5050505050505050505091939092505600a165627a7a7230582032177e069ae4110c8c4a603273d4a04482e613644296721d9e07c5486cdf7dd50029" + }; + + public static final String BINARY = String.join("", BINARY_ARRAY); + + public static final String[] SM_BINARY_ARRAY = { + "608060405234801561001057600080fd5b5061221f806100206000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630fe1160f1461007257806345710fa5146100f957806349cc36b5146101105780635b325d78146101dd578063e020d4641461032b575b600080fd5b34801561007e57600080fd5b506100e3600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001909291905050506103f8565b6040518082815260200191505060405180910390f35b34801561010557600080fd5b5061010e6108f1565b005b34801561011c57600080fd5b506101c7600480360381019080803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929080359060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610a83565b6040518082815260200191505060405180910390f35b3480156101e957600080fd5b50610244600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050611179565b60405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b8381101561028f578082015181840152602081019050610274565b50505050905001848103835286818151815260200191508051906020019060200280838360005b838110156102d15780820151818401526020810190506102b6565b50505050905001848103825285818151815260200191508051906020019060200280838360005b838110156103135780820151818401526020810190506102f8565b50505050905001965050505050505060405180910390f35b34801561033757600080fd5b506103e2600480360381019080803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929080359060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050611bd4565b6040518082815260200191505060405180910390f35b600080600080600061100193508373ffffffffffffffffffffffffffffffffffffffff166359a48b656040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825260068152602001807f745f746573740000000000000000000000000000000000000000000000000000815250602001915050602060405180830381600087803b1580156104a557600080fd5b505af11580156104b9573d6000803e3d6000fd5b505050506040513d60208110156104cf57600080fd5b810190808051906020019092919050505092508273ffffffffffffffffffffffffffffffffffffffff1663c74f8caf6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561054657600080fd5b505af115801561055a573d6000803e3d6000fd5b505050506040513d602081101561057057600080fd5b810190808051906020019092919050505091508173ffffffffffffffffffffffffffffffffffffffff1663ae763db5886040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808060200180602001838103835260048152602001807f6e616d6500000000000000000000000000000000000000000000000000000000815250602001838103825284818151815260200191508051906020019080838360005b83811015610643578082015181840152602081019050610628565b50505050905090810190601f1680156106705780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b15801561069057600080fd5b505af11580156106a4573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff1663d62b54b4876040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001838152602001828103825260078152602001807f6974656d5f69640000000000000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b15801561075057600080fd5b505af1158015610764573d6000803e3d6000fd5b505050508273ffffffffffffffffffffffffffffffffffffffff166309ff42f088846040518363ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180806020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818151815260200191508051906020019080838360005b83811015610823578082015181840152602081019050610808565b50505050905090810190601f1680156108505780820380516001836020036101000a031916815260200191505b509350505050602060405180830381600087803b15801561087057600080fd5b505af1158015610884573d6000803e3d6000fd5b505050506040513d602081101561089a57600080fd5b810190808051906020019092919050505090507f809ffa7913d4c04a8785eea307a714cf83228bb7eded9cebd577c114e36c9967816040518082815260200191505060405180910390a18094505050505092915050565b60008061100191508173ffffffffffffffffffffffffffffffffffffffff1663c92a78016040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180806020018060200180602001848103845260068152602001807f745f746573740000000000000000000000000000000000000000000000000000815250602001848103835260048152602001807f6e616d6500000000000000000000000000000000000000000000000000000000815250602001848103825260118152602001807f6974656d5f69642c6974656d5f6e616d650000000000000000000000000000008152506020019350505050602060405180830381600087803b158015610a0b57600080fd5b505af1158015610a1f573d6000803e3d6000fd5b505050506040513d6020811015610a3557600080fd5b810190808051906020019092919050505090507f698cf490d4172e8c174ef6380602ab47c18d429938f9f778cc2c0f3b5498f2c6816040518082815260200191505060405180910390a15050565b60008060008060008061100194508473ffffffffffffffffffffffffffffffffffffffff166359a48b656040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825260068152602001807f745f746573740000000000000000000000000000000000000000000000000000815250602001915050602060405180830381600087803b158015610b3157600080fd5b505af1158015610b45573d6000803e3d6000fd5b505050506040513d6020811015610b5b57600080fd5b810190808051906020019092919050505093508373ffffffffffffffffffffffffffffffffffffffff16635887ab246040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015610bd257600080fd5b505af1158015610be6573d6000803e3d6000fd5b505050506040513d6020811015610bfc57600080fd5b810190808051906020019092919050505092508273ffffffffffffffffffffffffffffffffffffffff16631a391cb4886040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808060200180602001838103835260098152602001807f6974656d5f6e616d650000000000000000000000000000000000000000000000815250602001838103825284818151815260200191508051906020019080838360005b83811015610ccf578082015181840152602081019050610cb4565b50505050905090810190601f168015610cfc5780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b158015610d1c57600080fd5b505af1158015610d30573d6000803e3d6000fd5b505050508373ffffffffffffffffffffffffffffffffffffffff1663c74f8caf6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015610d9857600080fd5b505af1158015610dac573d6000803e3d6000fd5b505050506040513d6020811015610dc257600080fd5b810190808051906020019092919050505091508173ffffffffffffffffffffffffffffffffffffffff1663ae763db58a6040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808060200180602001838103835260048152602001807f6e616d6500000000000000000000000000000000000000000000000000000000815250602001838103825284818151815260200191508051906020019080838360005b83811015610e95578082015181840152602081019050610e7a565b50505050905090810190601f168015610ec25780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b158015610ee257600080fd5b505af1158015610ef6573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff1663d62b54b4896040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001838152602001828103825260078152602001807f6974656d5f69640000000000000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b158015610fa257600080fd5b505af1158015610fb6573d6000803e3d6000fd5b505050508373ffffffffffffffffffffffffffffffffffffffff1663664b37d68a85856040518463ff", + "ffffff167c010000000000000000000000000000000000000000000000000000000002815260040180806020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828103825285818151815260200191508051906020019080838360005b838110156110a857808201518184015260208101905061108d565b50505050905090810190601f1680156110d55780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600087803b1580156110f657600080fd5b505af115801561110a573d6000803e3d6000fd5b505050506040513d602081101561112057600080fd5b810190808051906020019092919050505090507f21c0ede88315971cad0fa2aa5d177bf992894f6be25236454587141c48683046816040518082815260200191505060405180910390a180955050505050509392505050565b6060806060600080600080606080606060008061100198508873ffffffffffffffffffffffffffffffffffffffff166359a48b656040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825260068152602001807f745f746573740000000000000000000000000000000000000000000000000000815250602001915050602060405180830381600087803b15801561123157600080fd5b505af1158015611245573d6000803e3d6000fd5b505050506040513d602081101561125b57600080fd5b810190808051906020019092919050505097508773ffffffffffffffffffffffffffffffffffffffff1663c74f8caf6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156112d257600080fd5b505af11580156112e6573d6000803e3d6000fd5b505050506040513d60208110156112fc57600080fd5b810190808051906020019092919050505096508773ffffffffffffffffffffffffffffffffffffffff1663d8ac59578e896040518363ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180806020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818151815260200191508051906020019080838360005b838110156113ca5780820151818401526020810190506113af565b50505050905090810190601f1680156113f75780820380516001836020036101000a031916815260200191505b509350505050602060405180830381600087803b15801561141757600080fd5b505af115801561142b573d6000803e3d6000fd5b505050506040513d602081101561144157600080fd5b810190808051906020019092919050505095508573ffffffffffffffffffffffffffffffffffffffff1663d3e9af5a6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156114b857600080fd5b505af11580156114cc573d6000803e3d6000fd5b505050506040513d60208110156114e257600080fd5b81019080805190602001909291905050506040519080825280602002602001820160405280156115215781602001602082028038833980820191505090505b5094508573ffffffffffffffffffffffffffffffffffffffff1663d3e9af5a6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561158857600080fd5b505af115801561159c573d6000803e3d6000fd5b505050506040513d60208110156115b257600080fd5b81019080805190602001909291905050506040519080825280602002602001820160405280156115f15781602001602082028038833980820191505090505b5093508573ffffffffffffffffffffffffffffffffffffffff1663d3e9af5a6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561165857600080fd5b505af115801561166c573d6000803e3d6000fd5b505050506040513d602081101561168257600080fd5b81019080805190602001909291905050506040519080825280602002602001820160405280156116c15781602001602082028038833980820191505090505b509250600091505b8573ffffffffffffffffffffffffffffffffffffffff1663d3e9af5a6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561172d57600080fd5b505af1158015611741573d6000803e3d6000fd5b505050506040513d602081101561175757600080fd5b8101908080519060200190929190505050821215611bbb578573ffffffffffffffffffffffffffffffffffffffff16633dd2b614836040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b1580156117de57600080fd5b505af11580156117f2573d6000803e3d6000fd5b505050506040513d602081101561180857600080fd5b810190808051906020019092919050505090508073ffffffffffffffffffffffffffffffffffffffff1663fdebe4146040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825260048152602001807f6e616d6500000000000000000000000000000000000000000000000000000000815250602001915050602060405180830381600087803b1580156118bb57600080fd5b505af11580156118cf573d6000803e3d6000fd5b505050506040513d60208110156118e557600080fd5b8101908080519060200190929190505050858381518110151561190457fe5b9060200190602002019060001916908160001916815250508073ffffffffffffffffffffffffffffffffffffffff16634900862e6040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825260078152602001807f6974656d5f696400000000000000000000000000000000000000000000000000815250602001915050602060405180830381600087803b1580156119bc57600080fd5b505af11580156119d0573d6000803e3d6000fd5b505050506040513d60208110156119e657600080fd5b81019080805190602001909291905050508483815181101515611a0557fe5b90602001906020020181815250508073ffffffffffffffffffffffffffffffffffffffff1663fdebe4146040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825260098152602001807f6974656d5f6e616d650000000000000000000000000000000000000000000000815250602001915050602060405180830381600087803b158015611ab357600080fd5b505af1158015611ac7573d6000803e3d6000fd5b505050506040513d6020811015611add57600080fd5b81019080805190602001909291905050508383815181101515611afc57fe5b9060200190602002019060001916908160001916815250507fef677d3bedeedc56f98504970ca9c69a69871a4cf5d7abee1012f075f3d064888583815181101515611b4357fe5b906020019060200201518584815181101515611b5b57fe5b906020019060200201518585815181101515611b7357fe5b906020019060200201516040518084600019166000191681526020018381526020018260001916600019168152602001935050505060405180910390a18160010191506116c9565b8484849b509b509b505050505050505050509193909250565b600080600080600061100193508373ffffffffffffffffffffffffffffffffffffffff166359a48b656040518163ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825260068152602001807f745f746573740000000000000000000000000000000000000000000000000000815250602001915050602060405180830381600087803b158015611c8157600080fd5b505af1158015611c95573d6000803e3d6000fd5b505050506040513d6020811015611cab57600080fd5b810190808051906020019092919050505092508273ffffffffffffffffffffffffffffffffffffffff16635887ab246040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015611d2257600080fd5b505af1158015611d36573d6000803e3d6000fd5b505050506040513d6020811015611d4c57600080fd5b810190808051906020019092919050505091508173ffffffffffffffffffffffffffffffffffffffff16631a391cb4896040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808060200180602001838103835260048152602001807f6e616d6500000000000000000000000000000000000000000000000000000000815250602001838103825284818151815260200191508051906020019080838360005b83811015611e1f578082015181840152602081019050611e04565b50505050905090810190601f168015611e4c5780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b158015611e6c57600080fd5b505af1158015611e80573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff1663def42698886040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001838152602001828103825260078152602001807f6974656d5f69640000000000000000000000000000000000000000000000000081525060200192505050600060405180830381600087803b158015611f2c57600080fd5b505af1158015611f40573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff16631a391cb4876040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808060200180602001838103835260098152602001807f6974656d5f6e616d65000000000000000000000000000000000000000000000081525060200183810382528481815181526020019150805190", + "6020019080838360005b83811015612004578082015181840152602081019050611fe9565b50505050905090810190601f1680156120315780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b15801561205157600080fd5b505af1158015612065573d6000803e3d6000fd5b505050508273ffffffffffffffffffffffffffffffffffffffff16634c6f30c089846040518363ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180806020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818151815260200191508051906020019080838360005b83811015612124578082015181840152602081019050612109565b50505050905090810190601f1680156121515780820380516001836020036101000a031916815260200191505b509350505050602060405180830381600087803b15801561217157600080fd5b505af1158015612185573d6000803e3d6000fd5b505050506040513d602081101561219b57600080fd5b810190808051906020019092919050505090507f11edf97b45aa6c006853fb598a4a9be2e678d9498feb5e6c1f389b491e12bc4a816040518082815260200191505060405180910390a18094505050505093925050505600a165627a7a72305820c9979fb6dfc3ec7ef02df3bde20e569eeef6226bd9006cdc269fd95900538a410029" + }; + + public static final String SM_BINARY = String.join("", SM_BINARY_ARRAY); + + public static final String[] ABI_ARRAY = { + "[{\"constant\":false,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"item_id\",\"type\":\"int256\"},{\"name\":\"item_name\",\"type\":\"string\"}],\"name\":\"update\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"item_id\",\"type\":\"int256\"}],\"name\":\"remove\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"item_id\",\"type\":\"int256\"},{\"name\":\"item_name\",\"type\":\"string\"}],\"name\":\"insert\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"create\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"}],\"name\":\"select\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32[]\"},{\"name\":\"\",\"type\":\"int256[]\"},{\"name\":\"\",\"type\":\"bytes32[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"count\",\"type\":\"int256\"}],\"name\":\"createResult\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"name\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"item_id\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"item_name\",\"type\":\"bytes32\"}],\"name\":\"selectResult\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"count\",\"type\":\"int256\"}],\"name\":\"insertResult\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"count\",\"type\":\"int256\"}],\"name\":\"updateResult\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"count\",\"type\":\"int256\"}],\"name\":\"removeResult\",\"type\":\"event\"}]" + }; + + public static final String ABI = String.join("", ABI_ARRAY); + + public static final String FUNC_UPDATE = "update"; + + public static final String FUNC_REMOVE = "remove"; + + public static final String FUNC_INSERT = "insert"; + + public static final String FUNC_CREATE = "create"; + + public static final String FUNC_SELECT = "select"; + + public static final Event CREATERESULT_EVENT = + new Event( + "createResult", + Arrays.>asList(new TypeReference() {}));; + + public static final Event SELECTRESULT_EVENT = + new Event( + "selectResult", + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {}, + new TypeReference() {}));; + + public static final Event INSERTRESULT_EVENT = + new Event( + "insertResult", + Arrays.>asList(new TypeReference() {}));; + + public static final Event UPDATERESULT_EVENT = + new Event( + "updateResult", + Arrays.>asList(new TypeReference() {}));; + + public static final Event REMOVERESULT_EVENT = + new Event( + "removeResult", + Arrays.>asList(new TypeReference() {}));; + + protected TableTest(String contractAddress, Client client, CryptoKeyPair credential) { + super(getBinary(client.getCryptoSuite()), contractAddress, client, credential); + } + + public static String getBinary(CryptoSuite cryptoSuite) { + return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY); + } + + public TransactionReceipt update(String name, BigInteger item_id, String item_name) { + final Function function = + new Function( + FUNC_UPDATE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name), + new org.fisco.bcos.sdk.abi.datatypes.generated.Int256(item_id), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(item_name)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void update( + String name, BigInteger item_id, String item_name, TransactionCallback callback) { + final Function function = + new Function( + FUNC_UPDATE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name), + new org.fisco.bcos.sdk.abi.datatypes.generated.Int256(item_id), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(item_name)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForUpdate(String name, BigInteger item_id, String item_name) { + final Function function = + new Function( + FUNC_UPDATE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name), + new org.fisco.bcos.sdk.abi.datatypes.generated.Int256(item_id), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(item_name)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple3 getUpdateInput( + TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_UPDATE, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple3( + (String) results.get(0).getValue(), + (BigInteger) results.get(1).getValue(), + (String) results.get(2).getValue()); + } + + public Tuple1 getUpdateOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_UPDATE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public TransactionReceipt remove(String name, BigInteger item_id) { + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name), + new org.fisco.bcos.sdk.abi.datatypes.generated.Int256(item_id)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void remove(String name, BigInteger item_id, TransactionCallback callback) { + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name), + new org.fisco.bcos.sdk.abi.datatypes.generated.Int256(item_id)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForRemove(String name, BigInteger item_id) { + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name), + new org.fisco.bcos.sdk.abi.datatypes.generated.Int256(item_id)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple2 getRemoveInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple2( + (String) results.get(0).getValue(), (BigInteger) results.get(1).getValue()); + } + + public Tuple1 getRemoveOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public TransactionReceipt insert(String name, BigInteger item_id, String item_name) { + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name), + new org.fisco.bcos.sdk.abi.datatypes.generated.Int256(item_id), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(item_name)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void insert( + String name, BigInteger item_id, String item_name, TransactionCallback callback) { + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name), + new org.fisco.bcos.sdk.abi.datatypes.generated.Int256(item_id), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(item_name)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForInsert(String name, BigInteger item_id, String item_name) { + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name), + new org.fisco.bcos.sdk.abi.datatypes.generated.Int256(item_id), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(item_name)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple3 getInsertInput( + TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple3( + (String) results.get(0).getValue(), + (BigInteger) results.get(1).getValue(), + (String) results.get(2).getValue()); + } + + public Tuple1 getInsertOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public TransactionReceipt create() { + final Function function = + new Function( + FUNC_CREATE, + Arrays.asList(), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void create(TransactionCallback callback) { + final Function function = + new Function( + FUNC_CREATE, + Arrays.asList(), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForCreate() { + final Function function = + new Function( + FUNC_CREATE, + Arrays.asList(), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple3, List, List> select(String name) + throws ContractException { + final Function function = + new Function( + FUNC_SELECT, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name)), + Arrays.>asList( + new TypeReference>() {}, + new TypeReference>() {}, + new TypeReference>() {})); + List results = executeCallWithMultipleValueReturn(function); + return new Tuple3, List, List>( + convertToNative((List) results.get(0).getValue()), + convertToNative((List) results.get(1).getValue()), + convertToNative((List) results.get(2).getValue())); + } + + public List getCreateResultEvents( + TransactionReceipt transactionReceipt) { + List valueList = + extractEventParametersWithLog(CREATERESULT_EVENT, transactionReceipt); + ArrayList responses = + new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + CreateResultEventResponse typedResponse = new CreateResultEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.count = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public void subscribeCreateResultEvent( + String fromBlock, String toBlock, List otherTopics, EventCallback callback) { + String topic0 = eventEncoder.encode(CREATERESULT_EVENT); + subscribeEvent(ABI, BINARY, topic0, fromBlock, toBlock, otherTopics, callback); + } + + public void subscribeCreateResultEvent(EventCallback callback) { + String topic0 = eventEncoder.encode(CREATERESULT_EVENT); + subscribeEvent(ABI, BINARY, topic0, callback); + } + + public List getSelectResultEvents( + TransactionReceipt transactionReceipt) { + List valueList = + extractEventParametersWithLog(SELECTRESULT_EVENT, transactionReceipt); + ArrayList responses = + new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + SelectResultEventResponse typedResponse = new SelectResultEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.name = (byte[]) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.item_id = + (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); + typedResponse.item_name = (byte[]) eventValues.getNonIndexedValues().get(2).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public void subscribeSelectResultEvent( + String fromBlock, String toBlock, List otherTopics, EventCallback callback) { + String topic0 = eventEncoder.encode(SELECTRESULT_EVENT); + subscribeEvent(ABI, BINARY, topic0, fromBlock, toBlock, otherTopics, callback); + } + + public void subscribeSelectResultEvent(EventCallback callback) { + String topic0 = eventEncoder.encode(SELECTRESULT_EVENT); + subscribeEvent(ABI, BINARY, topic0, callback); + } + + public List getInsertResultEvents( + TransactionReceipt transactionReceipt) { + List valueList = + extractEventParametersWithLog(INSERTRESULT_EVENT, transactionReceipt); + ArrayList responses = + new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + InsertResultEventResponse typedResponse = new InsertResultEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.count = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public void subscribeInsertResultEvent( + String fromBlock, String toBlock, List otherTopics, EventCallback callback) { + String topic0 = eventEncoder.encode(INSERTRESULT_EVENT); + subscribeEvent(ABI, BINARY, topic0, fromBlock, toBlock, otherTopics, callback); + } + + public void subscribeInsertResultEvent(EventCallback callback) { + String topic0 = eventEncoder.encode(INSERTRESULT_EVENT); + subscribeEvent(ABI, BINARY, topic0, callback); + } + + public List getUpdateResultEvents( + TransactionReceipt transactionReceipt) { + List valueList = + extractEventParametersWithLog(UPDATERESULT_EVENT, transactionReceipt); + ArrayList responses = + new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + UpdateResultEventResponse typedResponse = new UpdateResultEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.count = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public void subscribeUpdateResultEvent( + String fromBlock, String toBlock, List otherTopics, EventCallback callback) { + String topic0 = eventEncoder.encode(UPDATERESULT_EVENT); + subscribeEvent(ABI, BINARY, topic0, fromBlock, toBlock, otherTopics, callback); + } + + public void subscribeUpdateResultEvent(EventCallback callback) { + String topic0 = eventEncoder.encode(UPDATERESULT_EVENT); + subscribeEvent(ABI, BINARY, topic0, callback); + } + + public List getRemoveResultEvents( + TransactionReceipt transactionReceipt) { + List valueList = + extractEventParametersWithLog(REMOVERESULT_EVENT, transactionReceipt); + ArrayList responses = + new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + RemoveResultEventResponse typedResponse = new RemoveResultEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.count = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public void subscribeRemoveResultEvent( + String fromBlock, String toBlock, List otherTopics, EventCallback callback) { + String topic0 = eventEncoder.encode(REMOVERESULT_EVENT); + subscribeEvent(ABI, BINARY, topic0, fromBlock, toBlock, otherTopics, callback); + } + + public void subscribeRemoveResultEvent(EventCallback callback) { + String topic0 = eventEncoder.encode(REMOVERESULT_EVENT); + subscribeEvent(ABI, BINARY, topic0, callback); + } + + public static TableTest load(String contractAddress, Client client, CryptoKeyPair credential) { + return new TableTest(contractAddress, client, credential); + } + + public static TableTest deploy(Client client, CryptoKeyPair credential) + throws ContractException { + return deploy(TableTest.class, client, credential, getBinary(client.getCryptoSuite()), ""); + } + + public static class CreateResultEventResponse { + public TransactionReceipt.Logs log; + + public BigInteger count; + } + + public static class SelectResultEventResponse { + public TransactionReceipt.Logs log; + + public byte[] name; + + public BigInteger item_id; + + public byte[] item_name; + } + + public static class InsertResultEventResponse { + public TransactionReceipt.Logs log; + + public BigInteger count; + } + + public static class UpdateResultEventResponse { + public TransactionReceipt.Logs log; + + public BigInteger count; + } + + public static class RemoveResultEventResponse { + public TransactionReceipt.Logs log; + + public BigInteger count; + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/DagTransfer.sol b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/DagTransfer.sol new file mode 100644 index 000000000..53b40e8a1 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/DagTransfer.sol @@ -0,0 +1,8 @@ +pragma solidity ^0.4.25; +contract DagTransfer{ + function userAdd(string user, uint256 balance) public returns(uint256); + function userSave(string user, uint256 balance) public returns(uint256); + function userDraw(string user, uint256 balance) public returns(uint256); + function userBalance(string user) public constant returns(uint256,uint256); + function userTransfer(string user_a, string user_b, uint256 amount) public returns(uint256); +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/Ok.sol b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/Ok.sol new file mode 100644 index 000000000..6fc46f070 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/Ok.sol @@ -0,0 +1,42 @@ +pragma solidity ^0.4.24; +contract Ok{ + + struct Account{ + address account; + uint balance; + } + + struct Translog { + string time; + address from; + address to; + uint amount; + } + + Account from; + Account to; + event TransEvent(uint num); + Translog[] log; + + function Ok(){ + from.account=0x1; + from.balance=10000000000; + to.account=0x2; + to.balance=0; + + } + + function get()constant returns(uint){ + return to.balance; + } + + function trans(uint num){ + if (from.balance < num || to.balance + num < to.balance) + return; // Deny overflow + + from.balance=from.balance-num; + to.balance+=num; + TransEvent(num); + log.push(Translog("20170413",from.account,to.account,num)); + } +} \ No newline at end of file diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/OkD.sol b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/OkD.sol new file mode 100644 index 000000000..ba7f16bce --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/OkD.sol @@ -0,0 +1,57 @@ +import "./Table.sol"; + +contract OkD{ + event insertResult(int count); + + struct Account{ + address account; + int balance; + } + + Account from; + Account to; + + function OkD(){ + + from.account=0x1; + from.balance=10000000000; + to.account=0x2; + to.balance=0; + + TableFactory tf = TableFactory(0x1001); + tf.createTable("t_ok", "from_accout", "from_balance,to_accout,to_balance"); + tf = TableFactory(0x1001); + Table table = tf.openTable("t_ok"); + Entry entry = table.newEntry(); + entry.set("from_accout", "0x1"); + entry.set("from_balance", "10000000000"); + entry.set("to_accout", "0x2"); + entry.set("to_balance", "0"); + + } + function get()constant returns(int){ + return to.balance; + } + function trans(string from_accout, int num){ + + if (from.balance < num || to.balance + num < to.balance) + return; // Deny overflow + + from.balance = from.balance - num; + to.balance += num; + + TableFactory tf = TableFactory(0x1001); + Table table = tf.openTable("t_ok"); + Entry entry = table.newEntry(); + entry.set("from_accout", from_accout); + entry.set("from_balance", from.balance); + entry.set("to_accout", "0x2"); + entry.set("to_balance", to.balance); + int count = table.insert(from_accout, entry); + insertResult(count); + + // log.push(Translog("20170413",from.account,to.account,num)); + + } + +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/ParallelContract.sol b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/ParallelContract.sol new file mode 100644 index 000000000..106403468 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/ParallelContract.sol @@ -0,0 +1,25 @@ +pragma solidity ^0.4.25; + +contract ParallelConfigPrecompiled +{ + function registerParallelFunctionInternal(address, string, uint256) public returns (int); + function unregisterParallelFunctionInternal(address, string) public returns (int); +} + +contract ParallelContract +{ + ParallelConfigPrecompiled precompiled = ParallelConfigPrecompiled(0x1006); + + function registerParallelFunction(string functionName, uint256 criticalSize) public + { + precompiled.registerParallelFunctionInternal(address(this), functionName, criticalSize); + } + + function unregisterParallelFunction(string functionName) public + { + precompiled.unregisterParallelFunctionInternal(address(this), functionName); + } + + function enableParallel() public; + function disableParallel() public; +} \ No newline at end of file diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/ParallelOk.sol b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/ParallelOk.sol new file mode 100644 index 000000000..99a868a31 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/ParallelOk.sol @@ -0,0 +1,49 @@ +pragma solidity ^0.4.25; + +import "./ParallelContract.sol"; + +// A parallel contract example +contract ParallelOk is ParallelContract +{ + mapping (string => uint256) _balance; + + // Just an example, overflow is ok, use 'SafeMath' if needed + function transfer(string from, string to, uint256 num) public + { + _balance[from] -= num; + _balance[to] += num; + } + + // Just for testing whether the parallel revert function is working well, no practical use + function transferWithRevert(string from, string to, uint256 num) public + { + _balance[from] -= num; + _balance[to] += num; + require(num <= 100); + } + + function set(string name, uint256 num) public + { + _balance[name] = num; + } + + function balanceOf(string name) public view returns (uint256) + { + return _balance[name]; + } + + // Register parallel function + function enableParallel() public + { + // critical number is to define how many critical params from start + registerParallelFunction("transfer(string,string,uint256)", 2); // critical: string string + registerParallelFunction("set(string,uint256)", 1); // critical: string + } + + // Disable register parallel function + function disableParallel() public + { + unregisterParallelFunction("transfer(string,string,uint256)"); + unregisterParallelFunction("set(string,uint256)"); + } +} \ No newline at end of file diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/TableTest.sol b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/TableTest.sol new file mode 100644 index 000000000..8d57ee2aa --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/TableTest.sol @@ -0,0 +1,87 @@ +import "./Table.sol"; + +contract TableTest { + event createResult(int count); + event selectResult(bytes32 name, int item_id, bytes32 item_name); + event insertResult(int count); + event updateResult(int count); + event removeResult(int count); + + //create table + function create() public { + TableFactory tf = TableFactory(0x1001); //The fixed address is 0x1001 for TableFactory + int count = tf.createTable("t_test", "name", "item_id,item_name"); + emit createResult(count); + } + + //select records + function select(string name) public constant returns(bytes32[], int[], bytes32[]){ + TableFactory tf = TableFactory(0x1001); + Table table = tf.openTable("t_test"); + + Condition condition = table.newCondition(); + //condition.EQ("name", name); + + Entries entries = table.select(name, condition); + bytes32[] memory user_name_bytes_list = new bytes32[](uint256(entries.size())); + int[] memory item_id_list = new int[](uint256(entries.size())); + bytes32[] memory item_name_bytes_list = new bytes32[](uint256(entries.size())); + + for(int i=0; i()); + eventLogParams.setTopics(new ArrayList<>()); + + class SubscribeCallback implements EventCallback { + public transient Semaphore semaphore = new Semaphore(1, true); + + SubscribeCallback() { + try { + semaphore.acquire(1); + } catch (InterruptedException e) { + logger.error("error :", e); + Thread.currentThread().interrupt(); + } + } + + @Override + public void onReceiveLog(int status, List logs) { + String str = "status in onReceiveLog : " + status; + logger.debug(str); + semaphore.release(); + if (logs != null) { + for (EventLog log : logs) { + logger.debug( + " blockNumber:" + + log.getBlockNumber() + + ",txIndex:" + + log.getTransactionIndex() + + " data:" + + log.getData()); + } + } + } + } + + SubscribeCallback subscribeEventCallback = new SubscribeCallback(); + String registerId = eventSubscribe.subscribeEvent(eventLogParams, subscribeEventCallback); + System.out.print("subscribe event, registerId is " + registerId); + + while (true) {} + } + + public static void main(String[] args) { + allEventLog(); + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/event/SendOk.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/event/SendOk.java new file mode 100644 index 000000000..44828e319 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/event/SendOk.java @@ -0,0 +1,71 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.demo.event; + +import java.math.BigInteger; +import java.net.URL; +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.demo.contract.Ok; +import org.fisco.bcos.sdk.model.ConstantConfig; + +public class SendOk { + + private static void usage() { + System.out.println(" Usage:"); + System.out.println( + " \t java -cp 'conf/:lib/*:apps/*' org.fisco.bcos.sdk.demo.event.SendOk [groupId] [count]."); + } + + public static void main(String[] args) { + try { + String configFileName = ConstantConfig.CONFIG_FILE_NAME; + URL configUrl = SendOk.class.getClassLoader().getResource(configFileName); + + if (configUrl == null) { + System.out.println("The configFile " + configFileName + " doesn't exist!"); + return; + } + if (args.length < 2) { + usage(); + return; + } + int groupId = Integer.valueOf(args[0]).intValue(); + Integer count = Integer.valueOf(args[1]); + + String configFile = configUrl.getPath(); + BcosSDK sdk = BcosSDK.build(configFile); + + // build the client + Client client = sdk.getClient(groupId); + + // deploy the HelloWorld + System.out.println("====== Deploy Ok ====== "); + Ok ok = Ok.deploy(client, client.getCryptoSuite().getCryptoKeyPair()); + System.out.println( + "====== Deploy Ok successfully, address: " + + ok.getContractAddress() + + " ====== "); + + System.out.println("====== Send Ok trans begin ======"); + for (int i = 0; i < count; i++) { + ok.trans(new BigInteger("4")); + System.out.println("transaction idx " + i + " sent"); + } + System.out.println("====== Send Ok trans end ======"); + } catch (Exception e) { + System.out.println("====== Send Ok failed, error message: " + e.getMessage()); + } + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/ParallelOkPerf.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/ParallelOkPerf.java new file mode 100644 index 000000000..abdedd6fd --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/ParallelOkPerf.java @@ -0,0 +1,174 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.demo.perf; + +import java.io.IOException; +import java.math.BigInteger; +import java.net.URL; +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.demo.contract.ParallelOk; +import org.fisco.bcos.sdk.demo.perf.model.DagUserInfo; +import org.fisco.bcos.sdk.demo.perf.parallel.DagPrecompiledDemo; +import org.fisco.bcos.sdk.demo.perf.parallel.ParallelOkDemo; +import org.fisco.bcos.sdk.model.ConstantConfig; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; +import org.fisco.bcos.sdk.utils.ThreadPoolService; + +public class ParallelOkPerf { + private static Client client; + private static DagUserInfo dagUserInfo = new DagUserInfo(); + + public static void Usage() { + System.out.println(" Usage:"); + System.out.println("===== ParallelOk test==========="); + System.out.println( + " \t java -cp 'conf/:lib/*:apps/*' org.fisco.bcos.sdk.demo.perf.ParallelOkPerf [parallelok] [groupID] [add] [count] [tps] [file]."); + System.out.println( + " \t java -cp 'conf/:lib/*:apps/*' org.fisco.bcos.sdk.demo.perf.ParallelOkPerf [parallelok] [groupID] [transfer] [count] [tps] [file]."); + System.out.println("===== DagTransafer test==========="); + System.out.println( + " \t java -cp 'conf/:lib/*:apps/*' org.fisco.bcos.sdk.demo.perf.ParallelOkPerf [precompiled] [groupID] [add] [count] [tps] [file]."); + System.out.println( + " \t java -cp 'conf/:lib/*:apps/*' org.fisco.bcos.sdk.demo.perf.ParallelOkPerf [precompiled] [groupID] [transfer] [count] [tps] [file]."); + } + + public static void main(String[] args) + throws ContractException, IOException, InterruptedException { + try { + String configFileName = ConstantConfig.CONFIG_FILE_NAME; + URL configUrl = ParallelOkPerf.class.getClassLoader().getResource(configFileName); + if (configUrl == null) { + System.out.println("The configFile " + configFileName + " doesn't exist!"); + return; + } + if (args.length < 6) { + Usage(); + return; + } + String perfType = args[0]; + Integer groupId = Integer.valueOf(args[1]); + String command = args[2]; + Integer count = Integer.valueOf(args[3]); + Integer qps = Integer.valueOf(args[4]); + String userFile = args[5]; + + String configFile = configUrl.getPath(); + BcosSDK sdk = BcosSDK.build(configFile); + client = sdk.getClient(Integer.valueOf(groupId)); + dagUserInfo.setFile(userFile); + ThreadPoolService threadPoolService = + new ThreadPoolService( + "ParallelOkPerf", + sdk.getConfig().getThreadPoolConfig().getMaxBlockingQueueSize()); + + if (perfType.compareToIgnoreCase("parallelok") == 0) { + parallelOkPerf(groupId, command, count, qps, threadPoolService); + } else if (perfType.compareToIgnoreCase("precompiled") == 0) { + dagTransferPerf(groupId, command, count, qps, threadPoolService); + } else { + System.out.println( + "invalid perf option: " + + perfType + + ", only support parallelok/precompiled now"); + Usage(); + } + } catch (Exception e) { + System.out.println("ParallelOkPerf test failed, error info: " + e.getMessage()); + System.exit(0); + } + } + + public static void parallelOkPerf( + Integer groupId, + String command, + Integer count, + Integer qps, + ThreadPoolService threadPoolService) + throws IOException, InterruptedException, ContractException { + System.out.println( + "====== ParallelOk trans, count: " + + count + + ", qps:" + + qps + + ", groupId: " + + groupId); + ParallelOk parallelOk; + ParallelOkDemo parallelOkDemo; + switch (command) { + case "add": + // deploy ParallelOk + parallelOk = ParallelOk.deploy(client, client.getCryptoSuite().getCryptoKeyPair()); + // enable parallel + parallelOk.enableParallel(); + System.out.println( + "====== ParallelOk userAdd, deploy success, address: " + + parallelOk.getContractAddress()); + parallelOkDemo = new ParallelOkDemo(parallelOk, dagUserInfo, threadPoolService); + parallelOkDemo.userAdd(BigInteger.valueOf(count), BigInteger.valueOf(qps)); + break; + case "transfer": + dagUserInfo.loadDagTransferUser(); + parallelOk = + ParallelOk.load( + dagUserInfo.getContractAddr(), + client, + client.getCryptoSuite().getCryptoKeyPair()); + System.out.println( + "====== ParallelOk trans, load success, address: " + + parallelOk.getContractAddress()); + parallelOkDemo = new ParallelOkDemo(parallelOk, dagUserInfo, threadPoolService); + parallelOkDemo.userTransfer(BigInteger.valueOf(count), BigInteger.valueOf(qps)); + break; + + default: + System.out.println("invalid command: " + command); + Usage(); + break; + } + } + + public static void dagTransferPerf( + Integer groupId, + String command, + Integer count, + Integer qps, + ThreadPoolService threadPoolService) + throws IOException, InterruptedException, ContractException { + System.out.println( + "====== DagTransfer trans, count: " + + count + + ", qps:" + + qps + + ", groupId: " + + groupId); + + DagPrecompiledDemo dagPrecompiledDemo; + switch (command) { + case "add": + dagPrecompiledDemo = new DagPrecompiledDemo(client, dagUserInfo, threadPoolService); + dagPrecompiledDemo.userAdd(BigInteger.valueOf(count), BigInteger.valueOf(qps)); + break; + case "transfer": + dagUserInfo.loadDagTransferUser(); + dagPrecompiledDemo = new DagPrecompiledDemo(client, dagUserInfo, threadPoolService); + dagPrecompiledDemo.userTransfer(BigInteger.valueOf(count), BigInteger.valueOf(qps)); + break; + default: + System.out.println("invalid command: " + command); + Usage(); + break; + } + } +}; diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/PerformanceOk.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/PerformanceOk.java new file mode 100644 index 000000000..b728cefcd --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/PerformanceOk.java @@ -0,0 +1,135 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.demo.perf; + +import com.google.common.util.concurrent.RateLimiter; +import java.math.BigInteger; +import java.net.URL; +import java.util.concurrent.atomic.AtomicInteger; +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.BcosSDKException; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.demo.contract.Ok; +import org.fisco.bcos.sdk.demo.perf.callback.PerformanceCallback; +import org.fisco.bcos.sdk.demo.perf.collector.PerformanceCollector; +import org.fisco.bcos.sdk.model.ConstantConfig; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; +import org.fisco.bcos.sdk.utils.ThreadPoolService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PerformanceOk { + private static Logger logger = LoggerFactory.getLogger(PerformanceOk.class); + private static AtomicInteger sendedTransactions = new AtomicInteger(0); + + private static void Usage() { + System.out.println(" Usage:"); + System.out.println( + " \t java -cp 'conf/:lib/*:apps/*' org.fisco.bcos.sdk.demo.perf.PerformanceOk [count] [tps] [groupId]."); + } + + public static void main(String[] args) { + try { + String configFileName = ConstantConfig.CONFIG_FILE_NAME; + URL configUrl = PerformanceOk.class.getClassLoader().getResource(configFileName); + + if (configUrl == null) { + System.out.println("The configFile " + configFileName + " doesn't exist!"); + return; + } + if (args.length < 3) { + Usage(); + return; + } + Integer count = Integer.valueOf(args[0]); + Integer qps = Integer.valueOf(args[1]); + Integer groupId = Integer.valueOf(args[2]); + System.out.println( + "====== PerformanceOk trans, count: " + + count + + ", qps:" + + qps + + ", groupId: " + + groupId); + + String configFile = configUrl.getPath(); + BcosSDK sdk = BcosSDK.build(configFile); + + // build the client + Client client = sdk.getClient(groupId); + + // deploy the HelloWorld + System.out.println("====== Deploy Ok ====== "); + Ok ok = Ok.deploy(client, client.getCryptoSuite().getCryptoKeyPair()); + System.out.println( + "====== Deploy Ok succ, address: " + ok.getContractAddress() + " ====== "); + + PerformanceCollector collector = new PerformanceCollector(); + collector.setTotal(count); + RateLimiter limiter = RateLimiter.create(qps); + Integer area = count / 10; + final Integer total = count; + + System.out.println("====== PerformanceOk trans start ======"); + + ThreadPoolService threadPoolService = + new ThreadPoolService( + "PerformanceOk", + sdk.getConfig().getThreadPoolConfig().getMaxBlockingQueueSize()); + + for (Integer i = 0; i < count; ++i) { + limiter.acquire(); + threadPoolService + .getThreadPool() + .execute( + new Runnable() { + @Override + public void run() { + PerformanceCallback callback = new PerformanceCallback(); + callback.setTimeout(0); + callback.setCollector(collector); + try { + ok.trans(new BigInteger("4"), callback); + } catch (Exception e) { + TransactionReceipt receipt = new TransactionReceipt(); + receipt.setStatus("-1"); + callback.onResponse(receipt); + logger.info(e.getMessage()); + } + int current = sendedTransactions.incrementAndGet(); + if (current >= area && ((current % area) == 0)) { + System.out.println( + "Already sended: " + + current + + "/" + + total + + " transactions"); + } + } + }); + } + // wait to collect all the receipts + while (!collector.getReceived().equals(count)) { + Thread.sleep(1000); + } + threadPoolService.stop(); + System.exit(0); + } catch (BcosSDKException | ContractException | InterruptedException e) { + System.out.println( + "====== PerformanceOk test failed, error message: " + e.getMessage()); + System.exit(0); + } + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/PerformanceOkD.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/PerformanceOkD.java new file mode 100644 index 000000000..cc50f5311 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/PerformanceOkD.java @@ -0,0 +1,138 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.demo.perf; + +import com.google.common.util.concurrent.RateLimiter; +import java.math.BigInteger; +import java.net.URL; +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.BcosSDKException; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.demo.contract.OkD; +import org.fisco.bcos.sdk.demo.perf.callback.PerformanceCallback; +import org.fisco.bcos.sdk.demo.perf.collector.PerformanceCollector; +import org.fisco.bcos.sdk.model.ConstantConfig; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; +import org.fisco.bcos.sdk.utils.ThreadPoolService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PerformanceOkD { + private static Logger logger = LoggerFactory.getLogger(PerformanceOkD.class); + private static AtomicInteger sendedTransactions = new AtomicInteger(0); + + private static void Usage() { + System.out.println(" Usage:"); + System.out.println( + " \t java -cp 'conf/:lib/*:apps/*' org.fisco.bcos.sdk.demo.perf.PerformanceOkD [count] [tps] [groupId]."); + } + + public static void main(String[] args) { + try { + String configFileName = ConstantConfig.CONFIG_FILE_NAME; + URL configUrl = PerformanceOkD.class.getClassLoader().getResource(configFileName); + if (configUrl == null) { + System.out.println("The configFile " + configFileName + " doesn't exist!"); + return; + } + if (args.length < 3) { + Usage(); + return; + } + Integer count = Integer.valueOf(args[0]); + Integer qps = Integer.valueOf(args[1]); + Integer groupId = Integer.valueOf(args[2]); + System.out.println( + "====== PerformanceOkD trans, count: " + + count + + ", qps:" + + qps + + ", groupId: " + + groupId); + + String configFile = configUrl.getPath(); + BcosSDK sdk = BcosSDK.build(configFile); + + // build the client + Client client = sdk.getClient(groupId); + + // deploy the HelloWorld + System.out.println("====== Deploy OkD ====== "); + OkD okd = OkD.deploy(client, client.getCryptoSuite().getCryptoKeyPair()); + System.out.println( + "====== Deploy OkD success, address: " + okd.getContractAddress() + " ====== "); + + PerformanceCollector collector = new PerformanceCollector(); + collector.setTotal(count); + RateLimiter limiter = RateLimiter.create(qps); + Integer area = count / 10; + final Integer total = count; + + System.out.println("====== PerformanceOkD trans start ======"); + + ThreadPoolService threadPoolService = + new ThreadPoolService( + "PerformanceOkD", + sdk.getConfig().getThreadPoolConfig().getMaxBlockingQueueSize()); + Random random = new Random(System.currentTimeMillis()); + for (Integer i = 0; i < count; ++i) { + limiter.acquire(); + threadPoolService + .getThreadPool() + .execute( + new Runnable() { + @Override + public void run() { + PerformanceCallback callback = new PerformanceCallback(); + callback.setTimeout(0); + callback.setCollector(collector); + try { + okd.trans( + String.valueOf(random.nextLong()), + new BigInteger("1"), + callback); + } catch (Exception e) { + TransactionReceipt receipt = new TransactionReceipt(); + receipt.setStatus("-1"); + callback.onResponse(receipt); + logger.info(e.getMessage()); + } + int current = sendedTransactions.incrementAndGet(); + if (current >= area && ((current % area) == 0)) { + System.out.println( + "Already sended: " + + current + + "/" + + total + + " transactions"); + } + } + }); + } + // wait to collect all the receipts + while (!collector.getReceived().equals(count)) { + Thread.sleep(1000); + } + threadPoolService.stop(); + System.exit(0); + } catch (BcosSDKException | ContractException | InterruptedException e) { + System.out.println( + "====== PerformanceOkD test failed, error message: " + e.getMessage()); + System.exit(0); + } + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/PerformanceRPC.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/PerformanceRPC.java new file mode 100644 index 000000000..3d17a5781 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/PerformanceRPC.java @@ -0,0 +1,168 @@ +package org.fisco.bcos.sdk.demo.perf; + +import com.google.common.util.concurrent.RateLimiter; +import java.math.BigInteger; +import java.net.URL; +import java.security.SecureRandom; +import java.util.concurrent.atomic.AtomicInteger; +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.demo.perf.collector.PerformanceCollector; +import org.fisco.bcos.sdk.model.ConstantConfig; +import org.fisco.bcos.sdk.model.JsonRpcResponse; +import org.fisco.bcos.sdk.utils.ThreadPoolService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PerformanceRPC { + private static Logger logger = LoggerFactory.getLogger(PerformanceRPC.class); + private static AtomicInteger sended = new AtomicInteger(0); + + public static void Usage() { + System.out.println(" Usage:"); + System.out.println( + " \t java -cp 'conf/:lib/*:apps/*' org.fisco.bcos.sdk.demo.perf.PerformanceRPC groupID totalCount qps"); + System.exit(0); + } + + public static void main(String[] args) throws Exception { + try { + String configFileName = ConstantConfig.CONFIG_FILE_NAME; + URL configUrl = PerformanceOk.class.getClassLoader().getResource(configFileName); + + if (configUrl == null) { + System.out.println("The configFile " + configFileName + " doesn't exist!"); + return; + } + + if (args.length < 3) { + Usage(); + } + + Integer count = Integer.parseInt(args[0]); + Integer qps = Integer.parseInt(args[1]); + int groupId = Integer.valueOf(args[2]); + String configFile = configUrl.getPath(); + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(groupId); + + System.out.println("Start test..."); + System.out.println( + "==================================================================="); + + PerformanceCollector collector = new PerformanceCollector(); + collector.setTotal(count); + + RateLimiter limiter = RateLimiter.create(qps); + Integer area = count / 10; + final Integer total = count; + ThreadPoolService threadPoolService = + new ThreadPoolService( + "PerformanceRPC", + sdk.getConfig().getThreadPoolConfig().getMaxBlockingQueueSize()); + + System.out.println("Start test, total: " + count); + for (Integer i = 0; i < count; ++i) { + threadPoolService + .getThreadPool() + .execute( + new Runnable() { + @Override + public void run() { + limiter.acquire(); + JsonRpcResponse response = new JsonRpcResponse(); + try { + int random = new SecureRandom().nextInt(50000); + int methodNum = 10; + Long startTime = System.nanoTime(); + + switch (random % methodNum) { + // 1. call getPendingTxSize + case 0: + response = client.getPendingTxSize(); + break; + // 2. call getBlockNumber + case 1: + response = client.getBlockNumber(); + break; + // 3. call getSyncStatus + case 2: + response = client.getSyncStatus(); + break; + // 4. call getConsensusStatus + // case 3: + // response = + // web3j.getConsensusStatus().send(); + // break; + // 5. call getSealerList + case 4: + response = client.getSealerList(); + break; + // 6. call getTotalTransactionCount + case 5: + response = client.getTotalTransactionCount(); + break; + // 7. call getObserverList + case 6: + response = client.getObserverList(); + break; + // 8. call getBlockHashByNumber + case 7: + BigInteger blockNumber = + client.getBlockNumber() + .getBlockNumber(); + response = + client.getBlockHashByNumber( + blockNumber); + break; + // 9. call getSystemConfigByKey + case 8: + response = + client.getSystemConfigByKey( + "tx_count_limit"); + break; + // 10. call getPbftView + case 9: + response = client.getPbftView(); + break; + default: + // default call getPbftView + response = client.getPbftView(); + } + Long cost = System.nanoTime() - startTime; + collector.onRpcMessage(response, cost); + + } catch (Exception e) { + logger.error( + "test rpc interface failed, error info: {}", + e.getMessage()); + JsonRpcResponse.Error error = + new JsonRpcResponse.Error(); + error.setCode(1); + response.setError(error); + collector.onRpcMessage(response, 0L); + } + + int current = sended.incrementAndGet(); + + if (current >= area && ((current % area) == 0)) { + System.out.println( + "Already sended: " + + current + + "/" + + total + + " RPC Requests"); + } + } + }); + } + while (collector.getReceived().longValue() < collector.getTotal().longValue()) { + Thread.sleep(50); + } + System.exit(0); + } catch (Exception e) { + e.printStackTrace(); + System.exit(-1); + } + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/PerformanceTable.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/PerformanceTable.java new file mode 100644 index 000000000..9ad858064 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/PerformanceTable.java @@ -0,0 +1,237 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.demo.perf; + +import com.google.common.util.concurrent.RateLimiter; +import java.math.BigInteger; +import java.net.URL; +import java.util.Random; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.BcosSDKException; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.demo.contract.TableTest; +import org.fisco.bcos.sdk.demo.perf.callback.PerformanceCallback; +import org.fisco.bcos.sdk.demo.perf.collector.PerformanceCollector; +import org.fisco.bcos.sdk.model.ConstantConfig; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; +import org.fisco.bcos.sdk.utils.ThreadPoolService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PerformanceTable { + private static Logger logger = LoggerFactory.getLogger(PerformanceTable.class); + private static AtomicInteger sendedTransactions = new AtomicInteger(0); + private static AtomicLong uniqueID = new AtomicLong(0); + + private static void Usage() { + System.out.println(" Usage:"); + System.out.println("===== PerformanceTable test==========="); + System.out.println( + " \t java -cp \'conf/:lib/*:apps/*\' org.fisco.bcos.sdk.demo.perf.PerformanceTable [insert] [count] [tps] [groupId]."); + System.out.println( + " \t java -cp \'conf/:lib/*:apps/*\' org.fisco.bcos.sdk.demo.perf.PerformanceTable [update] [count] [tps] [groupId]."); + System.out.println( + " \t java -cp \'conf/:lib/*:apps/*\' org.fisco.bcos.sdk.demo.perf.PerformanceTable [remove] [count] [tps] [groupId]."); + System.out.println( + " \t java -cp \'conf/:lib/*:apps/*\' org.fisco.bcos.sdk.demo.perf.PerformanceTable [query] [count] [tps] [groupId]."); + } + + public static void main(String[] args) { + try { + String configFileName = ConstantConfig.CONFIG_FILE_NAME; + URL configUrl = PerformanceTable.class.getClassLoader().getResource(configFileName); + if (configUrl == null) { + System.out.println("The configFile " + configFileName + " doesn't exist!"); + return; + } + if (args.length < 4) { + Usage(); + return; + } + String command = args[0]; + Integer count = Integer.valueOf(args[1]); + Integer qps = Integer.valueOf(args[2]); + Integer groupId = Integer.valueOf(args[3]); + System.out.println( + "====== PerformanceTable " + + command + + ", count: " + + count + + ", qps:" + + qps + + ", groupId: " + + groupId); + + String configFile = configUrl.getPath(); + BcosSDK sdk = BcosSDK.build(configFile); + + // build the client + Client client = sdk.getClient(groupId); + + // deploy the HelloWorld + System.out.println("====== Deploy TableTest ====== "); + TableTest tableTest = + TableTest.deploy(client, client.getCryptoSuite().getCryptoKeyPair()); + // create table + tableTest.create(); + System.out.println( + "====== Deploy TableTest success, address: " + + tableTest.getContractAddress() + + " ====== "); + + PerformanceCollector collector = new PerformanceCollector(); + collector.setTotal(count); + RateLimiter limiter = RateLimiter.create(qps); + Integer area = count / 10; + final Integer total = count; + + System.out.println("====== PerformanceTable " + command + " start ======"); + ThreadPoolService threadPoolService = + new ThreadPoolService( + "PerformanceTable", + sdk.getConfig().getThreadPoolConfig().getMaxBlockingQueueSize()); + for (Integer i = 0; i < count; ++i) { + limiter.acquire(); + threadPoolService + .getThreadPool() + .execute( + new Runnable() { + @Override + public void run() { + callTableOperation(command, tableTest, collector); + int current = sendedTransactions.incrementAndGet(); + if (current >= area && ((current % area) == 0)) { + System.out.println( + "Already sended: " + + current + + "/" + + total + + " transactions"); + } + } + }); + } + // wait to collect all the receipts + while (!collector.getReceived().equals(count)) { + Thread.sleep(1000); + } + threadPoolService.stop(); + System.exit(0); + } catch (BcosSDKException | ContractException | InterruptedException e) { + System.out.println( + "====== PerformanceTable test failed, error message: " + e.getMessage()); + System.exit(0); + } + } + + private static void callTableOperation( + String command, TableTest tableTest, PerformanceCollector collector) { + if (command.compareToIgnoreCase("insert") == 0) { + insert(tableTest, collector); + } + + if (command.compareToIgnoreCase("update") == 0) { + update(tableTest, collector); + } + if (command.compareToIgnoreCase("remove") == 0) { + remove(tableTest, collector); + } + if (command.compareToIgnoreCase("query") == 0) { + query(tableTest, collector); + } + } + + public static long getNextID() { + return uniqueID.getAndIncrement(); + } + + private static String getId() { + UUID uuid = UUID.randomUUID(); + return uuid.toString().replace("-", ""); + } + + private static PerformanceCallback createCallback(PerformanceCollector collector) { + PerformanceCallback callback = new PerformanceCallback(); + callback.setTimeout(0); + callback.setCollector(collector); + return callback; + } + + private static void sendTransactionException( + Exception e, String command, PerformanceCallback callback) { + TransactionReceipt receipt = new TransactionReceipt(); + receipt.setStatus("-1"); + callback.onResponse(receipt); + logger.info("call command {} failed, error info: {}", command, e.getMessage()); + } + + private static void insert(TableTest tableTest, PerformanceCollector collector) { + PerformanceCallback callback = createCallback(collector); + try { + long _id = getNextID(); + tableTest.insert( + "fruit" + _id % 100, BigInteger.valueOf(_id), "apple" + getId(), callback); + } catch (Exception e) { + sendTransactionException(e, "insert", callback); + } + } + + private static void update(TableTest tableTest, PerformanceCollector collector) { + PerformanceCallback callback = createCallback(collector); + try { + long _id = getNextID(); + Random r = new Random(); + long l1 = r.nextLong(); + tableTest.update( + "fruit" + l1 % 100, BigInteger.valueOf(_id), "apple" + getId(), callback); + } catch (Exception e) { + sendTransactionException(e, "update", callback); + } + } + + private static void remove(TableTest tableTest, PerformanceCollector collector) { + PerformanceCallback callback = createCallback(collector); + try { + long _id = getNextID(); + Random r = new Random(); + long l1 = r.nextLong(); + tableTest.remove("fruit" + l1 % 100, BigInteger.valueOf(_id), callback); + + } catch (Exception e) { + sendTransactionException(e, "remove", callback); + } + } + + private static void query(TableTest tableTest, PerformanceCollector collector) { + try { + Long time_before = System.currentTimeMillis(); + Random r = new Random(); + long l1 = r.nextLong(); + tableTest.select("fruit" + l1 % 100); + Long time_after = System.currentTimeMillis(); + TransactionReceipt receipt = new TransactionReceipt(); + receipt.setStatus("0x0"); + collector.onMessage(receipt, time_after - time_before); + } catch (Exception e) { + TransactionReceipt receipt = new TransactionReceipt(); + receipt.setStatus("-1"); + collector.onMessage(receipt, (long) (0)); + logger.error("query error: {}", e); + } + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/callback/ParallelOkCallback.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/callback/ParallelOkCallback.java new file mode 100644 index 000000000..88dccd746 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/callback/ParallelOkCallback.java @@ -0,0 +1,100 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.demo.perf.callback; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.demo.perf.collector.PerformanceCollector; +import org.fisco.bcos.sdk.demo.perf.model.DagTransferUser; +import org.fisco.bcos.sdk.demo.perf.model.DagUserInfo; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ParallelOkCallback extends TransactionCallback { + private static Logger logger = LoggerFactory.getLogger(ParallelOkCallback.class); + public static final String ADD_USER_CALLBACK = "add"; + public static final String TRANS_CALLBACK = "transfer"; + private Long startTime; + + private final PerformanceCollector collector; + private final DagUserInfo dagUserInfo; + private final String callbackType; + + private DagTransferUser user = null; + private DagTransferUser fromUser = null; + private DagTransferUser toUser = null; + private BigInteger amount = null; + + public ParallelOkCallback( + PerformanceCollector collector, DagUserInfo dagUserInfo, String callbackType) { + this.collector = collector; + this.dagUserInfo = dagUserInfo; + this.callbackType = callbackType; + } + + public void recordStartTime() { + this.startTime = System.currentTimeMillis(); + } + + @Override + public void onResponse(TransactionReceipt receipt) { + Long cost = System.currentTimeMillis() - startTime; + try { + if (receipt.isStatusOK()) { + if (callbackType.compareTo(ADD_USER_CALLBACK) == 0) { // add test + dagUserInfo.addUser(user); + } else if (callbackType.compareTo(TRANS_CALLBACK) == 0) { // transfer test + fromUser.decrease(amount); + toUser.increase(amount); + } + } + collector.onMessage(receipt, cost); + } catch (Exception e) { + logger.error("onMessage error: ", e); + } + } + + public DagTransferUser getFromUser() { + return fromUser; + } + + public void setFromUser(DagTransferUser fromUser) { + this.fromUser = fromUser; + } + + public DagTransferUser getToUser() { + return toUser; + } + + public void setToUser(DagTransferUser toUser) { + this.toUser = toUser; + } + + public BigInteger getAmount() { + return amount; + } + + public void setAmount(BigInteger amount) { + this.amount = amount; + } + + public DagTransferUser getUser() { + return user; + } + + public void setUser(DagTransferUser user) { + this.user = user; + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/callback/PerformanceCallback.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/callback/PerformanceCallback.java new file mode 100644 index 000000000..0631dcc01 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/callback/PerformanceCallback.java @@ -0,0 +1,49 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.demo.perf.callback; + +import org.fisco.bcos.sdk.demo.perf.collector.PerformanceCollector; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PerformanceCallback extends TransactionCallback { + + private static Logger logger = LoggerFactory.getLogger(PerformanceCallback.class); + private Long startTime = System.currentTimeMillis(); + + private PerformanceCollector collector; + + public PerformanceCollector getCollector() { + return collector; + } + + public void setCollector(PerformanceCollector collector) { + this.collector = collector; + } + + public PerformanceCallback() {} + + @Override + public void onResponse(TransactionReceipt receipt) { + Long cost = System.currentTimeMillis() - startTime; + + try { + collector.onMessage(receipt, cost); + } catch (Exception e) { + logger.error("onMessage error: ", e); + } + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/collector/PerformanceCollector.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/collector/PerformanceCollector.java new file mode 100644 index 000000000..d5505ebf6 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/collector/PerformanceCollector.java @@ -0,0 +1,191 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.demo.perf.collector; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import org.fisco.bcos.sdk.model.JsonRpcResponse; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PerformanceCollector { + private static Logger logger = LoggerFactory.getLogger(PerformanceCollector.class); + private AtomicLong less50 = new AtomicLong(0); + private AtomicLong less100 = new AtomicLong(0); + private AtomicLong less200 = new AtomicLong(0); + private AtomicLong less400 = new AtomicLong(0); + private AtomicLong less1000 = new AtomicLong(0); + private AtomicLong less2000 = new AtomicLong(0); + private AtomicLong timeout2000 = new AtomicLong(0); + private AtomicLong totalCost = new AtomicLong(0); + + private Integer total = 0; + private AtomicInteger received = new AtomicInteger(0); + private AtomicInteger error = new AtomicInteger(0); + private Long startTimestamp = System.currentTimeMillis(); + + public Integer getTotal() { + return total; + } + + public void setTotal(Integer total) { + this.total = total; + } + + public Integer getReceived() { + return received.get(); + } + + public void setReceived(Integer received) { + this.received.getAndSet(received); + } + + public void onRpcMessage(JsonRpcResponse response, Long cost) { + try { + boolean errorMessage = false; + if (response.getError() != null && response.getError().getCode() != 0) { + logger.warn("receive error jsonRpcResponse: {}", response.toString()); + errorMessage = true; + } + stat(errorMessage, cost); + } catch (Exception e) { + logger.error("onRpcMessage exception: {}", e.getMessage()); + } + } + + public void onMessage(TransactionReceipt receipt, Long cost) { + try { + boolean errorMessage = false; + if (!receipt.isStatusOK()) { + logger.error( + "error receipt, status: {}, output: {}, message: {}", + receipt.getStatus(), + receipt.getOutput(), + receipt.getMessage()); + errorMessage = true; + } + stat(errorMessage, cost); + } catch (Exception e) { + logger.error("error:", e); + } + } + + public void stat(boolean errorMessage, Long cost) { + if (errorMessage) { + error.addAndGet(1); + } + + if ((received.get() + 1) % (total / 10) == 0) { + System.out.println( + " |received:" + + String.valueOf((received.get() + 1) * 100 / total) + + "%"); + } + + if (cost < 50) { + less50.incrementAndGet(); + } else if (cost < 100) { + less100.incrementAndGet(); + } else if (cost < 200) { + less200.incrementAndGet(); + } else if (cost < 400) { + less400.incrementAndGet(); + } else if (cost < 1000) { + less1000.incrementAndGet(); + } else if (cost < 2000) { + less2000.incrementAndGet(); + } else { + timeout2000.incrementAndGet(); + } + + totalCost.addAndGet(cost); + + if (received.incrementAndGet() >= total) { + System.out.println("total"); + + Long totalTime = System.currentTimeMillis() - startTimestamp; + + System.out.println( + "==================================================================="); + + System.out.println("Total transactions: " + String.valueOf(total)); + System.out.println("Total time: " + String.valueOf(totalTime) + "ms"); + System.out.println( + "TPS(include error requests): " + + String.valueOf(total / ((double) totalTime / 1000))); + System.out.println( + "TPS(exclude error requests): " + + String.valueOf( + (double) (total - error.get()) / ((double) totalTime / 1000))); + System.out.println("Avg time cost: " + String.valueOf(totalCost.get() / total) + "ms"); + System.out.println( + "Error rate: " + + String.valueOf((error.get() / (double) received.get()) * 100) + + "%"); + + System.out.println("Time area:"); + System.out.println( + "0 < time < 50ms : " + + String.valueOf(less50) + + " : " + + String.valueOf((double) less50.get() / total * 100) + + "%"); + System.out.println( + "50 < time < 100ms : " + + String.valueOf(less100) + + " : " + + String.valueOf((double) less100.get() / total * 100) + + "%"); + System.out.println( + "100 < time < 200ms : " + + String.valueOf(less200) + + " : " + + String.valueOf((double) less200.get() / total * 100) + + "%"); + System.out.println( + "200 < time < 400ms : " + + String.valueOf(less400) + + " : " + + String.valueOf((double) less400.get() / total * 100) + + "%"); + System.out.println( + "400 < time < 1000ms : " + + String.valueOf(less1000) + + " : " + + String.valueOf((double) less1000.get() / total * 100) + + "%"); + System.out.println( + "1000 < time < 2000ms : " + + String.valueOf(less2000) + + " : " + + String.valueOf((double) less2000.get() / total * 100) + + "%"); + System.out.println( + "2000 < time : " + + String.valueOf(timeout2000) + + " : " + + String.valueOf((double) timeout2000.get() / total * 100) + + "%"); + } + } + + public void setStartTimestamp(Long startTimestamp) { + this.startTimestamp = startTimestamp; + } + + public Long getStartTimestamp() { + return startTimestamp; + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/model/DagTransferUser.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/model/DagTransferUser.java new file mode 100644 index 000000000..c0ac1f464 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/model/DagTransferUser.java @@ -0,0 +1,45 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.demo.perf.model; + +import java.math.BigInteger; + +public class DagTransferUser { + private String user; + private BigInteger amount; + + public String getUser() { + return user; + } + + public synchronized void setUser(String user) { + this.user = user; + } + + public synchronized BigInteger getAmount() { + return amount; + } + + public synchronized void setAmount(BigInteger amount) { + this.amount = amount; + } + + public synchronized void increase(BigInteger amount) { + this.amount = this.amount.add(amount); + } + + public synchronized void decrease(BigInteger amount) { + this.amount = this.amount.subtract(amount); + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/model/DagUserInfo.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/model/DagUserInfo.java new file mode 100644 index 000000000..9f6bbbc53 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/model/DagUserInfo.java @@ -0,0 +1,150 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.demo.perf.model; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DagUserInfo { + private static Logger logger = LoggerFactory.getLogger(DagUserInfo.class); + + private List userList = new ArrayList(); + + private String file = null; + + private String parallelokAddr = ""; + + public void setContractAddr(String addr) { + this.parallelokAddr = addr; + } + + public String getContractAddr() { + return this.parallelokAddr; + } + + public List getUserList() { + return userList; + } + + public void setUserList(List userList) { + this.userList = userList; + } + + public String getFile() { + return file; + } + + public void setFile(String file) { + this.file = file; + } + + public synchronized void addUser(DagTransferUser user) { + userList.add(user); + } + + public boolean isEmpty() { + return userList.isEmpty(); + } + + public DagTransferUser getFrom(int idx) { + assert !isEmpty() : "Has no user."; + return userList.get(idx % userList.size()); + } + + public DagTransferUser getTo(int idx) { + assert !isEmpty() : "Has no user."; + int mid = userList.size() / 2; + return userList.get((idx + mid) % userList.size()); + } + + public DagTransferUser getNext(int idx) { + return userList.get((idx + 1) % userList.size()); + } + + public void writeDagTransferUser() throws IOException { + if (file == null) { + return; + } + logger.info("file {}, begin load.", file); + + BufferedWriter bw = null; + try { + bw = new BufferedWriter(new FileWriter(new File(file))); + + // Write contract address first + bw.write(parallelokAddr + "\n"); + + // And write user + for (int i = 0; i < userList.size(); i++) { + bw.write(userList.get(i).getUser() + "\n"); + logger.trace(" write user , user is {}", userList.get(i).getUser()); + } + + bw.flush(); + + } finally { + if (bw != null) { + bw.close(); + } + } + + logger.info("file {}, load end, count is {}.", file, userList.size()); + System.out.println(" Write DagTransferUser end, count is " + userList.size()); + } + + public void loadDagTransferUser() throws IOException { + if (file == null) { + return; + } + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(new File(file))); + + String line = null; + + // Get contract addr first + if ((line = br.readLine()) != null) { + parallelokAddr = line; + } + + // And get user + while ((line = br.readLine()) != null) { + line = line.trim(); + if (!line.isEmpty()) { + DagTransferUser user = new DagTransferUser(); + user.setUser(line); + addUser(user); + // System.out.println("load DagTransferUser ==>> " + line); + } + } + + } finally { + if (br != null) { + br.close(); + } + } + + logger.info("file {}, load end, count is {}.", file, userList.size()); + + System.out.println("Load DagTransferUser end, count is " + userList.size()); + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/parallel/DagPrecompiledDemo.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/parallel/DagPrecompiledDemo.java new file mode 100644 index 000000000..01a3fa412 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/parallel/DagPrecompiledDemo.java @@ -0,0 +1,321 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.demo.perf.parallel; + +import com.google.common.util.concurrent.RateLimiter; +import java.io.IOException; +import java.math.BigInteger; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.demo.contract.DagTransfer; +import org.fisco.bcos.sdk.demo.perf.callback.ParallelOkCallback; +import org.fisco.bcos.sdk.demo.perf.collector.PerformanceCollector; +import org.fisco.bcos.sdk.demo.perf.model.DagTransferUser; +import org.fisco.bcos.sdk.demo.perf.model.DagUserInfo; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.utils.ThreadPoolService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DagPrecompiledDemo { + private static final Logger logger = LoggerFactory.getLogger(DagPrecompiledDemo.class); + private final DagTransfer dagTransfer; + private final DagUserInfo dagUserInfo; + private final PerformanceCollector collector; + private final ThreadPoolService threadPoolService; + private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private static final String DAG_TRANSFER_ADDR = "0x0000000000000000000000000000000000005002"; + + public DagPrecompiledDemo( + Client client, DagUserInfo dagUserInfo, ThreadPoolService threadPoolService) { + this.threadPoolService = threadPoolService; + this.dagTransfer = + DagTransfer.load( + DAG_TRANSFER_ADDR, client, client.getCryptoSuite().getCryptoKeyPair()); + this.dagUserInfo = dagUserInfo; + this.collector = new PerformanceCollector(); + } + + public void userAdd(BigInteger userCount, BigInteger qps) + throws InterruptedException, IOException { + System.out.println("Start userAdd test..."); + System.out.println("==================================================================="); + RateLimiter limiter = RateLimiter.create(qps.intValue()); + Integer area = userCount.intValue() / 10; + + long seconds = System.currentTimeMillis() / 1000L; + + this.collector.setStartTimestamp(System.currentTimeMillis()); + AtomicInteger sended = new AtomicInteger(0); + AtomicInteger sendFailed = new AtomicInteger(9); + collector.setTotal(userCount.intValue()); + + for (Integer i = 0; i < userCount.intValue(); i++) { + final Integer index = i; + limiter.acquire(); + threadPoolService + .getThreadPool() + .execute( + new Runnable() { + @Override + public void run() { + String user = + Long.toHexString(seconds) + Integer.toHexString(index); + BigInteger amount = new BigInteger("1000000000"); + DagTransferUser dtu = new DagTransferUser(); + dtu.setUser(user); + dtu.setAmount(amount); + ParallelOkCallback callback = + new ParallelOkCallback( + collector, + dagUserInfo, + ParallelOkCallback.ADD_USER_CALLBACK); + callback.setUser(dtu); + try { + callback.recordStartTime(); + callback.setTimeout(0); + dagTransfer.userAdd(user, amount, callback); + int current = sended.incrementAndGet(); + if (current >= area && ((current % area) == 0)) { + System.out.println( + "Already sended: " + + current + + "/" + + userCount + + " transactions"); + } + } catch (Exception e) { + TransactionReceipt receipt = new TransactionReceipt(); + receipt.setStatus("-1"); + callback.onResponse(receipt); + logger.error( + "dagTransfer add failed, error info: " + + e.getMessage()); + sendFailed.incrementAndGet(); + logger.info(e.getMessage()); + } + } + }); + } + while (collector.getReceived().intValue() != collector.getTotal().intValue()) { + logger.info( + " received: {}, total: {}, sendFailed: {}, sended: {}", + collector.getReceived().intValue(), + collector.getTotal(), + sendFailed.get(), + sended.get()); + Thread.sleep(2000); + } + // save the user info + dagUserInfo.writeDagTransferUser(); + System.exit(0); + } + + public void queryAccountInfo(BigInteger qps) throws InterruptedException { + System.out.println("Start queryAccountInfo..."); + // get the user + List allUser = dagUserInfo.getUserList(); + RateLimiter rateLimiter = RateLimiter.create(qps.intValue()); + AtomicInteger getted = new AtomicInteger(0); + for (Integer i = 0; i < allUser.size(); i++) { + final Integer index = i; + rateLimiter.acquire(); + threadPoolService + .getThreadPool() + .execute( + new Runnable() { + @Override + public void run() { + try { + Tuple2 result = + dagTransfer.userBalance( + allUser.get(index).getUser()); + + if (result.getValue1().compareTo(new BigInteger("0")) + == 0) { + allUser.get(index).setAmount(result.getValue2()); + } else { + System.out.println( + " Query failed, user is " + + allUser.get(index).getUser()); + System.exit(0); + } + int all = getted.incrementAndGet(); + if (all >= allUser.size()) { + System.out.println( + dateFormat.format(new Date()) + + " Query account finished"); + } + } catch (Exception e) { + System.out.println( + " Query failed, user is " + + allUser.get(index).getUser()); + System.exit(0); + } + } + }); + } + while (getted.get() < allUser.size()) { + Thread.sleep(50); + } + } + + public void userTransfer(BigInteger count, BigInteger qps) throws InterruptedException { + System.out.println("Start userTransfer test..."); + System.out.println("==================================================================="); + queryAccountInfo(qps); + long startTime = System.currentTimeMillis(); + AtomicInteger sended = new AtomicInteger(0); + AtomicInteger sendFailed = new AtomicInteger(0); + collector.setTotal(count.intValue()); + collector.setStartTimestamp(startTime); + Integer area = count.intValue() / 10; + RateLimiter rateLimiter = RateLimiter.create(qps.intValue()); + // transfer balance + for (Integer i = 0; i < count.intValue(); i++) { + final Integer index = i; + rateLimiter.acquire(); + threadPoolService + .getThreadPool() + .execute( + new Runnable() { + @Override + public void run() { + ParallelOkCallback callback = + new ParallelOkCallback( + collector, + dagUserInfo, + ParallelOkCallback.TRANS_CALLBACK); + try { + DagTransferUser from = dagUserInfo.getFrom(index); + DagTransferUser to = dagUserInfo.getTo(index); + Random random = new Random(); + int r = random.nextInt(100) + 1; + BigInteger amount = BigInteger.valueOf(r); + callback.setFromUser(from); + callback.setToUser(to); + callback.setAmount(amount); + callback.setTimeout(0); + callback.recordStartTime(); + dagTransfer.userTransfer( + from.getUser(), to.getUser(), amount, callback); + long elapsed = System.currentTimeMillis() - startTime; + sended.incrementAndGet(); + double sendSpeed = sended.get() / ((double) elapsed / 1000); + if (sended.get() >= area && ((sended.get() % area) == 0)) { + System.out.println( + "Already sent: " + + sended.get() + + "/" + + count + + " transactions"); + } + } catch (Exception e) { + logger.warn( + "userTransfer failed, error info: {}", + e.getMessage()); + TransactionReceipt receipt = new TransactionReceipt(); + receipt.setStatus("-1"); + receipt.setMessage( + "userTransfer failed, error info: " + + e.getMessage()); + callback.onResponse(receipt); + sendFailed.incrementAndGet(); + } + } + }); + } + while (collector.getReceived().intValue() != count.intValue()) { + Thread.sleep(2000); + logger.info( + " received: {}, total: {}, sended: {}, sendFailed: {}", + collector.getReceived().intValue(), + collector.getTotal(), + sended.get(), + sendFailed.get()); + } + veryTransferData(qps); + System.exit(0); + } + + public void veryTransferData(BigInteger qps) throws InterruptedException { + System.out.println("Start veryTransferData..."); + RateLimiter rateLimiter = RateLimiter.create(qps.intValue()); + AtomicInteger verify_success = new AtomicInteger(0); + AtomicInteger verify_failed = new AtomicInteger(0); + + List allUser = dagUserInfo.getUserList(); + for (Integer i = 0; i < allUser.size(); i++) { + final Integer index = i; + rateLimiter.acquire(); + threadPoolService + .getThreadPool() + .execute( + new Runnable() { + @Override + public void run() { + try { + Tuple2 result = + dagTransfer.userBalance( + allUser.get(index).getUser()); + + String user = allUser.get(index).getUser(); + BigInteger local = allUser.get(index).getAmount(); + BigInteger remote = result.getValue2(); + + if (result.getValue1().compareTo(new BigInteger("0")) + != 0) { + logger.error( + " query failed, user " + + user + + " ret code " + + result.getValue1()); + verify_failed.incrementAndGet(); + return; + } + if (local.compareTo(remote) != 0) { + verify_failed.incrementAndGet(); + logger.error( + " local amount is not same as remote, user " + + user + + " local " + + local + + " remote " + + remote); + } else { + verify_success.incrementAndGet(); + } + } catch (Exception e) { + logger.error( + "get amount failed, error info: {}", + e.getMessage()); + verify_failed.incrementAndGet(); + } + } + }); + } + while (verify_success.get() + verify_failed.get() < allUser.size()) { + Thread.sleep(40); + } + System.out.println("validation:"); + System.out.println(" \tuser count is " + allUser.size()); + System.out.println(" \tverify_success count is " + verify_success); + System.out.println(" \tverify_failed count is " + verify_failed); + } +} diff --git a/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/parallel/ParallelOkDemo.java b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/parallel/ParallelOkDemo.java new file mode 100644 index 000000000..04eb87787 --- /dev/null +++ b/sdk-demo/src/main/java/org/fisco/bcos/sdk/demo/perf/parallel/ParallelOkDemo.java @@ -0,0 +1,303 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.demo.perf.parallel; + +import com.google.common.util.concurrent.RateLimiter; +import java.io.IOException; +import java.math.BigInteger; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; +import org.fisco.bcos.sdk.demo.contract.ParallelOk; +import org.fisco.bcos.sdk.demo.perf.callback.ParallelOkCallback; +import org.fisco.bcos.sdk.demo.perf.collector.PerformanceCollector; +import org.fisco.bcos.sdk.demo.perf.model.DagTransferUser; +import org.fisco.bcos.sdk.demo.perf.model.DagUserInfo; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; +import org.fisco.bcos.sdk.utils.ThreadPoolService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ParallelOkDemo { + private static final Logger logger = LoggerFactory.getLogger(ParallelOkDemo.class); + private static AtomicInteger sended = new AtomicInteger(0); + private AtomicInteger getted = new AtomicInteger(0); + + private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private final ParallelOk parallelOk; + private final ThreadPoolService threadPoolService; + private final PerformanceCollector collector; + private final DagUserInfo dagUserInfo; + + public ParallelOkDemo( + ParallelOk parallelOk, DagUserInfo dagUserInfo, ThreadPoolService threadPoolService) { + this.threadPoolService = threadPoolService; + this.parallelOk = parallelOk; + this.dagUserInfo = dagUserInfo; + this.collector = new PerformanceCollector(); + } + + public void veryTransferData(BigInteger qps) throws InterruptedException { + RateLimiter rateLimiter = RateLimiter.create(qps.intValue()); + System.out.println("==================================================================="); + AtomicInteger verifyFailed = new AtomicInteger(0); + AtomicInteger verifySuccess = new AtomicInteger(0); + + final List userInfo = dagUserInfo.getUserList(); + int userSize = userInfo.size(); + for (int i = 0; i < userSize; i++) { + rateLimiter.acquire(); + final int userIndex = i; + threadPoolService + .getThreadPool() + .execute( + new Runnable() { + @Override + public void run() { + try { + String user = userInfo.get(userIndex).getUser(); + BigInteger balance = parallelOk.balanceOf(user); + BigInteger localAmount = + userInfo.get(userIndex).getAmount(); + if (localAmount.compareTo(balance) != 0) { + logger.error( + "local balance is not the same as the remote, user: {}, local balance: {}, remote balance: {}", + user, + localAmount, + balance); + verifyFailed.incrementAndGet(); + } else { + verifySuccess.incrementAndGet(); + } + } catch (ContractException exception) { + verifyFailed.incrementAndGet(); + logger.error( + "get remote balance failed, error info: " + + exception.getMessage()); + } + } + }); + } + while (verifySuccess.get() + verifyFailed.get() < userSize) { + Thread.sleep(40); + } + + System.out.println("validation:"); + System.out.println(" \tuser count is " + userSize); + System.out.println(" \tverify_success count is " + verifySuccess); + System.out.println(" \tverify_failed count is " + verifyFailed); + } + + public void userAdd(BigInteger userCount, BigInteger qps) + throws InterruptedException, IOException { + System.out.println("==================================================================="); + System.out.println("Start UserAdd test, count " + userCount); + RateLimiter limiter = RateLimiter.create(qps.intValue()); + + long currentSeconds = System.currentTimeMillis() / 1000L; + Integer area = userCount.intValue() / 10; + long startTime = System.currentTimeMillis(); + collector.setTotal(userCount.intValue()); + collector.setStartTimestamp(startTime); + AtomicInteger sendFailed = new AtomicInteger(0); + for (Integer i = 0; i < userCount.intValue(); i++) { + final Integer index = i; + limiter.acquire(); + threadPoolService + .getThreadPool() + .execute( + new Runnable() { + @Override + public void run() { + // generate the user according to currentSeconds + String user = + Long.toHexString(currentSeconds) + + Integer.toHexString(index); + BigInteger amount = new BigInteger("1000000000"); + DagTransferUser dtu = new DagTransferUser(); + dtu.setUser(user); + dtu.setAmount(amount); + ParallelOkCallback callback = + new ParallelOkCallback( + collector, + dagUserInfo, + ParallelOkCallback.ADD_USER_CALLBACK); + callback.setTimeout(0); + callback.setUser(dtu); + try { + callback.recordStartTime(); + parallelOk.set(user, amount, callback); + int current = sended.incrementAndGet(); + + if (current >= area && ((current % area) == 0)) { + long elapsed = System.currentTimeMillis() - startTime; + double sendSpeed = current / ((double) elapsed / 1000); + System.out.println( + "Already sended: " + + current + + "/" + + userCount + + " transactions" + + ",QPS=" + + sendSpeed); + } + + } catch (Exception e) { + logger.warn( + "addUser failed, error info: {}", e.getMessage()); + sendFailed.incrementAndGet(); + TransactionReceipt receipt = new TransactionReceipt(); + receipt.setStatus("-1"); + receipt.setMessage( + "userAdd failed, error info: " + e.getMessage()); + callback.onResponse(receipt); + } + } + }); + } + while (collector.getReceived().intValue() != userCount.intValue()) { + logger.info( + " sendFailed: {}, received: {}, total: {}", + sendFailed.get(), + collector.getReceived().intValue(), + collector.getTotal()); + Thread.sleep(100); + } + dagUserInfo.setContractAddr(parallelOk.getContractAddress()); + dagUserInfo.writeDagTransferUser(); + System.exit(0); + } + + public void queryAccount(BigInteger qps) throws InterruptedException { + final List allUsers = dagUserInfo.getUserList(); + RateLimiter rateLimiter = RateLimiter.create(qps.intValue()); + AtomicInteger sent = new AtomicInteger(0); + for (Integer i = 0; i < allUsers.size(); i++) { + final Integer index = i; + rateLimiter.acquire(); + threadPoolService + .getThreadPool() + .execute( + new Runnable() { + @Override + public void run() { + try { + BigInteger result = + parallelOk.balanceOf(allUsers.get(index).getUser()); + allUsers.get(index).setAmount(result); + int all = sent.incrementAndGet(); + if (all >= allUsers.size()) { + System.out.println( + dateFormat.format(new Date()) + + " Query account finished"); + } + } catch (ContractException exception) { + logger.warn( + "queryAccount for {} failed, error info: {}", + allUsers.get(index).getUser(), + exception.getMessage()); + System.exit(0); + } + } + }); + } + while (sent.get() < allUsers.size()) { + Thread.sleep(50); + } + } + + public void userTransfer(BigInteger count, BigInteger qps) + throws InterruptedException, IOException { + System.out.println("Querying account info..."); + queryAccount(qps); + System.out.println("Sending transfer transactions..."); + RateLimiter limiter = RateLimiter.create(qps.intValue()); + int division = count.intValue() / 10; + long startTime = System.currentTimeMillis(); + collector.setStartTimestamp(startTime); + collector.setTotal(count.intValue()); + AtomicInteger sendFailed = new AtomicInteger(0); + for (Integer i = 0; i < count.intValue(); i++) { + limiter.acquire(); + final int index = i; + threadPoolService + .getThreadPool() + .execute( + new Runnable() { + @Override + public void run() { + try { + Random random = new Random(); + int r = random.nextInt(100); + BigInteger amount = BigInteger.valueOf(r); + + ParallelOkCallback callback = + new ParallelOkCallback( + collector, + dagUserInfo, + ParallelOkCallback.TRANS_CALLBACK); + callback.setTimeout(0); + DagTransferUser from = dagUserInfo.getFrom(index); + DagTransferUser to = dagUserInfo.getTo(index); + + callback.setFromUser(from); + callback.setToUser(to); + callback.setAmount(amount); + callback.recordStartTime(); + parallelOk.transfer( + from.getUser(), to.getUser(), amount, callback); + int current = sended.incrementAndGet(); + if (current >= division && ((current % division) == 0)) { + long elapsed = System.currentTimeMillis() - startTime; + double sendSpeed = current / ((double) elapsed / 1000); + System.out.println( + "Already sent: " + + current + + "/" + + count + + " transactions" + + ",QPS=" + + sendSpeed); + } + } catch (Exception e) { + logger.error( + "call transfer failed, error info: {}", + e.getMessage()); + TransactionReceipt receipt = new TransactionReceipt(); + receipt.setStatus("-1"); + receipt.setMessage( + "call transfer failed, error info: " + + e.getMessage()); + collector.onMessage(receipt, Long.valueOf(0)); + sendFailed.incrementAndGet(); + } + } + }); + } + + while (collector.getReceived().intValue() != count.intValue()) { + Thread.sleep(3000); + logger.info( + "userTransfer: sendFailed: {}, received: {}, total: {}", + sendFailed.get(), + collector.getReceived().intValue(), + collector.getTotal()); + } + veryTransferData(qps); + System.exit(0); + } +} diff --git a/sdk-demo/src/test/resources/applicationContext-sample.xml b/sdk-demo/src/test/resources/applicationContext-sample.xml new file mode 100644 index 000000000..a4684aec2 --- /dev/null +++ b/sdk-demo/src/test/resources/applicationContext-sample.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + 127.0.0.1:20200 + 127.0.0.1:20201 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk-demo/src/test/resources/config-example.toml b/sdk-demo/src/test/resources/config-example.toml new file mode 100644 index 000000000..037bceb5f --- /dev/null +++ b/sdk-demo/src/test/resources/config-example.toml @@ -0,0 +1,54 @@ +[cryptoMaterial] + +certPath = "conf" # The certification path + +# The following configurations take the certPath by default if commented +# caCert = "conf/ca.crt" # CA cert file path + # If connect to the GM node, default CA cert path is ${certPath}/gm/gmca.crt + +# sslCert = "conf/sdk.crt" # SSL cert file path + # If connect to the GM node, the default SDK cert path is ${certPath}/gm/gmsdk.crt + +# sslKey = "conf/sdk.key" # SSL key file path + # If connect to the GM node, the default SDK privateKey path is ${certPath}/gm/gmsdk.key + +# enSslCert = "conf/gm/gmensdk.crt" # GM encryption cert file path + # default load the GM SSL encryption cert from ${certPath}/gm/gmensdk.crt + +# enSslKey = "conf/gm/gmensdk.key" # GM ssl cert file path + # default load the GM SSL encryption privateKey from ${certPath}/gm/gmensdk.key + +[network] +peers=["127.0.0.1:20200", "127.0.0.1:20201"] # The peer list to connect + +# Configure a private topic as a topic message sender. +# [[amop]] +# topicName = "PrivateTopic1" +# publicKeys = [ "conf/amop/consumer_public_key_1.pem" ] # Public keys of the nodes that you want to send AMOP message of this topic to. + +# Configure a private topic as a topic subscriber. +# [[amop]] +# topicName = "PrivateTopic2" +# privateKey = "conf/amop/consumer_private_key.p12" # Your private key that used to subscriber verification. +# password = "123456" + +[account] +keyStoreDir = "account" # The directory to load/store the account file, default is "account" +# accountFilePath = "" # The account file path (default load from the path specified by the keyStoreDir) +accountFileFormat = "pem" # The storage format of account file (Default is "pem", "p12" as an option) + +# accountAddress = "" # The transactions sending account address + # Default is a randomly generated account + # The randomly generated account is stored in the path specified by the keyStoreDir + +# password = "" # The password used to load the account file + +[threadPool] +# channelProcessorThreadSize = "16" # The size of the thread pool to process channel callback + # Default is the number of cpu cores + +# receiptProcessorThreadSize = "16" # The size of the thread pool to process transaction receipt notification + # Default is the number of cpu cores + +maxBlockingQueueSize = "102400" # The max blocking queue size of the thread pool + diff --git a/sdk-demo/src/test/resources/log4j.properties b/sdk-demo/src/test/resources/log4j.properties new file mode 100644 index 000000000..55785c234 --- /dev/null +++ b/sdk-demo/src/test/resources/log4j.properties @@ -0,0 +1,32 @@ +# +# Copyright 2014-2020 [fisco-dev] +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under the License +# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +# or implied. See the License for the specific language governing permissions and limitations under +# the License. +# +# + +### set log levels ### +log4j.rootLogger=DEBUG, file + +### output the log information to the file ### +log4j.appender.file=org.apache.log4j.DailyRollingFileAppender +log4j.appender.file.DatePattern='_'yyyyMMddHH'.log' +log4j.appender.file.File=./log/sdk.log +log4j.appender.file.Append=true +log4j.appender.file.filter.traceFilter=org.apache.log4j.varia.LevelRangeFilter +log4j.appender.file.layout=org.apache.log4j.PatternLayout +log4j.appender.file.layout.ConversionPattern=[%p] [%-d{yyyy-MM-dd HH:mm:ss}] %C{1}.%M(%L) | %m%n + +###output the log information to the console ### +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=[%p] [%-d{yyyy-MM-dd HH:mm:ss}] %C{1}.%M(%L) | %m%n diff --git a/sdk-service/build.gradle b/sdk-service/build.gradle new file mode 100644 index 000000000..34bcf561e --- /dev/null +++ b/sdk-service/build.gradle @@ -0,0 +1,53 @@ +// Apply the java-library plugin to add support for Java Library +plugins { + id 'java' +} +dependencies { + compile project(':sdk-amop') + compile project(':sdk-abi') + compile ("com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}") +} + +uploadArchives { + repositories { + mavenDeployer { + //beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + + repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { + authentication(userName: ossrhUsername, password: ossrhPassword) + } + + snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { + authentication(userName: ossrhUsername, password: ossrhPassword) + } + + pom.project { + name project.name + packaging 'jar' + description = 'fisco-bcos java-sdk' + url = 'http://www.fisco-bcos.org' + + scm { + connection = 'https://github.com/FISCO-BCOS/java-sdk.git' + url = 'https://github.com/FISCO-BCOS/java-sdk.git' + } + + licenses { + license { + name = 'The Apache License, Version 2.0' + url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + + developers { + developer { + id = 'zhangsan' + name = 'zhangsan' + email = 'zhangsan@example.com' + } + } + } + } + } +} + diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/BcosSDK.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/BcosSDK.java new file mode 100644 index 000000000..277e799c2 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/BcosSDK.java @@ -0,0 +1,213 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk; + +import io.netty.channel.ChannelException; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import org.fisco.bcos.sdk.amop.Amop; +import org.fisco.bcos.sdk.channel.Channel; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.config.Config; +import org.fisco.bcos.sdk.config.ConfigOption; +import org.fisco.bcos.sdk.config.exceptions.ConfigException; +import org.fisco.bcos.sdk.eventsub.EventResource; +import org.fisco.bcos.sdk.eventsub.EventSubscribe; +import org.fisco.bcos.sdk.model.ConstantConfig; +import org.fisco.bcos.sdk.service.GroupManagerService; +import org.fisco.bcos.sdk.service.GroupManagerServiceImpl; +import org.fisco.bcos.sdk.utils.ThreadPoolService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BcosSDK { + private static Logger logger = LoggerFactory.getLogger(BcosSDK.class); + public static final String ECDSA_TYPE_STR = "ecdsa"; + public static final String SM_TYPE_STR = "sm"; + + private final ConfigOption config; + private final Channel channel; + private final GroupManagerService groupManagerService; + private ConcurrentHashMap groupToClient = new ConcurrentHashMap<>(); + private long maxWaitEstablishConnectionTime = 30000; + private Amop amop; + private EventResource eventResource; + private ThreadPoolService threadPoolService; + + public static BcosSDK build(String tomlConfigFilePath) throws BcosSDKException { + try { + ConfigOption configOption = Config.load(tomlConfigFilePath); + logger.info("create BcosSDK, configPath: {}", tomlConfigFilePath); + return new BcosSDK(configOption); + } catch (ConfigException e) { + throw new BcosSDKException("create BcosSDK failed, error info: " + e.getMessage(), e); + } + } + + public BcosSDK(ConfigOption configOption) throws BcosSDKException { + try { + // create channel and load configuration file + this.channel = Channel.build(configOption); + this.channel.start(); + this.config = this.channel.getNetwork().getConfigOption(); + logger.info( + "create BcosSDK, start channel success, cryptoType: {}", + this.channel.getNetwork().getSslCryptoType()); + + threadPoolService = + new ThreadPoolService( + "channelProcessor", + this.config.getThreadPoolConfig().getChannelProcessorThreadSize(), + this.config.getThreadPoolConfig().getMaxBlockingQueueSize()); + channel.setThreadPool(threadPoolService.getThreadPool()); + logger.info( + "create BcosSDK, start channel succ, channelProcessorThreadSize: {}, receiptProcessorThreadSize: {}", + config.getThreadPoolConfig().getChannelProcessorThreadSize(), + config.getThreadPoolConfig().getReceiptProcessorThreadSize()); + if (!waitForEstablishConnection()) { + logger.error("create BcosSDK failed for the number of available peers is 0"); + throw new BcosSDKException( + "create BcosSDK failed for the number of available peers is 0"); + } + // create GroupMangerService + this.groupManagerService = new GroupManagerServiceImpl(this.channel, this.config); + logger.info("create BcosSDK, create groupManagerService success"); + // init amop + amop = Amop.build(this.channel, config); + this.groupManagerService.setAmop(amop); + amop.start(); + logger.info("create BcosSDK, create Amop success"); + // new EventResource + eventResource = new EventResource(); + } catch (ChannelException | ConfigException e) { + stopAll(); + throw new BcosSDKException("create BcosSDK failed, error info: " + e.getMessage(), e); + } + } + + private boolean waitForEstablishConnection() { + long startTime = System.currentTimeMillis(); + try { + while (System.currentTimeMillis() - startTime < maxWaitEstablishConnectionTime + && this.channel.getAvailablePeer().size() == 0) { + Thread.sleep(1000); + } + } catch (InterruptedException e) { + logger.warn("waitForEstablishConnection exceptioned, error info: {}", e.getMessage()); + } + return (this.channel.getAvailablePeer().size() > 0); + } + + public void checkGroupId(Integer groupId) { + if (groupId < ConstantConfig.MIN_GROUPID || groupId > ConstantConfig.MAX_GROUPID) { + throw new BcosSDKException( + "create client for group " + + groupId + + " failed for invalid groupId! The groupID must be no smaller than " + + ConstantConfig.MIN_GROUPID + + " and no more than " + + ConstantConfig.MAX_GROUPID); + } + } + + public Client getClient(Integer groupId) { + checkGroupId(groupId); + if (!waitForEstablishConnection()) { + logger.error( + "get client for group: {} failed for the number of available peers is 0", + groupId); + throw new BcosSDKException( + "get client for group " + + groupId + + " failed for the number of available peers is 0"); + } + if (!groupToClient.containsKey(groupId)) { + // create a new client for the specified group + Client client = + Client.build( + this.groupManagerService, this.channel, this.eventResource, groupId); + if (client == null) { + throw new BcosSDKException( + "create client for group " + + groupId + + " failed! Please check the existence of group " + + groupId + + " of the connected node!"); + } + groupToClient.put(groupId, client); + logger.info("create client for group {} success", groupId); + } + groupManagerService.fetchGroupList(); + Set nodeList = groupManagerService.getGroupNodeList(groupId); + if (nodeList.size() == 0) { + groupToClient.remove(groupId); + throw new BcosSDKException( + "create client for group " + + groupId + + " failed for no peers set up the group!"); + } + return groupToClient.get(groupId); + } + + public int getSSLCryptoType() { + return this.channel.getNetwork().getSslCryptoType(); + } + + public GroupManagerService getGroupManagerService() { + return this.groupManagerService; + } + + public ConfigOption getConfig() { + return this.config; + } + + public Amop getAmop() { + return amop; + } + + public EventResource getEventResource() { + return eventResource; + } + + public EventSubscribe getEventSubscribe(Integer groupId) { + return EventSubscribe.build(this.groupManagerService, this.eventResource, groupId); + } + + public Channel getChannel() { + return channel; + } + + public void stopAll() { + if (this.channel != null) { + this.channel.stop(); + } + if (this.threadPoolService != null) { + this.threadPoolService.stop(); + } + if (this.groupManagerService != null) { + this.groupManagerService.stop(); + } + if (this.amop != null) { + this.amop.stop(); + } + // stop the client + for (Integer groupId : groupToClient.keySet()) { + groupToClient.get(groupId).stop(); + EventSubscribe event = this.getEventSubscribe(groupId); + if (event != null) { + event.stop(); + } + } + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/BcosSDKException.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/BcosSDKException.java new file mode 100644 index 000000000..518b10703 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/BcosSDKException.java @@ -0,0 +1,25 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk; + +/** Exceptioned when calling BcosSDK. */ +public class BcosSDKException extends RuntimeException { + public BcosSDKException(String message) { + super(message); + } + + public BcosSDKException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/Client.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/Client.java new file mode 100644 index 000000000..9ec40c6f6 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/Client.java @@ -0,0 +1,855 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client; + +import java.math.BigInteger; +import java.util.List; +import java.util.Set; +import org.fisco.bcos.sdk.channel.Channel; +import org.fisco.bcos.sdk.client.protocol.request.Transaction; +import org.fisco.bcos.sdk.client.protocol.response.BcosBlock; +import org.fisco.bcos.sdk.client.protocol.response.BcosBlockHeader; +import org.fisco.bcos.sdk.client.protocol.response.BcosTransaction; +import org.fisco.bcos.sdk.client.protocol.response.BcosTransactionReceipt; +import org.fisco.bcos.sdk.client.protocol.response.BlockHash; +import org.fisco.bcos.sdk.client.protocol.response.BlockNumber; +import org.fisco.bcos.sdk.client.protocol.response.Call; +import org.fisco.bcos.sdk.client.protocol.response.Code; +import org.fisco.bcos.sdk.client.protocol.response.ConsensusStatus; +import org.fisco.bcos.sdk.client.protocol.response.GenerateGroup; +import org.fisco.bcos.sdk.client.protocol.response.GroupList; +import org.fisco.bcos.sdk.client.protocol.response.GroupPeers; +import org.fisco.bcos.sdk.client.protocol.response.NodeIDList; +import org.fisco.bcos.sdk.client.protocol.response.ObserverList; +import org.fisco.bcos.sdk.client.protocol.response.PbftView; +import org.fisco.bcos.sdk.client.protocol.response.Peers; +import org.fisco.bcos.sdk.client.protocol.response.PendingTransactions; +import org.fisco.bcos.sdk.client.protocol.response.PendingTxSize; +import org.fisco.bcos.sdk.client.protocol.response.QueryGroupStatus; +import org.fisco.bcos.sdk.client.protocol.response.RecoverGroup; +import org.fisco.bcos.sdk.client.protocol.response.RemoveGroup; +import org.fisco.bcos.sdk.client.protocol.response.SealerList; +import org.fisco.bcos.sdk.client.protocol.response.SendTransaction; +import org.fisco.bcos.sdk.client.protocol.response.StartGroup; +import org.fisco.bcos.sdk.client.protocol.response.StopGroup; +import org.fisco.bcos.sdk.client.protocol.response.SyncStatus; +import org.fisco.bcos.sdk.client.protocol.response.SystemConfig; +import org.fisco.bcos.sdk.client.protocol.response.TotalTransactionCount; +import org.fisco.bcos.sdk.client.protocol.response.TransactionReceiptWithProof; +import org.fisco.bcos.sdk.client.protocol.response.TransactionWithProof; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.eventsub.EventResource; +import org.fisco.bcos.sdk.model.NodeVersion; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.service.GroupManagerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This is the interface of client module. + * + * @author Maggie + */ +public interface Client { + static Logger logger = LoggerFactory.getLogger(Client.class); + + /** + * Build a client instance GroupId is identified, all interfaces are available + * + * @param channel the Channel instance + * @param groupId the group id + * @param groupManagerService the groupManagerService instance + * @param eventResource the eventResource instance + * @return a client instance + */ + static Client build( + GroupManagerService groupManagerService, + Channel channel, + EventResource eventResource, + Integer groupId) { + groupManagerService.fetchGroupList(); + groupManagerService.updateNodeVersion(); + // check the groupList + Set nodeList = groupManagerService.getGroupNodeList(groupId); + if (nodeList == null || nodeList.size() == 0) { + logger.warn("build client failed for no peers setup the group {}", groupId); + return null; + } + // get cryptoType + Integer cryptoType = null; + NodeVersion nodeVersion = null; + for (String node : nodeList) { + cryptoType = groupManagerService.getCryptoType(node); + if (cryptoType != null) { + nodeVersion = groupManagerService.getNodeVersion(node); + break; + } + } + if (cryptoType == null || nodeVersion == null) { + logger.warn( + "build client failed for get crypto type or nodeVersion failed, groupId: {}", + groupId); + return null; + } + CryptoSuite cryptoSuite = new CryptoSuite(cryptoType, groupManagerService.getConfig()); + logger.info("build client success for group {}", groupId); + return new ClientImpl( + groupManagerService, channel, groupId, cryptoSuite, nodeVersion, eventResource); + } + + static Client build(Channel channel) { + return new ClientImpl(channel); + } + + GroupManagerService getGroupManagerService(); + + CryptoSuite getCryptoSuite(); + + NodeVersion getClientNodeVersion(); + + Integer getCryptoType(); + + /** + * get groupId of the client + * + * @return the groupId + */ + Integer getGroupId(); + + /** + * Ledger operation: send transaction + * + * @param signedTransactionData transaction string + * @return SendTransaction + */ + SendTransaction sendRawTransaction(String signedTransactionData); + + /** + * Ledger operation: async send transaction + * + * @param signedTransactionData transaction string + * @param callback the callback that will be called when receive the response + */ + void sendRawTransactionAsync( + String signedTransactionData, RespCallback callback); + + /** + * Ledger operation: send raw transaction and get proof + * + * @param signedTransactionData transaction string + * @return a SendTransaction instance + */ + SendTransaction sendRawTransactionAndGetProof(String signedTransactionData); + + /** + * Ledger operation: async send transaction and get proof + * + * @param signedTransactionData transaction string + * @param callback the callback that will be called when receive the response + */ + void sendRawTransactionAndGetProofAsync( + String signedTransactionData, RespCallback callback); + + /** + * send transaction and get the receipt as the response + * + * @param signedTransactionData the transaction data sent to the node + * @return the transaction receipt + */ + TransactionReceipt sendRawTransactionAndGetReceipt(String signedTransactionData); + + /** + * send transaction to the node, and calls TransactionCallback when get the transaction receipt + * response + * + * @param signedTransactionData the transaction sent to the node + * @param callback the TransactionCallback called after get the transaction receipt + */ + void sendRawTransactionAndGetReceiptAsync( + String signedTransactionData, TransactionCallback callback); + + /** + * calls sendRawTransactionAndGetProof interface and get the transaction receipt + * + * @param signedTransactionData the transaction sent to the node + * @return the transaction receipt + */ + TransactionReceipt sendRawTransactionAndGetReceiptWithProof(String signedTransactionData); + + /** + * calls sendRawTransactionAndGetProof interface, calls TransactionCallback when get the + * transaction receipt + * + * @param signedTransactionData the transaction sent to the node + * @param callback the TransactionCallback called after get the transaction receipt + */ + void sendRawTransactionAndGetReceiptWithProofAsync( + String signedTransactionData, TransactionCallback callback); + + /** + * Ledger operation: call contract functions without sending transaction + * + * @param transaction transaction instance + * @return Call + */ + Call call(Transaction transaction); + + /** + * Ledger operation: async call contract functions without sending transaction + * + * @param transaction transaction instance + * @param callback the callback that will be called when receive the response + */ + void callAsync(Transaction transaction, RespCallback callback); + + /** + * Ledger operation: get block number + * + * @return block number + */ + BlockNumber getBlockNumber(); + + BlockNumber getBlockNumber(Integer groupId, String peerIpAndPort); + + /** + * Ledger operation: async get block number + * + * @param callback the callback that will be called when receive the response + */ + void getBlockNumberAsync(RespCallback callback); + + /** + * Ledger operation: get code + * + * @param address the address string + * @return a code instance + */ + Code getCode(String address); + + /** + * Ledger operation: async get code + * + * @param address the address string + * @param callback the callback that will be called when receive the response + */ + void getCodeAsync(String address, RespCallback callback); + + /** + * Ledger operation: get total transaction count + * + * @return TotalTransactionCount + */ + TotalTransactionCount getTotalTransactionCount(); + + /** + * Ledger operation: async get total transaction count + * + * @param callback the callback that will be called when receive the response + */ + void getTotalTransactionCountAsync(RespCallback callback); + + /** + * Ledger operation: get block by hash + * + * @param blockHash the hashcode of the block + * @param returnFullTransactionObjects the boolean define the tx is full or not + * @return a block + */ + BcosBlock getBlockByHash(String blockHash, boolean returnFullTransactionObjects); + + /** + * Ledger operation: async get block by hash + * + * @param blockHash the hashcode of the block + * @param returnFullTransactionObjects the boolean define the tx is full or not + * @param callback the callback that will be called when receive the response + */ + void getBlockByHashAsync( + String blockHash, + boolean returnFullTransactionObjects, + RespCallback callback); + + /** + * Ledger operation: get block by block number + * + * @param blockNumber the number of the block + * @param returnFullTransactionObjects the boolean define the tx is full or not + * @return block + */ + BcosBlock getBlockByNumber(BigInteger blockNumber, boolean returnFullTransactionObjects); + + /** + * Ledger operation: async get block by block number + * + * @param blockNumber the number of the block + * @param returnFullTransactionObjects the boolean define the tx is full or not + * @param callback the callback that will be called when receive the response + */ + void getBlockByNumberAsync( + BigInteger blockNumber, + boolean returnFullTransactionObjects, + RespCallback callback); + + /** + * Ledger operation: get block hash by block number + * + * @param blockNumber the number of the block + * @return block hash + */ + BlockHash getBlockHashByNumber(BigInteger blockNumber); + + /** + * Ledger operation: async get block hash by block number + * + * @param blockNumber the number of the block + * @param callback the callback that will be called when receive the response + */ + void getBlockHashByNumberAsync(BigInteger blockNumber, RespCallback callback); + + /** + * Ledger operation: get block header by block hash + * + * @param blockHash the hashcode of the block + * @param returnSignatureList the boolean define the signature list is returned or not + * @return block header + */ + BcosBlockHeader getBlockHeaderByHash(String blockHash, boolean returnSignatureList); + + /** + * Ledger operation: async get block header by block hash + * + * @param blockHash the hashcode of the block + * @param returnSignatureList the boolean define the signature list is returned or not + * @param callback the call back instance + */ + void getBlockHeaderByHashAsync( + String blockHash, boolean returnSignatureList, RespCallback callback); + + /** + * get block header by number + * + * @param blockNumber the number of the block + * @param returnSignatureList the boolean define the signature list is returned or not + * @return the block header response from the blockchain node + */ + BcosBlockHeader getBlockHeaderByNumber(BigInteger blockNumber, boolean returnSignatureList); + + void getBlockHeaderByNumberAsync( + BigInteger blockNumber, + boolean returnSignatureList, + RespCallback callback); + + /** + * Ledger operation: get trnasaction by hash + * + * @param transactionHash the hashcode of transaction + * @return transaction + */ + BcosTransaction getTransactionByHash(String transactionHash); + + /** + * Ledger operation: async get trnasaction by hash + * + * @param transactionHash the hashcode of transaction + * @param callback the callback that will be called when receive the response + */ + void getTransactionByHashAsync(String transactionHash, RespCallback callback); + + /** + * Ledger operation: get transaction and proof by hash + * + * @param transactionHash the hashcode of transaction + * @return transaction with proof + */ + TransactionWithProof getTransactionByHashWithProof(String transactionHash); + + /** + * Ledger operation: async get transaction and proof by hash + * + * @param transactionHash the hashcode of transaction + * @param callback the callback that will be called when receive the response + */ + void getTransactionByHashWithProofAsync( + String transactionHash, RespCallback callback); + + /** + * Ledger operation: get transaction by block number and index + * + * @param blockNumber the number of block + * @param transactionIndex the index of transaction + * @return transaction + */ + BcosTransaction getTransactionByBlockNumberAndIndex( + BigInteger blockNumber, BigInteger transactionIndex); + + /** + * Ledger operation: async get transaction by block number and index + * + * @param blockNumber the number of block + * @param transactionIndex the index of transaction + * @param callback the callback that will be called when receive the response + */ + void getTransactionByBlockNumberAndIndexAsync( + BigInteger blockNumber, + BigInteger transactionIndex, + RespCallback callback); + + BcosTransaction getTransactionByBlockHashAndIndex( + String blockHash, BigInteger transactionIndex); + + void getTransactionByBlockHashAndIndexAsync( + String blockHash, BigInteger transactionIndex, RespCallback callback); + + /** + * Ledger operation: get transaction receipt by transaction hash + * + * @param transactionHash the hashcode of transaction + * @return transaction receipt + */ + BcosTransactionReceipt getTransactionReceipt(String transactionHash); + + /** + * Ledger operation: async get transaction receipt by transaction hash + * + * @param transactionHash the hashcode of transaction + * @param callback the callback that will be called when receive the response + */ + void getTransactionReceiptAsync( + String transactionHash, RespCallback callback); + + /** + * Ledger operation: get transaction receipt and proof by transaction hash + * + * @param transactionHash the hashcode of transaction + * @return receipt and proof + */ + TransactionReceiptWithProof getTransactionReceiptByHashWithProof(String transactionHash); + + /** + * Ledger operation: async get transaction receipt and proof by transaction hash + * + * @param transactionHash the hashcode of transaction + * @param callback the callback that will be called when receive the response + */ + void getTransactionReceiptByHashWithProofAsync( + String transactionHash, RespCallback callback); + + /** + * Ledger operation: get pending transactions in transaction pool + * + * @return pending transactions + */ + PendingTransactions getPendingTransaction(); + + /** + * Ledger operation: async get pending transactions in transaction pool + * + * @param callback the callback that will be called when receive the response + */ + void getPendingTransactionAsync(RespCallback callback); + + /** + * Ledger operation: get pending transaction size + * + * @return PendingTxSize + */ + PendingTxSize getPendingTxSize(); + + /** + * Ledger operation: async get pending transaction size + * + * @param callback the callback that will be called when receive the response + */ + void getPendingTxSizeAsync(RespCallback callback); + + /** + * Get cached block height + * + * @return block number + */ + BigInteger getBlockLimit(); + + /** + * Group operation: generate a new group + * + * @param groupId the group id + * @param timestamp timestamp + * @param enableFreeStorage enable free storage + * @param nodeList give the ip string list of the nodes in the group + * @param peerIpPort send to the specific peer + * @return generate group reply message + */ + GenerateGroup generateGroup( + Integer groupId, + long timestamp, + boolean enableFreeStorage, + List nodeList, + String peerIpPort); + + /** + * Group operation: async generate a new group + * + * @param groupId the group id + * @param timestamp timestamp + * @param enableFreeStorage enable free storage + * @param nodeList the list of the nodes in the group + * @param peerIpPort send to the specific peer + * @param callback the callback that will be called when receive the response + */ + void generateGroupAsync( + Integer groupId, + long timestamp, + boolean enableFreeStorage, + List nodeList, + String peerIpPort, + RespCallback callback); + + /** + * Group operation: start a group + * + * @param groupId the group id + * @param peerIpPort the node that the request sent to + * @return start group rpc reply + */ + StartGroup startGroup(Integer groupId, String peerIpPort); + + /** + * Group operation: async start a group + * + * @param groupId the group id + * @param peerIpPort the node that the request sent to + * @param callback the callback that will be called when receive the response + */ + void startGroupAsync(Integer groupId, String peerIpPort, RespCallback callback); + + /** + * Group operation: stop a group + * + * @param groupId the group id + * @param peerIpPort the node that the request sent to + * @return stop group rpc reply + */ + StopGroup stopGroup(Integer groupId, String peerIpPort); + + /** + * Group operation: async stop a group + * + * @param groupId the group id + * @param peerIpPort the node that the request sent to + * @param callback the callback that will be called when receive the response + */ + void stopGroupAsync(Integer groupId, String peerIpPort, RespCallback callback); + + /** + * Group operation: remove a group + * + * @param groupId the group id + * @param peerIpPort the node that the request sent to + * @return remove group rpc reply + */ + RemoveGroup removeGroup(Integer groupId, String peerIpPort); + + /** + * Group operation: async remove a group + * + * @param groupId the group id + * @param peerIpPort the node that the request sent to + * @param callback the callback that will be called when receive the response + */ + void removeGroupAsync(Integer groupId, String peerIpPort, RespCallback callback); + + /** + * Group operation: recover a group + * + * @param groupId the group id + * @param peerIpPort the node that the request sent to + * @return recover group rpc reply + */ + RecoverGroup recoverGroup(Integer groupId, String peerIpPort); + + /** + * Group operation: async recover a group + * + * @param groupId the group id + * @param peerIpPort the node that the request sent to + * @param callback the callback that will be called when receive the response + */ + void recoverGroupAsync(Integer groupId, String peerIpPort, RespCallback callback); + + /** + * Group operation: query group status + * + * @param groupId the group id + * @return group status + */ + QueryGroupStatus queryGroupStatus(Integer groupId); + + /** + * Group operation: query group status + * + * @param groupId the group id + * @param peerIpPort the node that the request sent to + * @return group status + */ + QueryGroupStatus queryGroupStatus(Integer groupId, String peerIpPort); + + /** + * Group operation: async query group status + * + * @param groupId the group id + * @param callback the callback that will be called when receive the response + */ + void queryGroupStatusAsync(Integer groupId, RespCallback callback); + + /** + * Group operation: async query group status + * + * @param groupId the group that the request sent to + * @param peerIpPort the node that the request sent to + * @param callback the callback that will be called when receive the response + */ + void queryGroupStatusAsync( + Integer groupId, String peerIpPort, RespCallback callback); + + /** + * Group operation: get peer group list + * + * @return group list + */ + GroupList getGroupList(); + + /** + * Group operation: get peer group list + * + * @param peerIpPort send to the specific peer + * @return group list + */ + GroupList getGroupList(String peerIpPort); + + /** + * Group operation: async get peer group list + * + * @param callback the callback that will be called when receive the response + */ + void getGroupListAsync(RespCallback callback); + + /** + * Group operation: async get peer group list + * + * @param peerIpPort send to the specific peer + * @param callback the callback that will be called when receive the response + */ + void getGroupListAsync(String peerIpPort, RespCallback callback); + + /** + * Group operation: get group peers + * + * @return group peers + */ + GroupPeers getGroupPeers(); + + /** + * Group operation: get group peers + * + * @param peerIpPort the target node of the request + * @return group peers + */ + GroupPeers getGroupPeers(String peerIpPort); + + /** + * Group operation: async get group peers + * + * @param callback the callback that will be called when receive the response + */ + void getGroupPeersAsync(RespCallback callback); + + /** + * Group operation: async get group peers + * + * @param peerIpPort the target node of the request + * @param callback the callback that will be called when receive the response + */ + void getGroupPeersAsync(String peerIpPort, RespCallback callback); + + /** + * Peer operation: get connected peers + * + * @return peers + */ + Peers getPeers(); + + /** + * Peer operation: get connected peers + * + * @param endpoint the target node that receive the request + * @return peers + */ + Peers getPeers(String endpoint); + + /** + * Peer operation: async get connected peers + * + * @param callback the callback instance + */ + void getPeersAsync(RespCallback callback); + + /** + * Peer operation: get node ids + * + * @return node id list + */ + NodeIDList getNodeIDList(); + + NodeIDList getNodeIDList(String endpoint); + + /** + * Peer operation: async get node ids + * + * @param callback the callback instance + */ + void getNodeIDListAsync(RespCallback callback); + + /** + * Peer operation: get observer node list + * + * @return observer node list + */ + ObserverList getObserverList(); + + /** + * Peer operation: async get observer node list + * + * @param callback the callback instance + */ + void getObserverList(RespCallback callback); + + /** + * Peer operation: get sealer node list + * + * @return sealer node list + */ + SealerList getSealerList(); + + /** + * Peer operation: async get sealer node list + * + * @param callback the callback instance + */ + void getSealerListAsync(RespCallback callback); + + /** + * Peer operation: get pbft view + * + * @return pbft view + */ + PbftView getPbftView(); + + /** + * Peer operation: async get pbft view + * + * @param callback the callback instance + */ + void getPbftViewAsync(RespCallback callback); + + NodeVersion getNodeVersion(String ipAndPort); + + /** + * Peer operation: get node version + * + * @return node version + */ + NodeVersion getNodeVersion(); + + /** + * Peer operation: get node version + * + * @param callback the callback instance + */ + void getNodeVersion(RespCallback callback); + + /** + * Peer operation: get consensus status + * + * @return consensus status + */ + ConsensusStatus getConsensusStatus(); + + /** + * Peer operation: async get consensus status + * + * @param callback the callback instance + */ + void getConsensusStates(RespCallback callback); + + /** + * Peer operation: get system config + * + * @param key the string of key + * @return system config + */ + SystemConfig getSystemConfigByKey(String key); + + /** + * Peer operation: get system config + * + * @param key the string of key + * @param peerIpPort the node that the request sent to + * @return system config + */ + SystemConfig getSystemConfigByKey(String key, String peerIpPort); + + /** + * Peer operation: async get system config + * + * @param key the string of key + * @param callback the callback instance + */ + void getSystemConfigByKeyAsync(String key, RespCallback callback); + + /** + * Peer operation: async get system config + * + * @param key the string of key + * @param peerIpPort the port string of + * @param callback the callback instance + */ + void getSystemConfigByKeyAsync( + String key, String peerIpPort, RespCallback callback); + + /** + * Peer operation: get sync status + * + * @return sync status + */ + SyncStatus getSyncStatus(); + + /** + * Peer operation: async get sync status + * + * @param callback the callback instance + */ + void getSyncStatus(RespCallback callback); + + /** + * Get EventPushMsgHandler and FilterManager. + * + * @return EventResource + */ + EventResource getEventResource(); + + void stop(); +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/ClientImpl.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/ClientImpl.java new file mode 100644 index 000000000..c2cbc3caa --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/ClientImpl.java @@ -0,0 +1,988 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.client; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Semaphore; +import org.fisco.bcos.sdk.channel.Channel; +import org.fisco.bcos.sdk.client.protocol.request.GenerateGroupParam; +import org.fisco.bcos.sdk.client.protocol.request.JsonRpcMethods; +import org.fisco.bcos.sdk.client.protocol.request.JsonRpcRequest; +import org.fisco.bcos.sdk.client.protocol.request.Transaction; +import org.fisco.bcos.sdk.client.protocol.response.BcosBlock; +import org.fisco.bcos.sdk.client.protocol.response.BcosBlockHeader; +import org.fisco.bcos.sdk.client.protocol.response.BcosTransaction; +import org.fisco.bcos.sdk.client.protocol.response.BcosTransactionReceipt; +import org.fisco.bcos.sdk.client.protocol.response.BlockHash; +import org.fisco.bcos.sdk.client.protocol.response.BlockNumber; +import org.fisco.bcos.sdk.client.protocol.response.Call; +import org.fisco.bcos.sdk.client.protocol.response.Code; +import org.fisco.bcos.sdk.client.protocol.response.ConsensusStatus; +import org.fisco.bcos.sdk.client.protocol.response.GenerateGroup; +import org.fisco.bcos.sdk.client.protocol.response.GroupList; +import org.fisco.bcos.sdk.client.protocol.response.GroupPeers; +import org.fisco.bcos.sdk.client.protocol.response.NodeIDList; +import org.fisco.bcos.sdk.client.protocol.response.ObserverList; +import org.fisco.bcos.sdk.client.protocol.response.PbftView; +import org.fisco.bcos.sdk.client.protocol.response.Peers; +import org.fisco.bcos.sdk.client.protocol.response.PendingTransactions; +import org.fisco.bcos.sdk.client.protocol.response.PendingTxSize; +import org.fisco.bcos.sdk.client.protocol.response.QueryGroupStatus; +import org.fisco.bcos.sdk.client.protocol.response.RecoverGroup; +import org.fisco.bcos.sdk.client.protocol.response.RemoveGroup; +import org.fisco.bcos.sdk.client.protocol.response.SealerList; +import org.fisco.bcos.sdk.client.protocol.response.SendTransaction; +import org.fisco.bcos.sdk.client.protocol.response.StartGroup; +import org.fisco.bcos.sdk.client.protocol.response.StopGroup; +import org.fisco.bcos.sdk.client.protocol.response.SyncStatus; +import org.fisco.bcos.sdk.client.protocol.response.SystemConfig; +import org.fisco.bcos.sdk.client.protocol.response.TotalTransactionCount; +import org.fisco.bcos.sdk.client.protocol.response.TransactionReceiptWithProof; +import org.fisco.bcos.sdk.client.protocol.response.TransactionWithProof; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.eventsub.EventResource; +import org.fisco.bcos.sdk.model.NodeVersion; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.service.GroupManagerService; +import org.fisco.bcos.sdk.utils.Numeric; + +public class ClientImpl implements Client { + private final JsonRpcService jsonRpcService; + private final Integer groupId; + private final Integer DefaultGroupId = Integer.valueOf(1); + private final CryptoSuite cryptoSuite; + private final NodeVersion nodeVersion; + private final GroupManagerService groupManagerService; + private EventResource eventResource; + + protected ClientImpl( + GroupManagerService groupManagerService, + Channel channel, + Integer groupId, + CryptoSuite cryptoSuite, + NodeVersion nodeVersion, + EventResource eventResource) { + this.jsonRpcService = new JsonRpcService(groupManagerService, channel, groupId); + this.groupId = groupId; + this.cryptoSuite = cryptoSuite; + this.nodeVersion = nodeVersion; + this.groupManagerService = groupManagerService; + this.eventResource = eventResource; + // send request to the group, and get the blockNumber information + getBlockLimit(); + } + + protected ClientImpl(Channel channel) { + this.jsonRpcService = new JsonRpcService(null, channel, null); + this.groupId = null; + this.cryptoSuite = null; + this.nodeVersion = null; + this.groupManagerService = null; + } + + @Override + public GroupManagerService getGroupManagerService() { + return this.groupManagerService; + } + + @Override + public CryptoSuite getCryptoSuite() { + return this.cryptoSuite; + } + + @Override + public NodeVersion getClientNodeVersion() { + return this.nodeVersion; + } + + @Override + public Integer getCryptoType() { + return this.cryptoSuite.getCryptoTypeConfig(); + } + + @Override + public Integer getGroupId() { + return this.groupId; + } + + @Override + public SendTransaction sendRawTransaction(String signedTransactionData) { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.SEND_RAWTRANSACTION, + Arrays.asList(this.groupId, signedTransactionData)), + SendTransaction.class); + } + + @Override + public void sendRawTransactionAsync( + String signedTransactionData, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.SEND_RAWTRANSACTION, + Arrays.asList(this.groupId, signedTransactionData)), + SendTransaction.class, + callback); + } + + @Override + public Call call(Transaction transaction) { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.CALL, Arrays.asList(this.groupId, transaction)), + Call.class); + } + + @Override + public void callAsync(Transaction transaction, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.CALL, Arrays.asList(this.groupId, transaction)), + Call.class, + callback); + } + + @Override + public SendTransaction sendRawTransactionAndGetProof(String signedTransactionData) { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.SEND_RAWTRANSACTION_AND_GET_PROOF, + Arrays.asList(this.groupId, signedTransactionData)), + SendTransaction.class); + } + + @Override + public void sendRawTransactionAndGetProofAsync( + String signedTransactionData, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.SEND_RAWTRANSACTION_AND_GET_PROOF, + Arrays.asList(this.groupId, signedTransactionData)), + SendTransaction.class, + callback); + } + + @Override + public BlockNumber getBlockNumber() { + // create request + JsonRpcRequest request = + new JsonRpcRequest(JsonRpcMethods.GET_BLOCK_NUMBER, Arrays.asList(this.groupId)); + return this.jsonRpcService.sendRequestToGroup(request, BlockNumber.class); + } + + @Override + public BlockNumber getBlockNumber(Integer groupId, String peerIpAndPort) { + // create request + JsonRpcRequest request = + new JsonRpcRequest(JsonRpcMethods.GET_BLOCK_NUMBER, Arrays.asList(groupId)); + return this.jsonRpcService.sendRequestToPeer(request, peerIpAndPort, BlockNumber.class); + } + + @Override + public void getBlockNumberAsync(RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_BLOCK_NUMBER, Arrays.asList(this.groupId)), + BlockNumber.class, + callback); + } + + @Override + public Code getCode(String address) { + // create request + JsonRpcRequest request = + new JsonRpcRequest(JsonRpcMethods.GET_CODE, Arrays.asList(this.groupId, address)); + return this.jsonRpcService.sendRequestToGroup(request, Code.class); + } + + @Override + public void getCodeAsync(String address, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_CODE, Arrays.asList(this.groupId, address)), + Code.class, + callback); + } + + @Override + public TotalTransactionCount getTotalTransactionCount() { + // create request for getTotalTransactionCount + JsonRpcRequest request = + new JsonRpcRequest( + JsonRpcMethods.GET_TOTAL_TRANSACTION_COUNT, Arrays.asList(this.groupId)); + return this.jsonRpcService.sendRequestToGroup(request, TotalTransactionCount.class); + } + + @Override + public void getTotalTransactionCountAsync(RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_TOTAL_TRANSACTION_COUNT, Arrays.asList(this.groupId)), + TotalTransactionCount.class, + callback); + } + + @Override + public BcosBlock getBlockByHash(String blockHash, boolean returnFullTransactionObjects) { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_BLOCK_BY_HASH, + Arrays.asList(this.groupId, blockHash, returnFullTransactionObjects)), + BcosBlock.class); + } + + @Override + public void getBlockByHashAsync( + String blockHash, + boolean returnFullTransactionObjects, + RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_BLOCK_BY_HASH, + Arrays.asList(this.groupId, blockHash, returnFullTransactionObjects)), + BcosBlock.class, + callback); + } + + @Override + public BcosBlock getBlockByNumber( + BigInteger blockNumber, boolean returnFullTransactionObjects) { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_BLOCK_BY_NUMBER, + Arrays.asList( + this.groupId, + String.valueOf(blockNumber), + returnFullTransactionObjects)), + BcosBlock.class); + } + + @Override + public void getBlockByNumberAsync( + BigInteger blockNumber, + boolean returnFullTransactionObjects, + RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_BLOCK_BY_NUMBER, + Arrays.asList( + this.groupId, + String.valueOf(blockNumber), + returnFullTransactionObjects)), + BcosBlock.class, + callback); + } + + @Override + public BlockHash getBlockHashByNumber(BigInteger blockNumber) { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_BLOCKHASH_BY_NUMBER, + Arrays.asList(this.groupId, String.valueOf(blockNumber))), + BlockHash.class); + } + + @Override + public void getBlockHashByNumberAsync( + BigInteger blockNumber, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_BLOCKHASH_BY_NUMBER, + Arrays.asList(this.groupId, String.valueOf(blockNumber))), + BlockHash.class, + callback); + } + + @Override + public BcosBlockHeader getBlockHeaderByHash(String blockHash, boolean returnSignatureList) { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_BLOCKHEADER_BY_HASH, + Arrays.asList(this.groupId, blockHash, returnSignatureList)), + BcosBlockHeader.class); + } + + @Override + public void getBlockHeaderByHashAsync( + String blockHash, boolean returnSignatureList, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_BLOCKHEADER_BY_HASH, + Arrays.asList(this.groupId, blockHash, returnSignatureList)), + BcosBlockHeader.class, + callback); + } + + @Override + public BcosBlockHeader getBlockHeaderByNumber( + BigInteger blockNumber, boolean returnSignatureList) { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_BLOCKHEADER_BY_NUMBER, + Arrays.asList( + this.groupId, String.valueOf(blockNumber), returnSignatureList)), + BcosBlockHeader.class); + } + + @Override + public void getBlockHeaderByNumberAsync( + BigInteger blockNumber, + boolean returnSignatureList, + RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_BLOCKHEADER_BY_NUMBER, + Arrays.asList( + this.groupId, String.valueOf(blockNumber), returnSignatureList)), + BcosBlockHeader.class, + callback); + } + + @Override + public BcosTransaction getTransactionByHash(String transactionHash) { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_TRANSACTION_BY_HASH, + Arrays.asList(this.groupId, transactionHash)), + BcosTransaction.class); + } + + @Override + public void getTransactionByHashAsync( + String transactionHash, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_TRANSACTION_BY_HASH, + Arrays.asList(this.groupId, transactionHash)), + BcosTransaction.class, + callback); + } + + @Override + public TransactionWithProof getTransactionByHashWithProof(String transactionHash) { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_TRANSACTION_BY_HASH_WITH_PROOF, + Arrays.asList(this.groupId, transactionHash)), + TransactionWithProof.class); + } + + @Override + public void getTransactionByHashWithProofAsync( + String transactionHash, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_TRANSACTION_BY_HASH_WITH_PROOF, + Arrays.asList(this.groupId, transactionHash)), + TransactionWithProof.class, + callback); + } + + @Override + public BcosTransaction getTransactionByBlockNumberAndIndex( + BigInteger blockNumber, BigInteger transactionIndex) { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_TRANSACTION_BY_BLOCKNUMBER_AND_INDEX, + Arrays.asList( + this.groupId, + String.valueOf(blockNumber), + Numeric.encodeQuantity(transactionIndex))), + BcosTransaction.class); + } + + @Override + public void getTransactionByBlockNumberAndIndexAsync( + BigInteger blockNumber, + BigInteger transactionIndex, + RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_TRANSACTION_BY_BLOCKNUMBER_AND_INDEX, + Arrays.asList( + this.groupId, + String.valueOf(blockNumber), + Numeric.encodeQuantity(transactionIndex))), + BcosTransaction.class, + callback); + } + + @Override + public BcosTransaction getTransactionByBlockHashAndIndex( + String blockHash, BigInteger transactionIndex) { + return jsonRpcService.sendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_TRANSACTION_BY_BLOCKHASH_AND_INDEX, + Arrays.asList( + this.groupId, blockHash, Numeric.encodeQuantity(transactionIndex))), + BcosTransaction.class); + } + + @Override + public void getTransactionByBlockHashAndIndexAsync( + String blockHash, BigInteger transactionIndex, RespCallback callback) { + jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_TRANSACTION_BY_BLOCKHASH_AND_INDEX, + Arrays.asList( + this.groupId, blockHash, Numeric.encodeQuantity(transactionIndex))), + BcosTransaction.class, + callback); + } + + @Override + public BcosTransactionReceipt getTransactionReceipt(String transactionHash) { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_TRANSACTIONRECEIPT, + Arrays.asList(this.groupId, transactionHash)), + BcosTransactionReceipt.class); + } + + @Override + public void getTransactionReceiptAsync( + String transactionHash, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_TRANSACTIONRECEIPT, + Arrays.asList(this.groupId, transactionHash)), + BcosTransactionReceipt.class, + callback); + } + + @Override + public TransactionReceiptWithProof getTransactionReceiptByHashWithProof( + String transactionHash) { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_TRANSACTION_RECEIPT_BY_HASH_WITH_PROOF, + Arrays.asList(this.groupId, transactionHash)), + TransactionReceiptWithProof.class); + } + + @Override + public void getTransactionReceiptByHashWithProofAsync( + String transactionHash, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_TRANSACTION_RECEIPT_BY_HASH_WITH_PROOF, + Arrays.asList(this.groupId, transactionHash)), + TransactionReceiptWithProof.class, + callback); + } + + @Override + public PendingTransactions getPendingTransaction() { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_PENDING_TRANSACTIONS, Arrays.asList(this.groupId)), + PendingTransactions.class); + } + + @Override + public void getPendingTransactionAsync(RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_PENDING_TRANSACTIONS, Arrays.asList(this.groupId)), + PendingTransactions.class, + callback); + } + + @Override + public PendingTxSize getPendingTxSize() { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_PENDING_TX_SIZE, Arrays.asList(this.groupId)), + PendingTxSize.class); + } + + @Override + public void getPendingTxSizeAsync(RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_PENDING_TX_SIZE, Arrays.asList(this.groupId)), + PendingTxSize.class, + callback); + } + + @Override + public BigInteger getBlockLimit() { + Integer groupId = Integer.valueOf(this.groupId); + return this.jsonRpcService.getGroupManagerService().getBlockLimitByGroup(groupId); + } + + @Override + public GenerateGroup generateGroup( + Integer groupId, + long timestamp, + boolean enableFreeStorage, + List nodeList, + String peerIpPort) { + GenerateGroupParam generateGroupParam = + new GenerateGroupParam(String.valueOf(timestamp), enableFreeStorage, nodeList); + JsonRpcRequest request = + new JsonRpcRequest( + JsonRpcMethods.GENERATE_GROUP, Arrays.asList(groupId, generateGroupParam)); + return this.jsonRpcService.sendRequestToPeer(request, peerIpPort, GenerateGroup.class); + } + + @Override + public void generateGroupAsync( + Integer groupId, + long timestamp, + boolean enableFreeStorage, + List nodeList, + String peerIpPort, + RespCallback callback) { + GenerateGroupParam generateGroupParam = + new GenerateGroupParam(String.valueOf(timestamp), enableFreeStorage, nodeList); + JsonRpcRequest request = + new JsonRpcRequest( + JsonRpcMethods.GENERATE_GROUP, Arrays.asList(groupId, generateGroupParam)); + this.jsonRpcService.asyncSendRequestToPeer( + request, peerIpPort, GenerateGroup.class, callback); + } + + @Override + public StartGroup startGroup(Integer groupId, String peerIpPort) { + return this.jsonRpcService.sendRequestToPeer( + new JsonRpcRequest(JsonRpcMethods.START_GROUP, Arrays.asList(groupId)), + peerIpPort, + StartGroup.class); + } + + @Override + public void startGroupAsync( + Integer groupId, String peerIpPort, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToPeer( + new JsonRpcRequest(JsonRpcMethods.START_GROUP, Arrays.asList(this.groupId)), + peerIpPort, + StartGroup.class, + callback); + } + + @Override + public StopGroup stopGroup(Integer groupId, String peerIpPort) { + return this.jsonRpcService.sendRequestToPeer( + new JsonRpcRequest(JsonRpcMethods.STOP_GROUP, Arrays.asList(groupId)), + peerIpPort, + StopGroup.class); + } + + @Override + public void stopGroupAsync( + Integer groupId, String peerIpPort, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToPeer( + new JsonRpcRequest(JsonRpcMethods.STOP_GROUP, Arrays.asList(this.groupId)), + peerIpPort, + StopGroup.class, + callback); + } + + @Override + public RemoveGroup removeGroup(Integer groupId, String peerIpPort) { + return this.jsonRpcService.sendRequestToPeer( + new JsonRpcRequest(JsonRpcMethods.REMOVE_GROUP, Arrays.asList(groupId)), + peerIpPort, + RemoveGroup.class); + } + + @Override + public void removeGroupAsync( + Integer groupId, String peerIpPort, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToPeer( + new JsonRpcRequest(JsonRpcMethods.REMOVE_GROUP, Arrays.asList(this.groupId)), + peerIpPort, + RemoveGroup.class, + callback); + } + + @Override + public RecoverGroup recoverGroup(Integer groupId, String peerIpPort) { + return this.jsonRpcService.sendRequestToPeer( + new JsonRpcRequest(JsonRpcMethods.RECOVER_GROUP, Arrays.asList(groupId)), + peerIpPort, + RecoverGroup.class); + } + + @Override + public void recoverGroupAsync( + Integer groupId, String peerIpPort, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToPeer( + new JsonRpcRequest(JsonRpcMethods.RECOVER_GROUP, Arrays.asList(this.groupId)), + peerIpPort, + RecoverGroup.class, + callback); + } + + @Override + public QueryGroupStatus queryGroupStatus(Integer groupId) { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.QUERY_GROUP_STATUS, Arrays.asList(groupId)), + QueryGroupStatus.class); + } + + @Override + public QueryGroupStatus queryGroupStatus(Integer groupId, String peerIpPort) { + return this.jsonRpcService.sendRequestToPeer( + new JsonRpcRequest(JsonRpcMethods.QUERY_GROUP_STATUS, Arrays.asList(groupId)), + peerIpPort, + QueryGroupStatus.class); + } + + @Override + public void queryGroupStatusAsync(Integer groupId, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.QUERY_GROUP_STATUS, Arrays.asList(this.groupId)), + QueryGroupStatus.class, + callback); + } + + @Override + public void queryGroupStatusAsync( + Integer groupId, String peerIpPort, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToPeer( + new JsonRpcRequest(JsonRpcMethods.QUERY_GROUP_STATUS, Arrays.asList(this.groupId)), + peerIpPort, + QueryGroupStatus.class, + callback); + } + + @Override + public GroupList getGroupList() { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_GROUP_LIST, Arrays.asList()), + GroupList.class); + } + + @Override + public GroupList getGroupList(String peerIpPort) { + return this.jsonRpcService.sendRequestToPeer( + new JsonRpcRequest(JsonRpcMethods.GET_GROUP_LIST, Arrays.asList()), + peerIpPort, + GroupList.class); + } + + @Override + public void getGroupListAsync(RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_GROUP_LIST, Arrays.asList()), + GroupList.class, + callback); + } + + @Override + public void getGroupListAsync(String peerIpPort, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToPeer( + new JsonRpcRequest(JsonRpcMethods.GET_GROUP_LIST, Arrays.asList()), + peerIpPort, + GroupList.class, + callback); + } + + @Override + public GroupPeers getGroupPeers() { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_GROUP_PEERS, Arrays.asList(this.groupId)), + GroupPeers.class); + } + + @Override + public GroupPeers getGroupPeers(String peerIpPort) { + return this.jsonRpcService.sendRequestToPeer( + new JsonRpcRequest(JsonRpcMethods.GET_GROUP_PEERS, Arrays.asList(this.groupId)), + peerIpPort, + GroupPeers.class); + } + + @Override + public void getGroupPeersAsync(RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_GROUP_PEERS, Arrays.asList(this.groupId)), + GroupPeers.class, + callback); + } + + @Override + public void getGroupPeersAsync(String peerIpPort, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToPeer( + new JsonRpcRequest(JsonRpcMethods.GET_GROUP_PEERS, Arrays.asList(this.groupId)), + peerIpPort, + GroupPeers.class, + callback); + } + + @Override + public Peers getPeers() { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_PEERS, Arrays.asList(DefaultGroupId)), + Peers.class); + } + + @Override + public Peers getPeers(String endpoint) { + return this.jsonRpcService.sendRequestToPeer( + new JsonRpcRequest(JsonRpcMethods.GET_PEERS, Arrays.asList(DefaultGroupId)), + endpoint, + Peers.class); + } + + @Override + public void getPeersAsync(RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_PEERS, Arrays.asList(this.groupId)), + Peers.class, + callback); + } + + @Override + public NodeIDList getNodeIDList() { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_NODEIDLIST, Arrays.asList(DefaultGroupId)), + NodeIDList.class); + } + + @Override + public NodeIDList getNodeIDList(String endpoint) { + return this.jsonRpcService.sendRequestToPeer( + new JsonRpcRequest(JsonRpcMethods.GET_NODEIDLIST, Arrays.asList(DefaultGroupId)), + endpoint, + NodeIDList.class); + } + + @Override + public void getNodeIDListAsync(RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_NODEIDLIST, Arrays.asList()), + NodeIDList.class, + callback); + } + + @Override + public ObserverList getObserverList() { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_OBSERVER_LIST, Arrays.asList(this.groupId)), + ObserverList.class); + } + + @Override + public void getObserverList(RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_OBSERVER_LIST, Arrays.asList(this.groupId)), + ObserverList.class, + callback); + } + + @Override + public SealerList getSealerList() { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_SEALER_LIST, Arrays.asList(this.groupId)), + SealerList.class); + } + + @Override + public void getSealerListAsync(RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_SEALER_LIST, Arrays.asList(this.groupId)), + SealerList.class, + callback); + } + + @Override + public PbftView getPbftView() { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_PBFT_VIEW, Arrays.asList(this.groupId)), + PbftView.class); + } + + @Override + public void getPbftViewAsync(RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_PBFT_VIEW, Arrays.asList(this.groupId)), + PbftView.class, + callback); + } + + @Override + public NodeVersion getNodeVersion() { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_NODE_VERSION, Arrays.asList()), + NodeVersion.class); + } + + @Override + public NodeVersion getNodeVersion(String ipAndPort) { + return this.jsonRpcService.sendRequestToPeer( + new JsonRpcRequest(JsonRpcMethods.GET_NODE_VERSION, Arrays.asList()), + ipAndPort, + NodeVersion.class); + } + + @Override + public void getNodeVersion(RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_NODE_VERSION, Arrays.asList()), + NodeVersion.class, + callback); + } + + @Override + public ConsensusStatus getConsensusStatus() { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_CONSENSUS_STATUS, Arrays.asList(this.groupId)), + ConsensusStatus.class); + } + + @Override + public void getConsensusStates(RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_CONSENSUS_STATUS, Arrays.asList(this.groupId)), + ConsensusStatus.class, + callback); + } + + @Override + public SystemConfig getSystemConfigByKey(String key) { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_SYSTEM_CONFIG_BY_KEY, Arrays.asList(this.groupId, key)), + SystemConfig.class); + } + + @Override + public SystemConfig getSystemConfigByKey(String key, String peerIpPort) { + return this.jsonRpcService.sendRequestToPeer( + new JsonRpcRequest( + JsonRpcMethods.GET_SYSTEM_CONFIG_BY_KEY, Arrays.asList(this.groupId, key)), + peerIpPort, + SystemConfig.class); + } + + @Override + public void getSystemConfigByKeyAsync(String key, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest( + JsonRpcMethods.GET_SYSTEM_CONFIG_BY_KEY, Arrays.asList(this.groupId)), + SystemConfig.class, + callback); + } + + @Override + public void getSystemConfigByKeyAsync( + String key, String peerIpPort, RespCallback callback) { + this.jsonRpcService.asyncSendRequestToPeer( + new JsonRpcRequest( + JsonRpcMethods.GET_SYSTEM_CONFIG_BY_KEY, Arrays.asList(this.groupId)), + peerIpPort, + SystemConfig.class, + callback); + } + + @Override + public SyncStatus getSyncStatus() { + return this.jsonRpcService.sendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_SYNC_STATUS, Arrays.asList(this.groupId)), + SyncStatus.class); + } + + @Override + public void getSyncStatus(RespCallback callback) { + this.jsonRpcService.asyncSendRequestToGroup( + new JsonRpcRequest(JsonRpcMethods.GET_SYNC_STATUS, Arrays.asList(this.groupId)), + SyncStatus.class, + callback); + } + + class SynchronousTransactionCallback extends TransactionCallback { + public TransactionReceipt receipt; + public Semaphore semaphore = new Semaphore(1, true); + + SynchronousTransactionCallback() { + try { + semaphore.acquire(1); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + @Override + public void onTimeout() { + super.onTimeout(); + semaphore.release(); + } + + // wait until get the transactionReceipt + @Override + public void onResponse(TransactionReceipt receipt) { + this.receipt = receipt; + semaphore.release(); + } + } + + @Override + public TransactionReceipt sendRawTransactionAndGetReceipt(String signedTransactionData) { + SynchronousTransactionCallback callback = new SynchronousTransactionCallback(); + sendRawTransactionAndGetReceiptAsync(signedTransactionData, callback); + try { + callback.semaphore.acquire(1); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + return callback.receipt; + } + + @Override + public void sendRawTransactionAndGetReceiptAsync( + String signedTransactionData, TransactionCallback callback) { + this.jsonRpcService.asyncSendTransactionToGroup( + new JsonRpcRequest( + JsonRpcMethods.SEND_RAWTRANSACTION, + Arrays.asList(this.groupId, signedTransactionData)), + callback, + SendTransaction.class); + } + + @Override + public void sendRawTransactionAndGetReceiptWithProofAsync( + String signedTransactionData, TransactionCallback callback) { + this.jsonRpcService.asyncSendTransactionToGroup( + new JsonRpcRequest( + JsonRpcMethods.SEND_RAWTRANSACTION_AND_GET_PROOF, + Arrays.asList(this.groupId, signedTransactionData)), + callback, + SendTransaction.class); + } + + @Override + public TransactionReceipt sendRawTransactionAndGetReceiptWithProof( + String signedTransactionData) { + SynchronousTransactionCallback callback = new SynchronousTransactionCallback(); + sendRawTransactionAndGetReceiptWithProofAsync(signedTransactionData, callback); + try { + callback.semaphore.acquire(1); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + return callback.receipt; + } + + @Override + public EventResource getEventResource() { + return eventResource; + } + + @Override + public void stop() { + Thread.currentThread().interrupt(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/JsonRpcService.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/JsonRpcService.java new file mode 100644 index 000000000..18e96e409 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/JsonRpcService.java @@ -0,0 +1,277 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.client; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.fisco.bcos.sdk.channel.Channel; +import org.fisco.bcos.sdk.channel.ResponseCallback; +import org.fisco.bcos.sdk.channel.model.Options; +import org.fisco.bcos.sdk.client.exceptions.ClientException; +import org.fisco.bcos.sdk.client.protocol.request.JsonRpcRequest; +import org.fisco.bcos.sdk.model.JsonRpcResponse; +import org.fisco.bcos.sdk.model.Message; +import org.fisco.bcos.sdk.model.MsgType; +import org.fisco.bcos.sdk.model.Response; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.service.GroupManagerService; +import org.fisco.bcos.sdk.utils.ChannelUtils; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JsonRpcService { + protected final ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(); + private static Logger logger = LoggerFactory.getLogger(JsonRpcService.class); + + private final GroupManagerService groupManagerService; + public final Channel channel; + private final Integer groupId; + + public JsonRpcService( + GroupManagerService groupManagerService, Channel channel, Integer groupId) { + this.groupManagerService = groupManagerService; + this.channel = channel; + this.groupId = groupId; + } + + public Channel getChannel() { + return this.channel; + } + + public GroupManagerService getGroupManagerService() { + return this.groupManagerService; + } + + public T sendRequestToPeer( + JsonRpcRequest request, String peerIpPort, Class responseType) { + return this.sendRequestToPeer( + request, MsgType.CHANNEL_RPC_REQUEST, responseType, peerIpPort); + } + + public T sendRequestToGroup( + JsonRpcRequest request, Class responseType) { + return this.sendRequestToGroup(request, MsgType.CHANNEL_RPC_REQUEST, responseType); + } + + public T sendRequestToPeer( + JsonRpcRequest request, MsgType messageType, Class responseType, String peerIpPort) { + Message message = + encodeRequestToMessage(request, Short.valueOf((short) messageType.getType())); + Response response = channel.sendToPeer(message, peerIpPort); + return this.parseResponseIntoJsonRpcResponse(request, response, responseType); + } + + public T sendRequestToGroup( + JsonRpcRequest request, MsgType messageType, Class responseType) { + Message message = + encodeRequestToMessage(request, Short.valueOf((short) messageType.getType())); + Response response = this.groupManagerService.sendMessageToGroup(this.groupId, message); + if (response == null) { + throw new ClientException( + "sendRequestToGroup to " + + this.groupId + + " failed for select peers to send message failed, please make sure that the group exists"); + } + return this.parseResponseIntoJsonRpcResponse(request, response, responseType); + } + + public void asyncSendRequestToPeer( + JsonRpcRequest request, + String peerIpAndPort, + Class responseType, + RespCallback callback) { + asyncSendRequestToPeer( + request, MsgType.CHANNEL_RPC_REQUEST, peerIpAndPort, responseType, callback); + } + + public void asyncSendRequestToPeer( + JsonRpcRequest request, + MsgType messageType, + String peerIpAndPort, + Class responseType, + RespCallback callback) { + Message message = + encodeRequestToMessage(request, Short.valueOf((short) messageType.getType())); + this.channel.asyncSendToPeer( + message, + peerIpAndPort, + new ResponseCallback() { + @Override + public void onResponse(Response response) { + try { + // decode the transaction + T jsonRpcResponse = + parseResponseIntoJsonRpcResponse( + request, response, responseType); + callback.onResponse(jsonRpcResponse); + } catch (ClientException e) { + Response errorResponse = new Response(); + errorResponse.setErrorMessage(e.getErrorMessage()); + errorResponse.setErrorCode(e.getErrorCode()); + callback.onError(errorResponse); + } + } + }, + new Options()); + } + + public void asyncSendRequestToGroup( + JsonRpcRequest request, Class responseType, RespCallback callback) { + asyncSendRequestToGroup(request, MsgType.CHANNEL_RPC_REQUEST, responseType, callback); + } + + public void asyncSendRequestToGroup( + JsonRpcRequest request, + MsgType messageType, + Class responseType, + RespCallback callback) { + Message message = + encodeRequestToMessage(request, Short.valueOf((short) messageType.getType())); + this.groupManagerService.asyncSendMessageToGroup( + this.groupId, + message, + new ResponseCallback() { + @Override + public void onResponse(Response response) { + try { + // decode the transaction + T jsonRpcResponse = + parseResponseIntoJsonRpcResponse( + request, response, responseType); + callback.onResponse(jsonRpcResponse); + } catch (ClientException e) { + callback.onError(response); + } + } + }); + } + + public void asyncSendTransactionToGroup( + JsonRpcRequest request, TransactionCallback callback, Class responseType) { + Message message = + encodeRequestToMessage( + request, Short.valueOf((short) MsgType.CHANNEL_RPC_REQUEST.getType())); + this.groupManagerService.asyncSendTransaction( + this.groupId, + message, + callback, + new ResponseCallback() { + @Override + public void onResponse(Response response) { + try { + // decode the transaction + parseResponseIntoJsonRpcResponse(request, response, responseType); + } catch (ClientException e) { + if (message != null) { + groupManagerService.eraseTransactionSeq(message.getSeq()); + } + if (response != null) { + groupManagerService.eraseTransactionSeq(response.getMessageID()); + } + // fake the transactionReceipt + callback.onError(e.getErrorCode(), e.getErrorMessage()); + } + } + }); + } + + protected T parseResponseIntoJsonRpcResponse( + JsonRpcRequest request, Response response, Class responseType) { + try { + if (response.getErrorCode() == 0) { + // parse the response into JsonRPCResponse + T jsonRpcResponse = objectMapper.readValue(response.getContent(), responseType); + if (jsonRpcResponse.getError() != null) { + logger.error( + "parseResponseIntoJsonRpcResponse failed for non-empty error message, method: {}, group: {}, seq: {}, retErrorMessage: {}, retErrorCode: {}", + request.getMethod(), + this.groupId, + response.getMessageID(), + jsonRpcResponse.getError().getMessage(), + jsonRpcResponse.getError().getCode()); + throw new ClientException( + jsonRpcResponse.getError().getCode(), + jsonRpcResponse.getError().getMessage(), + "parseResponseIntoJsonRpcResponse failed for non-empty error message, method: " + + request.getMethod() + + " ,group: " + + this.groupId + + " ,seq:" + + response.getMessageID() + + ",retErrorMessage: " + + jsonRpcResponse.getError().getMessage()); + } + return jsonRpcResponse; + } else { + logger.error( + "parseResponseIntoJsonRpcResponse failed, method: {}, group: {}, seq: {}, retErrorMessage: {}, retErrorCode: {}", + request.getMethod(), + this.groupId, + response.getMessageID(), + response.getErrorMessage(), + response.getErrorCode()); + throw new ClientException( + response.getErrorCode(), + response.getErrorMessage(), + "get response failed, errorCode:" + + response.getErrorCode() + + ", error message:" + + response.getErrorMessage()); + } + + } catch (JsonProcessingException e) { + logger.error( + "parseResponseIntoJsonRpcResponse failed for decode the message exceptioned, errorMessge: {}, groupId: {}", + e.getMessage(), + this.groupId); + throw new ClientException( + "parseResponseIntoJsonRpcResponse failed for decode the message exceptioned, error message:" + + e.getMessage(), + e); + } + } + + /** + * encode the request into message + * + * @return the messaged encoded from the request + */ + private Message encodeRequestToMessage(JsonRpcRequest request, Short messageType) { + try { + byte[] encodedData = objectMapper.writeValueAsBytes(request); + Message message = new Message(); + message.setSeq(ChannelUtils.newSeq()); + message.setResult(0); + message.setType(messageType); + message.setData(encodedData); + logger.trace( + "encodeRequestToMessage, seq: {}, method: {}, messageType: {}", + message.getSeq(), + request.getMethod(), + message.getType()); + return message; + } catch (JsonProcessingException e) { + logger.error( + "sendRequestToGroup failed for decode the message exceptioned, errorMessge: {}", + e.getMessage()); + throw new ClientException( + "sendRequestToGroup to " + + this.groupId + + "failed for decode the message exceptioned, error message:" + + e.getMessage(), + e); + } + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/RespCallback.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/RespCallback.java new file mode 100644 index 000000000..4f3430d76 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/RespCallback.java @@ -0,0 +1,35 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client; + +import org.fisco.bcos.sdk.model.Response; + +/** + * Callback function to executed when client get response from the node. + * + * @author Maggie + * @param for the response data structures in package client/response + */ +public interface RespCallback { + /** + * onResponse is the call back function + * + * @param t the response data structure + */ + void onResponse(T t); + + void onError(Response errorResponse); +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/exceptions/ClientException.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/exceptions/ClientException.java new file mode 100644 index 000000000..c558ab82f --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/exceptions/ClientException.java @@ -0,0 +1,76 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.client.exceptions; + +import java.util.Objects; + +/** Exceptioned when calling. */ +public class ClientException extends RuntimeException { + private int errorCode; + private String errorMessage; + + public ClientException(int errorCode, String errorMessage, String message) { + super(message); + this.errorCode = errorCode; + this.errorMessage = errorMessage; + } + + public ClientException(String message) { + super(message); + } + + public ClientException(String message, Throwable cause) { + super(message, cause); + } + + public int getErrorCode() { + return errorCode; + } + + public void setErrorCode(int errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + @Override + public String toString() { + return "ClientException{" + + "errorCode=" + + errorCode + + ", errorMessage='" + + errorMessage + + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ClientException that = (ClientException) o; + return errorCode == that.errorCode && Objects.equals(errorMessage, that.errorMessage); + } + + @Override + public int hashCode() { + return Objects.hash(errorCode, errorMessage); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/handler/BlockNumberNotifyHandler.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/handler/BlockNumberNotifyHandler.java new file mode 100644 index 000000000..7d960bb55 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/handler/BlockNumberNotifyHandler.java @@ -0,0 +1,99 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.handler; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.util.AttributeKey; +import java.util.function.Consumer; +import org.fisco.bcos.sdk.channel.ChannelVersionNegotiation; +import org.fisco.bcos.sdk.channel.model.ChannelProtocol; +import org.fisco.bcos.sdk.channel.model.EnumChannelProtocolVersion; +import org.fisco.bcos.sdk.channel.model.EnumSocketChannelAttributeKey; +import org.fisco.bcos.sdk.model.AmopMsg; +import org.fisco.bcos.sdk.model.Message; +import org.fisco.bcos.sdk.model.MsgType; +import org.fisco.bcos.sdk.network.MsgHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BlockNumberNotifyHandler implements MsgHandler { + private static Logger logger = LoggerFactory.getLogger(BlockNumberNotifyHandler.class); + private final OnReceiveBlockNotifyFunc blockNumberUpdater; + private final Consumer disconnectHandler; + + public BlockNumberNotifyHandler( + OnReceiveBlockNotifyFunc blockNumberUpdater, Consumer disconnectHandler) { + this.blockNumberUpdater = blockNumberUpdater; + this.disconnectHandler = disconnectHandler; + } + + @Override + public void onConnect(ChannelHandlerContext ctx) { + logger.debug("set BlockNumberNotifyHandler"); + } + + @Override + public void onMessage(ChannelHandlerContext ctx, Message msg) { + if (msg.getType() != MsgType.BLOCK_NOTIFY.getType()) { + return; + } + // get version + ChannelProtocol protocol = null; + if (ctx.channel() + .attr( + AttributeKey.valueOf( + EnumSocketChannelAttributeKey.CHANNEL_PROTOCOL_KEY + .getKey())) + != null + && ctx.channel() + .attr( + AttributeKey.valueOf( + EnumSocketChannelAttributeKey.CHANNEL_PROTOCOL_KEY + .getKey())) + .get() + != null) { + protocol = + (ChannelProtocol) + (ctx.channel() + .attr( + AttributeKey.valueOf( + EnumSocketChannelAttributeKey + .CHANNEL_PROTOCOL_KEY.getKey())) + .get()); + } + // default use version 1 + EnumChannelProtocolVersion channelProtocolVersion = EnumChannelProtocolVersion.VERSION_1; + if (protocol != null) { + channelProtocolVersion = protocol.getEnumProtocol(); + } + // get host + String peerIpAndPort = ChannelVersionNegotiation.getPeerHost(ctx); + // get block notification data + AmopMsg amopMsg = new AmopMsg(msg); + amopMsg.decodeAmopBody(msg.getData()); + // update block number information + blockNumberUpdater.OnReceiveBlockNotify(channelProtocolVersion, peerIpAndPort, amopMsg); + } + + @Override + public void onDisconnect(ChannelHandlerContext ctx) { + String peerIpAndPort = ChannelVersionNegotiation.getPeerHost(ctx); + if (disconnectHandler != null) { + disconnectHandler.accept(peerIpAndPort); + } + logger.debug("onDisconnect, endpoint: {}", peerIpAndPort); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/handler/GetNodeVersionHandler.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/handler/GetNodeVersionHandler.java new file mode 100644 index 000000000..e12c36b04 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/handler/GetNodeVersionHandler.java @@ -0,0 +1,50 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.handler; + +import io.netty.channel.ChannelHandlerContext; +import java.util.function.Consumer; +import org.fisco.bcos.sdk.channel.ChannelVersionNegotiation; +import org.fisco.bcos.sdk.model.Message; +import org.fisco.bcos.sdk.network.MsgHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GetNodeVersionHandler implements MsgHandler { + private static Logger logger = LoggerFactory.getLogger(GetNodeVersionHandler.class); + private final Consumer nodeVersionUpdater; + + public GetNodeVersionHandler(Consumer nodeVersionUpdater) { + this.nodeVersionUpdater = nodeVersionUpdater; + } + + @Override + public void onConnect(ChannelHandlerContext ctx) { + String peerIpAndPort = ChannelVersionNegotiation.getPeerHost(ctx); + this.nodeVersionUpdater.accept(peerIpAndPort); + logger.info("GetNodeVersionHandler: onConnect, endpoint: {}", peerIpAndPort); + } + + @Override + public void onMessage(ChannelHandlerContext ctx, Message msg) {} + + @Override + public void onDisconnect(ChannelHandlerContext ctx) { + logger.info( + "GetNodeVersionHandler: onDisconnect, endpoint: {}", + ChannelVersionNegotiation.getPeerHost(ctx)); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/handler/OnReceiveBlockNotifyFunc.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/handler/OnReceiveBlockNotifyFunc.java new file mode 100644 index 000000000..37bf015c1 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/handler/OnReceiveBlockNotifyFunc.java @@ -0,0 +1,23 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.client.handler; + +import org.fisco.bcos.sdk.channel.model.EnumChannelProtocolVersion; +import org.fisco.bcos.sdk.model.Message; + +@FunctionalInterface +public interface OnReceiveBlockNotifyFunc { + void OnReceiveBlockNotify( + EnumChannelProtocolVersion version, String peerIpAndPort, Message message); +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/handler/TransactionNotifyHandler.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/handler/TransactionNotifyHandler.java new file mode 100644 index 000000000..b838f0766 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/handler/TransactionNotifyHandler.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.client.handler; + +import io.netty.channel.ChannelHandlerContext; +import java.util.function.Consumer; +import org.fisco.bcos.sdk.channel.ChannelVersionNegotiation; +import org.fisco.bcos.sdk.model.Message; +import org.fisco.bcos.sdk.model.MsgType; +import org.fisco.bcos.sdk.network.MsgHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TransactionNotifyHandler implements MsgHandler { + private static Logger logger = LoggerFactory.getLogger(TransactionNotifyHandler.class); + private final Consumer transactionNotifyReceiver; + + public TransactionNotifyHandler(Consumer transactionNotifyReceiver) { + this.transactionNotifyReceiver = transactionNotifyReceiver; + } + + @Override + public void onConnect(ChannelHandlerContext ctx) { + logger.debug("onConnect, endpoint: {}", ChannelVersionNegotiation.getPeerHost(ctx)); + } + + @Override + public void onMessage(ChannelHandlerContext ctx, Message msg) { + if (msg.getType() != MsgType.TRANSACTION_NOTIFY.getType()) { + return; + } + transactionNotifyReceiver.accept(msg); + } + + @Override + public void onDisconnect(ChannelHandlerContext ctx) { + logger.debug("onDisconnect, endpoint: {}", ChannelVersionNegotiation.getPeerHost(ctx)); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/model/GroupStatus.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/model/GroupStatus.java new file mode 100644 index 000000000..6804d0994 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/model/GroupStatus.java @@ -0,0 +1,77 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.client.protocol.model; + +import java.util.Objects; + +public class GroupStatus { + private String code; + private String message; + private String status; + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + GroupStatus that = (GroupStatus) o; + return Objects.equals(code, that.code) + && Objects.equals(message, that.message) + && Objects.equals(status, that.status); + } + + @Override + public int hashCode() { + return Objects.hash(code, message, status); + } + + @Override + public String toString() { + return "GroupStatus{" + + "code='" + + code + + '\'' + + ", message='" + + message + + '\'' + + ", status='" + + status + + '\'' + + '}'; + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/model/JsonRpcRetCode.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/model/JsonRpcRetCode.java new file mode 100644 index 000000000..6924b8ca5 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/model/JsonRpcRetCode.java @@ -0,0 +1,19 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.client.protocol.model; + +public class JsonRpcRetCode { + public static int SDK_PERMISSION_DENIED = -40012; +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/model/JsonTransactionResponse.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/model/JsonTransactionResponse.java new file mode 100644 index 000000000..02f4a3155 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/model/JsonTransactionResponse.java @@ -0,0 +1,199 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.client.protocol.model; + +import java.math.BigInteger; +import java.util.Objects; +import org.fisco.bcos.sdk.utils.Numeric; + +public class JsonTransactionResponse { + // the fields related to get-transaction + private String blockHash; + private String blockNumber; + private String from; + private String gas; + private String hash; + private String input; + private String nonce; + private String to; + private String transactionIndex; + private String value; + + // the fields related to get-block + private String gasPrice; + + public String getBlockHash() { + return blockHash; + } + + public void setBlockHash(String blockHash) { + this.blockHash = blockHash; + } + + public BigInteger getBlockNumber() { + return Numeric.decodeQuantity(blockNumber); + } + + public void setBlockNumber(String blockNumber) { + this.blockNumber = blockNumber; + } + + public String getFrom() { + return from; + } + + public void setFrom(String from) { + this.from = from; + } + + public String getGas() { + return gas; + } + + public void setGas(String gas) { + this.gas = gas; + } + + public String getHash() { + return hash; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public String getInput() { + return input; + } + + public void setInput(String input) { + this.input = input; + } + + public String getNonce() { + return nonce; + } + + public void setNonce(String nonce) { + this.nonce = nonce; + } + + public String getTo() { + return to; + } + + public void setTo(String to) { + this.to = to; + } + + public String getTransactionIndex() { + return transactionIndex; + } + + public void setTransactionIndex(String transactionIndex) { + this.transactionIndex = transactionIndex; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getGasPrice() { + return gasPrice; + } + + public void setGasPrice(String gasPrice) { + this.gasPrice = gasPrice; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + JsonTransactionResponse that = (JsonTransactionResponse) o; + return Objects.equals(blockHash, that.blockHash) + && Objects.equals( + Numeric.decodeQuantity(blockNumber), + Numeric.decodeQuantity(that.blockNumber)) + && Objects.equals(from, that.from) + && Objects.equals(gas, that.gas) + && Objects.equals(hash, that.hash) + && Objects.equals(input, that.input) + && Objects.equals(nonce, that.nonce) + && Objects.equals(to, that.to) + && Objects.equals(transactionIndex, that.transactionIndex) + && Objects.equals(value, that.value) + && Objects.equals(gasPrice, that.gasPrice); + } + + @Override + public int hashCode() { + return Objects.hash( + blockHash, + Numeric.decodeQuantity(blockNumber), + from, + gas, + hash, + input, + nonce, + to, + transactionIndex, + value, + gasPrice); + } + + @Override + public String toString() { + return "Transaction {" + + "blockHash='" + + blockHash + + '\'' + + ", blockNumber='" + + blockNumber + + '\'' + + ", from='" + + from + + '\'' + + ", gas='" + + gas + + '\'' + + ", hash='" + + hash + + '\'' + + ", input='" + + input + + '\'' + + ", nonce='" + + nonce + + '\'' + + ", to='" + + to + + '\'' + + ", transactionIndex='" + + transactionIndex + + '\'' + + ", value='" + + value + + '\'' + + ", gasPrice='" + + gasPrice + + '\'' + + '}'; + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/request/GenerateGroupParam.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/request/GenerateGroupParam.java new file mode 100644 index 000000000..6816f2ee6 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/request/GenerateGroupParam.java @@ -0,0 +1,55 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.client.protocol.request; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +public class GenerateGroupParam { + private String timestamp; + private List sealers; + + @JsonProperty("enable_free_storage") + private boolean enableFreeStorage; + + public GenerateGroupParam(String timestamp, boolean enableFreeStorage, List sealers) { + this.timestamp = timestamp; + this.enableFreeStorage = enableFreeStorage; + this.sealers = sealers; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public List getSealers() { + return sealers; + } + + public void setSealers(List sealers) { + this.sealers = sealers; + } + + public boolean isEnableFreeStorage() { + return enableFreeStorage; + } + + public void setEnableFreeStorage(boolean enableFreeStorage) { + this.enableFreeStorage = enableFreeStorage; + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/request/JsonRpcMethods.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/request/JsonRpcMethods.java new file mode 100644 index 000000000..999e74f60 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/request/JsonRpcMethods.java @@ -0,0 +1,66 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.client.protocol.request; + +public class JsonRpcMethods { + /** define the method name for all jsonRPC interfaces */ + // the interface related to the group + public static final String GET_BLOCK_NUMBER = "getBlockNumber"; + + public static final String GET_NODE_VERSION = "getClientVersion"; + public static final String GET_PBFT_VIEW = "getPbftView"; + public static final String GET_SEALER_LIST = "getSealerList"; + public static final String GET_SYSTEM_CONFIG_BY_KEY = "getSystemConfigByKey"; + public static final String GET_OBSERVER_LIST = "getObserverList"; + public static final String GET_CONSENSUS_STATUS = "getConsensusStatus"; + public static final String GET_SYNC_STATUS = "getSyncStatus"; + public static final String GET_GROUP_PEERS = "getGroupPeers"; + public static final String GET_BLOCK_BY_HASH = "getBlockByHash"; + public static final String GET_BLOCKHEADER_BY_HASH = "getBlockHeaderByHash"; + public static final String GET_BLOCK_BY_NUMBER = "getBlockByNumber"; + public static final String GET_BLOCKHEADER_BY_NUMBER = "getBlockHeaderByNumber"; + public static final String GET_BLOCKHASH_BY_NUMBER = "getBlockHashByNumber"; + public static final String GET_TRANSACTION_BY_HASH = "getTransactionByHash"; + public static final String GET_TRANSACTION_BY_BLOCKHASH_AND_INDEX = + "getTransactionByBlockHashAndIndex"; + public static final String GET_TRANSACTION_BY_BLOCKNUMBER_AND_INDEX = + "getTransactionByBlockNumberAndIndex"; + public static final String GET_TRANSACTIONRECEIPT = "getTransactionReceipt"; + public static final String GET_PENDING_TX_SIZE = "getPendingTxSize"; + public static final String GET_PENDING_TRANSACTIONS = "getPendingTransactions"; + public static final String CALL = "call"; + public static final String SEND_RAWTRANSACTION = "sendRawTransaction"; + public static final String SEND_RAWTRANSACTION_AND_GET_PROOF = "sendRawTransactionAndGetProof"; + public static final String GET_CODE = "getCode"; + public static final String GET_TOTAL_TRANSACTION_COUNT = "getTotalTransactionCount"; + public static final String GET_TRANSACTION_BY_HASH_WITH_PROOF = "getTransactionByHashWithProof"; + public static final String GET_TRANSACTION_RECEIPT_BY_HASH_WITH_PROOF = + "getTransactionReceiptByHashWithProof"; + + // the interface related to the node + public static final String GET_CLIENT_VERSION = "getClientVersion"; + public static final String GET_PEERS = "getPeers"; + public static final String GET_GROUP_LIST = "getGroupList"; + public static final String GET_NODEIDLIST = "getNodeIDList"; + + // the interface related to group-runtime-manager + public static final String GENERATE_GROUP = "generateGroup"; + public static final String START_GROUP = "startGroup"; + public static final String STOP_GROUP = "stopGroup"; + public static final String REMOVE_GROUP = "removeGroup"; + public static final String RECOVER_GROUP = "recoverGroup"; + public static final String QUERY_GROUP_STATUS = "queryGroupStatus"; + + private JsonRpcMethods() {} +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/request/JsonRpcRequest.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/request/JsonRpcRequest.java new file mode 100644 index 000000000..c8e8f8635 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/request/JsonRpcRequest.java @@ -0,0 +1,110 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.client.protocol.request; + +import java.util.List; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicLong; + +public class JsonRpcRequest { + // for set the json id + private static AtomicLong nextIdGetter = new AtomicLong(0); + // the jsonrpc version, default is 2.0 + private String jsonrpc = "2.0"; + // rpc method + private String method; + // params for the rpc interface + private List params; + // the json rpc request id + private long id; + + public JsonRpcRequest(String method, List params) { + this.method = method; + this.params = params; + this.id = nextIdGetter.getAndIncrement(); + } + + public static AtomicLong getNextIdGetter() { + return nextIdGetter; + } + + public static void setNextIdGetter(AtomicLong nextIdGetter) { + JsonRpcRequest.nextIdGetter = nextIdGetter; + } + + public String getJsonrpc() { + return jsonrpc; + } + + public void setJsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public List getParams() { + return params; + } + + public void setParams(List params) { + this.params = params; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + JsonRpcRequest that = (JsonRpcRequest) o; + return id == that.id + && Objects.equals(jsonrpc, that.jsonrpc) + && Objects.equals(method, that.method) + && Objects.equals(params, that.params); + } + + @Override + public int hashCode() { + return Objects.hash(jsonrpc, method, params, id); + } + + @Override + public String toString() { + return "JsonRpcRequest{" + + "jsonrpc='" + + jsonrpc + + '\'' + + ", method='" + + method + + '\'' + + ", params=" + + params + + ", id=" + + id + + '}'; + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/request/Transaction.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/request/Transaction.java new file mode 100644 index 000000000..7c4119461 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/request/Transaction.java @@ -0,0 +1,75 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.request; + +import java.util.Objects; + +public class Transaction { + private String from; + private String to; + private String data; + + /** + * @param from from address + * @param to to address + * @param encodedFunction the string encodedFunction + */ + public Transaction(String from, String to, String encodedFunction) { + super(); + this.from = from; + this.to = to; + this.data = encodedFunction; + } + + public String getFrom() { + return from; + } + + public void setFrom(String from) { + this.from = from; + } + + public String getTo() { + return to; + } + + public void setTo(String to) { + this.to = to; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Transaction that = (Transaction) o; + return Objects.equals(from, that.from) + && Objects.equals(to, that.to) + && Objects.equals(data, that.data); + } + + @Override + public int hashCode() { + return Objects.hash(from, to, data); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/BcosBlock.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/BcosBlock.java new file mode 100644 index 000000000..db8bd9a5c --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/BcosBlock.java @@ -0,0 +1,217 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.ObjectReader; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import org.fisco.bcos.sdk.client.protocol.model.JsonTransactionResponse; +import org.fisco.bcos.sdk.model.JsonRpcResponse; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class BcosBlock extends JsonRpcResponse { + @Override + @JsonDeserialize(using = BcosBlock.BlockDeserialiser.class) + public void setResult(Block result) { + super.setResult(result); + } + + public Block getBlock() { + return getResult(); + } + + public interface TransactionResult { + T get(); + } + + public static class TransactionHash implements TransactionResult { + private String value; + + public TransactionHash() {} + + public TransactionHash(String value) { + this.value = value; + } + + public String get() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TransactionHash that = (TransactionHash) o; + return Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + + @Override + public String toString() { + return "TransactionHash{" + "value='" + value + '\'' + '}'; + } + } + + public static class TransactionObject extends JsonTransactionResponse + implements TransactionResult { + public JsonTransactionResponse get() { + return this; + } + } + + public static class Block extends BcosBlockHeader.BlockHeader { + private List transactions; + + public List getTransactions() { + return transactions; + } + + @JsonDeserialize(using = TransactionResultDeserialiser.class) + public void setTransactions(List transactions) { + this.transactions = transactions; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + Block block = (Block) o; + return Objects.equals(transactions, block.transactions); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), transactions); + } + + @Override + public String toString() { + return "Block{" + + "transactions=" + + transactions + + ", number='" + + number + + '\'' + + ", hash='" + + hash + + '\'' + + ", parentHash='" + + parentHash + + '\'' + + ", logsBloom='" + + logsBloom + + '\'' + + ", transactionsRoot='" + + transactionsRoot + + '\'' + + ", receiptsRoot='" + + receiptsRoot + + '\'' + + ", dbHash='" + + dbHash + + '\'' + + ", stateRoot='" + + stateRoot + + '\'' + + ", sealer='" + + sealer + + '\'' + + ", sealerList=" + + sealerList + + ", extraData=" + + extraData + + ", gasLimit='" + + gasLimit + + '\'' + + ", gasUsed='" + + gasUsed + + '\'' + + ", timestamp='" + + timestamp + + '\'' + + ", signatureList=" + + signatureList + + '}'; + } + } + + // decode transactionResult + public static class TransactionResultDeserialiser + extends JsonDeserializer> { + + private ObjectReader objectReader = ObjectMapperFactory.getObjectReader(); + + @Override + public List deserialize( + JsonParser jsonParser, DeserializationContext deserializationContext) + throws IOException { + List transactionResults = new ArrayList<>(); + JsonToken nextToken = jsonParser.nextToken(); + + if (nextToken == JsonToken.START_OBJECT) { + Iterator transactionObjectIterator = + objectReader.readValues(jsonParser, TransactionObject.class); + while (transactionObjectIterator.hasNext()) { + transactionResults.add(transactionObjectIterator.next()); + } + } else if (nextToken == JsonToken.VALUE_STRING) { + jsonParser.getValueAsString(); + + Iterator transactionHashIterator = + objectReader.readValues(jsonParser, TransactionHash.class); + while (transactionHashIterator.hasNext()) { + transactionResults.add(transactionHashIterator.next()); + } + } + return transactionResults; + } + } + + // decode the block + public static class BlockDeserialiser extends JsonDeserializer { + private ObjectReader objectReader = ObjectMapperFactory.getObjectReader(); + + @Override + public Block deserialize( + JsonParser jsonParser, DeserializationContext deserializationContext) + throws IOException { + if (jsonParser.getCurrentToken() != JsonToken.VALUE_NULL) { + return objectReader.readValue(jsonParser, Block.class); + } else { + return null; // null is wrapped by Optional in above getter + } + } + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/BcosBlockHeader.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/BcosBlockHeader.java new file mode 100644 index 000000000..7cecba883 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/BcosBlockHeader.java @@ -0,0 +1,311 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import java.math.BigInteger; +import java.util.List; +import java.util.Objects; +import org.fisco.bcos.sdk.model.JsonRpcResponse; +import org.fisco.bcos.sdk.utils.Numeric; + +public class BcosBlockHeader extends JsonRpcResponse { + + @Override + public void setResult(BlockHeader result) { + super.setResult(result); + } + + public BlockHeader getBlockHeader() { + return getResult(); + } + + public static class Signature { + private String index; + private String signature; + + public Signature() {} + + public String getIndex() { + return index; + } + + public void setIndex(String index) { + this.index = index; + } + + public String getSignature() { + return signature; + } + + public void setSignature(String signature) { + this.signature = signature; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Signature signature1 = (Signature) o; + return Objects.equals(index, signature1.index) + && Objects.equals(signature, signature1.signature); + } + + @Override + public int hashCode() { + return Objects.hash(index, signature); + } + + @Override + public String toString() { + return "Signature{" + + "index='" + + index + + '\'' + + ", signature='" + + signature + + '\'' + + '}'; + } + } + + public static class BlockHeader { + protected String number; + protected String hash; + protected String parentHash; + protected String logsBloom; + protected String transactionsRoot; + protected String receiptsRoot; + protected String dbHash; + protected String stateRoot; + protected String sealer; + protected List sealerList; + protected List extraData; + protected String gasLimit; + protected String gasUsed; + protected String timestamp; + protected List signatureList; + + public void setSignatureList(List signatureList) { + this.signatureList = signatureList; + } + + public List getSignatureList() { + return this.signatureList; + } + + public void setNumber(String number) { + this.number = number; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public void setParentHash(String parentHash) { + this.parentHash = parentHash; + } + + public void setLogsBloom(String logsBloom) { + this.logsBloom = logsBloom; + } + + public void setTransactionsRoot(String transactionsRoot) { + this.transactionsRoot = transactionsRoot; + } + + public void setReceiptsRoot(String receiptsRoot) { + this.receiptsRoot = receiptsRoot; + } + + public void setDbHash(String dbHash) { + this.dbHash = dbHash; + } + + public void setStateRoot(String stateRoot) { + this.stateRoot = stateRoot; + } + + public void setSealer(String sealer) { + this.sealer = sealer; + } + + public void setSealerList(List sealerList) { + this.sealerList = sealerList; + } + + public void setExtraData(List extraData) { + this.extraData = extraData; + } + + public void setGasLimit(String gasLimit) { + this.gasLimit = gasLimit; + } + + public void setGasUsed(String gasUsed) { + this.gasUsed = gasUsed; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public BigInteger getNumber() { + return Numeric.decodeQuantity(number); + } + + public String getHash() { + return hash; + } + + public String getParentHash() { + return parentHash; + } + + public String getLogsBloom() { + return logsBloom; + } + + public String getTransactionsRoot() { + return transactionsRoot; + } + + public String getReceiptsRoot() { + return receiptsRoot; + } + + public String getDbHash() { + return dbHash; + } + + public String getStateRoot() { + return stateRoot; + } + + public String getSealer() { + return sealer; + } + + public List getSealerList() { + return sealerList; + } + + public List getExtraData() { + return extraData; + } + + public String getGasLimit() { + return gasLimit; + } + + public String getGasUsed() { + return gasUsed; + } + + public String getTimestamp() { + return timestamp; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BlockHeader that = (BlockHeader) o; + return Objects.equals( + Numeric.decodeQuantity(number), Numeric.decodeQuantity(that.number)) + && Objects.equals(hash, that.hash) + && Objects.equals(parentHash, that.parentHash) + && Objects.equals(logsBloom, that.logsBloom) + && Objects.equals(transactionsRoot, that.transactionsRoot) + && Objects.equals(receiptsRoot, that.receiptsRoot) + && Objects.equals(dbHash, that.dbHash) + && Objects.equals(stateRoot, that.stateRoot) + && Objects.equals(sealer, that.sealer) + && Objects.equals(sealerList, that.sealerList) + && Objects.equals(extraData, that.extraData) + && Objects.equals(gasLimit, that.gasLimit) + && Objects.equals(gasUsed, that.gasUsed) + && Objects.equals(timestamp, that.timestamp) + && Objects.equals(signatureList, that.signatureList); + } + + @Override + public int hashCode() { + return Objects.hash( + Numeric.decodeQuantity(number), + hash, + parentHash, + logsBloom, + transactionsRoot, + receiptsRoot, + dbHash, + stateRoot, + sealer, + sealerList, + extraData, + gasLimit, + gasUsed, + timestamp, + signatureList); + } + + @Override + public String toString() { + return "BlockHeader{" + + "number=" + + number + + ", hash='" + + hash + + '\'' + + ", parentHash='" + + parentHash + + '\'' + + ", logsBloom='" + + logsBloom + + '\'' + + ", transactionsRoot='" + + transactionsRoot + + '\'' + + ", receiptsRoot='" + + receiptsRoot + + '\'' + + ", dbHash='" + + dbHash + + '\'' + + ", stateRoot='" + + stateRoot + + '\'' + + ", sealer='" + + sealer + + '\'' + + ", sealerList=" + + sealerList + + ", extraData=" + + extraData + + ", gasLimit='" + + gasLimit + + '\'' + + ", gasUsed='" + + gasUsed + + '\'' + + ", timestamp='" + + timestamp + + '\'' + + ", signatureList=" + + signatureList + + '}'; + } + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/BcosTransaction.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/BcosTransaction.java new file mode 100644 index 000000000..1af6e53c5 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/BcosTransaction.java @@ -0,0 +1,33 @@ +package org.fisco.bcos.sdk.client.protocol.response; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.ObjectReader; +import java.io.IOException; +import java.util.Optional; +import org.fisco.bcos.sdk.client.protocol.model.JsonTransactionResponse; +import org.fisco.bcos.sdk.model.JsonRpcResponse; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; + +public class BcosTransaction extends JsonRpcResponse { + public Optional getTransaction() { + return Optional.ofNullable(getResult()); + } + + public static class ResponseDeserialiser extends JsonDeserializer { + private ObjectReader objectReader = ObjectMapperFactory.getObjectReader(); + + @Override + public JsonTransactionResponse deserialize( + JsonParser jsonParser, DeserializationContext deserializationContext) + throws IOException { + if (jsonParser.getCurrentToken() != JsonToken.VALUE_NULL) { + return objectReader.readValue(jsonParser, JsonTransactionResponse.class); + } else { + return null; // null is wrapped by Optional in above getter + } + } + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/BcosTransactionReceipt.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/BcosTransactionReceipt.java new file mode 100644 index 000000000..650872380 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/BcosTransactionReceipt.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.ObjectReader; +import java.io.IOException; +import java.util.Optional; +import org.fisco.bcos.sdk.model.JsonRpcResponse; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; + +/** getTransactionReceipt. */ +public class BcosTransactionReceipt extends JsonRpcResponse { + public Optional getTransactionReceipt() { + return Optional.ofNullable(getResult()); + } + + public static class ResponseDeserialiser extends JsonDeserializer { + private ObjectReader objectReader = ObjectMapperFactory.getObjectReader(); + + @Override + public TransactionReceipt deserialize( + JsonParser jsonParser, DeserializationContext deserializationContext) + throws IOException { + if (jsonParser.getCurrentToken() != JsonToken.VALUE_NULL) { + return objectReader.readValue(jsonParser, TransactionReceipt.class); + } else { + return null; // null is wrapped by Optional in above getter + } + } + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/BlockHash.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/BlockHash.java new file mode 100644 index 000000000..30e00f32c --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/BlockHash.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +/** getBlockHashByNumber */ +public class BlockHash extends JsonRpcResponse { + public String getBlockHashByNumber() { + return getResult(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/BlockNumber.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/BlockNumber.java new file mode 100644 index 000000000..57c64a94a --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/BlockNumber.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.model.JsonRpcResponse; +import org.fisco.bcos.sdk.utils.Numeric; + +/** getblockNumber. */ +public class BlockNumber extends JsonRpcResponse { + public BigInteger getBlockNumber() { + return Numeric.decodeQuantity(getResult()); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/Call.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/Call.java new file mode 100644 index 000000000..01bdeebdb --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/Call.java @@ -0,0 +1,98 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import java.math.BigInteger; +import java.util.Objects; +import org.fisco.bcos.sdk.model.JsonRpcResponse; +import org.fisco.bcos.sdk.utils.Numeric; + +/** + * RPC response of ledger call + * + * @author Maggie + */ +public class Call extends JsonRpcResponse { + public static class CallOutput { + private String currentBlockNumber; + private String status; + private String output; + + public BigInteger getCurrentBlockNumber() { + return Numeric.decodeQuantity(currentBlockNumber); + } + + public void setCurrentBlockNumber(String currentBlockNumber) { + this.currentBlockNumber = currentBlockNumber; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getOutput() { + return output; + } + + public void setOutput(String output) { + this.output = output; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CallOutput that = (CallOutput) o; + return Objects.equals( + Numeric.decodeQuantity(currentBlockNumber), + Numeric.decodeQuantity(that.currentBlockNumber)) + && Objects.equals(status, that.status) + && Objects.equals(output, that.output); + } + + @Override + public int hashCode() { + return Objects.hash(Numeric.decodeQuantity(currentBlockNumber), status, output); + } + + @Override + public String toString() { + return "CallOutput{" + + "currentBlockNumber='" + + currentBlockNumber + + '\'' + + ", status='" + + status + + '\'' + + ", output='" + + output + + '\'' + + '}'; + } + } + + public void setResult(CallOutput result) { + super.setResult(result); + } + + public CallOutput getCallResult() { + return getResult(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/Code.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/Code.java new file mode 100644 index 000000000..e95c1ed72 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/Code.java @@ -0,0 +1,29 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +/** + * Get code response + * + * @author Maggie + */ +public class Code extends JsonRpcResponse { + public String getCode() { + return this.getResult(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/ConsensusStatus.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/ConsensusStatus.java new file mode 100644 index 000000000..ce13d66e8 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/ConsensusStatus.java @@ -0,0 +1,475 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import org.fisco.bcos.sdk.model.JsonRpcResponse; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; + +/** getConsensusStatus */ +public class ConsensusStatus extends JsonRpcResponse { + @Override + @JsonDeserialize(using = ConsensusStatusDeserializer.class) + public void setResult(ConsensusStatus.ConsensusInfo result) { + super.setResult(result); + } + + public ConsensusInfo getConsensusStatus() { + return getResult(); + } + + public static class ViewInfo { + private String nodeId; + private String view; + + public String getNodeId() { + return nodeId; + } + + public void setNodeId(String nodeId) { + this.nodeId = nodeId; + } + + public String getView() { + return view; + } + + public void setView(String view) { + this.view = view; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ViewInfo viewInfo = (ViewInfo) o; + return Objects.equals(nodeId, viewInfo.nodeId) && Objects.equals(view, viewInfo.view); + } + + @Override + public int hashCode() { + return Objects.hash(nodeId, view); + } + + @Override + public String toString() { + return "ViewInfo{" + "nodeId='" + nodeId + '\'' + ", view='" + view + '\'' + '}'; + } + } + + public static class BasicConsensusInfo { + private String nodeNum; + + @JsonProperty("node_index") + private String nodeIndex; + + @JsonProperty("node index") + private String raftNodeIndex; + + @JsonProperty("max_faulty_leader") + private String maxFaultyNodeNum; + + @JsonProperty("sealer.") + private List sealerList; + + private String consensusedBlockNumber; + private String highestblockNumber; + private String groupId; + private String protocolId; + private String accountType; + private String cfgErr; + private String omitEmptyBlock; + private String nodeId; + private String allowFutureBlocks; + private String connectedNodes; + private String currentView; + private String toView; + private String leaderFailed; + private String highestblockHash; + private String leaderId; + private String leaderIdx; + + public String getRaftNodeIndex() { + return raftNodeIndex; + } + + public void setRaftNodeIndex(String raftNodeIndex) { + this.raftNodeIndex = raftNodeIndex; + } + + public String getLeaderId() { + return leaderId; + } + + public void setLeaderId(String leaderId) { + this.leaderId = leaderId; + } + + public String getLeaderIdx() { + return leaderIdx; + } + + public void setLeaderIdx(String leaderIdx) { + this.leaderIdx = leaderIdx; + } + + public String getNodeIndex() { + return nodeIndex; + } + + public void setNodeIndex(String nodeIndex) { + this.nodeIndex = nodeIndex; + } + + public String getHighestblockHash() { + return highestblockHash; + } + + public void setHighestblockHash(String highestblockHash) { + this.highestblockHash = highestblockHash; + } + + public String getNodeNum() { + return nodeNum; + } + + public void setNodeNum(String nodeNum) { + this.nodeNum = nodeNum; + } + + public String getMaxFaultyNodeNum() { + return maxFaultyNodeNum; + } + + public void setMaxFaultyNodeNum(String maxFaultyNodeNum) { + this.maxFaultyNodeNum = maxFaultyNodeNum; + } + + public List getSealerList() { + return sealerList; + } + + public void setSealerList(List sealerList) { + this.sealerList = sealerList; + } + + public String getConsensusedBlockNumber() { + return consensusedBlockNumber; + } + + public void setConsensusedBlockNumber(String consensusedBlockNumber) { + this.consensusedBlockNumber = consensusedBlockNumber; + } + + public String getHighestblockNumber() { + return highestblockNumber; + } + + public void setHighestblockNumber(String highestblockNumber) { + this.highestblockNumber = highestblockNumber; + } + + public String getGroupId() { + return groupId; + } + + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + public String getProtocolId() { + return protocolId; + } + + public void setProtocolId(String protocolId) { + this.protocolId = protocolId; + } + + public String getAccountType() { + return accountType; + } + + public void setAccountType(String accountType) { + this.accountType = accountType; + } + + public String getCfgErr() { + return cfgErr; + } + + public void setCfgErr(String cfgErr) { + this.cfgErr = cfgErr; + } + + public String getOmitEmptyBlock() { + return omitEmptyBlock; + } + + public void setOmitEmptyBlock(String omitEmptyBlock) { + this.omitEmptyBlock = omitEmptyBlock; + } + + public String getNodeId() { + return nodeId; + } + + public void setNodeId(String nodeId) { + this.nodeId = nodeId; + } + + public String getAllowFutureBlocks() { + return allowFutureBlocks; + } + + public void setAllowFutureBlocks(String allowFutureBlocks) { + this.allowFutureBlocks = allowFutureBlocks; + } + + public String getConnectedNodes() { + return connectedNodes; + } + + public void setConnectedNodes(String connectedNodes) { + this.connectedNodes = connectedNodes; + } + + public String getCurrentView() { + return currentView; + } + + public void setCurrentView(String currentView) { + this.currentView = currentView; + } + + public String getToView() { + return toView; + } + + public void setToView(String toView) { + this.toView = toView; + } + + public String getLeaderFailed() { + return leaderFailed; + } + + public void setLeaderFailed(String leaderFailed) { + this.leaderFailed = leaderFailed; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BasicConsensusInfo that = (BasicConsensusInfo) o; + return Objects.equals(nodeNum, that.nodeNum) + && Objects.equals(nodeIndex, that.nodeIndex) + && Objects.equals(maxFaultyNodeNum, that.maxFaultyNodeNum) + && Objects.equals(sealerList, that.sealerList) + && Objects.equals(consensusedBlockNumber, that.consensusedBlockNumber) + && Objects.equals(highestblockNumber, that.highestblockNumber) + && Objects.equals(groupId, that.groupId) + && Objects.equals(protocolId, that.protocolId) + && Objects.equals(accountType, that.accountType) + && Objects.equals(cfgErr, that.cfgErr) + && Objects.equals(omitEmptyBlock, that.omitEmptyBlock) + && Objects.equals(nodeId, that.nodeId) + && Objects.equals(allowFutureBlocks, that.allowFutureBlocks) + && Objects.equals(connectedNodes, that.connectedNodes) + && Objects.equals(currentView, that.currentView) + && Objects.equals(toView, that.toView) + && Objects.equals(leaderFailed, that.leaderFailed) + && Objects.equals(highestblockHash, that.highestblockHash); + } + + @Override + public int hashCode() { + return Objects.hash( + nodeNum, + nodeIndex, + maxFaultyNodeNum, + sealerList, + consensusedBlockNumber, + highestblockNumber, + groupId, + protocolId, + accountType, + cfgErr, + omitEmptyBlock, + nodeId, + allowFutureBlocks, + connectedNodes, + currentView, + toView, + leaderFailed, + highestblockHash); + } + + @Override + public String toString() { + return "BasicConsensusInfo{" + + "nodeNum='" + + nodeNum + + '\'' + + ", nodeIndex='" + + nodeIndex + + '\'' + + ", maxFaultyNodeNum='" + + maxFaultyNodeNum + + '\'' + + ", sealerList=" + + sealerList + + ", consensusedBlockNumber='" + + consensusedBlockNumber + + '\'' + + ", highestblockNumber='" + + highestblockNumber + + '\'' + + ", groupId='" + + groupId + + '\'' + + ", protocolId='" + + protocolId + + '\'' + + ", accountType='" + + accountType + + '\'' + + ", cfgErr='" + + cfgErr + + '\'' + + ", omitEmptyBlock='" + + omitEmptyBlock + + '\'' + + ", nodeId='" + + nodeId + + '\'' + + ", allowFutureBlocks='" + + allowFutureBlocks + + '\'' + + ", connectedNodes='" + + connectedNodes + + '\'' + + ", currentView='" + + currentView + + '\'' + + ", toView='" + + toView + + '\'' + + ", leaderFailed='" + + leaderFailed + + '\'' + + ", highestblockHash='" + + highestblockHash + + '\'' + + '}'; + } + } + + public static class ConsensusInfo { + private BasicConsensusInfo baseConsensusInfo; + private List viewInfos; + + public ConsensusInfo() {} + + public ConsensusInfo(BasicConsensusInfo baseConsensusInfo, List viewInfos) { + this.baseConsensusInfo = baseConsensusInfo; + this.viewInfos = viewInfos; + } + + public BasicConsensusInfo getBaseConsensusInfo() { + return baseConsensusInfo; + } + + public void setBaseConsensusInfo(BasicConsensusInfo baseConsensusInfo) { + this.baseConsensusInfo = baseConsensusInfo; + } + + public List getViewInfos() { + return viewInfos; + } + + public void setViewInfos(List viewInfos) { + this.viewInfos = viewInfos; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ConsensusInfo that = (ConsensusInfo) o; + return Objects.equals(baseConsensusInfo, that.baseConsensusInfo) + && Objects.equals(viewInfos, that.viewInfos); + } + + @Override + public int hashCode() { + return Objects.hash(baseConsensusInfo, viewInfos); + } + + @Override + public String toString() { + return "ConsensusInfo{" + + "baseConsensusInfo=" + + baseConsensusInfo + + ", viewInfos=" + + viewInfos + + '}'; + } + } + + public static class ConsensusStatusDeserializer extends JsonDeserializer { + private ObjectMapper objecMapper = ObjectMapperFactory.getObjectMapper(); + + @Override + public ConsensusInfo deserialize( + JsonParser jsonParser, DeserializationContext deserializationContext) + throws IOException { + JsonNode node = jsonParser.getCodec().readTree(jsonParser); + BasicConsensusInfo baseConsensusInfo = null; + List viewInfos = null; + if (node.size() > 0) { + baseConsensusInfo = + objecMapper.readValue(node.get(0).toString(), BasicConsensusInfo.class); + Integer sealersNum = Integer.valueOf(baseConsensusInfo.getNodeNum()); + baseConsensusInfo.setSealerList(new ArrayList(sealersNum)); + // parse sealerList + for (Integer i = 0; i < sealersNum; i++) { + String key = "sealer." + String.valueOf(i); + if (node.get(0).has(key)) { + baseConsensusInfo.getSealerList().add(i, node.get(0).get(key).asText()); + } + } + } + if (node.size() > 1) { + viewInfos = + objecMapper.readValue( + node.get(1).toString(), new TypeReference>() {}); + } + return new ConsensusInfo(baseConsensusInfo, viewInfos); + } + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/GenerateGroup.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/GenerateGroup.java new file mode 100644 index 000000000..74ade7483 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/GenerateGroup.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import org.fisco.bcos.sdk.client.protocol.model.GroupStatus; +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +public class GenerateGroup extends JsonRpcResponse { + public GroupStatus getGroupStatus() { + return getResult(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/GroupList.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/GroupList.java new file mode 100644 index 000000000..8a9b0df82 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/GroupList.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import java.util.List; +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +/** getGroupList */ +public class GroupList extends JsonRpcResponse> { + public List getGroupList() { + return getResult(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/GroupPeers.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/GroupPeers.java new file mode 100644 index 000000000..1a875cd4e --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/GroupPeers.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import java.util.List; +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +/** getGroupPeers */ +public class GroupPeers extends JsonRpcResponse> { + public List getGroupPeers() { + return getResult(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/NodeIDList.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/NodeIDList.java new file mode 100644 index 000000000..0533d45fa --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/NodeIDList.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import java.util.List; +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +/** getNodeIDList */ +public class NodeIDList extends JsonRpcResponse> { + public List getNodeIDList() { + return getResult(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/ObserverList.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/ObserverList.java new file mode 100644 index 000000000..93a4172dc --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/ObserverList.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import java.util.List; +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +public class ObserverList extends JsonRpcResponse> { + public List getObserverList() { + return getResult(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/PbftView.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/PbftView.java new file mode 100644 index 000000000..addf21664 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/PbftView.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.model.JsonRpcResponse; +import org.fisco.bcos.sdk.utils.Numeric; + +/** getPbftView */ +public class PbftView extends JsonRpcResponse { + public BigInteger getPbftView() { + return Numeric.decodeQuantity(getResult()); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/Peers.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/Peers.java new file mode 100644 index 000000000..a342f7fe9 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/Peers.java @@ -0,0 +1,122 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import java.util.Objects; +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +/** getPeers */ +public class Peers extends JsonRpcResponse> { + public List getPeers() { + return getResult(); + } + + public static class PeerInfo { + @JsonProperty("NodeID") + private String nodeID; + + @JsonProperty("IPAndPort") + private String ipAndPort; + + @JsonProperty("Agency") + private String agency; + + @JsonProperty("Topic") + private List topic; + + @JsonProperty("Node") + private String node; + + public String getNode() { + return node; + } + + public void setNode(String node) { + this.node = node; + } + + public String getNodeID() { + return nodeID; + } + + public void setNodeID(String nodeID) { + this.nodeID = nodeID; + } + + public String getIpAndPort() { + return ipAndPort; + } + + public void setIpAndPort(String ipAndPort) { + this.ipAndPort = ipAndPort; + } + + public String getAgency() { + return agency; + } + + public void setAgency(String agency) { + this.agency = agency; + } + + public List getTopic() { + return topic; + } + + public void setTopic(List topic) { + this.topic = topic; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PeerInfo peerInfo = (PeerInfo) o; + return Objects.equals(nodeID, peerInfo.nodeID) + && Objects.equals(ipAndPort, peerInfo.ipAndPort) + && Objects.equals(agency, peerInfo.agency) + && Objects.equals(topic, peerInfo.topic) + && Objects.equals(node, peerInfo.node); + } + + @Override + public int hashCode() { + return Objects.hash(nodeID, ipAndPort, agency, topic, node); + } + + @Override + public String toString() { + return "PeerInfo{" + + "nodeID='" + + nodeID + + '\'' + + ", ipAndPort='" + + ipAndPort + + '\'' + + ", agency='" + + agency + + '\'' + + ", topic=" + + topic + + ", node='" + + node + + '\'' + + '}'; + } + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/PendingTransactions.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/PendingTransactions.java new file mode 100644 index 000000000..9e7eea841 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/PendingTransactions.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import java.util.List; +import org.fisco.bcos.sdk.client.protocol.model.JsonTransactionResponse; +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +/** getPendingTransactions */ +public class PendingTransactions extends JsonRpcResponse> { + public List getPendingTransactions() { + return getResult(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/PendingTxSize.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/PendingTxSize.java new file mode 100644 index 000000000..c619f021f --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/PendingTxSize.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.model.JsonRpcResponse; +import org.fisco.bcos.sdk.utils.Numeric; + +/** getPendingTxSize */ +public class PendingTxSize extends JsonRpcResponse { + public BigInteger getPendingTxSize() { + return Numeric.decodeQuantity(getResult()); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/QueryGroupStatus.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/QueryGroupStatus.java new file mode 100644 index 000000000..85bd443c7 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/QueryGroupStatus.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import org.fisco.bcos.sdk.client.protocol.model.GroupStatus; +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +public class QueryGroupStatus extends JsonRpcResponse { + public GroupStatus getGroupStatus() { + return getResult(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/RecoverGroup.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/RecoverGroup.java new file mode 100644 index 000000000..7639b55e2 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/RecoverGroup.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import org.fisco.bcos.sdk.client.protocol.model.GroupStatus; +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +public class RecoverGroup extends JsonRpcResponse { + public GroupStatus getGroupStatus() { + return getResult(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/RemoveGroup.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/RemoveGroup.java new file mode 100644 index 000000000..93b4f7d3c --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/RemoveGroup.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import org.fisco.bcos.sdk.client.protocol.model.GroupStatus; +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +public class RemoveGroup extends JsonRpcResponse { + public GroupStatus getGroupStatus() { + return getResult(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/SealerList.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/SealerList.java new file mode 100644 index 000000000..ab684e82d --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/SealerList.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import java.util.List; +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +public class SealerList extends JsonRpcResponse> { + public List getSealerList() { + return getResult(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/SendTransaction.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/SendTransaction.java new file mode 100644 index 000000000..43323f415 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/SendTransaction.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +/** Return data structure of send transaction */ +public class SendTransaction extends JsonRpcResponse { + public String getTransactionHash() { + return getResult(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/StartGroup.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/StartGroup.java new file mode 100644 index 000000000..081a3c1a8 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/StartGroup.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import org.fisco.bcos.sdk.client.protocol.model.GroupStatus; +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +public class StartGroup extends JsonRpcResponse { + public GroupStatus getGroupStatus() { + return getResult(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/StopGroup.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/StopGroup.java new file mode 100644 index 000000000..4c8db4911 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/StopGroup.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import org.fisco.bcos.sdk.client.protocol.model.GroupStatus; +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +public class StopGroup extends JsonRpcResponse { + public GroupStatus getGroupStatus() { + return getResult(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/SyncStatus.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/SyncStatus.java new file mode 100644 index 000000000..686de1d1b --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/SyncStatus.java @@ -0,0 +1,264 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import java.util.List; +import java.util.Objects; +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +/** + * getSyncStatus. + * + *

Returns an object with data about the sync status or false. + */ +public class SyncStatus extends JsonRpcResponse { + public SyncStatus.SyncStatusInfo getSyncStatus() { + return getResult(); + } + + public static class PeersInfo { + private String nodeId; + private String genesisHash; + private String blockNumber; + private String latestHash; + + public String getNodeId() { + return nodeId; + } + + public void setNodeId(String nodeId) { + this.nodeId = nodeId; + } + + public String getGenesisHash() { + return genesisHash; + } + + public void setGenesisHash(String genesisHash) { + this.genesisHash = genesisHash; + } + + public String getBlockNumber() { + return blockNumber; + } + + public void setBlockNumber(String blockNumber) { + this.blockNumber = blockNumber; + } + + public String getLatestHash() { + return latestHash; + } + + public void setLatestHash(String latestHash) { + this.latestHash = latestHash; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PeersInfo peersInfo = (PeersInfo) o; + return Objects.equals(nodeId, peersInfo.nodeId) + && Objects.equals(genesisHash, peersInfo.genesisHash) + && Objects.equals(blockNumber, peersInfo.blockNumber) + && Objects.equals(latestHash, peersInfo.latestHash); + } + + @Override + public int hashCode() { + return Objects.hash(nodeId, genesisHash, blockNumber, latestHash); + } + + @Override + public String toString() { + return "PeersInfo{" + + "nodeId='" + + nodeId + + '\'' + + ", genesisHash='" + + genesisHash + + '\'' + + ", blockNumber='" + + blockNumber + + '\'' + + ", latestHash='" + + latestHash + + '\'' + + '}'; + } + } + + public static class SyncStatusInfo { + private String isSyncing; + private String protocolId; + private String genesisHash; + private String nodeId; + private String blockNumber; + private String latestHash; + private String knownHighestNumber; + private String txPoolSize; + private List peers; + private String knownLatestHash; + + public String getKnownLatestHash() { + return knownLatestHash; + } + + public void setKnownLatestHash(String knownLatestHash) { + this.knownLatestHash = knownLatestHash; + } + + public String getIsSyncing() { + return isSyncing; + } + + public void setIsSyncing(String isSyncing) { + this.isSyncing = isSyncing; + } + + public String getProtocolId() { + return protocolId; + } + + public void setProtocolId(String protocolId) { + this.protocolId = protocolId; + } + + public String getGenesisHash() { + return genesisHash; + } + + public void setGenesisHash(String genesisHash) { + this.genesisHash = genesisHash; + } + + public String getNodeId() { + return nodeId; + } + + public void setNodeId(String nodeId) { + this.nodeId = nodeId; + } + + public String getBlockNumber() { + return blockNumber; + } + + public void setBlockNumber(String blockNumber) { + this.blockNumber = blockNumber; + } + + public String getLatestHash() { + return latestHash; + } + + public void setLatestHash(String latestHash) { + this.latestHash = latestHash; + } + + public String getKnownHighestNumber() { + return knownHighestNumber; + } + + public void setKnownHighestNumber(String knownHighestNumber) { + this.knownHighestNumber = knownHighestNumber; + } + + public String getTxPoolSize() { + return txPoolSize; + } + + public void setTxPoolSize(String txPoolSize) { + this.txPoolSize = txPoolSize; + } + + public List getPeers() { + return peers; + } + + public void setPeers(List peers) { + this.peers = peers; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SyncStatusInfo that = (SyncStatusInfo) o; + return Objects.equals(isSyncing, that.isSyncing) + && Objects.equals(protocolId, that.protocolId) + && Objects.equals(genesisHash, that.genesisHash) + && Objects.equals(nodeId, that.nodeId) + && Objects.equals(blockNumber, that.blockNumber) + && Objects.equals(latestHash, that.latestHash) + && Objects.equals(knownHighestNumber, that.knownHighestNumber) + && Objects.equals(txPoolSize, that.txPoolSize) + && Objects.equals(peers, that.peers) + && Objects.equals(knownLatestHash, that.knownLatestHash); + } + + @Override + public int hashCode() { + return Objects.hash( + isSyncing, + protocolId, + genesisHash, + nodeId, + blockNumber, + latestHash, + knownHighestNumber, + txPoolSize, + peers, + knownLatestHash); + } + + @Override + public String toString() { + return "SyncStatusInfo{" + + "isSyncing='" + + isSyncing + + '\'' + + ", protocolId='" + + protocolId + + '\'' + + ", genesisHash='" + + genesisHash + + '\'' + + ", nodeId='" + + nodeId + + '\'' + + ", blockNumber='" + + blockNumber + + '\'' + + ", latestHash='" + + latestHash + + '\'' + + ", knownHighestNumber='" + + knownHighestNumber + + '\'' + + ", txPoolSize='" + + txPoolSize + + '\'' + + ", peers=" + + peers + + ", knownLatestHash='" + + knownLatestHash + + '\'' + + '}'; + } + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/SystemConfig.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/SystemConfig.java new file mode 100644 index 000000000..99121a5d4 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/SystemConfig.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +/** getSystemConfigByKey */ +public class SystemConfig extends JsonRpcResponse { + public String getSystemConfig() { + return getResult(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/TotalTransactionCount.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/TotalTransactionCount.java new file mode 100644 index 000000000..c0c235b53 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/TotalTransactionCount.java @@ -0,0 +1,87 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import java.util.Objects; +import org.fisco.bcos.sdk.model.JsonRpcResponse; + +/** getTotalTransactionCount */ +public class TotalTransactionCount + extends JsonRpcResponse { + public TransactionCountInfo getTotalTransactionCount() { + return getResult(); + } + + public static class TransactionCountInfo { + private String txSum; + private String blockNumber; + private String failedTxSum; + + public String getTxSum() { + return txSum; + } + + public void setTxSum(String txSum) { + this.txSum = txSum; + } + + public String getBlockNumber() { + return blockNumber; + } + + public void setBlockNumber(String blockNumber) { + this.blockNumber = blockNumber; + } + + public String getFailedTxSum() { + return failedTxSum; + } + + public void setFailedTxSum(String failedTxSum) { + this.failedTxSum = failedTxSum; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TransactionCountInfo that = (TransactionCountInfo) o; + return Objects.equals(txSum, that.txSum) + && Objects.equals(blockNumber, that.blockNumber) + && Objects.equals(failedTxSum, that.failedTxSum); + } + + @Override + public int hashCode() { + return Objects.hash(txSum, blockNumber, failedTxSum); + } + + @Override + public String toString() { + return "TransactionCountInfo{" + + "txSum='" + + txSum + + '\'' + + ", blockNumber='" + + blockNumber + + '\'' + + ", failedTxSum='" + + failedTxSum + + '\'' + + '}'; + } + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/TransactionReceiptWithProof.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/TransactionReceiptWithProof.java new file mode 100644 index 000000000..5d3fa96e0 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/TransactionReceiptWithProof.java @@ -0,0 +1,79 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import java.util.Objects; +import org.fisco.bcos.sdk.model.JsonRpcResponse; +import org.fisco.bcos.sdk.model.MerkleProofUnit; +import org.fisco.bcos.sdk.model.TransactionReceipt; + +/** getTransactionReceiptWithProof. */ +public class TransactionReceiptWithProof + extends JsonRpcResponse { + public ReceiptAndProof getTransactionReceiptWithProof() { + return getResult(); + } + + public static class ReceiptAndProof { + @JsonProperty("transactionReceipt") + private TransactionReceipt receipt; + + @JsonProperty("receiptProof") + private List receiptProof; + + public TransactionReceipt getReceipt() { + return receipt; + } + + public void setReceipt(TransactionReceipt receipt) { + this.receipt = receipt; + } + + public List getReceiptProof() { + return receiptProof; + } + + public void setReceiptProof(List receiptProof) { + this.receiptProof = receiptProof; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ReceiptAndProof that = (ReceiptAndProof) o; + return Objects.equals(receipt, that.receipt) + && Objects.equals(receiptProof, that.receiptProof); + } + + @Override + public int hashCode() { + return Objects.hash(receipt, receiptProof); + } + + @Override + public String toString() { + return "ReceiptAndProof{" + + "receipt=" + + receipt + + ", receiptProof=" + + receiptProof + + '}'; + } + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/TransactionWithProof.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/TransactionWithProof.java new file mode 100644 index 000000000..0cf320d1d --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/client/protocol/response/TransactionWithProof.java @@ -0,0 +1,79 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.client.protocol.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import java.util.Objects; +import org.fisco.bcos.sdk.client.protocol.model.JsonTransactionResponse; +import org.fisco.bcos.sdk.model.JsonRpcResponse; +import org.fisco.bcos.sdk.model.MerkleProofUnit; + +/** getTransactionWithProof. */ +public class TransactionWithProof + extends JsonRpcResponse { + public TransactionWithProof.TransactionAndProof getTransactionWithProof() { + return getResult(); + } + + public static class TransactionAndProof { + @JsonProperty("transaction") + private JsonTransactionResponse transaction; + + @JsonProperty("txProof") + private List transactionProof; + + public JsonTransactionResponse getTransaction() { + return transaction; + } + + public void setTransaction(JsonTransactionResponse transaction) { + this.transaction = transaction; + } + + public List getTransactionProof() { + return transactionProof; + } + + public void setTransactionProof(List transactionProof) { + this.transactionProof = transactionProof; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TransactionAndProof that = (TransactionAndProof) o; + return Objects.equals(transaction, that.transaction) + && Objects.equals(transactionProof, that.transactionProof); + } + + @Override + public int hashCode() { + return Objects.hash(transaction, transactionProof); + } + + @Override + public String toString() { + return "TransactionAndProof{" + + "transaction=" + + transaction + + ", transactionProof=" + + transactionProof + + '}'; + } + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/EventCallback.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/EventCallback.java new file mode 100644 index 000000000..545eb1ad5 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/EventCallback.java @@ -0,0 +1,32 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.eventsub; + +import java.util.List; +import org.fisco.bcos.sdk.model.EventLog; + +/** Event callback */ +public interface EventCallback { + + /** + * onReceiveLog called when sdk receive any response of the target subscription. logs will be + * parsed by the user through the ABI module. + * + * @param status the status that peer response to sdk. + * @param logs logs from the message. + */ + void onReceiveLog(int status, List logs); +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/EventLogParams.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/EventLogParams.java new file mode 100644 index 000000000..f2f4180d5 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/EventLogParams.java @@ -0,0 +1,227 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.eventsub; + +import java.math.BigInteger; +import java.util.List; +import org.fisco.bcos.sdk.abi.tools.TopicTools; +import org.fisco.bcos.sdk.utils.AddressUtils; +import org.fisco.bcos.sdk.utils.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EventLogParams { + private static Logger logger = LoggerFactory.getLogger(EventLogParams.class); + private String fromBlock; + private String toBlock; + private List addresses; + private List topics; + + public static Logger getLogger() { + return logger; + } + + public static void setLogger(Logger logger) { + EventLogParams.logger = logger; + } + + public String getFromBlock() { + return fromBlock; + } + + public void setFromBlock(String fromBlock) { + this.fromBlock = fromBlock; + } + + public String getToBlock() { + return toBlock; + } + + public void setToBlock(String toBlock) { + this.toBlock = toBlock; + } + + public List getAddresses() { + return addresses; + } + + public void setAddresses(List addresses) { + this.addresses = addresses; + } + + public List getTopics() { + return topics; + } + + public void setTopics(List topics) { + this.topics = topics; + } + + @Override + public String toString() { + return "EventLogFilterParams [fromBlock=" + + fromBlock + + ", toBlock=" + + toBlock + + ", addresses=" + + addresses + + ", topics=" + + topics + + "]"; + } + + public boolean checkAddresses() { + if (getAddresses() == null) { + return false; + } + for (String address : getAddresses()) { + // check if address valid + if (!AddressUtils.isValidAddress(address)) { + return false; + } + } + return true; + } + + /** + * check if topics valid + * + * @return + */ + private boolean checkTopics() { + + // topics + if ((getTopics() == null) || (getTopics().size() > TopicTools.MAX_NUM_TOPIC_EVENT_LOG)) { + return false; + } + + for (Object topic : getTopics()) { + if (topic == null) { + continue; + } + if (topic instanceof String) { + // if valid topic + if (((String) topic).isEmpty()) { + return false; + } + } else if (topic instanceof List) { + for (Object o : (List) topic) { + // if valid topic + if (((String) o).isEmpty()) { + return false; + } + } + } else { + return false; + } + } + + return true; + } + + private boolean checkToBlock(BigInteger blockNumber) { + + // fromBlock="latest" but toBlock is not + // range in (latest,10), blockNumber 1 ok, 6 ok, 11 fail + BigInteger toBlock = new BigInteger(getToBlock()); + return (blockNumber.compareTo(BigInteger.ONE) <= 0) + || (blockNumber.compareTo(BigInteger.ONE) > 0 + && (toBlock.compareTo(blockNumber)) > 0); + } + + private boolean checkFromBlock(BigInteger blockNumber) { + + // toBlock="latest" but fromBlock is not + // range in (10,latest), blockNumber 6 ok, 11 fail + BigInteger fromBlock = new BigInteger(getFromBlock()); + // fromBlock is bigger than block number of the blockchain + if (fromBlock.compareTo(BigInteger.ZERO) <= 0) { + return false; + } + + if (blockNumber.compareTo(BigInteger.ONE) > 0 && (fromBlock.compareTo(blockNumber) > 0)) { + logger.info( + " future block range request, from: {}, to: {}", getFromBlock(), getToBlock()); + } + + return true; + } + + private boolean checkFromToBlock(BigInteger blockNumber) throws NumberFormatException { + + // fromBlock and toBlock none is "latest" + // range in (10,20), blockNumber 6 ok, 11 ok, 25 ok + BigInteger fromBlock = new BigInteger(getFromBlock()); + BigInteger toBlock = new BigInteger(getToBlock()); + + if ((fromBlock.compareTo(BigInteger.ZERO) <= 0) || (fromBlock.compareTo(toBlock) > 0)) { + return false; + } else { + if (blockNumber.compareTo(BigInteger.ONE) > 0 + && (fromBlock.compareTo(blockNumber) > 0)) { + logger.info( + " future block range request, from: {}, to: {}", + getFromBlock(), + getToBlock()); + } + return true; + } + } + + /** + * check if valid fromBlock and toBlock + * + * @param blockNumber + * @return + */ + private boolean checkBlockRange(BigInteger blockNumber) { + + if (StringUtils.isEmpty(getFromBlock()) || StringUtils.isEmpty(getToBlock())) { + return false; + } + + boolean isValidBlockRange = true; + + try { + if (getFromBlock().equals(TopicTools.LATEST) + && !getToBlock().equals(TopicTools.LATEST)) { + // fromBlock="latest" but toBlock is not + isValidBlockRange = checkToBlock(blockNumber); + } else if (!getFromBlock().equals(TopicTools.LATEST) + && getToBlock().equals(TopicTools.LATEST)) { + // toBlock="latest" but fromBlock is not + isValidBlockRange = checkFromBlock(blockNumber); + } else if (!getFromBlock().equals(TopicTools.LATEST) + && !getToBlock().equals(TopicTools.LATEST)) { + isValidBlockRange = checkFromToBlock(blockNumber); + } + } catch (Exception e) { + // invalid blockNumber format string + isValidBlockRange = false; + } + + return isValidBlockRange; + } + + /** + * @param blockNumber block number of blockchain + * @return check 3 params + */ + @SuppressWarnings("unchecked") + public boolean checkParams(BigInteger blockNumber) { + return checkBlockRange(blockNumber) && checkAddresses() && checkTopics(); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/EventMsg.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/EventMsg.java new file mode 100644 index 000000000..395a71d64 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/EventMsg.java @@ -0,0 +1,71 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.eventsub; + +import io.netty.buffer.ByteBuf; +import java.io.UnsupportedEncodingException; +import org.fisco.bcos.sdk.model.Message; + +public class EventMsg extends Message { + + private static final long serialVersionUID = -7276897518418560354L; + private String topic; + + public EventMsg() {} + + public EventMsg(Message msg) { + length = msg.getLength(); + type = msg.getType(); + seq = msg.getSeq(); + result = msg.getResult(); + } + + @Override + public void encode(ByteBuf encodedData) { + writeHeader(encodedData); + writeExtra(encodedData); + } + + @Override + public void writeHeader(ByteBuf out) { + // total length + try { + length = Message.HEADER_LENGTH + 1 + topic.getBytes("utf-8").length + data.length; + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(" topic string to utf8 failed, topic: " + topic); + } + super.writeHeader(out); + } + + public void writeExtra(ByteBuf out) { + try { + out.writeByte(1 + topic.getBytes("utf-8").length); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(" topic string to utf8 failed, topic: " + topic); + } + out.writeBytes(topic.getBytes()); + + out.writeBytes(data); + } + + public String getTopic() { + return topic; + } + + public void setTopic(String toTopic) { + this.topic = toTopic; + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/EventResource.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/EventResource.java new file mode 100644 index 000000000..e49b1ca63 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/EventResource.java @@ -0,0 +1,38 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.eventsub; + +import org.fisco.bcos.sdk.eventsub.filter.EventPushMsgHandler; +import org.fisco.bcos.sdk.eventsub.filter.FilterManager; + +public class EventResource { + + private FilterManager filterManager; + private EventPushMsgHandler msgHander; + + public EventResource() { + filterManager = new FilterManager(); + msgHander = new EventPushMsgHandler(filterManager); + } + + public FilterManager getFilterManager() { + return filterManager; + } + + public EventPushMsgHandler getMsgHander() { + return msgHander; + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/EventSubscribe.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/EventSubscribe.java new file mode 100644 index 000000000..56b4384e1 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/EventSubscribe.java @@ -0,0 +1,83 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.eventsub; + +import java.util.List; +import java.util.UUID; +import org.fisco.bcos.sdk.eventsub.filter.EventLogFilter; +import org.fisco.bcos.sdk.service.GroupManagerService; + +/** + * Event subscribe interface. + * + * @author Maggie + */ +public interface EventSubscribe { + /** + * Create a Event Subscraibe instance + * + * @param groupManagerService the groupManager Service instance + * @param groupId the id of group + * @param eventResource the eventResource instance + * @return EventSubscribe Object + */ + static EventSubscribe build( + GroupManagerService groupManagerService, EventResource eventResource, Integer groupId) { + return new EventSubscribeImp(groupManagerService, eventResource, groupId); + } + + static String newSeq() { + String seq = UUID.randomUUID().toString().replaceAll("-", ""); + return seq; + } + + /** + * Subscribe event + * + * @param params the EventLogParams instance + * @param callback the EventCallback instance + * @return registerId of event + */ + String subscribeEvent(EventLogParams params, EventCallback callback); + + /** + * Unsubscribe events + * + * @param registerID the ID of register + * @param callback the EventCallback instance + */ + void unsubscribeEvent(String registerID, EventCallback callback); + + /** + * Get all subscribed event. + * + * @return list of event log filters + */ + List getAllSubscribedEvent(); + + /** + * Get EventPushMsgHandler and FilterManager. + * + * @return EventResource + */ + EventResource getEventResource(); + + /** Start */ + void start(); + + /** Stop */ + void stop(); +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/EventSubscribeImp.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/EventSubscribeImp.java new file mode 100644 index 000000000..00f2b635c --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/EventSubscribeImp.java @@ -0,0 +1,318 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.eventsub; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.math.BigInteger; +import java.util.List; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import org.fisco.bcos.sdk.channel.Channel; +import org.fisco.bcos.sdk.channel.ResponseCallback; +import org.fisco.bcos.sdk.eventsub.filter.EventLogFilter; +import org.fisco.bcos.sdk.eventsub.filter.EventLogFilterStatus; +import org.fisco.bcos.sdk.eventsub.filter.EventLogResponse; +import org.fisco.bcos.sdk.eventsub.filter.EventPushMsgHandler; +import org.fisco.bcos.sdk.eventsub.filter.EventSubNodeRespStatus; +import org.fisco.bcos.sdk.eventsub.filter.FilterManager; +import org.fisco.bcos.sdk.eventsub.filter.ScheduleTimeConfig; +import org.fisco.bcos.sdk.model.*; +import org.fisco.bcos.sdk.service.GroupManagerService; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EventSubscribeImp implements EventSubscribe { + private static final Logger logger = LoggerFactory.getLogger(EventSubscribeImp.class); + private Channel channel; + private GroupManagerService groupManagerService; + private Integer groupId; + private FilterManager filterManager; + private EventPushMsgHandler msgHander; + private EventResource eventResource; + private boolean running = false; + ScheduledThreadPoolExecutor resendSchedule = new ScheduledThreadPoolExecutor(1); + + public EventSubscribeImp( + GroupManagerService groupManagerService, EventResource eventResource, Integer groupId) { + this.channel = groupManagerService.getChannel(); + this.groupManagerService = groupManagerService; + this.groupId = groupId; + this.eventResource = eventResource; + filterManager = eventResource.getFilterManager(); + msgHander = eventResource.getMsgHander(); + channel.addMessageHandler(MsgType.EVENT_LOG_PUSH, msgHander); + channel.addDisconnectHandler(msgHander); + } + + @Override + public EventResource getEventResource() { + return eventResource; + } + + @Override + public String subscribeEvent(EventLogParams params, EventCallback callback) { + BigInteger number = groupManagerService.getLatestBlockNumberByGroup(groupId); + logger.info(" subscribe event at block num:" + number); + if (!params.checkParams(number)) { + callback.onReceiveLog(EventSubNodeRespStatus.INVALID_PARAMS.getStatus(), null); + return null; + } + EventLogFilter filter = new EventLogFilter(); + filter.setRegisterID(EventSubscribe.newSeq()); + filter.setParams(params); + filter.setCallback(callback); + filterManager.addFilter(filter); + sendFilter(filter); + + logger.info( + " subscribe event, registerID: {}, filterID : {}", + filter.getRegisterID(), + filter.getFilterID()); + return filter.getRegisterID(); + } + + @Override + public void unsubscribeEvent(String registerID, EventCallback callback) { + EventLogFilter filter = filterManager.getFilter(registerID); + if (filter == null) { + logger.info(" try to unsubscribe an nonexistent event"); + return; + } + // update callback to handle unsubscribe result + filter.setCallback(callback); + filterManager.addCallback(filter.getFilterID(), callback); + + // send message to unsubscribe event + Message msg = new Message(); + msg.setSeq(EventSubscribe.newSeq()); + msg.setType(Short.valueOf((short) MsgType.CLIENT_UNREGISTER_EVENT_LOG.getType())); + msg.setResult(0); + try { + String content = + filter.getParamJsonString(String.valueOf(groupId), filter.getFilterID()); + logger.info( + " unsubscribe event, registerID: {}, filterID : {}", + filter.getRegisterID(), + filter.getFilterID()); + msg.setData(content.getBytes()); + } catch (JsonProcessingException e) { + logger.error(" unsubscribe event error: {}", e.getMessage()); + } + + EventMsg eventMsg = new EventMsg(msg); + eventMsg.setTopic(""); + eventMsg.setData(msg.getData()); + this.groupManagerService.asyncSendMessageToGroup( + groupId, eventMsg, new UnRegisterEventSubRespCallback(filterManager, filter)); + } + + @Override + public List getAllSubscribedEvent() { + return filterManager.getAllSubscribedEvent(); + } + + @Override + public void start() { + if (running) { + return; + } + running = true; + resendSchedule.scheduleAtFixedRate( + () -> { + resendWaitingFilters(); + }, + 0, + ScheduleTimeConfig.resendFrequency, + TimeUnit.MILLISECONDS); + } + + @Override + public void stop() { + if (!running) { + return; + } + running = false; + resendSchedule.shutdown(); + // unsubscribe events, fisco bcos 2.7.0 + /*List filterList = getAllSubscribedEvent(); + for (EventLogFilter filter : filterList) { + EventCallback callback = + new EventCallback() { + @Override + public void onReceiveLog(int status, List logs) { + logger.info( + "unsubscribe event registerId : {}, result : {}", + filter.getRegisterID(), + status); + } + }; + unsubscribeEvent(filter.getRegisterID(), callback); + }*/ + } + + private void resendWaitingFilters() { + List filters = filterManager.getWaitingReqFilters(); + try { + for (EventLogFilter filter : filters) { + sendFilter(filter); + } + logger.info("Resend waiting filters, size: {}", filters.size()); + } catch (Exception e) { + logger.error("resendWaitingFilters exception : {}", e.getMessage()); + for (EventLogFilter filter : filters) { + filter.setStatus(EventLogFilterStatus.WAITING_REQUEST); + } + } + } + + private void sendFilter(EventLogFilter filter) { + Message msg = new Message(); + msg.setSeq(EventSubscribe.newSeq()); + msg.setType(Short.valueOf((short) MsgType.CLIENT_REGISTER_EVENT_LOG.getType())); + msg.setResult(0); + try { + String content = filter.getNewParamJsonString(String.valueOf(groupId)); + msg.setData(content.getBytes()); + } catch (JsonProcessingException e) { + logger.error( + "send filter error and remove bad filter, registerID: {},filterID : {}, error: {}", + filter.getRegisterID(), + filter.getFilterID(), + e.getMessage()); + filterManager.removeFilter(filter.getRegisterID()); + } + + filterManager.addCallback(filter.getFilterID(), filter.getCallback()); + EventMsg eventMsg = new EventMsg(msg); + eventMsg.setTopic(""); + eventMsg.setData(msg.getData()); + this.groupManagerService.asyncSendMessageToGroup( + groupId, + eventMsg, + new RegisterEventSubRespCallback( + filterManager, filter, filter.getFilterID(), filter.getRegisterID())); + } + + class RegisterEventSubRespCallback extends ResponseCallback { + FilterManager filterManager; + EventLogFilter filter; + String filterID; + String registerID; + + public RegisterEventSubRespCallback( + FilterManager filterManager, + EventLogFilter filter, + String filterID, + String registerID) { + this.filterManager = filterManager; + this.filter = filter; + this.filterID = filterID; + this.registerID = registerID; + } + + @Override + public void onResponse(Response response) { + logger.info( + " event filter callback response, registerID: {}, filterID: {}, seq: {}, error code: {}, content: {}", + registerID, + filterID, + response.getMessageID(), + response.getErrorCode(), + response.getContent()); + try { + if (0 == response.getErrorCode()) { + EventLogResponse resp = + ObjectMapperFactory.getObjectMapper() + .readValue( + response.getContent().trim(), EventLogResponse.class); + if (resp.getResult() == 0) { + // node give an "OK" response, event log will be pushed soon + filterManager.updateFilterStatus( + filter, EventLogFilterStatus.EVENT_LOG_PUSHING, response.getCtx()); + logger.info( + " filter {} status changed to EVENT_LOG_PUSHING", + filter.getFilterID()); + } else { + // node give a bad response, will not push event log, trigger callback + filterManager.removeFilter(registerID); + filterManager.removeCallback(filterID); + } + filter.getCallback().onReceiveLog(resp.getResult(), null); + } else { + filterManager.updateFilterStatus( + filter, EventLogFilterStatus.WAITING_REQUEST, null); + filterManager.removeCallback(filterID); + } + } catch (Exception e) { + logger.error( + " event filter response message exception, filterID: {}, registerID: {}, exception message: {}", + filterID, + registerID, + e.getMessage()); + filter.getCallback() + .onReceiveLog(EventSubNodeRespStatus.OTHER_ERROR.getStatus(), null); + filterManager.removeFilter(registerID); + filterManager.removeCallback(filterID); + } + } + } + + class UnRegisterEventSubRespCallback extends ResponseCallback { + FilterManager filterManager; + EventLogFilter filter; + + public UnRegisterEventSubRespCallback(FilterManager filterManager, EventLogFilter filter) { + this.filterManager = filterManager; + this.filter = filter; + } + + @Override + public void onResponse(Response response) { + String registerId = filter.getRegisterID(); + logger.info( + " unregister event callback response, registerID: {}, seq: {}, error code: {}, content: {}", + registerId, + response.getMessageID(), + response.getErrorCode(), + response.getContent()); + try { + if (0 == response.getErrorCode()) { + EventLogResponse resp = + ObjectMapperFactory.getObjectMapper() + .readValue( + response.getContent().trim(), EventLogResponse.class); + if (resp.getResult() == 0) { + // node give an "OK" response, event log will be deleted + logger.info(" unregister event success"); + filterManager.removeFilter(filter.getRegisterID()); + filterManager.removeCallback(filter.getFilterID()); + } else { + logger.warn(" unregister event fail"); + } + filter.getCallback().onReceiveLog(resp.getResult(), null); + } + } catch (Exception e) { + logger.error( + " unregister event response message exception, registerID: {}, exception message: {}", + registerId, + e.getMessage()); + filter.getCallback() + .onReceiveLog(EventSubNodeRespStatus.OTHER_ERROR.getStatus(), null); + } + } + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/exception/EventSubException.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/exception/EventSubException.java new file mode 100644 index 000000000..c0227a8ff --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/exception/EventSubException.java @@ -0,0 +1,30 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.eventsub.exception; + +public class EventSubException extends Exception { + public EventSubException(String message) { + super(message); + } + + public EventSubException(Throwable cause) { + super(cause); + } + + public EventSubException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/EventLogFilter.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/EventLogFilter.java new file mode 100644 index 000000000..fdf22e469 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/EventLogFilter.java @@ -0,0 +1,169 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.eventsub.filter; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.netty.channel.ChannelHandlerContext; +import java.math.BigInteger; +import java.util.List; +import org.fisco.bcos.sdk.eventsub.EventCallback; +import org.fisco.bcos.sdk.eventsub.EventLogParams; +import org.fisco.bcos.sdk.eventsub.EventSubscribe; +import org.fisco.bcos.sdk.model.EventLog; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; + +/** An event log filter is a subscription. */ +public class EventLogFilter { + private String registerID; + private String filterID; + private EventLogParams params; + private EventCallback callback; + private EventLogFilterStatus status = EventLogFilterStatus.WAITING_REQUEST; + private ChannelHandlerContext ctx = null; + + private BigInteger lastBlockNumber = null; + private long logCount = 0; + + public String getNewParamJsonString(String groupId) throws JsonProcessingException { + String newFilterId = EventSubscribe.newSeq(); + EventLogRequestParams requestParams = + new EventLogRequestParams(generateNewParams(), groupId, newFilterId); + filterID = newFilterId; + String content = requestParams.toJsonString(); + return content; + } + + public String getParamJsonString(String groupId, String filterId) + throws JsonProcessingException { + EventLogRequestParams requestParams = + new EventLogRequestParams(generateNewParams(), groupId, filterId); + String content = requestParams.toJsonString(); + return content; + } + + public class EventLogRequestParams extends EventLogParams { + private String groupID; + private String filterID; + private int timeout = 0; + + public EventLogRequestParams(EventLogParams params, String groupID, String filterID) { + this.setFromBlock(params.getFromBlock()); + this.setToBlock(params.getToBlock()); + this.setAddresses(params.getAddresses()); + this.setTopics(params.getTopics()); + this.setGroupID(groupID); + this.setFilterID(filterID); + } + + public void setGroupID(String groupID) { + this.groupID = groupID; + } + + public void setFilterID(String filterID) { + this.filterID = filterID; + } + + public String getGroupID() { + return this.groupID; + } + + public String getFilterID() { + return this.filterID; + } + + public String toJsonString() throws JsonProcessingException { + String content = ObjectMapperFactory.getObjectMapper().writeValueAsString(this); + return content; + } + } + + private EventLogParams generateNewParams() { + EventLogParams params = new EventLogParams(); + params.setToBlock(getParams().getToBlock()); + params.setAddresses(getParams().getAddresses()); + params.setTopics(getParams().getTopics()); + if (lastBlockNumber == null) { + params.setFromBlock(params.getFromBlock()); + } else { + params.setFromBlock(lastBlockNumber.toString()); + } + return params; + } + + public void updateCountsAndLatestBlock(List logs) { + if (logs.isEmpty()) { + return; + } + EventLog latestOne = logs.get(logs.size() - 1); + if (lastBlockNumber == null) { + lastBlockNumber = latestOne.getBlockNumber(); + logCount += logs.size(); + } else { + if (latestOne.getBlockNumber().compareTo(lastBlockNumber) > 0) { + lastBlockNumber = latestOne.getBlockNumber(); + logCount += logs.size(); + } + } + } + + public String getRegisterID() { + return registerID; + } + + public void setRegisterID(String registerID) { + this.registerID = registerID; + } + + public EventLogParams getParams() { + return params; + } + + public void setParams(EventLogParams params) { + this.params = params; + } + + public EventLogFilterStatus getStatus() { + return status; + } + + public void setStatus(EventLogFilterStatus status) { + this.status = status; + } + + public EventCallback getCallback() { + return callback; + } + + public void setCallback(EventCallback callback) { + this.callback = callback; + } + + public String getFilterID() { + return filterID; + } + + public void setFilterID(String filterID) { + this.filterID = filterID; + } + + public ChannelHandlerContext getCtx() { + return ctx; + } + + public void setCtx(ChannelHandlerContext ctx) { + this.ctx = ctx; + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/EventLogFilterStatus.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/EventLogFilterStatus.java new file mode 100644 index 000000000..661b89242 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/EventLogFilterStatus.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.eventsub.filter; + +public enum EventLogFilterStatus { + // event log is pushing from node normally + EVENT_LOG_PUSHING(0x1), + // request already send, wait for response + WAITING_RESPONSE(0x2), + // response not ok, wait for resend + WAITING_REQUEST(0x3); + + private int status; + + private EventLogFilterStatus(int i) {} + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/EventLogResponse.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/EventLogResponse.java new file mode 100644 index 000000000..f211426c8 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/EventLogResponse.java @@ -0,0 +1,60 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.eventsub.filter; + +import java.util.List; +import org.fisco.bcos.sdk.model.EventLog; + +public class EventLogResponse { + private int result; + private String filterID; + private List logs; + + @Override + public String toString() { + return "EventLogResponse [result=" + + result + + ", filterID=" + + filterID + + ", logs=" + + logs + + "]"; + } + + public int getResult() { + return result; + } + + public void setResult(int result) { + this.result = result; + } + + public String getFilterID() { + return filterID; + } + + public void setFilterID(String filterID) { + this.filterID = filterID; + } + + public List getLogs() { + return logs; + } + + public void setLogs(List logs) { + this.logs = logs; + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/EventPushMsgHandler.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/EventPushMsgHandler.java new file mode 100644 index 000000000..3207f9da3 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/EventPushMsgHandler.java @@ -0,0 +1,93 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.eventsub.filter; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.netty.channel.ChannelHandlerContext; +import java.util.List; +import org.fisco.bcos.sdk.eventsub.EventCallback; +import org.fisco.bcos.sdk.model.EventLog; +import org.fisco.bcos.sdk.model.Message; +import org.fisco.bcos.sdk.network.MsgHandler; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; +import org.fisco.bcos.sdk.utils.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** EventPushMsgHandler is the type of EVENT_LOG_PUSH message handler. */ +public class EventPushMsgHandler implements MsgHandler { + private static final Logger logger = LoggerFactory.getLogger(EventPushMsgHandler.class); + FilterManager filterManager; + + public EventPushMsgHandler(FilterManager filterManager) { + this.filterManager = filterManager; + } + + @Override + public void onConnect(ChannelHandlerContext ctx) { + logger.warn("onConnect accidentally called"); + } + + @Override + public void onMessage(ChannelHandlerContext ctx, Message msg) { + String content = new String(msg.getData()); + try { + EventLogResponse resp = + ObjectMapperFactory.getObjectMapper() + .readValue(content, EventLogResponse.class); + if (resp == null || StringUtils.isEmpty(resp.getFilterID())) { + logger.error(" event log response invalid format, content: {}", content); + return; + } + + EventCallback callback = filterManager.getCallBack(resp.getFilterID()); + + if (callback == null) { + logger.debug( + " event log push message cannot find callback, filterID: {}, content: {}", + resp.getFilterID(), + content); + return; + } + + if (resp.getResult() == EventSubNodeRespStatus.SUCCESS.getStatus()) { + List logs = resp.getLogs(); + if (!logs.isEmpty()) { + callback.onReceiveLog(resp.getResult(), logs); + // update status + EventLogFilter filter = filterManager.getFilterById(resp.getFilterID()); + if (filter != null) { + filter.updateCountsAndLatestBlock(logs); + } else { + logger.error("cannot find filter to update log count and latest block "); + } + logger.info( + " log size: {}, blocknumber: {}", + logs.size(), + logs.get(0).getBlockNumber()); + } + } + } catch (JsonProcessingException e) { + logger.error("EventLogResponse error : " + e.getMessage()); + } + } + + @Override + public void onDisconnect(ChannelHandlerContext ctx) { + logger.info(" filter connection disconnect"); + filterManager.updateEventLogFilterStatus(ctx); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/EventSubNodeRespStatus.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/EventSubNodeRespStatus.java new file mode 100644 index 000000000..75da90faf --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/EventSubNodeRespStatus.java @@ -0,0 +1,101 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.eventsub.filter; + +public enum EventSubNodeRespStatus { + /** When make a subscribe of an event, the node would response the status. */ + SUCCESS(0), + PUSH_COMPLETED(1), + INVALID_PARAMS(-41000), + INVALID_REQUEST(-41001), + GROUP_NOT_EXIST(-41002), + INVALID_RANGE(-41003), + INVALID_RESPONSE(-41004), + REQUEST_TIMEOUT(-41005), + SDK_PERMISSION_DENIED(-41006), + // reserve 100 errors + OTHER_ERROR(42000), + ; + + private int status; + + private EventSubNodeRespStatus(int status) { + this.setStatus(status); + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public static EventSubNodeRespStatus fromIntStatus(int status) { + for (EventSubNodeRespStatus e : EventSubNodeRespStatus.values()) { + if (e.getStatus() == status) { + return e; + } + } + return EventSubNodeRespStatus.OTHER_ERROR; + } + + public static String getDescMessage(int status) { + return getDescMessage(fromIntStatus(status)); + } + + public static String getDescMessage(EventSubNodeRespStatus status) { + + String desc; + + switch (status) { + case SUCCESS: + desc = "success"; + break; + case PUSH_COMPLETED: + desc = "push completed"; + break; + case INVALID_PARAMS: + desc = "params invalid"; + break; + case INVALID_REQUEST: + desc = "register request not valid format"; + break; + case REQUEST_TIMEOUT: + desc = "register request timeout"; + break; + case GROUP_NOT_EXIST: + desc = "group not exist"; + break; + case INVALID_RANGE: + desc = "register parameters not in a range within permision"; + break; + case INVALID_RESPONSE: + desc = "response message not invalid format"; + break; + case SDK_PERMISSION_DENIED: + desc = "the SDK is not allowed to access this group."; + break; + default: + { + desc = "other errors"; + break; + } + } + + return desc; + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/FilterManager.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/FilterManager.java new file mode 100644 index 000000000..279c476e6 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/FilterManager.java @@ -0,0 +1,141 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.eventsub.filter; + +import io.netty.channel.ChannelHandlerContext; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.fisco.bcos.sdk.eventsub.EventCallback; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Filter manager is to maintain a EventLogFilter list, as well as a EventCallback list. Include + * add, remove, update operations to the two list and filters. + */ +public class FilterManager { + private static final Logger logger = LoggerFactory.getLogger(FilterManager.class); + + /** + * Register id of a filter is generated when register a subscribe. Filter id of a filter is + * generated when send one subscribe request to node. + */ + private Map regId2Filter = + new ConcurrentHashMap(); + + private Map filterID2Callback = + new ConcurrentHashMap(); + + public List getAllSubscribedEvent() { + List list = new ArrayList<>(); + regId2Filter.forEach( + (regId, filter) -> { + list.add(filter); + }); + return list; + } + + public EventLogFilter getFilterById(String filterId) { + for (EventLogFilter filter : regId2Filter.values()) { + if (filter.getFilterID().equals(filterId)) { + return filter; + } + } + return null; + } + + public void addFilter(EventLogFilter filter) { + regId2Filter.put(filter.getRegisterID(), filter); + logger.info( + "add event log filter , registerID: {}, filter: {}", + filter.getRegisterID(), + filter); + } + + public EventLogFilter getFilter(String registerId) { + return regId2Filter.get(registerId); + } + + public void removeFilter(String registerId) { + logger.info("remove filter, registerID: {}", registerId); + regId2Filter.remove(registerId); + } + + public void addCallback(String filterID, EventCallback callback) { + filterID2Callback.put(filterID, callback); + } + + public void removeCallback(String filterID) { + filterID2Callback.remove(filterID); + } + + public void updateFilterStatus( + EventLogFilter filter, EventLogFilterStatus status, ChannelHandlerContext ctx) { + synchronized (this) { + filter.setStatus(status); + filter.setCtx(ctx); + } + } + + public EventCallback getCallBack(String filterID) { + return filterID2Callback.get(filterID); + } + + public List getWaitingReqFilters() { + List filters = new ArrayList(); + synchronized (this) { + for (EventLogFilter filter : regId2Filter.values()) { + logger.trace( + " filter in list, id:{}, status:{}", + filter.getFilterID(), + filter.getStatus()); + if (filter.getStatus() == EventLogFilterStatus.WAITING_REQUEST) { + logger.info( + " resend filter, update event filter status: {}, registerID: {}, filter: {}", + filter.getStatus(), + filter.getRegisterID(), + filter); + filters.add(filter); + filter.setStatus(EventLogFilterStatus.WAITING_RESPONSE); + } + } + } + return filters; + } + + // update event filter status when socket disconnect + public void updateEventLogFilterStatus(ChannelHandlerContext ctx) { + synchronized (this) { + for (EventLogFilter filter : regId2Filter.values()) { + if (filter.getCtx() == ctx) { + filter.setCtx(null); + filter.setStatus(EventLogFilterStatus.WAITING_REQUEST); + removeCallback(filter.getFilterID()); + + logger.info( + " disconnect, update event filter status, ctx: {}, status: {}, registerID: {}, filterID: {}, filter: {}", + System.identityHashCode(ctx), + filter.getStatus(), + filter.getFilterID(), + filter.getRegisterID(), + filter); + } + } + } + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/ScheduleTimeConfig.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/ScheduleTimeConfig.java new file mode 100644 index 000000000..59c8d3310 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/eventsub/filter/ScheduleTimeConfig.java @@ -0,0 +1,21 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.eventsub.filter; + +/** Resend task time cofing */ +public class ScheduleTimeConfig { + public static long resendFrequency = (long) 10000; +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/service/GroupManagerService.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/service/GroupManagerService.java new file mode 100644 index 000000000..450ad0820 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/service/GroupManagerService.java @@ -0,0 +1,166 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.service; + +import java.math.BigInteger; +import java.util.List; +import java.util.Set; +import org.fisco.bcos.sdk.amop.Amop; +import org.fisco.bcos.sdk.channel.Channel; +import org.fisco.bcos.sdk.channel.PeerSelectRule; +import org.fisco.bcos.sdk.channel.ResponseCallback; +import org.fisco.bcos.sdk.config.ConfigOption; +import org.fisco.bcos.sdk.model.Message; +import org.fisco.bcos.sdk.model.NodeVersion; +import org.fisco.bcos.sdk.model.Response; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.network.ConnectionInfo; +import org.fisco.bcos.sdk.service.callback.BlockNumberNotifyCallback; + +public interface GroupManagerService { + public static final BigInteger BLOCK_LIMIT = BigInteger.valueOf(500); + + /** + * Update the group list information of the node + * + * @param peerIpAndPort Node ip and port information + * @param groupList Group list of nodes + */ + void updateGroupInfo(String peerIpAndPort, List groupList); + + Channel getChannel(); + /** + * update the block number information for the specified group + * + * @param groupId the specified groupId + * @param peerInfo the info of the peers + * @param currentBlockNumber the current blockNumber + */ + void updateBlockNumberInfo(Integer groupId, String peerInfo, BigInteger currentBlockNumber); + + List getGroupConnectionInfo(Integer groupId); + + /** + * get available ip and port info of specified group + * + * @param groupId get the connection info of the group + * @return the available ip and port info of the group + */ + List getGroupAvailablePeers(Integer groupId); + + /** + * Get block limit of specified group + * + * @param groupId The specified groupId + * @return the blockLimit(needed by the transaction module) + */ + BigInteger getBlockLimitByGroup(Integer groupId); + + /** + * Get the node list of the specified group + * + * @param groupId The group id + * @return The node list that started the group + */ + Set getGroupNodeList(Integer groupId); + + /** + * Get the group list of specified node + * + * @param nodeAddress The ip and port info of the node + * @return List of groups started by the node + */ + List getGroupInfoByNodeInfo(String nodeAddress); + + /** + * Send a message to a node in the group and select the node with the highest block height in + * the group + * + * @param groupId The group the message is sent to + * @param message The message to be sent + * @return response of the node located in the specified group + */ + Response sendMessageToGroup(Integer groupId, Message message); + + /** + * Send messages to nodes in the group according to specified rules (If multiple nodes are + * filtered out, only select one of them to send the message) + * + * @param groupId The group the message is sent to + * @param message The message to be sent + * @param rule Rule for filtering the target nodes + * @return callback to be called after receiving response + */ + Response sendMessageToGroupByRule(Integer groupId, Message message, PeerSelectRule rule); + + /** + * Send a message to a node in the group and select the node with the highest block height in + * the group + * + * @param groupId The group the message is sent to + * @param message The message to be sent + * @param callback callback to be called after receiving response + */ + void asyncSendMessageToGroup(Integer groupId, Message message, ResponseCallback callback); + + /** + * Send messages to nodes in the group according to specified rules (If multiple nodes are + * filtered out, only select one of them to send the message) + * + * @param groupId The group the message is sent to + * @param message The message to be sent + * @param rule Rules for filtering the target nodes + * @param callback Function to be called after receiving response + */ + void asyncSendMessageToGroupByRule( + Integer groupId, Message message, PeerSelectRule rule, ResponseCallback callback); + + /** + * Broadcast messages to all the nodes of the specified group + * + * @param groupId The group the message is sent to + * @param message The message to be sent + */ + void broadcastMessageToGroup(Integer groupId, Message message); + + void asyncSendTransaction( + Integer groupId, + Message transactionData, + TransactionCallback callback, + ResponseCallback responseCallback); + + void eraseTransactionSeq(String seq); + + NodeVersion getNodeVersion(String peerInfo); + + Integer getCryptoType(String peerInfo); + + ConfigOption getConfig(); + + void updateNodeVersion(); + + void fetchGroupList(); + + void stop(); + + BigInteger getLatestBlockNumberByGroup(Integer groupId); + + String registerBlockNotifyCallback(BlockNumberNotifyCallback callback); + + void eraseBlockNotifyCallback(String registerId); + + Set getGroupList(); + + void setAmop(Amop amop); +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/service/GroupManagerServiceImpl.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/service/GroupManagerServiceImpl.java new file mode 100644 index 000000000..48efccc53 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/service/GroupManagerServiceImpl.java @@ -0,0 +1,791 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.service; + +import io.netty.util.HashedWheelTimer; +import io.netty.util.Timeout; +import io.netty.util.Timer; +import io.netty.util.TimerTask; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; +import org.fisco.bcos.sdk.amop.Amop; +import org.fisco.bcos.sdk.channel.Channel; +import org.fisco.bcos.sdk.channel.PeerSelectRule; +import org.fisco.bcos.sdk.channel.ResponseCallback; +import org.fisco.bcos.sdk.channel.model.ChannelMessageError; +import org.fisco.bcos.sdk.channel.model.EnumChannelProtocolVersion; +import org.fisco.bcos.sdk.channel.model.Options; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.client.exceptions.ClientException; +import org.fisco.bcos.sdk.client.handler.BlockNumberNotifyHandler; +import org.fisco.bcos.sdk.client.handler.GetNodeVersionHandler; +import org.fisco.bcos.sdk.client.handler.OnReceiveBlockNotifyFunc; +import org.fisco.bcos.sdk.client.handler.TransactionNotifyHandler; +import org.fisco.bcos.sdk.client.protocol.response.BlockNumber; +import org.fisco.bcos.sdk.client.protocol.response.GroupList; +import org.fisco.bcos.sdk.config.ConfigOption; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.Message; +import org.fisco.bcos.sdk.model.MsgType; +import org.fisco.bcos.sdk.model.NodeVersion; +import org.fisco.bcos.sdk.model.Response; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.network.ConnectionInfo; +import org.fisco.bcos.sdk.service.callback.BlockNumberNotifyCallback; +import org.fisco.bcos.sdk.service.model.BlockNumberMessageDecoder; +import org.fisco.bcos.sdk.service.model.BlockNumberNotification; +import org.fisco.bcos.sdk.utils.ChannelUtils; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; +import org.fisco.bcos.sdk.utils.ThreadPoolService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GroupManagerServiceImpl implements GroupManagerService { + public static final String SM_CRYPTO_STR = "gm"; + + private static Logger logger = LoggerFactory.getLogger(GroupManagerServiceImpl.class); + private final Channel channel; + private final BlockNumberMessageDecoder blockNumberMessageDecoder; + private Amop amop; + private final GroupServiceFactory groupServiceFactory; + private ConcurrentHashMap groupIdToService = new ConcurrentHashMap<>(); + private ConcurrentHashMap> nodeToGroupIDList = new ConcurrentHashMap<>(); + private ConcurrentHashMap nodeToNodeVersion = new ConcurrentHashMap<>(); + private ConcurrentHashMap registerIdToBlockNotifyCallback = + new ConcurrentHashMap<>(); + + private ConcurrentHashMap seq2TransactionCallback = + new ConcurrentHashMap<>(); + private final Timer timeoutHandler = new HashedWheelTimer(); + private Client groupInfoGetter; + private long fetchGroupListIntervalMs = 60000; + private ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1); + + // the thread pool is used to handle the block_notify message and transaction_notify message + private final ThreadPoolService threadPool; + AtomicBoolean running = new AtomicBoolean(false); + + private final ConfigOption config; + + public GroupManagerServiceImpl(Channel channel, ConfigOption configOption) { + this.channel = channel; + this.config = configOption; + this.threadPool = + new ThreadPoolService( + "GroupManagerServiceImpl", + configOption.getThreadPoolConfig().getReceiptProcessorThreadSize(), + configOption.getThreadPoolConfig().getMaxBlockingQueueSize()); + this.blockNumberMessageDecoder = new BlockNumberMessageDecoder(); + this.groupServiceFactory = new GroupServiceFactory(); + this.groupInfoGetter = Client.build(channel); + // Note: must register the handlers at first + registerGetNodeVersionHandler(); + registerBlockNumberNotifyHandler(); + registerTransactionNotifyHandler(); + fetchGroupList(); + updateNodeVersion(); + this.start(); + } + + @Override + public ConfigOption getConfig() { + return this.config; + } + + @Override + public Integer getCryptoType(String peerInfo) { + if (!nodeToNodeVersion.containsKey(peerInfo)) { + return null; + } + NodeVersion nodeVersion = nodeToNodeVersion.get(peerInfo); + if (nodeVersion.getNodeVersion().getVersion().contains(SM_CRYPTO_STR)) { + return CryptoType.SM_TYPE; + } + return CryptoType.ECDSA_TYPE; + } + + @Override + public NodeVersion getNodeVersion(String peerInfo) { + if (!nodeToNodeVersion.containsKey(peerInfo)) { + return null; + } + return nodeToNodeVersion.get(peerInfo); + } + + @Override + public void updateNodeVersion() { + List peers = this.channel.getAvailablePeer(); + for (String peer : peers) { + updateNodeVersion(peer); + } + } + + private void updateNodeVersion(String peerIpAndPort) { + try { + NodeVersion nodeVersion = groupInfoGetter.getNodeVersion(peerIpAndPort); + nodeToNodeVersion.put(peerIpAndPort, nodeVersion); + } catch (Exception e) { + logger.error( + "updateNodeVersion for {} failed, error message: {}", + peerIpAndPort, + e.getMessage()); + } + } + + public void registerGetNodeVersionHandler() { + GetNodeVersionHandler handler = + new GetNodeVersionHandler( + new Consumer() { + @Override + public void accept(String peerIpAndPort) { + threadPool + .getThreadPool() + .execute( + new Runnable() { + @Override + public void run() { + fetchGroupList(peerIpAndPort); + updateNodeVersion(peerIpAndPort); + } + }); + } + }); + this.channel.addEstablishHandler(handler); + } + + private void onDisconnect(String peerIpAndPort) { + try { + nodeToNodeVersion.remove(peerIpAndPort); + if (!nodeToGroupIDList.containsKey(peerIpAndPort)) { + return; + } + List groupList = nodeToGroupIDList.get(peerIpAndPort); + for (String group : groupList) { + Integer groupId = Integer.valueOf(group); + GroupService groupService = groupIdToService.get(groupId); + if (groupService == null) { + continue; + } + if (groupService.removeNode(peerIpAndPort)) { + updateBlockNotify(peerIpAndPort, this.nodeToGroupIDList.get(peerIpAndPort)); + } + if (groupService.getGroupNodesInfo().size() == 0) { + groupIdToService.remove(groupId); + } + } + nodeToGroupIDList.remove(peerIpAndPort); + } catch (Exception e) { + logger.warn( + "onDisconnect to {} failed, error message: {}", peerIpAndPort, e.getMessage()); + } + } + + public void registerBlockNumberNotifyHandler() { + OnReceiveBlockNotifyFunc onReceiveBlockNotifyFunc = + (version, peerIpAndPort, blockNumberNotifyMessage) -> + threadPool + .getThreadPool() + .execute( + new Runnable() { + @Override + public void run() { + onReceiveBlockNotifyImpl( + version, + peerIpAndPort, + blockNumberNotifyMessage); + } + }); + BlockNumberNotifyHandler handler = + new BlockNumberNotifyHandler( + onReceiveBlockNotifyFunc, + new Consumer() { + @Override + public void accept(String disconnectedEndpoint) { + threadPool + .getThreadPool() + .execute( + new Runnable() { + @Override + public void run() { + onDisconnect(disconnectedEndpoint); + } + }); + } + }); + this.channel.addMessageHandler(MsgType.BLOCK_NOTIFY, handler); + this.channel.addDisconnectHandler(handler); + logger.info("registerBlockNumberNotifyHandler"); + } + + public void registerTransactionNotifyHandler() { + TransactionNotifyHandler handler = + new TransactionNotifyHandler( + new Consumer() { + @Override + public void accept(Message message) { + threadPool + .getThreadPool() + .execute( + new Runnable() { + // decode the message into transaction + @Override + public void run() { + onReceiveTransactionNotify(message); + } + }); + } + }); + this.channel.addMessageHandler(MsgType.TRANSACTION_NOTIFY, handler); + logger.info("registerTransactionNotifyHandler"); + } + + /** + * Get the blockNumber notify message from the AMOP module, parse the package and update the + * latest block height of each group + * + * @param version the EnumChannelProtocolVersion instance + * @param peerIpAndPort Node ip and port + * @param blockNumberNotifyMessage the blockNumber notify message + */ + protected void onReceiveBlockNotifyImpl( + EnumChannelProtocolVersion version, + String peerIpAndPort, + Message blockNumberNotifyMessage) { + try { + BlockNumberNotification blockNumberInfo = + blockNumberMessageDecoder.decode(version, blockNumberNotifyMessage); + if (blockNumberInfo == null) { + return; + } + + // set the block number + updateBlockNumberInfo( + Integer.valueOf(blockNumberInfo.getGroupId()), + peerIpAndPort, + new BigInteger(blockNumberInfo.getBlockNumber())); + + threadPool + .getThreadPool() + .execute( + new Runnable() { + @Override + public void run() { + try { + for (String registerId : + registerIdToBlockNotifyCallback.keySet()) { + BlockNumberNotifyCallback callback = + registerIdToBlockNotifyCallback.get(registerId); + callback.onReceiveBlockNumberInfo( + peerIpAndPort, blockNumberInfo); + } + } catch (Exception e) { + logger.warn( + "Calls BlockNumberNotifyCallback failed, error info: {}", + e.getMessage()); + } + } + }); + } catch (Exception e) { + logger.error("onReceiveBlockNotify failed, error message: {}", e.getMessage()); + } + } + + @Override + public String registerBlockNotifyCallback(BlockNumberNotifyCallback callback) { + String registerId = ChannelUtils.newSeq(); + registerIdToBlockNotifyCallback.put(registerId, callback); + logger.debug("register BlockNumberNotifyCallback, registerId: {}", registerId); + return registerId; + } + + @Override + public void eraseBlockNotifyCallback(String registerId) { + if (registerIdToBlockNotifyCallback.containsKey(registerId)) { + registerIdToBlockNotifyCallback.remove(registerId); + } + } + + /** + * calls the transaction callback when receive the transaction notify + * + * @param message the message contains the transactionReceipt + */ + protected void onReceiveTransactionNotify(Message message) { + String seq = message.getSeq(); + if (seq == null) { + return; + } + // get the transaction callback + TransactionCallback callback = seq2TransactionCallback.get(seq); + try { + // remove the callback + seq2TransactionCallback.remove(seq); + if (callback == null) { + logger.error("transaction callback is null, seq: {}", seq); + return; + } + callback.cancelTimeout(); + // decode the message into receipt + TransactionReceipt receipt = null; + + receipt = + ObjectMapperFactory.getObjectMapper() + .readValue(message.getData(), TransactionReceipt.class); + callback.onResponse(receipt); + } catch (Exception e) { + // fake the receipt + TransactionReceipt receipt = new TransactionReceipt(); + receipt.setStatus(String.valueOf(ChannelMessageError.MESSAGE_DECODE_ERROR.getError())); + receipt.setMessage( + "Decode receipt error, seq: " + seq + ", reason: " + e.getLocalizedMessage()); + callback.onResponse(receipt); + } + } + + @Override + public void asyncSendTransaction( + Integer groupId, + Message transactionMessage, + TransactionCallback callback, + ResponseCallback responseCallback) { + if (callback.getTimeout() > 0) { + callback.setTimeoutHandler( + timeoutHandler.newTimeout( + new TimerTask() { + @Override + public void run(Timeout timeout) throws Exception { + callback.onTimeout(); + logger.info( + "Transaction timeout: {}", transactionMessage.getSeq()); + seq2TransactionCallback.remove(transactionMessage.getSeq()); + } + }, + callback.getTimeout(), + TimeUnit.MILLISECONDS)); + } + seq2TransactionCallback.put(transactionMessage.getSeq(), callback); + asyncSendMessageToGroup(groupId, transactionMessage, responseCallback); + } + + @Override + public void eraseTransactionSeq(String seq) { + if (seq != null && seq2TransactionCallback.containsKey(seq)) { + seq2TransactionCallback.remove(seq); + } + } + + @Override + public Channel getChannel() { + return this.channel; + } + + /** Stop group list fetching thread */ + @Override + public void stop() { + if (!running.get()) { + logger.warn("GroupManagerService has already been stopped!"); + return; + } + logger.debug("stop GroupManagerService..."); + timeoutHandler.stop(); + ThreadPoolService.stopThreadPool(scheduledExecutorService); + threadPool.stop(); + logger.debug("stop GroupManagerService succ..."); + running.set(false); + } + + /** start the thread to obtain group list information periodically */ + protected void start() { + if (running.get()) { + logger.warn("GroupManagerService has already been started!"); + return; + } + logger.debug("start GroupManagerService..."); + running.set(true); + // heartbeat: 3 s + scheduledExecutorService.scheduleAtFixedRate( + () -> fetchGroupList(), 0, fetchGroupListIntervalMs, TimeUnit.MILLISECONDS); + } + + @Override + public void updateGroupInfo(String peerIpAndPort, List groupList) { + List orgGroupList = nodeToGroupIDList.get(peerIpAndPort); + if (orgGroupList != null) { + for (int i = 0; i < orgGroupList.size(); i++) { + Integer groupId = Integer.valueOf(orgGroupList.get(i)); + if (!groupList.contains(orgGroupList.get(i)) + && groupIdToService.containsKey(groupId)) { + if (groupIdToService.get(groupId).removeNode(peerIpAndPort)) { + updateBlockNotify(peerIpAndPort, this.nodeToGroupIDList.get(peerIpAndPort)); + } + logger.info("remove group {} from {}", orgGroupList.get(i), peerIpAndPort); + } + } + } + nodeToGroupIDList.put(peerIpAndPort, groupList); + + for (String groupIdStr : groupList) { + Integer groupId = Integer.valueOf(groupIdStr); + if (groupId == null) { + continue; + } + // create groupService for the new groupId + if (tryToCreateGroupService(peerIpAndPort, groupId)) { + // fetch the block number information for the group + getAndUpdateBlockNumberForAllPeers(groupId); + continue; + } + // update the group information + if (groupIdToService.get(groupId).insertNode(peerIpAndPort)) { + fetchAndUpdateBlockNumberInfo(groupId, peerIpAndPort); + updateBlockNotify(peerIpAndPort, this.nodeToGroupIDList.get(peerIpAndPort)); + } + } + logger.trace("update groupInfo for {}, groupList: {}", peerIpAndPort, groupList); + } + + @Override + public void updateBlockNumberInfo( + Integer groupId, String peerInfo, BigInteger currentBlockNumber) { + tryToCreateGroupService(peerInfo, groupId); + // update the blockNumber Info for the group + GroupService groupService = groupIdToService.get(groupId); + groupService.updatePeersBlockNumberInfo(peerInfo, currentBlockNumber); + } + + private boolean tryToCreateGroupService(String peerIpAndPort, Integer groupId) { + // create groupService for the new groupId + if (!groupIdToService.containsKey(groupId)) { + groupIdToService.put( + groupId, this.groupServiceFactory.createGroupSerivce(groupId, peerIpAndPort)); + updateBlockNotify(peerIpAndPort, this.nodeToGroupIDList.get(peerIpAndPort)); + return true; + } + return false; + } + + @Override + public BigInteger getBlockLimitByGroup(Integer groupId) { + return getLatestBlockNumberByGroup(groupId).add(BLOCK_LIMIT); + } + + @Override + public BigInteger getLatestBlockNumberByGroup(Integer groupId) { + if (groupIdToService.containsKey(groupId) + && groupIdToService.get(groupId).getLatestBlockNumber().equals(BigInteger.ZERO)) { + getAndUpdateBlockNumberForAllPeers(groupId); + } + if (groupIdToService.containsKey(groupId)) { + return groupIdToService.get(groupId).getLatestBlockNumber(); + } + return BigInteger.ZERO; + } + + private void getAndUpdateBlockNumberForAllPeers(Integer groupId) { + List availablePeers = getGroupAvailablePeers(groupId); + logger.debug( + "g: {}, getAndUpdateBlockNumberForAllPeers, group availablePeers:{}", + groupId, + availablePeers.toString()); + for (String peer : availablePeers) { + fetchAndUpdateBlockNumberInfo(groupId, peer); + } + } + + private void fetchAndUpdateBlockNumberInfo(Integer groupId, String peer) { + try { + BlockNumber blockNumber = this.groupInfoGetter.getBlockNumber(groupId, peer); + // update the block number information + updateBlockNumberInfo(groupId, peer, blockNumber.getBlockNumber()); + logger.debug( + "fetch and update the blockNumber information, groupId: {}, peer:{}, blockNumber: {}", + groupId, + peer, + blockNumber.getBlockNumber()); + } catch (ClientException e) { + logger.error( + "GetBlockNumber from {} failed, error information:{}", peer, e.getMessage()); + } + } + + @Override + public Set getGroupNodeList(Integer groupId) { + if (!groupIdToService.containsKey(groupId)) { + return new HashSet<>(); + } + return groupIdToService.get(groupId).getGroupNodesInfo(); + } + + @Override + public List getGroupInfoByNodeInfo(String nodeAddress) { + if (!nodeToGroupIDList.containsKey(nodeAddress)) { + return new ArrayList<>(); + } + return nodeToGroupIDList.get(nodeAddress); + } + + private boolean checkGroupStatus(Integer groupId) { + if (!groupIdToService.containsKey(groupId)) { + logger.warn("checkGroupStatus failed for group {} doesn't exist", groupId); + return false; + } + return true; + } + + @Override + public Response sendMessageToGroup(Integer groupId, Message message) { + if (!checkGroupStatus(groupId)) { + return null; + } + // get the node with the latest block number + String targetNode = groupIdToService.get(groupId).getNodeWithTheLatestBlockNumber(); + if (targetNode == null) { + logger.error( + "sendMessageToGroup message failed for get the node with the latest block number failed, groupId: {}, seq: {}, type: {}", + groupId, + message.getSeq(), + message.getType()); + return null; + } + logger.trace( + "g:{}, sendMessageToGroup, selectedPeer: {}, message type: {}, seq: {}, length:{}", + groupId, + targetNode, + message.getType(), + message.getSeq(), + message.getLength()); + return this.channel.sendToPeer(message, targetNode); + } + + @Override + public void asyncSendMessageToGroup( + Integer groupId, Message message, ResponseCallback callback) { + if (!checkGroupStatus(groupId)) { + if (callback != null) { + callback.onError( + "asyncSendMessageToGroup to group " + + groupId + + " failed, please check the connections."); + } + return; + } + // get the node with the latest block number + String targetNode = groupIdToService.get(groupId).getNodeWithTheLatestBlockNumber(); + if (targetNode == null) { + logger.warn( + "g:{}, asyncSendMessageToGroup, selectedPeer failed, seq: {}, type: {}", + groupId, + message.getSeq(), + message.getType()); + throw new ClientException( + "asyncSendMessageToGroup to " + + groupId + + " failed for selectPeer failed, messageSeq: " + + message.getSeq()); + } + logger.trace( + "g:{}, asyncSendMessageToGroup, selectedPeer:{}, message type: {}, seq: {}, length:{}", + groupId, + targetNode, + message.getType(), + message.getSeq(), + message.getLength()); + this.channel.asyncSendToPeer(message, targetNode, callback, new Options()); + } + + @Override + public Response sendMessageToGroupByRule( + Integer groupId, Message message, PeerSelectRule rule) { + String selectedPeer = selectGroupPeersByRule(groupId, rule); + if (selectedPeer == null) { + logger.warn( + "g:{}, sendMessageToGroupByRule, no peer is selected by the rule, message type: {}, seq: {}, length:{}", + groupId, + message.getType(), + message.getSeq(), + message.getLength()); + return null; + } + logger.debug( + "g:{}, sendMessageToGroupByRule, send message to {}, selectedPeer: {}, message type: {}, seq: {}, length:{}", + groupId, + selectedPeer, + selectedPeer, + message.getType(), + message.getSeq(), + message.getLength()); + return this.channel.sendToPeer(message, selectedPeer); + } + + private String selectGroupPeersByRule(Integer groupId, PeerSelectRule rule) { + if (!checkGroupStatus(groupId)) { + return null; + } + // select nodes with rule + List groupConnnectionInfos = getGroupConnectionInfo(groupId); + return rule.select(groupConnnectionInfos); + } + + @Override + public List getGroupConnectionInfo(Integer groupId) { + if (!checkGroupStatus(groupId)) { + return new ArrayList<>(); + } + return getGroupConnectionInfo(groupIdToService.get(groupId)); + } + + private List getGroupConnectionInfo(GroupService groupService) { + List connectionInfos = this.channel.getConnectionInfo(); + List groupConnectionInfos = new ArrayList<>(); + for (ConnectionInfo connectionInfo : connectionInfos) { + if (groupService.existPeer(connectionInfo.getEndPoint())) { + groupConnectionInfos.add(connectionInfo); + } + } + return groupConnectionInfos; + } + + @Override + public List getGroupAvailablePeers(Integer groupId) { + if (!checkGroupStatus(groupId)) { + return new ArrayList<>(); + } + return getGroupAvailablePeers(groupIdToService.get(groupId)); + } + + private List getGroupAvailablePeers(GroupService groupService) { + List availablePeers = this.channel.getAvailablePeer(); + List groupAvailablePeers = new ArrayList<>(); + // filter the available peers of the given group + for (String peer : availablePeers) { + if (groupService.existPeer(peer)) { + groupAvailablePeers.add(peer); + } + } + return groupAvailablePeers; + } + + @Override + public void asyncSendMessageToGroupByRule( + Integer groupId, Message message, PeerSelectRule rule, ResponseCallback callback) { + String errorMessage; + if (!checkGroupStatus(groupId)) { + errorMessage = + "asyncSendMessageToGroupByRule to " + + groupId + + " failed for the group doesn't exit, message seq: " + + message.getSeq(); + callback.onError(errorMessage); + } + // select nodes with rule + String selectedPeer = selectGroupPeersByRule(groupId, rule); + if (selectedPeer == null) { + logger.warn( + "g:{}, asyncSendMessageToGroup, no peer is selected by the rule, message type: {}, seq: {}, length:{}", + groupId, + message.getType(), + message.getSeq(), + message.getLength()); + errorMessage = + "asyncSendMessageToGroupByRule to " + + groupId + + " failed for no peer is selected by the rule"; + callback.onError(errorMessage); + return; + } + logger.trace( + "g:{}, asyncSendMessageToGroupByRule, selectedPeer: {}, message type: {}, seq: {}, length:{}", + groupId, + selectedPeer, + message.getType(), + message.getSeq(), + message.getLength()); + this.channel.asyncSendToPeer(message, selectedPeer, callback, new Options()); + } + + @Override + public void broadcastMessageToGroup(Integer groupId, Message message) { + // get the group connections + List groupConnnectionInfos = getGroupConnectionInfo(groupId); + if (groupConnnectionInfos == null) { + logger.warn( + "g:{}, broadcastMessageToGroup, broadcast message failed for the group has no connected peers, message type: {}, seq: {}, length:{}", + groupId, + message.getType(), + message.getSeq(), + message.getLength()); + return; + } + for (ConnectionInfo connectionInfo : groupConnnectionInfos) { + this.channel.asyncSendToPeer( + message, connectionInfo.getEndPoint(), null, new Options()); + } + } + + // fetch the groupIDList from all the peers + @Override + public void fetchGroupList() { + List peers = this.channel.getAvailablePeer(); + for (String peerEndPoint : peers) { + fetchGroupList(peerEndPoint); + } + } + + private void fetchGroupList(String peerEndPoint) { + try { + GroupList groupList = this.groupInfoGetter.getGroupList(peerEndPoint); + this.updateGroupInfo(peerEndPoint, groupList.getGroupList()); + } catch (ClientException e) { + logger.warn( + "fetchGroupList from {} failed, error info: {}", peerEndPoint, e.getMessage()); + } + } + + @Override + public Set getGroupList() { + fetchGroupList(); + return groupIdToService.keySet(); + } + + protected void updateBlockNotify(String peer, List groupList) { + if (this.amop == null) { + return; + } + this.amop.getTopicManager().updateBlockNotify(peer, groupList); + this.amop.sendSubscribe(); + } + + @Override + public void setAmop(Amop amop) { + this.amop = amop; + List availablePeers = this.channel.getAvailablePeer(); + for (String peer : availablePeers) { + List groupList = this.getGroupInfoByNodeInfo(peer); + logger.debug("register blockNotify for {}, groupList: {}", peer, groupList.toString()); + if (groupList != null && groupList.size() > 0) { + updateBlockNotify(peer, groupList); + } + } + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/service/GroupService.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/service/GroupService.java new file mode 100644 index 000000000..b44bacbd0 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/service/GroupService.java @@ -0,0 +1,56 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.service; + +import java.math.BigInteger; +import java.util.Set; + +public interface GroupService { + /** + * Get the node information of the group + * + * @return Nodes' ip and port list + */ + Set getGroupNodesInfo(); + + /** + * remove node from the group + * + * @param nodeAddress the ip and port of the removed node + * @return if nodes in the original list that needed to be removed return True, else false. + */ + boolean removeNode(String nodeAddress); + + /** + * add nodeInfo to the group + * + * @param nodeAddress the node ip and port + * @return if nodes in the original list that needed to be inserted return True, else false. + */ + boolean insertNode(String nodeAddress); + + /** + * update the latest block number of the specified group + * + * @param peerIpAndPort the node that notify the block number info + * @param blockNumber the notified block number + */ + void updatePeersBlockNumberInfo(String peerIpAndPort, BigInteger blockNumber); + + BigInteger getLatestBlockNumber(); + + String getNodeWithTheLatestBlockNumber(); + + boolean existPeer(String peer); +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/service/GroupServiceFactory.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/service/GroupServiceFactory.java new file mode 100644 index 000000000..b3fcb547d --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/service/GroupServiceFactory.java @@ -0,0 +1,24 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.service; + +public class GroupServiceFactory { + public GroupService createGroupSerivce(Integer groupId, String nodeIpAndPortInfo) { + return new GroupServiceImpl(groupId, nodeIpAndPortInfo); + } + + public GroupService createGroupSerivce(Integer groupId) { + return new GroupServiceImpl(groupId); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/service/GroupServiceImpl.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/service/GroupServiceImpl.java new file mode 100644 index 000000000..1d4ba1e07 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/service/GroupServiceImpl.java @@ -0,0 +1,206 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.service; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.AtomicLong; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GroupServiceImpl implements GroupService { + + private static Logger logger = LoggerFactory.getLogger(GroupServiceImpl.class); + + private ConcurrentHashMap groupNodeToBlockNumber = + new ConcurrentHashMap<>(); + private Set groupNodeSet = new CopyOnWriteArraySet<>(); + private final Integer groupId; + private AtomicLong latestBlockNumber = new AtomicLong(0); + private List nodeWithLatestBlockNumber = new CopyOnWriteArrayList(); + + public GroupServiceImpl(Integer groupId) { + this.groupId = groupId; + } + + public GroupServiceImpl(Integer groupId, String groupNodeAddress) { + this.groupId = groupId; + this.groupNodeSet.add(groupNodeAddress); + logger.debug("insert group: {} for peer {}", groupId, groupNodeAddress); + } + + @Override + public Set getGroupNodesInfo() { + return this.groupNodeSet; + } + + @Override + public boolean removeNode(String nodeAddress) { + boolean shouldResetLatestBlockNumber = false; + if (groupNodeToBlockNumber.containsKey(nodeAddress)) { + groupNodeToBlockNumber.remove(nodeAddress); + shouldResetLatestBlockNumber = true; + } + if (nodeWithLatestBlockNumber.contains(nodeAddress)) { + nodeWithLatestBlockNumber.remove(nodeAddress); + shouldResetLatestBlockNumber = true; + } + if (shouldResetLatestBlockNumber) { + resetLatestBlockNumber(); + } + logger.debug( + "g:{}, removeNode={}, blockNumberInfoSize={}, latestBlockNumber:{}", + groupId, + nodeAddress, + this.groupNodeToBlockNumber.size(), + latestBlockNumber); + if (groupNodeSet.contains(nodeAddress)) { + groupNodeSet.remove(nodeAddress); + return true; + } + return false; + } + + @Override + public boolean insertNode(String nodeAddress) { + if (!groupNodeSet.contains(nodeAddress)) { + groupNodeSet.add(nodeAddress); + logger.debug( + "g:{}, insertNode={}, nodeSize={}, blockNumberInfoSize={}", + groupId, + nodeAddress, + this.groupNodeSet.size(), + this.groupNodeToBlockNumber.size()); + return true; + } + if (!groupNodeToBlockNumber.containsKey(nodeAddress)) { + groupNodeToBlockNumber.put(nodeAddress, BigInteger.valueOf(0)); + } + return false; + } + + @Override + public void updatePeersBlockNumberInfo(String peerIpAndPort, BigInteger blockNumber) { + // Note: In order to ensure that the cache information is updated in time when the node is + // restarted, the block height information of the node must be directly updated + if (!groupNodeToBlockNumber.containsKey(peerIpAndPort) + || !groupNodeToBlockNumber.get(peerIpAndPort).equals(blockNumber)) { + logger.debug( + "updatePeersBlockNumberInfo for {}, updated blockNumber: {}, groupId: {}", + peerIpAndPort, + blockNumber, + groupId); + groupNodeToBlockNumber.put(peerIpAndPort, blockNumber); + } + if (!groupNodeSet.contains(peerIpAndPort)) { + groupNodeSet.add(peerIpAndPort); + } + updateLatestBlockNumber(peerIpAndPort, blockNumber); + } + + private void updateLatestBlockNumber(String peerIpAndPort, BigInteger blockNumber) { + if (blockNumber.longValue() == latestBlockNumber.get() + && !nodeWithLatestBlockNumber.contains(peerIpAndPort)) { + nodeWithLatestBlockNumber.add(peerIpAndPort); + } + if (blockNumber.longValue() > latestBlockNumber.get()) { + latestBlockNumber.getAndSet(blockNumber.longValue()); + nodeWithLatestBlockNumber.clear(); + nodeWithLatestBlockNumber.add(peerIpAndPort); + } + logger.debug( + "g:{}, updateLatestBlockNumber, latestBlockNumber: {}, nodeWithLatestBlockNumber:{}", + groupId, + latestBlockNumber.get(), + nodeWithLatestBlockNumber.toString()); + } + + private void resetLatestBlockNumber() { + BigInteger maxBlockNumber = null; + if (groupNodeToBlockNumber.size() == 0) { + latestBlockNumber.getAndSet(BigInteger.ZERO.longValue()); + return; + } + for (String groupNode : groupNodeToBlockNumber.keySet()) { + BigInteger blockNumber = groupNodeToBlockNumber.get(groupNode); + if (blockNumber == null) { + continue; + } + if (maxBlockNumber == null || blockNumber.compareTo(maxBlockNumber) > 0) { + maxBlockNumber = blockNumber; + } + } + + if (maxBlockNumber == null) { + return; + } + latestBlockNumber.getAndSet(maxBlockNumber.longValue()); + nodeWithLatestBlockNumber.clear(); + for (String groupNode : groupNodeToBlockNumber.keySet()) { + BigInteger blockNumber = groupNodeToBlockNumber.get(groupNode); + if (latestBlockNumber.equals(blockNumber)) { + nodeWithLatestBlockNumber.add(groupNode); + } + } + logger.debug( + "g:{}, resetLatestBlockNumber, latestBlockNumber: {}, nodeWithLatestBlockNumber:{}, maxBlockNumber: {}", + groupId, + latestBlockNumber.get(), + nodeWithLatestBlockNumber.toString(), + maxBlockNumber); + } + + @Override + public BigInteger getLatestBlockNumber() { + return BigInteger.valueOf(this.latestBlockNumber.get()); + } + + @Override + public String getNodeWithTheLatestBlockNumber() { + try { + // in case of nodeWithLatestBlockNumber modified + final List tmpNodeWithLatestBlockNumber = + new ArrayList<>(nodeWithLatestBlockNumber); + // the case that the sdk is allowed to access all the connected node, select the first + // connected node to send the request + if (tmpNodeWithLatestBlockNumber.size() > 0) { + // Note: when the nodeWithLatestBlockNumber modified, and the random value + // calculated after the modification, and the nodeWithLatestBlockNumber.get is + // called after the modification, this function will throw + // ArrayIndexOutOfBoundsException + int random = (int) (Math.random() * (tmpNodeWithLatestBlockNumber.size())); + return tmpNodeWithLatestBlockNumber.get(random); + } + } catch (Exception e) { + logger.warn( + "getNodeWithTheLatestBlockNumber failed for {}, select the node to send message randomly", + e); + } + // select the first element + if (!groupNodeSet.isEmpty()) { + return groupNodeSet.iterator().next(); + } + return null; + } + + @Override + public boolean existPeer(String peer) { + return groupNodeSet.contains(peer); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/service/callback/BlockNumberNotifyCallback.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/service/callback/BlockNumberNotifyCallback.java new file mode 100644 index 000000000..17a66aecd --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/service/callback/BlockNumberNotifyCallback.java @@ -0,0 +1,21 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.service.callback; + +import org.fisco.bcos.sdk.service.model.BlockNumberNotification; + +public interface BlockNumberNotifyCallback { + void onReceiveBlockNumberInfo( + String peerIpAndPort, BlockNumberNotification blockNumberNotification); +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/service/model/BlockNumberMessageDecoder.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/service/model/BlockNumberMessageDecoder.java new file mode 100644 index 000000000..1161c2991 --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/service/model/BlockNumberMessageDecoder.java @@ -0,0 +1,73 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.service.model; + +import java.io.IOException; +import org.fisco.bcos.sdk.channel.model.EnumChannelProtocolVersion; +import org.fisco.bcos.sdk.model.Message; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BlockNumberMessageDecoder { + private static Logger logger = LoggerFactory.getLogger(BlockNumberMessageDecoder.class); + + public BlockNumberNotification decode(EnumChannelProtocolVersion version, Message message) { + BlockNumberNotification blockNumberNotification; + switch (version) { + case VERSION_1: + { + blockNumberNotification = decodeV1(message); + } + break; + default: + { + blockNumberNotification = decodeByDefault(message); + } + break; + } + return blockNumberNotification; + } + + /** + * @param message the notification message + * @return the decoded block number information + */ + protected BlockNumberNotification decodeByDefault(Message message) { + try { + return ObjectMapperFactory.getObjectMapper() + .readValue(message.getData(), BlockNumberNotification.class); + } catch (IOException e) { + logger.error( + "BlockNumberMessageDecoder: decode BlockNumberNotification message failed, type: {}, seq: {}, size: {}, reason: {}", + message.getType(), + message.getSeq(), + message.getLength(), + e.getMessage()); + return null; + } + } + + /** + * @param message the notification message + * @return the decoded block number information + */ + protected BlockNumberNotification decodeV1(Message message) { + String[] split = message.getData().toString().split(","); + if (split.length != 2) { + return null; + } + return new BlockNumberNotification(split[0], split[1]); + } +} diff --git a/sdk-service/src/main/java/org/fisco/bcos/sdk/service/model/BlockNumberNotification.java b/sdk-service/src/main/java/org/fisco/bcos/sdk/service/model/BlockNumberNotification.java new file mode 100644 index 000000000..63f510ede --- /dev/null +++ b/sdk-service/src/main/java/org/fisco/bcos/sdk/service/model/BlockNumberNotification.java @@ -0,0 +1,73 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.service.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Objects; + +public class BlockNumberNotification { + private String blockNumber; + + @JsonProperty("groupID") + private String groupId; + + public BlockNumberNotification() {} + + public BlockNumberNotification(String groupId, String blockNumber) { + this.groupId = groupId; + this.blockNumber = blockNumber; + } + + public String getBlockNumber() { + return blockNumber; + } + + public void setBlockNumber(String blockNumber) { + this.blockNumber = blockNumber; + } + + public String getGroupId() { + return groupId; + } + + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BlockNumberNotification that = (BlockNumberNotification) o; + return Objects.equals(blockNumber, that.blockNumber) + && Objects.equals(groupId, that.groupId); + } + + @Override + public int hashCode() { + return Objects.hash(blockNumber, groupId); + } + + @Override + public String toString() { + return "BlockNumberNotification{" + + "blockNumber='" + + blockNumber + + '\'' + + ", groupId='" + + groupId + + '\'' + + '}'; + } +} diff --git a/sdk-service/src/test/java/org/fisco/bcos/sdk/client/ResponseTest.java b/sdk-service/src/test/java/org/fisco/bcos/sdk/client/ResponseTest.java new file mode 100644 index 000000000..d631989a7 --- /dev/null +++ b/sdk-service/src/test/java/org/fisco/bcos/sdk/client/ResponseTest.java @@ -0,0 +1,1416 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.test.client; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.List; +import org.fisco.bcos.sdk.client.protocol.model.GroupStatus; +import org.fisco.bcos.sdk.client.protocol.response.BcosBlock; +import org.fisco.bcos.sdk.client.protocol.response.BcosBlockHeader; +import org.fisco.bcos.sdk.client.protocol.response.BcosTransaction; +import org.fisco.bcos.sdk.client.protocol.response.BcosTransactionReceipt; +import org.fisco.bcos.sdk.client.protocol.response.BlockHash; +import org.fisco.bcos.sdk.client.protocol.response.BlockNumber; +import org.fisco.bcos.sdk.client.protocol.response.Call; +import org.fisco.bcos.sdk.client.protocol.response.Code; +import org.fisco.bcos.sdk.client.protocol.response.ConsensusStatus; +import org.fisco.bcos.sdk.client.protocol.response.GenerateGroup; +import org.fisco.bcos.sdk.client.protocol.response.GroupList; +import org.fisco.bcos.sdk.client.protocol.response.GroupPeers; +import org.fisco.bcos.sdk.client.protocol.response.NodeIDList; +import org.fisco.bcos.sdk.client.protocol.response.ObserverList; +import org.fisco.bcos.sdk.client.protocol.response.PbftView; +import org.fisco.bcos.sdk.client.protocol.response.Peers; +import org.fisco.bcos.sdk.client.protocol.response.PendingTransactions; +import org.fisco.bcos.sdk.client.protocol.response.PendingTxSize; +import org.fisco.bcos.sdk.client.protocol.response.RecoverGroup; +import org.fisco.bcos.sdk.client.protocol.response.SealerList; +import org.fisco.bcos.sdk.client.protocol.response.SendTransaction; +import org.fisco.bcos.sdk.client.protocol.response.StartGroup; +import org.fisco.bcos.sdk.client.protocol.response.StopGroup; +import org.fisco.bcos.sdk.client.protocol.response.SyncStatus; +import org.fisco.bcos.sdk.client.protocol.response.SystemConfig; +import org.fisco.bcos.sdk.client.protocol.response.TotalTransactionCount; +import org.fisco.bcos.sdk.client.protocol.response.TransactionReceiptWithProof; +import org.fisco.bcos.sdk.client.protocol.response.TransactionWithProof; +import org.fisco.bcos.sdk.model.NodeVersion; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; +import org.junit.Assert; +import org.junit.Test; + +public class ResponseTest { + private static ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(); + + @Test + public void testBlockHeaderResponse() { + String blockHeaderString = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": {\n" + + " \"dbHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n" + + " \"extraData\": [],\n" + + " \"gasLimit\": \"0x100\",\n" + + " \"gasUsed\": \"0x200\",\n" + + " \"hash\": \"0xc558dd020df46dd3c2753dc8e1f85b79bf7849005dd4b84e3c8b5c1f6f642a82\",\n" + + " \"logsBloom\": \"0x0000abc123\",\n" + + " \"number\": 1,\n" + + " \"parentHash\": \"0x3d161a0302bb05d97d68e129c552a83f171e673d0b6b866c1f687c3da98d9a08\",\n" + + " \"receiptsRoot\": \"0x69a04fa6073e4fc0947bac7ee6990e788d1e2c5ec0fe6c2436d0892e7f3c09d2\",\n" + + " \"sealer\": \"0x3\",\n" + + " \"sealerList\": [\n" + + " \"11e1be251ca08bb44f36fdeedfaeca40894ff80dfd80084607a75509edeaf2a9c6fee914f1e9efda571611cf4575a1577957edfd2baa9386bd63eb034868625f\",\n" + + " \"b8acb51b9fe84f88d670646be36f31c52e67544ce56faf3dc8ea4cf1b0ebff0864c6b218fdcd9cf9891ebd414a995847911bd26a770f429300085f37e1131f36\"\n" + + " ],\n" + + " \"signatureList\": [\n" + + " {\n" + + " \"index\": \"0x0\",\n" + + " \"signature\": \"0x2e491c54f75c3b501745e1b2c92898f9434751326a17e4bcd37b93d5930405e14a461cff9ea7857da33fbf8b5ae6450ff0e281953553193aefb298b66d45b38401\"\n" + + " },\n" + + " {\n" + + " \"index\": \"0x3\",\n" + + " \"signature\": \"0x5cf59da9e2f580f0b62f8a43f0debe85a209a1c0e3bf66da58913841cb0daf50439baf9807c63a2cebcbac72a5ba679447a9101e39f7c08f1634ca5c99da970c01\"\n" + + " }\n" + + " ],\n" + + " \"stateRoot\": \"0x000000000000000000000000000000000000000000000000000c000000000000\",\n" + + " \"timestamp\": \"0x1736f190efb\",\n" + + " \"transactionsRootCopyed\": \"0x9eec1be2effb2d7934928d4ccab1bd2886b920b1cf29f8744e3be1d253102cd7\",\n" + + " \"transactionsRoot\": \"0x9eec1be2effb2d7934928d4ccab1bd2886b920b1cf29f8744e3be1d253102cd7\"\n" + + " }\n" + + "}"; + try { + // decode the block header + BcosBlockHeader blockHeader = + objectMapper.readValue(blockHeaderString.getBytes(), BcosBlockHeader.class); + // check the value field of the blockHeader + Assert.assertEquals("2.0", blockHeader.getJsonrpc()); + Assert.assertEquals(1, blockHeader.getId()); + Assert.assertEquals(BigInteger.valueOf(1), blockHeader.getBlockHeader().getNumber()); + Assert.assertEquals( + "0xc558dd020df46dd3c2753dc8e1f85b79bf7849005dd4b84e3c8b5c1f6f642a82", + blockHeader.getBlockHeader().getHash()); + Assert.assertEquals("0x0000abc123", blockHeader.getBlockHeader().getLogsBloom()); + Assert.assertEquals( + "0x9eec1be2effb2d7934928d4ccab1bd2886b920b1cf29f8744e3be1d253102cd7", + blockHeader.getBlockHeader().getTransactionsRoot()); + Assert.assertEquals("0x1736f190efb", blockHeader.getBlockHeader().getTimestamp()); + Assert.assertEquals( + "11e1be251ca08bb44f36fdeedfaeca40894ff80dfd80084607a75509edeaf2a9c6fee914f1e9efda571611cf4575a1577957edfd2baa9386bd63eb034868625f", + blockHeader.getBlockHeader().getSealerList().get(0)); + Assert.assertEquals( + "0x2e491c54f75c3b501745e1b2c92898f9434751326a17e4bcd37b93d5930405e14a461cff9ea7857da33fbf8b5ae6450ff0e281953553193aefb298b66d45b38401", + blockHeader.getBlockHeader().getSignatureList().get(0).getSignature()); + Assert.assertEquals( + "0x3", blockHeader.getBlockHeader().getSignatureList().get(1).getIndex()); + Assert.assertEquals("0x3", blockHeader.getBlockHeader().getSealer()); + Assert.assertEquals( + "0x3d161a0302bb05d97d68e129c552a83f171e673d0b6b866c1f687c3da98d9a08", + blockHeader.getBlockHeader().getParentHash()); + Assert.assertEquals( + "0x69a04fa6073e4fc0947bac7ee6990e788d1e2c5ec0fe6c2436d0892e7f3c09d2", + blockHeader.getBlockHeader().getReceiptsRoot()); + Assert.assertEquals("0x100", blockHeader.getBlockHeader().getGasLimit()); + Assert.assertEquals("0x200", blockHeader.getBlockHeader().getGasUsed()); + Assert.assertEquals( + "0x000000000000000000000000000000000000000000000000000c000000000000", + blockHeader.getBlockHeader().getStateRoot()); + Assert.assertEquals(2, blockHeader.getBlockHeader().getSignatureList().size()); + + // encode the block header + byte[] encodedData = objectMapper.writeValueAsBytes(blockHeader); + // decode the encoded block header + BcosBlockHeader decodedBlockHeader = + objectMapper.readValue(encodedData, BcosBlockHeader.class); + + // check decodedBlockHeader and blockHeader + Assert.assertEquals(blockHeader.getBlockHeader(), decodedBlockHeader.getBlockHeader()); + Assert.assertEquals( + blockHeader.getBlockHeader().hashCode(), + decodedBlockHeader.getBlockHeader().hashCode()); + } catch (JsonParseException e) { + e.printStackTrace(); + } catch (JsonMappingException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Test + public void testTransacation() throws IOException { + String transactionString = + "{\n" + + " \"id\": 100,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": {\n" + + " \"blockHash\": \"0xc558dd020df46dd3c2753dc8e1f85b79bf7849005dd4b84e3c8b5c1f6f642a82\",\n" + + " \"blockNumber\": \"0x1001\",\n" + + " \"from\": \"0x2d6300a8f067872ebc87252d711b83a0c9325d35\",\n" + + " \"gas\": \"0x2faf080\",\n" + + " \"gasPrice\": \"0xa\",\n" + + " \"hash\": \"0x83ae369e15e1aafb18df7da2ff30de009bf53a1ff72ced3d1c342182409c4f87\",\n" + + " \"input\": \"0x4ed3885e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a464953434f2042434f5300000000000000000000000000000000000000000000\",\n" + + " \"nonce\": \"0x3eb675ec791c2d19858c91d0046821c27d815e2e9c151595296779000016038\",\n" + + " \"to\": \"0x8c17cf316c1063ab6c89df875e96c9f0f5b2f744\",\n" + + " \"transactionIndex\": \"0x199\",\n" + + " \"value\": \"0x010\"\n" + + " }\n" + + "}"; + // decode the BcosTransaction object from the given string + BcosTransaction transaction = + objectMapper.readValue(transactionString.getBytes(), BcosTransaction.class); + Assert.assertEquals("2.0", transaction.getJsonrpc()); + Assert.assertEquals(100, transaction.getId()); + Assert.assertEquals(null, transaction.getError()); + Assert.assertEquals( + "0xc558dd020df46dd3c2753dc8e1f85b79bf7849005dd4b84e3c8b5c1f6f642a82", + transaction.getTransaction().get().getBlockHash()); + Assert.assertEquals( + BigInteger.valueOf(0x1001), transaction.getTransaction().get().getBlockNumber()); + Assert.assertEquals( + "0x2d6300a8f067872ebc87252d711b83a0c9325d35", + transaction.getTransaction().get().getFrom()); + Assert.assertEquals("0x2faf080", transaction.getTransaction().get().getGas()); + Assert.assertEquals("0xa", transaction.getTransaction().get().getGasPrice()); + Assert.assertEquals( + "0x83ae369e15e1aafb18df7da2ff30de009bf53a1ff72ced3d1c342182409c4f87", + transaction.getTransaction().get().getHash()); + Assert.assertEquals( + "0x4ed3885e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a464953434f2042434f5300000000000000000000000000000000000000000000", + transaction.getTransaction().get().getInput()); + Assert.assertEquals( + "0x3eb675ec791c2d19858c91d0046821c27d815e2e9c151595296779000016038", + transaction.getTransaction().get().getNonce()); + Assert.assertEquals( + "0x8c17cf316c1063ab6c89df875e96c9f0f5b2f744", + transaction.getTransaction().get().getTo()); + Assert.assertEquals("0x199", transaction.getTransaction().get().getTransactionIndex()); + Assert.assertEquals("0x010", transaction.getTransaction().get().getValue()); + + // encode the transaction + byte[] encodedData = objectMapper.writeValueAsBytes(transaction); + // decode the transaction + BcosTransaction decodedTransaction = + objectMapper.readValue(encodedData, BcosTransaction.class); + + // check `hashCode` and `equals` + Assert.assertEquals( + transaction.getTransaction().get(), decodedTransaction.getTransaction().get()); + Assert.assertEquals( + transaction.getTransaction().get().hashCode(), + decodedTransaction.getTransaction().get().hashCode()); + } + + @Test + public void testBcosBlockWithTransaction() throws IOException { + String blockString = + "{\n" + + " \"id\": 10001,\n" + + " \"jsonrpc\": \"3.0\",\n" + + " \"result\": {\n" + + " \"dbHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n" + + " \"extraData\": [],\n" + + " \"gasLimit\": \"0x0\",\n" + + " \"gasUsed\": \"0x0\",\n" + + " \"hash\": \"0xc558dd020df46dd3c2753dc8e1f85b79bf7849005dd4b84e3c8b5c1f6f642a82\",\n" + + " \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n" + + " \"number\": \"0x100\",\n" + + " \"parentHash\": \"0x3d161a0302bb05d97d68e129c552a83f171e673d0b6b866c1f687c3da98d9a08\",\n" + + " \"receiptsRoot\": \"0x69a04fa6073e4fc0947bac7ee6990e788d1e2c5ec0fe6c2436d0892e7f3c09d2\",\n" + + " \"sealer\": \"0x4\",\n" + + " \"sealerList\": [\n" + + " \"11e1be251ca08bb44f36fdeedfaeca40894ff80dfd80084607a75509edeaf2a9c6fee914f1e9efda571611cf4575a1577957edfd2baa9386bd63eb034868625f\",\n" + + " \"b8acb51b9fe84f88d670646be36f31c52e67544ce56faf3dc8ea4cf1b0ebff0864c6b218fdcd9cf9891ebd414a995847911bd26a770f429300085f37e1131f36\"\n" + + " ],\n" + + " \"stateRoot\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n" + + " \"timestamp\": \"0x1736f190efb\",\n" + + " \"transactions\": [\n" + + " {\n" + + " \"blockHash\": \"0xc558dd020df46dd3c2753dc8e1f85b79bf7849005dd4b84e3c8b5c1f6f642a82\",\n" + + " \"blockNumber\": \"0x100\",\n" + + " \"from\": \"0x2d6300a8f067872ebc87252d711b83a0c9325d35\",\n" + + " \"gas\": \"0x2faf080\",\n" + + " \"gasPrice\": \"0xa\",\n" + + " \"hash\": \"0x83ae369e15e1aafb18df7da2ff30de009bf53a1ff72ced3d1c342182409c4f87\",\n" + + " \"input\": \"0x4ed3885e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a464953434f2042434f5300000000000000000000000000000000000000000000\",\n" + + " \"nonce\": \"0x3eb675ec791c2d19858c91d0046821c27d815e2e9c151595296779000016038\",\n" + + " \"to\": \"0x8c17cf316c1063ab6c89df875e96c9f0f5b2f744\",\n" + + " \"transactionIndex\": \"0x0\",\n" + + " \"value\": \"0x0\"\n" + + " }\n" + + " ],\n" + + " \"transactionsRoot\": \"0x9eec1be2effb2d7934928d4ccab1bd2886b920b1cf29f8744e3be1d253102cd7\"\n" + + " }\n" + + " }"; + // encode the string into object + BcosBlock bcosBlock = objectMapper.readValue(blockString.getBytes(), BcosBlock.class); + checkBlockHeader(bcosBlock); + // check the transaction + checkTransactionsForBlock(bcosBlock); + checkEncodeDecode(bcosBlock); + } + + public void testBcosBlockWithoutTransaction() throws IOException { + String blockString = + "{\n" + + " \"id\": 10001,\n" + + " \"jsonrpc\": \"3.0\",\n" + + " \"result\": {\n" + + " \"dbHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n" + + " \"extraData\": [],\n" + + " \"gasLimit\": \"0x0\",\n" + + " \"gasUsed\": \"0x0\",\n" + + " \"hash\": \"0xc558dd020df46dd3c2753dc8e1f85b79bf7849005dd4b84e3c8b5c1f6f642a82\",\n" + + " \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n" + + " \"number\": \"0x100\",\n" + + " \"parentHash\": \"0x3d161a0302bb05d97d68e129c552a83f171e673d0b6b866c1f687c3da98d9a08\",\n" + + " \"receiptsRoot\": \"0x69a04fa6073e4fc0947bac7ee6990e788d1e2c5ec0fe6c2436d0892e7f3c09d2\",\n" + + " \"sealer\": \"0x4\",\n" + + " \"sealerList\": [\n" + + " \"11e1be251ca08bb44f36fdeedfaeca40894ff80dfd80084607a75509edeaf2a9c6fee914f1e9efda571611cf4575a1577957edfd2baa9386bd63eb034868625f\",\n" + + " \"b8acb51b9fe84f88d670646be36f31c52e67544ce56faf3dc8ea4cf1b0ebff0864c6b218fdcd9cf9891ebd414a995847911bd26a770f429300085f37e1131f36\"\n" + + " ],\n" + + " \"stateRoot\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n" + + " \"timestamp\": \"0x1736f190efb\",\n" + + " \"transactions\": [ \n" + + " \"0x19e5f919888038fcb16c7d75bb86945e1bf6349c591d33e3b5fdcda973577875\" \n" + + " ],\n" + + " \"transactionsRoot\": \"0x9eec1be2effb2d7934928d4ccab1bd2886b920b1cf29f8744e3be1d253102cd7\"\n" + + " }\n" + + " }"; + BcosBlock bcosBlock = objectMapper.readValue(blockString.getBytes(), BcosBlock.class); + checkBlockHeader(bcosBlock); + // check transaction + BcosBlock.TransactionHash transactionHash = + ((BcosBlock.TransactionHash) bcosBlock.getBlock().getTransactions().get(0)); + // check the transactionHash + Assert.assertEquals( + "0x19e5f919888038fcb16c7d75bb86945e1bf6349c591d33e3b5fdcda973577875", + transactionHash); + checkEncodeDecode(bcosBlock); + } + + private void checkEncodeDecode(BcosBlock bcosBlock) throws IOException { + // encode the block + byte[] encodedData = objectMapper.writeValueAsBytes(bcosBlock); + // decode the block + BcosBlock decodedBlock = objectMapper.readValue(encodedData, BcosBlock.class); + // check the block + Assert.assertEquals(bcosBlock.getBlock(), decodedBlock.getBlock()); + Assert.assertEquals(bcosBlock.getBlock().hashCode(), decodedBlock.getBlock().hashCode()); + } + + private void checkBlockHeader(BcosBlock bcosBlock) { + // check the BcosBlock object + Assert.assertEquals("3.0", bcosBlock.getJsonrpc()); + Assert.assertEquals(10001, bcosBlock.getId()); + Assert.assertEquals(BigInteger.valueOf(0x100), bcosBlock.getBlock().getNumber()); + Assert.assertEquals( + "0xc558dd020df46dd3c2753dc8e1f85b79bf7849005dd4b84e3c8b5c1f6f642a82", + bcosBlock.getBlock().getHash()); + Assert.assertEquals( + "0x3d161a0302bb05d97d68e129c552a83f171e673d0b6b866c1f687c3da98d9a08", + bcosBlock.getBlock().getParentHash()); + Assert.assertEquals( + "0x69a04fa6073e4fc0947bac7ee6990e788d1e2c5ec0fe6c2436d0892e7f3c09d2", + bcosBlock.getBlock().getReceiptsRoot()); + Assert.assertEquals(2, bcosBlock.getBlock().getSealerList().size()); + Assert.assertEquals( + "11e1be251ca08bb44f36fdeedfaeca40894ff80dfd80084607a75509edeaf2a9c6fee914f1e9efda571611cf4575a1577957edfd2baa9386bd63eb034868625f", + bcosBlock.getBlock().getSealerList().get(0)); + Assert.assertEquals("0x4", bcosBlock.getBlock().getSealer()); + Assert.assertEquals("0x1736f190efb", bcosBlock.getBlock().getTimestamp()); + Assert.assertEquals(0, bcosBlock.getBlock().getExtraData().size()); + } + + private void checkTransactionsForBlock(BcosBlock bcosBlock) { + Assert.assertEquals(1, bcosBlock.getBlock().getTransactions().size()); + BcosBlock.TransactionObject transaction = + ((BcosBlock.TransactionObject) bcosBlock.getBlock().getTransactions().get(0)); + Assert.assertEquals( + "0xc558dd020df46dd3c2753dc8e1f85b79bf7849005dd4b84e3c8b5c1f6f642a82", + transaction.getBlockHash()); + Assert.assertEquals(BigInteger.valueOf(0x100), transaction.getBlockNumber()); + Assert.assertEquals("0x2d6300a8f067872ebc87252d711b83a0c9325d35", transaction.getFrom()); + Assert.assertEquals("0x2faf080", transaction.getGas()); + Assert.assertEquals("0xa", transaction.getGasPrice()); + Assert.assertEquals( + "0x83ae369e15e1aafb18df7da2ff30de009bf53a1ff72ced3d1c342182409c4f87", + transaction.getHash()); + Assert.assertEquals( + "0x4ed3885e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a464953434f2042434f5300000000000000000000000000000000000000000000", + transaction.getInput()); + Assert.assertEquals( + "0x3eb675ec791c2d19858c91d0046821c27d815e2e9c151595296779000016038", + transaction.getNonce()); + Assert.assertEquals("0x8c17cf316c1063ab6c89df875e96c9f0f5b2f744", transaction.getTo()); + Assert.assertEquals("0x0", transaction.getTransactionIndex()); + Assert.assertEquals("0x0", transaction.getValue()); + } + + @Test + public void testBlockHash() throws IOException { + // test BlockHash + String blockHashString = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": \"0xc558dd020df46dd3c2753dc8e1f85b79bf7849005dd4b84e3c8b5c1f6f642a82\"\n" + + "}"; + BlockHash blockHash = objectMapper.readValue(blockHashString.getBytes(), BlockHash.class); + // check the blockHash + Assert.assertEquals( + "0xc558dd020df46dd3c2753dc8e1f85b79bf7849005dd4b84e3c8b5c1f6f642a82", + blockHash.getBlockHashByNumber()); + + // encode the blockHash + byte[] encodedData = objectMapper.writeValueAsBytes(blockHash); + BlockHash decodedBlockHash = objectMapper.readValue(encodedData, BlockHash.class); + Assert.assertEquals( + blockHash.getBlockHashByNumber(), decodedBlockHash.getBlockHashByNumber()); + Assert.assertEquals( + blockHash.getBlockHashByNumber().hashCode(), + decodedBlockHash.getBlockHashByNumber().hashCode()); + } + + @Test + public void testBlockNumber() throws IOException { + // test BlockNumber + String blockNumberString = + "{\n" + + " \"id\": 11,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": \"0x200\"\n" + + "}"; + BlockNumber blockNumber = + objectMapper.readValue(blockNumberString.getBytes(), BlockNumber.class); + Assert.assertEquals(BigInteger.valueOf(0x200), blockNumber.getBlockNumber()); + Assert.assertEquals("2.0", blockNumber.getJsonrpc()); + Assert.assertEquals(11, blockNumber.getId()); + + // encode the block number + byte[] encodedData = objectMapper.writeValueAsBytes(blockNumber); + BlockNumber decodedBlockNumber = objectMapper.readValue(encodedData, BlockNumber.class); + Assert.assertEquals(blockNumber.getBlockNumber(), decodedBlockNumber.getBlockNumber()); + Assert.assertEquals( + blockNumber.getBlockNumber().hashCode(), + decodedBlockNumber.getBlockNumber().hashCode()); + } + + @Test + public void testCall() throws IOException { + String callString = + "{\n" + + " \"id\": 102,\n" + + " \"jsonrpc\": \"3.0\",\n" + + " \"result\": {\n" + + " \"currentBlockNumber\": \"0xb\",\n" + + " \"output\": \"0x\",\n" + + " \"status\": \"0x0\"\n" + + " }\n" + + "}"; + Call callResult = objectMapper.readValue(callString.getBytes(), Call.class); + Assert.assertEquals("3.0", callResult.getJsonrpc()); + Assert.assertEquals(102, callResult.getId()); + // check callResult + Call.CallOutput callOutput = callResult.getCallResult(); + Assert.assertEquals(BigInteger.valueOf(0xb), callOutput.getCurrentBlockNumber()); + Assert.assertEquals("0x", callOutput.getOutput()); + Assert.assertEquals("0x0", callOutput.getStatus()); + + // encode the callResult + byte[] encodedData = objectMapper.writeValueAsBytes(callResult); + Call decodedCallResult = objectMapper.readValue(encodedData, Call.class); + Assert.assertEquals(callResult.getCallResult(), decodedCallResult.getCallResult()); + Assert.assertEquals( + callResult.getCallResult().hashCode(), + decodedCallResult.getCallResult().hashCode()); + } + + @Test + public void testGetCode() throws IOException { + String codeStr = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": \"0x60606040523415600b57fe5b5b60928061001a6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636d4ce63c14603a575bfe5b3415604157fe5b6047605d565b6040518082815260200191505060405180910390f35b60004290505b905600a165627a7a723058203d9c292921247163d180a161baa8db840c9da6764cab1d23f1e11a5cff13c7910029\"\n" + + "}"; + Code code = objectMapper.readValue(codeStr.getBytes(), Code.class); + Assert.assertEquals("2.0", code.getJsonrpc()); + Assert.assertEquals(1, code.getId()); + // check result + Assert.assertEquals( + "0x60606040523415600b57fe5b5b60928061001a6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636d4ce63c14603a575bfe5b3415604157fe5b6047605d565b6040518082815260200191505060405180910390f35b60004290505b905600a165627a7a723058203d9c292921247163d180a161baa8db840c9da6764cab1d23f1e11a5cff13c7910029", + code.getCode()); + // encode the code + byte[] encodedData = objectMapper.writeValueAsBytes(code); + Code decodedCode = objectMapper.readValue(encodedData, Code.class); + Assert.assertEquals(code.getCode(), decodedCode.getCode()); + Assert.assertEquals(code.getCode().hashCode(), decodedCode.getCode().hashCode()); + } + + @Test + public void testPBFTConsensusStatus() throws IOException { + String pbftConsensusStatusString = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": [\n" + + " {\n" + + " \"accountType\": 1,\n" + + " \"allowFutureBlocks\": true,\n" + + " \"cfgErr\": false,\n" + + " \"connectedNodes\": 3,\n" + + " \"consensusedBlockNumber\": 38207,\n" + + " \"currentView\": 54477,\n" + + " \"groupId\": 1,\n" + + " \"highestblockHash\": \"0x19a16e8833e671aa11431de589c866a6442ca6c8548ba40a44f50889cd785069\",\n" + + " \"highestblockNumber\": 38206,\n" + + " \"leaderFailed\": false,\n" + + " \"max_faulty_leader\": 1,\n" + + " \"nodeId\": \"f72648fe165da17a889bece08ca0e57862cb979c4e3661d6a77bcc2de85cb766af5d299fec8a4337eedd142dca026abc2def632f6e456f80230902f93e2bea13\",\n" + + " \"nodeNum\": 4,\n" + + " \"node_index\": 3,\n" + + " \"omitEmptyBlock\": true,\n" + + " \"protocolId\": 65544,\n" + + " \"sealer.0\": \"6a99f357ecf8a001e03b68aba66f68398ee08f3ce0f0147e777ec77995369aac470b8c9f0f85f91ebb58a98475764b7ca1be8e37637dd6cb80b3355749636a3d\",\n" + + " \"sealer.1\": \"8a453f1328c80b908b2d02ba25adca6341b16b16846d84f903c4f4912728c6aae1050ce4f24cd9c13e010ce922d3393b846f6f5c42f6af59c65a814de733afe4\",\n" + + " \"sealer.2\": \"ed483837e73ee1b56073b178f5ac0896fa328fc0ed418ae3e268d9e9109721421ec48d68f28d6525642868b40dd26555c9148dbb8f4334ca071115925132889c\",\n" + + " \"sealer.3\": \"f72648fe165da17a889bece08ca0e57862cb979c4e3661d6a77bcc2de85cb766af5d299fec8a4337eedd142dca026abc2def632f6e456f80230902f93e2bea13\",\n" + + " \"toView\": 54477\n" + + " },\n" + + " [\n" + + " {\n" + + " \"nodeId\": \"6a99f357ecf8a001e03b68aba66f68398ee08f3ce0f0147e777ec77995369aac470b8c9f0f85f91ebb58a98475764b7ca1be8e37637dd6cb80b3355749636a3d\",\n" + + " \"view\": 54474\n" + + " },\n" + + " {\n" + + " \"nodeId\": \"8a453f1328c80b908b2d02ba25adca6341b16b16846d84f903c4f4912728c6aae1050ce4f24cd9c13e010ce922d3393b846f6f5c42f6af59c65a814de733afe4\",\n" + + " \"view\": 54475\n" + + " },\n" + + " {\n" + + " \"nodeId\": \"ed483837e73ee1b56073b178f5ac0896fa328fc0ed418ae3e268d9e9109721421ec48d68f28d6525642868b40dd26555c9148dbb8f4334ca071115925132889c\",\n" + + " \"view\": 54476\n" + + " },\n" + + " {\n" + + " \"nodeId\": \"f72648fe165da17a889bece08ca0e57862cb979c4e3661d6a77bcc2de85cb766af5d299fec8a4337eedd142dca026abc2def632f6e456f80230902f93e2bea13\",\n" + + " \"view\": 54477\n" + + " }\n" + + " ]\n" + + " ]\n" + + "}"; + ConsensusStatus status = + objectMapper.readValue(pbftConsensusStatusString.getBytes(), ConsensusStatus.class); + Assert.assertEquals("2.0", status.getJsonrpc()); + Assert.assertEquals(1, status.getId()); + ConsensusStatus.BasicConsensusInfo basicConsensusInfo = + status.getConsensusStatus().getBaseConsensusInfo(); + Assert.assertEquals( + "6a99f357ecf8a001e03b68aba66f68398ee08f3ce0f0147e777ec77995369aac470b8c9f0f85f91ebb58a98475764b7ca1be8e37637dd6cb80b3355749636a3d", + basicConsensusInfo.getSealerList().get(0).toString()); + Assert.assertEquals("1", basicConsensusInfo.getAccountType()); + Assert.assertEquals("4", basicConsensusInfo.getNodeNum()); + Assert.assertEquals(4, basicConsensusInfo.getSealerList().size()); + Assert.assertEquals( + "f72648fe165da17a889bece08ca0e57862cb979c4e3661d6a77bcc2de85cb766af5d299fec8a4337eedd142dca026abc2def632f6e456f80230902f93e2bea13", + basicConsensusInfo.getNodeId()); + Assert.assertEquals("54477", basicConsensusInfo.getCurrentView()); + Assert.assertEquals("1", basicConsensusInfo.getGroupId()); + Assert.assertEquals("38206", basicConsensusInfo.getHighestblockNumber()); + Assert.assertEquals( + "0x19a16e8833e671aa11431de589c866a6442ca6c8548ba40a44f50889cd785069", + basicConsensusInfo.getHighestblockHash()); + Assert.assertEquals("38206", basicConsensusInfo.getHighestblockNumber()); + Assert.assertEquals("false", basicConsensusInfo.getLeaderFailed()); + Assert.assertEquals("1", basicConsensusInfo.getMaxFaultyNodeNum()); + Assert.assertEquals("3", basicConsensusInfo.getNodeIndex()); + Assert.assertEquals("true", basicConsensusInfo.getOmitEmptyBlock()); + Assert.assertEquals("65544", basicConsensusInfo.getProtocolId()); + Assert.assertEquals("54477", basicConsensusInfo.getToView()); + + // check ViewInfo + List viewInfoList = status.getConsensusStatus().getViewInfos(); + Assert.assertEquals(4, viewInfoList.size()); + Assert.assertEquals( + "6a99f357ecf8a001e03b68aba66f68398ee08f3ce0f0147e777ec77995369aac470b8c9f0f85f91ebb58a98475764b7ca1be8e37637dd6cb80b3355749636a3d", + viewInfoList.get(0).getNodeId()); + Assert.assertEquals("54474", viewInfoList.get(0).getView()); + Assert.assertEquals("54475", viewInfoList.get(1).getView()); + Assert.assertEquals("54476", viewInfoList.get(2).getView()); + Assert.assertEquals("54477", viewInfoList.get(3).getView()); + + ConsensusStatus status2 = + objectMapper.readValue(pbftConsensusStatusString.getBytes(), ConsensusStatus.class); + Assert.assertEquals(status.getConsensusStatus(), status2.getConsensusStatus()); + Assert.assertEquals( + status.getConsensusStatus().hashCode(), status2.getConsensusStatus().hashCode()); + } + + @Test + public void testRaftConsensusStatus() throws IOException { + String raftConsenusStatus = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": [\n" + + " {\n" + + " \"accountType\": 1,\n" + + " \"allowFutureBlocks\": true,\n" + + " \"cfgErr\": false,\n" + + " \"consensusedBlockNumber\": 1,\n" + + " \"groupId\": 1,\n" + + " \"highestblockHash\": \"0x4765a126a9de8d876b87f01119208be507ec28495bef09c1e30a8ab240cf00f2\",\n" + + " \"highestblockNumber\": 0,\n" + + " \"leaderId\": \"d5b3a9782c6aca271c9642aea391415d8b258e3a6d92082e59cc5b813ca123745440792ae0b29f4962df568f8ad58b75fc7cea495684988e26803c9c5198f3f8\",\n" + + " \"leaderIdx\": 3,\n" + + " \"max_faulty_leader\": 1,\n" + + " \"sealer.0\": \"29c34347a190c1ec0c4507c6eed6a5bcd4d7a8f9f54ef26da616e81185c0af11a8cea4eacb74cf6f61820292b24bc5d9e426af24beda06fbd71c217960c0dff0\",\n" + + " \"sealer.1\": \"41285429582cbfe6eed501806391d2825894b3696f801e945176c7eb2379a1ecf03b36b027d72f480e89d15bacd43462d87efd09fb0549e0897f850f9eca82ba\",\n" + + " \"sealer.2\": \"87774114e4a496c68f2482b30d221fa2f7b5278876da72f3d0a75695b81e2591c1939fc0d3fadb15cc359c997bafc9ea6fc37345346acaf40b6042b5831c97e1\",\n" + + " \"sealer.3\": \"d5b3a9782c6aca271c9642aea391415d8b258e3a6d92082e59cc5b813ca123745440792ae0b29f4962df568f8ad58b75fc7cea495684988e26803c9c5198f3f8\",\n" + + " \"node index\": 1,\n" + + " \"nodeId\": \"41285429582cbfe6eed501806391d2825894b3696f801e945176c7eb2379a1ecf03b36b027d72f480e89d15bacd43462d87efd09fb0549e0897f850f9eca82ba\",\n" + + " \"nodeNum\": 4,\n" + + " \"omitEmptyBlock\": true,\n" + + " \"protocolId\": 267\n" + + " }\n" + + " ]\n" + + "}"; + ConsensusStatus status = + objectMapper.readValue(raftConsenusStatus.getBytes(), ConsensusStatus.class); + ConsensusStatus.BasicConsensusInfo basicConsensusInfo = + status.getConsensusStatus().getBaseConsensusInfo(); + Assert.assertEquals("1", basicConsensusInfo.getAccountType()); + Assert.assertEquals("true", basicConsensusInfo.getAllowFutureBlocks()); + Assert.assertEquals( + "d5b3a9782c6aca271c9642aea391415d8b258e3a6d92082e59cc5b813ca123745440792ae0b29f4962df568f8ad58b75fc7cea495684988e26803c9c5198f3f8", + basicConsensusInfo.getLeaderId()); + Assert.assertEquals("3", basicConsensusInfo.getLeaderIdx()); + Assert.assertEquals("267", basicConsensusInfo.getProtocolId()); + Assert.assertEquals(4, basicConsensusInfo.getSealerList().size()); + Assert.assertEquals("1", basicConsensusInfo.getMaxFaultyNodeNum()); + Assert.assertEquals("1", basicConsensusInfo.getRaftNodeIndex()); + Assert.assertEquals(null, status.getConsensusStatus().getViewInfos()); + } + + @Test + public void testGroupStatus() throws IOException { + String groupStatusStr = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": {\n" + + " \"code\": \"0x0\",\n" + + " \"message\": \"\",\n" + + " \"status\": \"STOPPED\"\n" + + " }\n" + + "}"; + // test generateGropu + GroupStatus groupStatus = + objectMapper + .readValue(groupStatusStr.getBytes(), GenerateGroup.class) + .getGroupStatus(); + checkGroupStatus(groupStatus, "0x0", "", "STOPPED"); + + groupStatus = + objectMapper + .readValue(groupStatusStr.getBytes(), StartGroup.class) + .getGroupStatus(); + checkGroupStatus(groupStatus, "0x0", "", "STOPPED"); + + groupStatus = + objectMapper.readValue(groupStatusStr.getBytes(), StopGroup.class).getGroupStatus(); + checkGroupStatus(groupStatus, "0x0", "", "STOPPED"); + + groupStatus = + objectMapper + .readValue(groupStatusStr.getBytes(), RecoverGroup.class) + .getGroupStatus(); + checkGroupStatus(groupStatus, "0x0", "", "STOPPED"); + } + + private void checkGroupStatus( + GroupStatus status, String expectedCode, String expectedMsg, String expectedStatus) + throws IOException { + Assert.assertEquals(expectedCode, status.getCode()); + Assert.assertEquals(expectedMsg, status.getMessage()); + Assert.assertEquals(expectedStatus, status.getStatus()); + + // check encode/decode + byte[] encodedData = objectMapper.writeValueAsBytes(status); + GroupStatus decodedStatus = objectMapper.readValue(encodedData, GroupStatus.class); + Assert.assertEquals(status, decodedStatus); + Assert.assertEquals(status.hashCode(), decodedStatus.hashCode()); + } + + @Test + public void testGroupList() throws IOException { + String groupListStr = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": [1,2,3]\n" + + "}"; + GroupList groupList = objectMapper.readValue(groupListStr.getBytes(), GroupList.class); + Assert.assertEquals(3, groupList.getGroupList().size()); + List parsedGroupList = Arrays.asList("1", "2", "3"); + Assert.assertTrue(groupList.getGroupList().equals(parsedGroupList)); + + // encode + byte[] encodedBytes = objectMapper.writeValueAsBytes(groupList.getGroupList()); + List decodedGroupList = + objectMapper.readValue(encodedBytes, new TypeReference>() {}); + encodedBytes = objectMapper.writeValueAsBytes(decodedGroupList); + + Assert.assertEquals(groupList.getGroupList(), decodedGroupList); + Assert.assertEquals(groupList.getGroupList().hashCode(), decodedGroupList.hashCode()); + } + + @Test + public void testGroupPeers() throws IOException { + String groupPeersStr = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": [\n" + + " \"0c0bbd25152d40969d3d3cee3431fa28287e07cff2330df3258782d3008b876d146ddab97eab42796495bfbb281591febc2a0069dcc7dfe88c8831801c5b5801\",\n" + + " \"037c255c06161711b6234b8c0960a6979ef039374ccc8b723afea2107cba3432dbbc837a714b7da20111f74d5a24e91925c773a72158fa066f586055379a1772\",\n" + + " \"622af37b2bd29c60ae8f15d467b67c0a7fe5eb3e5c63fdc27a0ee8066707a25afa3aa0eb5a3b802d3a8e5e26de9d5af33806664554241a3de9385d3b448bcd73\",\n" + + " \"10b3a2d4b775ec7f3c2c9e8dc97fa52beb8caab9c34d026db9b95a72ac1d1c1ad551c67c2b7fdc34177857eada75836e69016d1f356c676a6e8b15c45fc9bc34\"\n" + + " ]\n" + + "}"; + GroupPeers groupPeers = objectMapper.readValue(groupPeersStr.getBytes(), GroupPeers.class); + Assert.assertEquals(4, groupPeers.getGroupPeers().size()); + Assert.assertEquals( + "0c0bbd25152d40969d3d3cee3431fa28287e07cff2330df3258782d3008b876d146ddab97eab42796495bfbb281591febc2a0069dcc7dfe88c8831801c5b5801", + groupPeers.getGroupPeers().get(0)); + Assert.assertEquals( + "10b3a2d4b775ec7f3c2c9e8dc97fa52beb8caab9c34d026db9b95a72ac1d1c1ad551c67c2b7fdc34177857eada75836e69016d1f356c676a6e8b15c45fc9bc34", + groupPeers.getGroupPeers().get(3)); + } + + @Test + public void testNodeIDList() throws IOException { + String nodeIdListStr = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": [\n" + + " \"0c0bbd25152d40969d3d3cee3431fa28287e07cff2330df3258782d3008b876d146ddab97eab42796495bfbb281591febc2a0069dcc7dfe88c8831801c5b5801\",\n" + + " \"037c255c06161711b6234b8c0960a6979ef039374ccc8b723afea2107cba3432dbbc837a714b7da20111f74d5a24e91925c773a72158fa066f586055379a1772\",\n" + + " \"622af37b2bd29c60ae8f15d467b67c0a7fe5eb3e5c63fdc27a0ee8066707a25afa3aa0eb5a3b802d3a8e5e26de9d5af33806664554241a3de9385d3b448bcd73\",\n" + + " \"10b3a2d4b775ec7f3c2c9e8dc97fa52beb8caab9c34d026db9b95a72ac1d1c1ad551c67c2b7fdc34177857eada75836e69016d1f356c676a6e8b15c45fc9bc34\"\n" + + " ]\n" + + "}"; + NodeIDList nodeIDList = objectMapper.readValue(nodeIdListStr.getBytes(), NodeIDList.class); + Assert.assertEquals(4, nodeIDList.getNodeIDList().size()); + Assert.assertEquals( + "0c0bbd25152d40969d3d3cee3431fa28287e07cff2330df3258782d3008b876d146ddab97eab42796495bfbb281591febc2a0069dcc7dfe88c8831801c5b5801", + nodeIDList.getNodeIDList().get(0)); + Assert.assertEquals( + "622af37b2bd29c60ae8f15d467b67c0a7fe5eb3e5c63fdc27a0ee8066707a25afa3aa0eb5a3b802d3a8e5e26de9d5af33806664554241a3de9385d3b448bcd73", + nodeIDList.getNodeIDList().get(2)); + } + + @Test + public void testNodeVersion() throws IOException { + String nodeVersionStr = + "{\n" + + " \"id\": 83,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": {\n" + + " \"Build Time\": \"20190106 20:49:10\",\n" + + " \"Build Type\": \"Linux/g++/RelWithDebInfo\",\n" + + " \"FISCO-BCOS Version\": \"2.0.0\",\n" + + " \"Git Branch\": \"master\",\n" + + " \"Git Commit Hash\": \"693a709ddab39965d9c39da0104836cfb4a72054\"\n" + + " }\n" + + "}\n"; + NodeVersion nodeVersion = + objectMapper.readValue(nodeVersionStr.getBytes(), NodeVersion.class); + Assert.assertEquals("20190106 20:49:10", nodeVersion.getNodeVersion().getBuildTime()); + Assert.assertEquals( + "Linux/g++/RelWithDebInfo", nodeVersion.getNodeVersion().getBuildType()); + Assert.assertEquals("2.0.0", nodeVersion.getNodeVersion().getVersion()); + Assert.assertEquals("master", nodeVersion.getNodeVersion().getGitBranch()); + Assert.assertEquals( + "693a709ddab39965d9c39da0104836cfb4a72054", + nodeVersion.getNodeVersion().getGitCommitHash()); + } + + @Test + public void testObserverList() throws IOException { + String observerListStr = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": [\n" + + " \"10b3a2d4b775ec7f3c2c9e8dc97fa52beb8caab9c34d026db9b95a72ac1d1c1ad551c67c2b7fdc34177857eada75836e69016d1f356c676a6e8b15c45fc9bc34\"\n" + + " ]\n" + + "}"; + + ObserverList observerList = + objectMapper.readValue(observerListStr.getBytes(), ObserverList.class); + Assert.assertEquals(1, observerList.getObserverList().size()); + Assert.assertEquals( + "10b3a2d4b775ec7f3c2c9e8dc97fa52beb8caab9c34d026db9b95a72ac1d1c1ad551c67c2b7fdc34177857eada75836e69016d1f356c676a6e8b15c45fc9bc34", + observerList.getObserverList().get(0)); + } + + @Test + public void testPbftView() throws IOException { + String pbftViewStr = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": \"0x1a0\"\n" + + "}"; + PbftView pbftView = objectMapper.readValue(pbftViewStr.getBytes(), PbftView.class); + Assert.assertEquals(BigInteger.valueOf(0x1a0), pbftView.getPbftView()); + } + + @Test + public void testPeers() throws IOException { + String peerStr = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": [\n" + + " {\n" + + " \"Agency\": \"agency\",\n" + + " \"IPAndPort\": \"127.0.0.1:51869\",\n" + + " \"Node\": \"node2\",\n" + + " \"NodeID\": \"78a313b426c3de3267d72b53c044fa9fe70c2a27a00af7fea4a549a7d65210ed90512fc92b6194c14766366d434235c794289d66deff0796f15228e0e14a9191\",\n" + + " \"Topic\": []\n" + + " },\n" + + " {\n" + + " \"Agency\": \"agency\",\n" + + " \"IPAndPort\": \"127.0.0.1:30303\",\n" + + " \"Node\": \"node3\",\n" + + " \"NodeID\": \"95b7ff064f91de76598f90bc059bec1834f0d9eeb0d05e1086d49af1f9c2f321062d011ee8b0df7644bd54c4f9ca3d8515a3129bbb9d0df8287c9fa69552887e\",\n" + + " \"Topic\": []\n" + + " },\n" + + " {\n" + + " \"Agency\": \"agency\",\n" + + " \"IPAndPort\": \"127.0.0.1:30301\",\n" + + " \"Node\": \"node1\",\n" + + " \"NodeID\": \"11e1be251ca08bb44f36fdeedfaeca40894ff80dfd80084607a75509edeaf2a9c6fee914f1e9efda571611cf4575a1577957edfd2baa9386bd63eb034868625f\",\n" + + " \"Topic\": []\n" + + " }\n" + + " ]\n" + + "}"; + Peers peers = objectMapper.readValue(peerStr.getBytes(), Peers.class); + Assert.assertEquals(3, peers.getPeers().size()); + Assert.assertEquals("127.0.0.1:51869", peers.getPeers().get(0).getIpAndPort()); + Assert.assertEquals( + "95b7ff064f91de76598f90bc059bec1834f0d9eeb0d05e1086d49af1f9c2f321062d011ee8b0df7644bd54c4f9ca3d8515a3129bbb9d0df8287c9fa69552887e", + peers.getPeers().get(1).getNodeID()); + Assert.assertTrue(peers.getPeers().get(0).getTopic().isEmpty()); + Assert.assertEquals("node1", peers.getPeers().get(2).getNode()); + Assert.assertEquals("agency", peers.getPeers().get(2).getAgency()); + } + + @Test + public void testPendingTransactions() throws IOException { + String pendingListStr = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": [\n" + + " {\n" + + " \"from\": \"0x6bc952a2e4db9c0c86a368d83e9df0c6ab481102\",\n" + + " \"gas\": \"0x9184e729fff\",\n" + + " \"gasPrice\": \"0x174876e7ff\",\n" + + " \"hash\": \"0x7536cf1286b5ce6c110cd4fea5c891467884240c9af366d678eb4191e1c31c6f\",\n" + + " \"input\": \"0x48f85bce000000000000000000000000000000000000000000000000000000000000001bf5bd8a9e7ba8b936ea704292ff4aaa5797bf671fdc8526dcd159f23c1f5a05f44e9fa862834dc7cb4541558f2b4961dc39eaaf0af7f7395028658d0e01b86a37\",\n" + + " \"nonce\": \"0x65f0d06e39dc3c08e32ac10a5070858962bc6c0f5760baca823f2d5582d03f\",\n" + + " \"to\": \"0xd6f1a71052366dbae2f7ab2d5d5845e77965cf0d\",\n" + + " \"value\": \"0x0\"\n" + + " }\n" + + " ]\n" + + "}"; + PendingTransactions pendingTransactions = + objectMapper.readValue(pendingListStr.getBytes(), PendingTransactions.class); + Assert.assertEquals(1, pendingTransactions.getPendingTransactions().size()); + Assert.assertEquals( + "0x7536cf1286b5ce6c110cd4fea5c891467884240c9af366d678eb4191e1c31c6f", + pendingTransactions.getPendingTransactions().get(0).getHash()); + Assert.assertEquals( + "0x48f85bce000000000000000000000000000000000000000000000000000000000000001bf5bd8a9e7ba8b936ea704292ff4aaa5797bf671fdc8526dcd159f23c1f5a05f44e9fa862834dc7cb4541558f2b4961dc39eaaf0af7f7395028658d0e01b86a37", + pendingTransactions.getPendingTransactions().get(0).getInput()); + Assert.assertEquals( + "0xd6f1a71052366dbae2f7ab2d5d5845e77965cf0d", + pendingTransactions.getPendingTransactions().get(0).getTo()); + Assert.assertEquals( + "0x6bc952a2e4db9c0c86a368d83e9df0c6ab481102", + pendingTransactions.getPendingTransactions().get(0).getFrom()); + } + + @Test + public void testPendingTxSize() throws IOException { + String pendingTxSizeStr = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": \"0x100\"\n" + + "}"; + PendingTxSize pendingTxSize = + objectMapper.readValue(pendingTxSizeStr.getBytes(), PendingTxSize.class); + Assert.assertEquals(BigInteger.valueOf(0x100), pendingTxSize.getPendingTxSize()); + } + + @Test + public void testSealerList() throws JsonProcessingException { + String sealerListStr = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": [\n" + + " \"037c255c06161711b6234b8c0960a6979ef039374ccc8b723afea2107cba3432dbbc837a714b7da20111f74d5a24e91925c773a72158fa066f586055379a1772\",\n" + + " \"0c0bbd25152d40969d3d3cee3431fa28287e07cff2330df3258782d3008b876d146ddab97eab42796495bfbb281591febc2a0069dcc7dfe88c8831801c5b5801\",\n" + + " \"622af37b2bd29c60ae8f15d467b67c0a7fe5eb3e5c63fdc27a0ee8066707a25afa3aa0eb5a3b802d3a8e5e26de9d5af33806664554241a3de9385d3b448bcd73\"\n" + + " ]\n" + + "}"; + SealerList sealerList = objectMapper.readValue(sealerListStr, SealerList.class); + Assert.assertEquals(3, sealerList.getSealerList().size()); + Assert.assertEquals( + "0c0bbd25152d40969d3d3cee3431fa28287e07cff2330df3258782d3008b876d146ddab97eab42796495bfbb281591febc2a0069dcc7dfe88c8831801c5b5801", + sealerList.getSealerList().get(1)); + Assert.assertEquals( + "037c255c06161711b6234b8c0960a6979ef039374ccc8b723afea2107cba3432dbbc837a714b7da20111f74d5a24e91925c773a72158fa066f586055379a1772", + sealerList.getSealerList().get(0)); + Assert.assertEquals( + "622af37b2bd29c60ae8f15d467b67c0a7fe5eb3e5c63fdc27a0ee8066707a25afa3aa0eb5a3b802d3a8e5e26de9d5af33806664554241a3de9385d3b448bcd73", + sealerList.getSealerList().get(2)); + } + + @Test + public void testSendTransaction() throws JsonProcessingException { + String sendRawTransactionStr = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": \"0x0accad4228274b0d78939f48149767883a6e99c95941baa950156e926f1c96ba\"\n" + + "}"; + SendTransaction sendTransaction = + objectMapper.readValue(sendRawTransactionStr, SendTransaction.class); + Assert.assertEquals( + "0x0accad4228274b0d78939f48149767883a6e99c95941baa950156e926f1c96ba", + sendTransaction.getTransactionHash()); + } + + @Test + public void testSyncStatus() throws JsonProcessingException { + String syncStatusStr = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": {\n" + + " \"blockNumber\": 100,\n" + + " \"genesisHash\": \"0x4765a126a9de8d876b87f01119208be507ec28495bef09c1e30a8ab240cf00f2\",\n" + + " \"isSyncing\": false,\n" + + " \"knownHighestNumber\":0,\n" + + " \"knownLatestHash\":\"0x4765a126a9de8d876b87f01119208be507ec28495bef09c1e30a8ab240cf00f2\",\n" + + " \"latestHash\": \"0x4765a126a9de8d876b87f01119208be507ec28495bef09c1e30a8ab240cf00f2\",\n" + + " \"nodeId\": \"41285429582cbfe6eed501806391d2825894b3696f801e945176c7eb2379a1ecf03b36b027d72f480e89d15bacd43462d87efd09fb0549e0897f850f9eca82ba\",\n" + + " \"peers\": [\n" + + " {\n" + + " \"blockNumber\": 0,\n" + + " \"genesisHash\": \"0x4765a126a9de8d876b87f01119208be507ec28495bef09c1e30a8ab240cf00f2\",\n" + + " \"latestHash\": \"0x4765a126a9de8d876b87f01119208be507ec28495bef09c1e30a8ab240cf00f2\",\n" + + " \"nodeId\": \"29c34347a190c1ec0c4507c6eed6a5bcd4d7a8f9f54ef26da616e81185c0af11a8cea4eacb74cf6f61820292b24bc5d9e426af24beda06fbd71c217960c0dff0\"\n" + + " },\n" + + " {\n" + + " \"blockNumber\": 0,\n" + + " \"genesisHash\": \"0x4765a126a9de8d876b87f01119208be507ec28495bef09c1e30a8ab240cf00f2\",\n" + + " \"latestHash\": \"0x4765a126a9de8d876b87f01119208be507ec28495bef09c1e30a8ab240cf00f2\",\n" + + " \"nodeId\": \"87774114e4a496c68f2482b30d221fa2f7b5278876da72f3d0a75695b81e2591c1939fc0d3fadb15cc359c997bafc9ea6fc37345346acaf40b6042b5831c97e1\"\n" + + " },\n" + + " {\n" + + " \"blockNumber\": 0,\n" + + " \"genesisHash\": \"0x4765a126a9de8d876b87f01119208be507ec28495bef09c1e30a8ab240cf00f2\",\n" + + " \"latestHash\": \"0x4765a126a9de8d876b87f01119208be507ec28495bef09c1e30a8ab240cf00f2\",\n" + + " \"nodeId\": \"d5b3a9782c6aca271c9642aea391415d8b258e3a6d92082e59cc5b813ca123745440792ae0b29f4962df568f8ad58b75fc7cea495684988e26803c9c5198f3f8\"\n" + + " }\n" + + " ],\n" + + " \"protocolId\": 265,\n" + + " \"txPoolSize\": \"0\"\n" + + " }\n" + + "}"; + SyncStatus syncStatus = objectMapper.readValue(syncStatusStr, SyncStatus.class); + Assert.assertEquals("100", syncStatus.getSyncStatus().getBlockNumber()); + Assert.assertEquals( + "0x4765a126a9de8d876b87f01119208be507ec28495bef09c1e30a8ab240cf00f2", + syncStatus.getSyncStatus().getGenesisHash()); + Assert.assertEquals("false", syncStatus.getSyncStatus().getIsSyncing()); + Assert.assertEquals("0", syncStatus.getSyncStatus().getKnownHighestNumber()); + Assert.assertEquals( + "0x4765a126a9de8d876b87f01119208be507ec28495bef09c1e30a8ab240cf00f2", + syncStatus.getSyncStatus().getKnownLatestHash()); + Assert.assertEquals( + "0x4765a126a9de8d876b87f01119208be507ec28495bef09c1e30a8ab240cf00f2", + syncStatus.getSyncStatus().getLatestHash()); + Assert.assertEquals( + "41285429582cbfe6eed501806391d2825894b3696f801e945176c7eb2379a1ecf03b36b027d72f480e89d15bacd43462d87efd09fb0549e0897f850f9eca82ba", + syncStatus.getSyncStatus().getNodeId()); + Assert.assertEquals("265", syncStatus.getSyncStatus().getProtocolId()); + Assert.assertEquals("0", syncStatus.getSyncStatus().getTxPoolSize()); + // check peers + Assert.assertEquals(3, syncStatus.getSyncStatus().getPeers().size()); + Assert.assertEquals("0", syncStatus.getSyncStatus().getPeers().get(2).getBlockNumber()); + Assert.assertEquals( + "0x4765a126a9de8d876b87f01119208be507ec28495bef09c1e30a8ab240cf00f2", + syncStatus.getSyncStatus().getPeers().get(2).getGenesisHash()); + Assert.assertEquals( + "0x4765a126a9de8d876b87f01119208be507ec28495bef09c1e30a8ab240cf00f2", + syncStatus.getSyncStatus().getPeers().get(2).getLatestHash()); + Assert.assertEquals( + "d5b3a9782c6aca271c9642aea391415d8b258e3a6d92082e59cc5b813ca123745440792ae0b29f4962df568f8ad58b75fc7cea495684988e26803c9c5198f3f8", + syncStatus.getSyncStatus().getPeers().get(2).getNodeId()); + } + + @Test + public void testSystemConfig() throws IOException { + String systemConfigStr = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": \"1000\"\n" + + "}"; + SystemConfig systemConfig = + objectMapper.readValue(systemConfigStr.getBytes(), SystemConfig.class); + Assert.assertEquals("1000", systemConfig.getSystemConfig().toString()); + } + + @Test + public void testTotalTransactionCount() throws JsonProcessingException { + String totalTxCountStr = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": {\n" + + " \"blockNumber\": \"0x1\",\n" + + " \"failedTxSum\": \"0x0\",\n" + + " \"txSum\": \"0x20\"\n" + + " }\n" + + "}"; + TotalTransactionCount txCount = + objectMapper.readValue(totalTxCountStr, TotalTransactionCount.class); + Assert.assertEquals("0x1", txCount.getTotalTransactionCount().getBlockNumber()); + Assert.assertEquals("0x0", txCount.getTotalTransactionCount().getFailedTxSum()); + Assert.assertEquals("0x20", txCount.getTotalTransactionCount().getTxSum()); + } + + @Test + public void testTransactionReceipt() throws JsonProcessingException { + String receiptStr = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": {\n" + + " \"blockHash\": \"0x977efec48c248ea4be87016446b40d7785d7b71b7d4e3aa0b103b9cf0f5fe19e\",\n" + + " \"blockNumber\": \"0xa\",\n" + + " \"contractAddress\": \"0x0000000000000000000000000000000000000000\",\n" + + " \"from\": \"0xcdcce60801c0a2e6bb534322c32ae528b9dec8d2\",\n" + + " \"gasUsed\": \"0x1fb8d\",\n" + + " \"input\": \"0xb602109a000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000203078313030303030303030303030303030303030303030303030303030303030000000000000000000000000000000000000000000000000000000000000000832303139303733300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002616100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000026262000000000000000000000000000000000000000000000000000000000000\",\n" + + " \"logs\": [ ],\n" + + " \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n" + + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n" + + " \"root\":\"0x38723a2e5e8a17aa7950dc008209944e898f69a7bd10a23c839d341e935fd5ca\",\n" + + " \"status\": \"0xc\",\n" + + " \"to\": \"0x15538acd403ac1b2ff09083c70d04856b8c0bdfd\",\n" + + " \"transactionHash\": \"0x708b5781b62166bd86e543217be6cd954fd815fd192b9a124ee9327580df8f3f\",\n" + + " \"transactionIndex\": \"0x10\"\n" + + " }\n" + + "}"; + BcosTransactionReceipt transactionReceipt = + objectMapper.readValue(receiptStr, BcosTransactionReceipt.class); + Assert.assertEquals( + "0x977efec48c248ea4be87016446b40d7785d7b71b7d4e3aa0b103b9cf0f5fe19e", + transactionReceipt.getTransactionReceipt().get().getBlockHash()); + Assert.assertEquals( + "0xa", transactionReceipt.getTransactionReceipt().get().getBlockNumber()); + Assert.assertEquals( + "0x0000000000000000000000000000000000000000", + transactionReceipt.getTransactionReceipt().get().getContractAddress()); + Assert.assertEquals( + "0xcdcce60801c0a2e6bb534322c32ae528b9dec8d2", + transactionReceipt.getTransactionReceipt().get().getFrom()); + Assert.assertEquals( + "0x1fb8d", transactionReceipt.getTransactionReceipt().get().getGasUsed()); + Assert.assertEquals( + "0xb602109a000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000203078313030303030303030303030303030303030303030303030303030303030000000000000000000000000000000000000000000000000000000000000000832303139303733300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002616100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000026262000000000000000000000000000000000000000000000000000000000000", + transactionReceipt.getTransactionReceipt().get().getInput()); + Assert.assertEquals(0, transactionReceipt.getTransactionReceipt().get().getLogs().size()); + Assert.assertEquals( + "0x0000000000000000000000000000000000000000000000000000000000000000", + transactionReceipt.getTransactionReceipt().get().getOutput()); + Assert.assertEquals( + "0x38723a2e5e8a17aa7950dc008209944e898f69a7bd10a23c839d341e935fd5ca", + transactionReceipt.getTransactionReceipt().get().getRoot()); + Assert.assertEquals("0xc", transactionReceipt.getTransactionReceipt().get().getStatus()); + Assert.assertEquals( + "0x15538acd403ac1b2ff09083c70d04856b8c0bdfd", + transactionReceipt.getTransactionReceipt().get().getTo()); + Assert.assertEquals( + "0x708b5781b62166bd86e543217be6cd954fd815fd192b9a124ee9327580df8f3f", + transactionReceipt.getTransactionReceipt().get().getTransactionHash()); + Assert.assertEquals( + "0x10", transactionReceipt.getTransactionReceipt().get().getTransactionIndex()); + } + + @Test + public void testTransactionReceiptWithProof() throws JsonProcessingException { + String receiptWithProofStr = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": {\n" + + " \"receiptProof\": [\n" + + " {\n" + + " \"left\": [\n" + + " \"3088b5c8f9d92a3411a911f35ff0119a02e8f8f04852cf2fdfaa659843eac6a3ad\",\n" + + " \"31170ac8fd555dc50e59050841da0d96e4c4bc7e6266e1c6865c08c3b2391801dd\"\n" + + " ],\n" + + " \"right\": [\n" + + " \"33c572c8f961e0c56689d641fcf274916857819769a74e6424c58659bf530e90e3\",\n" + + " \"341233933ea3d357b4fdd6b3d1ed732dcff15cfd54e527c93c15a4e0238585ed11\",\n" + + " \"351e7ba09965cce1cfb820aced1d37204b06d96a21c5c2cf36850ffc62cf1fc84c\",\n" + + " \"361f65633d9ae843d4d3679b255fd448546a7b531c0056e8161ea0adbf1af12c0f\",\n" + + " \"37744f6e0d320314536b230d28b2fd6ac90b0111fb1e3bf4a750689abc282d8589\",\n" + + " \"386e60d9daa0be9825019fcf3d08cdaf51a90dc62a22a6e11371f94a8e516679cc\",\n" + + " \"391ef2f2cee81f3561a9900d5333af18f59aa3cd14e70241b5e86305ba697bf5f2\",\n" + + " \"3ac9999d4f36d76c95c61761879eb9ec60b964a489527f5af844398ffaa8617f0d\",\n" + + " \"3b0039ce903e275170640f3a464ce2e1adc2a7caee41267c195469365074032401\",\n" + + " \"3ca53017502028a0cb5bbf6c47c4779f365138da6910ffcfebf9591b45b89abd48\",\n" + + " \"3de04fc8766a344bb73d3fe6360c61d036e2eeedfd9ecdb86a0498d7849ed591f0\",\n" + + " \"3e2fc73ee22c4986111423dd20e8db317a313c9df29fa5aa3090f27097ecc4e1a9\",\n" + + " \"3fa7d31ad5c6e7bba3f99f9efc03ed8dd97cb1504003c34ad6bde5a662481f00a0\"\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"left\": [\n" + + " \"cd46118c0e99be585ffcf50423630348dbc486e54e9d9293a6a8754020a68a92\",\n" + + " \"3be78209b3e3c83af3668ec3192b5bf232531323ef66b66de80a11f386270132\",\n" + + " \"bd3a11d74a3fd79b1e1ea17e45b76eda4d25f6a5ec7fc5f067ea0d086b1ce70f\"\n" + + " ],\n" + + " \"right\": [\n" + + " \"6a6cefef8b48e455287a8c8694b06f4f7cb7950017ab048d6e6bdd8029f9f8c9\",\n" + + " \"0a27c5ee02e618d919d228e6a754dc201d299c91c9e4420a48783bb6fcd09be5\"\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"left\": [],\n" + + " \"right\": []\n" + + " }\n" + + " ],\n" + + " \"transactionReceipt\": {\n" + + " \"blockHash\": \"0xcd31b05e466bce99460b1ed70d6069fdfbb15e6eef84e9b9e4534358edb3899a\",\n" + + " \"blockNumber\": \"0x5\",\n" + + " \"contractAddress\": \"0x0000000000000000000000000000000000000000\",\n" + + " \"from\": \"0x148947262ec5e21739fe3a931c29e8b84ee34a0f\",\n" + + " \"gasUsed\": \"0x21dc1b\",\n" + + " \"input\": \"0x8a42ebe90000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000000000000a3564646636663863653800000000000000000000000000000000000000000000\",\n" + + " \"logs\": [],\n" + + " \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n" + + " \"output\": \"0x\",\n" + + " \"root\": \"0xc3b4185963c78a4ca8eb90240e5cd95371d7217a9ce2bfa1149d53f79c73afbb\",\n" + + " \"status\": \"0x0\",\n" + + " \"to\": \"0xd6c8a04b8826b0a37c6d4aa0eaa8644d8e35b79f\",\n" + + " \"transactionHash\": \"0xd2c12e211315ef09dbad53407bc820d062780232841534954f9c23ab11d8ab4c\",\n" + + " \"transactionIndex\": \"0x32\"\n" + + " }\n" + + " }\n" + + "}"; + TransactionReceiptWithProof receiptWithProof = + objectMapper.readValue(receiptWithProofStr, TransactionReceiptWithProof.class); + Assert.assertEquals( + 3, receiptWithProof.getTransactionReceiptWithProof().getReceiptProof().size()); + Assert.assertEquals( + 2, + receiptWithProof + .getTransactionReceiptWithProof() + .getReceiptProof() + .get(0) + .getLeft() + .size()); + Assert.assertEquals( + 13, + receiptWithProof + .getTransactionReceiptWithProof() + .getReceiptProof() + .get(0) + .getRight() + .size()); + Assert.assertEquals( + 3, + receiptWithProof + .getTransactionReceiptWithProof() + .getReceiptProof() + .get(1) + .getLeft() + .size()); + Assert.assertEquals( + 2, + receiptWithProof + .getTransactionReceiptWithProof() + .getReceiptProof() + .get(1) + .getRight() + .size()); + Assert.assertEquals( + 0, + receiptWithProof + .getTransactionReceiptWithProof() + .getReceiptProof() + .get(2) + .getLeft() + .size()); + Assert.assertEquals( + 0, + receiptWithProof + .getTransactionReceiptWithProof() + .getReceiptProof() + .get(2) + .getRight() + .size()); + Assert.assertEquals( + "cd46118c0e99be585ffcf50423630348dbc486e54e9d9293a6a8754020a68a92", + receiptWithProof + .getTransactionReceiptWithProof() + .getReceiptProof() + .get(1) + .getLeft() + .get(0)); + Assert.assertEquals( + "6a6cefef8b48e455287a8c8694b06f4f7cb7950017ab048d6e6bdd8029f9f8c9", + receiptWithProof + .getTransactionReceiptWithProof() + .getReceiptProof() + .get(1) + .getRight() + .get(0)); + // check receipt + Assert.assertEquals( + "0xcd31b05e466bce99460b1ed70d6069fdfbb15e6eef84e9b9e4534358edb3899a", + receiptWithProof.getTransactionReceiptWithProof().getReceipt().getBlockHash()); + Assert.assertEquals( + "0x5", + receiptWithProof.getTransactionReceiptWithProof().getReceipt().getBlockNumber()); + Assert.assertEquals( + "0x0000000000000000000000000000000000000000", + receiptWithProof + .getTransactionReceiptWithProof() + .getReceipt() + .getContractAddress()); + Assert.assertEquals( + "0x148947262ec5e21739fe3a931c29e8b84ee34a0f", + receiptWithProof.getTransactionReceiptWithProof().getReceipt().getFrom()); + Assert.assertEquals( + "0x21dc1b", + receiptWithProof.getTransactionReceiptWithProof().getReceipt().getGasUsed()); + Assert.assertEquals( + "0xc3b4185963c78a4ca8eb90240e5cd95371d7217a9ce2bfa1149d53f79c73afbb", + receiptWithProof.getTransactionReceiptWithProof().getReceipt().getRoot()); + Assert.assertEquals( + "0x0", receiptWithProof.getTransactionReceiptWithProof().getReceipt().getStatus()); + Assert.assertEquals( + "0xd6c8a04b8826b0a37c6d4aa0eaa8644d8e35b79f", + receiptWithProof.getTransactionReceiptWithProof().getReceipt().getTo()); + Assert.assertEquals( + null, receiptWithProof.getTransactionReceiptWithProof().getReceipt().getTxProof()); + Assert.assertEquals( + null, + receiptWithProof.getTransactionReceiptWithProof().getReceipt().getReceiptProof()); + } + + @Test + public void testTransactionWithProof() throws IOException { + String transactionWithProofStr = + "{\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"result\": {\n" + + " \"transaction\": {\n" + + " \"blockHash\": \"0xcd31b05e466bce99460b1ed70d6069fdfbb15e6eef84e9b9e4534358edb3899a\",\n" + + " \"blockNumber\": \"0x5\",\n" + + " \"from\": \"0x148947262ec5e21739fe3a931c29e8b84ee34a0f\",\n" + + " \"gas\": \"0x1c9c380\",\n" + + " \"gasPrice\": \"0x1c9c380\",\n" + + " \"hash\": \"0xd2c12e211315ef09dbad53407bc820d062780232841534954f9c23ab11d8ab4c\",\n" + + " \"input\": \"0x8a42ebe90000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000000000000a3564646636663863653800000000000000000000000000000000000000000000\",\n" + + " \"nonce\": \"0x208f6fd78d48aad370df51c6fdf866f8ab022de765c2959841ff2e81bfd9af9\",\n" + + " \"to\": \"0xd6c8a04b8826b0a37c6d4aa0eaa8644d8e35b79f\",\n" + + " \"transactionIndex\": \"0x32\",\n" + + " \"value\": \"0x0\"\n" + + " },\n" + + " \"txProof\": [\n" + + " {\n" + + " \"left\": [\n" + + " \"30f0abfcf4ca152815548620e33d21fd0feaa7c78867791c751e57cb5aa38248c2\",\n" + + " \"31a864156ca9841da8176738bb981d5da9102d9703746039b3e5407fa987e5183e\"\n" + + " ],\n" + + " \"right\": [\n" + + " \"33d8078d7e71df3544f8845a9db35aa35b2638e8468a321423152e64b9004367b4\",\n" + + " \"34343a4bce325ec8f6cf48517588830cd15f69b60a05598b78b03c3656d1fbf2f5\",\n" + + " \"35ac231554047ce77c0b31cd1c469f1f39ebe23404fa8ff6cc7819ad83e2c029e7\",\n" + + " \"361f6c588e650323e03afe6460dd89a9c061583e0d62c117ba64729d2c9d79317c\",\n" + + " \"377606f79f3e08b1ba3759eceada7fde3584f01822467855aa6356652f2499c738\",\n" + + " \"386722fe270659232c5572ba54ce23b474c85d8b709e7c08e85230afb1c155fe18\",\n" + + " \"39a9441d668e5e09a5619c365577c8c31365f44a984bde04300d4dbba190330c0b\",\n" + + " \"3a78a8c288120cbe612c24a33cce2731dd3a8fe6927d9ee25cb2350dba08a541f5\",\n" + + " \"3bd9b67256e201b5736f6081f39f83bcb917261144384570bdbb8766586c3bb417\",\n" + + " \"3c3158e5a82a1ac1ed41c4fd78d5be06bf79327f60b094895b886e7aae57cff375\",\n" + + " \"3de9a4d98c5ae658ffe764fbfa81edfdd4774e01b35ccb42beacb67064a5457863\",\n" + + " \"3e525e60c0f7eb935125f1156a692eb455ab4038c6b16390ce30937b0d1b314298\",\n" + + " \"3f1600afe67dec2d21582b8c7b76a15e569371d736d7bfc7a96c0327d280b91dfc\"\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"left\": [\n" + + " \"3577673b86ad4d594d86941d731f17d1515f4669483aed091d49f279d677cb19\",\n" + + " \"75603bfea5b44df4c41fbb99268364641896334f006af3a3f67edaa4b26477ca\",\n" + + " \"1339d43c526f0f34d8a0f4fb3bb47b716fdfde8d35697be5992e0888e4d794c9\"\n" + + " ],\n" + + " \"right\": [\n" + + " \"63c8e574fb2ef52e995427a8acaa72c27073dd8e37736add8dbf36be4f609ecb\",\n" + + " \"e65353d911d6cc8ead3fad53ab24cab69a1e31df8397517b124f578ba908558d\"\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"left\": [],\n" + + " \"right\": []\n" + + " }\n" + + " ]\n" + + " }\n" + + "}"; + TransactionWithProof transactionWithProof = + objectMapper.readValue( + transactionWithProofStr.getBytes(), TransactionWithProof.class); + Assert.assertEquals( + 3, transactionWithProof.getTransactionWithProof().getTransactionProof().size()); + Assert.assertEquals( + 2, + transactionWithProof + .getTransactionWithProof() + .getTransactionProof() + .get(0) + .getLeft() + .size()); + Assert.assertEquals( + 13, + transactionWithProof + .getTransactionWithProof() + .getTransactionProof() + .get(0) + .getRight() + .size()); + + Assert.assertEquals( + 3, + transactionWithProof + .getTransactionWithProof() + .getTransactionProof() + .get(1) + .getLeft() + .size()); + Assert.assertEquals( + 2, + transactionWithProof + .getTransactionWithProof() + .getTransactionProof() + .get(1) + .getRight() + .size()); + + Assert.assertEquals( + 0, + transactionWithProof + .getTransactionWithProof() + .getTransactionProof() + .get(2) + .getLeft() + .size()); + Assert.assertEquals( + 0, + transactionWithProof + .getTransactionWithProof() + .getTransactionProof() + .get(2) + .getRight() + .size()); + + Assert.assertEquals( + "3577673b86ad4d594d86941d731f17d1515f4669483aed091d49f279d677cb19", + transactionWithProof + .getTransactionWithProof() + .getTransactionProof() + .get(1) + .getLeft() + .get(0)); + Assert.assertEquals( + "63c8e574fb2ef52e995427a8acaa72c27073dd8e37736add8dbf36be4f609ecb", + transactionWithProof + .getTransactionWithProof() + .getTransactionProof() + .get(1) + .getRight() + .get(0)); + + // check transaction + Assert.assertEquals( + "0xcd31b05e466bce99460b1ed70d6069fdfbb15e6eef84e9b9e4534358edb3899a", + transactionWithProof.getTransactionWithProof().getTransaction().getBlockHash()); + Assert.assertEquals( + BigInteger.valueOf(0x5), + transactionWithProof.getTransactionWithProof().getTransaction().getBlockNumber()); + Assert.assertEquals( + "0x148947262ec5e21739fe3a931c29e8b84ee34a0f", + transactionWithProof.getTransactionWithProof().getTransaction().getFrom()); + Assert.assertEquals( + "0x1c9c380", + transactionWithProof.getTransactionWithProof().getTransaction().getGas()); + Assert.assertEquals( + "0x1c9c380", + transactionWithProof.getTransactionWithProof().getTransaction().getGasPrice()); + Assert.assertEquals( + "0xd2c12e211315ef09dbad53407bc820d062780232841534954f9c23ab11d8ab4c", + transactionWithProof.getTransactionWithProof().getTransaction().getHash()); + Assert.assertEquals( + "0x8a42ebe90000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000000000000a3564646636663863653800000000000000000000000000000000000000000000", + transactionWithProof.getTransactionWithProof().getTransaction().getInput()); + Assert.assertEquals( + "0x208f6fd78d48aad370df51c6fdf866f8ab022de765c2959841ff2e81bfd9af9", + transactionWithProof.getTransactionWithProof().getTransaction().getNonce()); + Assert.assertEquals( + "0xd6c8a04b8826b0a37c6d4aa0eaa8644d8e35b79f", + transactionWithProof.getTransactionWithProof().getTransaction().getTo()); + Assert.assertEquals( + "0x32", + transactionWithProof + .getTransactionWithProof() + .getTransaction() + .getTransactionIndex()); + Assert.assertEquals( + "0x0", transactionWithProof.getTransactionWithProof().getTransaction().getValue()); + } +} diff --git a/sdk-service/src/test/java/org/fisco/bcos/sdk/precompiled/PrecompiledRetCodeTest.java b/sdk-service/src/test/java/org/fisco/bcos/sdk/precompiled/PrecompiledRetCodeTest.java new file mode 100644 index 000000000..fe2c3ff06 --- /dev/null +++ b/sdk-service/src/test/java/org/fisco/bcos/sdk/precompiled/PrecompiledRetCodeTest.java @@ -0,0 +1,142 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.test.precompiled; + +import org.fisco.bcos.sdk.model.PrecompiledRetCode; +import org.fisco.bcos.sdk.model.RetCode; +import org.junit.Assert; +import org.junit.Test; + +public class PrecompiledRetCodeTest { + @Test + public void testGetPrecompiledResponse() { + checkResponse( + PrecompiledRetCode.CODE_CURRENT_VALUE_IS_EXPECTED_VALUE.getCode(), + PrecompiledRetCode.CODE_CURRENT_VALUE_IS_EXPECTED_VALUE.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_ACCOUNT_FROZEN.getCode(), + PrecompiledRetCode.CODE_ACCOUNT_FROZEN.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_ACCOUNT_ALREADY_AVAILABLE.getCode(), + PrecompiledRetCode.CODE_ACCOUNT_ALREADY_AVAILABLE.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_INVALID_ACCOUNT_ADDRESS.getCode(), + PrecompiledRetCode.CODE_INVALID_ACCOUNT_ADDRESS.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_ACCOUNT_NOT_EXIST.getCode(), + PrecompiledRetCode.CODE_ACCOUNT_NOT_EXIST.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_OPERATOR_NOT_EXIST.getCode(), + PrecompiledRetCode.CODE_OPERATOR_NOT_EXIST.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_OPERATOR_EXIST.getCode(), + PrecompiledRetCode.CODE_OPERATOR_EXIST.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_COMMITTEE_MEMBER_CANNOT_BE_OPERATOR.getCode(), + PrecompiledRetCode.CODE_COMMITTEE_MEMBER_CANNOT_BE_OPERATOR.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_OPERATOR_CANNOT_BE_COMMITTEE_MEMBER.getCode(), + PrecompiledRetCode.CODE_OPERATOR_CANNOT_BE_COMMITTEE_MEMBER.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_INVALID_THRESHOLD.getCode(), + PrecompiledRetCode.CODE_INVALID_THRESHOLD.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_INVALID_REQUEST_PERMISSION_DENIED.getCode(), + PrecompiledRetCode.CODE_INVALID_REQUEST_PERMISSION_DENIED.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_COMMITTEE_MEMBER_NOT_EXIST.getCode(), + PrecompiledRetCode.CODE_COMMITTEE_MEMBER_NOT_EXIST.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_COMMITTEE_MEMBER_EXIST.getCode(), + PrecompiledRetCode.CODE_COMMITTEE_MEMBER_EXIST.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_INVALID_NO_AUTHORIZED.getCode(), + PrecompiledRetCode.CODE_INVALID_NO_AUTHORIZED.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_INVALID_TABLE_NOT_EXIST.getCode(), + PrecompiledRetCode.CODE_INVALID_TABLE_NOT_EXIST.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_INVALID_CONTRACT_ADDRESS.getCode(), + PrecompiledRetCode.CODE_INVALID_CONTRACT_ADDRESS.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_INVALID_CONTRACT_REPEAT_AUTHORIZATION.getCode(), + PrecompiledRetCode.CODE_INVALID_CONTRACT_REPEAT_AUTHORIZATION.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_INVALID_CONTRACT_AVAILABLE.getCode(), + PrecompiledRetCode.CODE_INVALID_CONTRACT_AVAILABLE.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_INVALID_CONTRACT_FEOZEN.getCode(), + PrecompiledRetCode.CODE_INVALID_CONTRACT_FEOZEN.getMessage()); + checkResponse( + PrecompiledRetCode.VERIFY_RING_SIG_FAILED.getCode(), + PrecompiledRetCode.VERIFY_RING_SIG_FAILED.getMessage()); + checkResponse( + PrecompiledRetCode.VERIFY_GROUP_SIG_FAILED.getCode(), + PrecompiledRetCode.VERIFY_GROUP_SIG_FAILED.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_INVALID_CIPHERS.getCode(), + PrecompiledRetCode.CODE_INVALID_CIPHERS.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_CONDITION_OPERATION_UNDEFINED.getCode(), + PrecompiledRetCode.CODE_CONDITION_OPERATION_UNDEFINED.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_PARSE_CONDITION_ERROR.getCode(), + PrecompiledRetCode.CODE_PARSE_CONDITION_ERROR.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_PARSE_ENTRY_ERROR.getCode(), + PrecompiledRetCode.CODE_PARSE_ENTRY_ERROR.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_INVALID_CONFIGURATION_VALUES.getCode(), + PrecompiledRetCode.CODE_INVALID_CONFIGURATION_VALUES.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_VERSION_LENGTH_OVERFLOW.getCode(), + PrecompiledRetCode.CODE_VERSION_LENGTH_OVERFLOW.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_ADDRESS_AND_VERSION_EXIST.getCode(), + PrecompiledRetCode.CODE_ADDRESS_AND_VERSION_EXIST.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_LAST_SEALER.getCode(), + PrecompiledRetCode.CODE_LAST_SEALER.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_INVALID_NODEID.getCode(), + PrecompiledRetCode.CODE_INVALID_NODEID.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_COMMITTEE_PERMISSION.getCode(), + PrecompiledRetCode.CODE_COMMITTEE_PERMISSION.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_CONTRACT_NOT_EXIST.getCode(), + PrecompiledRetCode.CODE_CONTRACT_NOT_EXIST.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_TABLE_NAME_OVERFLOW.getCode(), + PrecompiledRetCode.CODE_TABLE_NAME_OVERFLOW.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_TABLE_AND_ADDRESS_EXIST.getCode(), + PrecompiledRetCode.CODE_TABLE_AND_ADDRESS_EXIST.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_ADDRESS_INVALID.getCode(), + PrecompiledRetCode.CODE_ADDRESS_INVALID.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_UNKNOWN_FUNCTION_CALL.getCode(), + PrecompiledRetCode.CODE_UNKNOWN_FUNCTION_CALL.getMessage()); + checkResponse( + PrecompiledRetCode.CODE_SUCCESS.getCode(), + PrecompiledRetCode.CODE_SUCCESS.getMessage()); + } + + private void checkResponse(int code, String expectedMessage) { + RetCode retCode = PrecompiledRetCode.getPrecompiledResponse(code, ""); + Assert.assertTrue(expectedMessage.equals(retCode.getMessage())); + Assert.assertEquals(code, retCode.getCode()); + } +} diff --git a/sdk-service/src/test/java/org/fisco/bcos/sdk/service/GroupServiceTest.java b/sdk-service/src/test/java/org/fisco/bcos/sdk/service/GroupServiceTest.java new file mode 100644 index 000000000..43cde7069 --- /dev/null +++ b/sdk-service/src/test/java/org/fisco/bcos/sdk/service/GroupServiceTest.java @@ -0,0 +1,139 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.test.service; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import org.fisco.bcos.sdk.service.GroupService; +import org.fisco.bcos.sdk.service.GroupServiceImpl; +import org.junit.Assert; +import org.junit.Test; + +public class GroupServiceTest { + @Test + public void testUpdateGroupNodeList() throws InterruptedException { + GroupService groupService = new GroupServiceImpl(1); + ExecutorService threadPool = Executors.newFixedThreadPool(50); + List nodeList = (new ArrayList<>()); + for (int i = 1; i <= 100; i++) { + nodeList.add("127.0.0.1:" + (20200 + i)); + } + // access the groupService concurrently + for (int i = 0; i < 100; i++) { + final Integer nodeIndex = i; + threadPool.execute( + new Runnable() { + @Override + public void run() { + try { + String insertedNode = nodeList.get(nodeIndex); + groupService.insertNode(insertedNode); + Assert.assertEquals( + true, + groupService.getGroupNodesInfo().contains(insertedNode)); + } catch (Exception e) { + System.out.println("run exception, error info:" + e.getMessage()); + } + } + }); + } + awaitAfterShutdown(threadPool); + // check the groupService + Assert.assertEquals(100, groupService.getGroupNodesInfo().size()); + ExecutorService threadPool2 = Executors.newCachedThreadPool(); + for (int i = 0; i < 100; i++) { + final Integer nodeIndex = i; + threadPool2.execute( + new Runnable() { + @Override + public void run() { + try { + String removedNode = nodeList.get(nodeIndex); + groupService.removeNode(removedNode); + Assert.assertEquals( + false, + groupService.getGroupNodesInfo().contains(removedNode)); + } catch (Exception e) { + System.out.println( + "run remove exception, error info:" + e.getMessage()); + } + } + }); + } + awaitAfterShutdown(threadPool2); + Assert.assertEquals(0, groupService.getGroupNodesInfo().size()); + } + + @Test + public void testConcurrency() { + GroupService groupService = new GroupServiceImpl(1); + List nodeList = (new ArrayList<>()); + for (int i = 1; i <= 100; i++) { + nodeList.add("127.0.0.1:" + (20200 + i)); + } + // two thread pool, one insert and the another remove + ExecutorService threadPool1 = Executors.newCachedThreadPool(); + ExecutorService threadPool2 = Executors.newCachedThreadPool(); + for (int i = 0; i < 100; i++) { + final Integer nodeIndex = i; + threadPool1.execute( + new Runnable() { + @Override + public void run() { + try { + String insertedNode = nodeList.get(nodeIndex); + groupService.insertNode(insertedNode); + } catch (Exception e) { + System.out.println( + "run insert exception, error info:" + e.getMessage()); + } + } + }); + } + for (int i = 0; i < 100; i++) { + final Integer nodeIndex = i; + threadPool2.execute( + new Runnable() { + @Override + public void run() { + try { + String removedNode = nodeList.get(nodeIndex); + groupService.removeNode(removedNode); + } catch (Exception e) { + System.out.println( + "run remove exception, error info:" + e.getMessage()); + } + } + }); + } + awaitAfterShutdown(threadPool1); + awaitAfterShutdown(threadPool2); + } + + public static void awaitAfterShutdown(ExecutorService threadPool) { + threadPool.shutdown(); + try { + while (!threadPool.isTerminated()) { + threadPool.awaitTermination(10, TimeUnit.MILLISECONDS); + } + threadPool.shutdownNow(); + } catch (InterruptedException ex) { + threadPool.shutdownNow(); + Thread.currentThread().interrupt(); + } + } +} diff --git a/sdk-transaction/build.gradle b/sdk-transaction/build.gradle new file mode 100644 index 000000000..6a7a0b186 --- /dev/null +++ b/sdk-transaction/build.gradle @@ -0,0 +1,52 @@ +// Apply the java-library plugin to add support for Java Library +plugins { + id 'java' +} +dependencies { + compile project(':sdk-service') + compile ("org.apache.commons:commons-lang3:${commonsLang3Version}") + compile ("commons-io:commons-io:${commonsIOVersion}") + compile ("com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}") +} +uploadArchives { + repositories { + mavenDeployer { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + + repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { + authentication(userName: ossrhUsername, password: ossrhPassword) + } + + snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { + authentication(userName: ossrhUsername, password: ossrhPassword) + } + + pom.project { + name project.name + packaging 'jar' + description = 'fisco-bcos java-sdk' + url = 'http://www.fisco-bcos.org' + + scm { + connection = 'https://github.com/FISCO-BCOS/java-sdk.git' + url = 'https://github.com/FISCO-BCOS/java-sdk.git' + } + + licenses { + license { + name = 'The Apache License, Version 2.0' + url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + + developers { + developer { + id = 'zhangsan' + name = 'zhangsan' + email = 'zhangsan@example.com' + } + } + } + } + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/Contract.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/Contract.java new file mode 100644 index 000000000..e78967d84 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/Contract.java @@ -0,0 +1,403 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.contract; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import org.fisco.bcos.sdk.abi.EventEncoder; +import org.fisco.bcos.sdk.abi.EventValues; +import org.fisco.bcos.sdk.abi.FunctionEncoder; +import org.fisco.bcos.sdk.abi.FunctionReturnDecoder; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.datatypes.Address; +import org.fisco.bcos.sdk.abi.datatypes.Event; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.client.protocol.response.Call; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.eventsub.EventCallback; +import org.fisco.bcos.sdk.eventsub.EventLogParams; +import org.fisco.bcos.sdk.eventsub.EventSubscribe; +import org.fisco.bcos.sdk.model.RetCode; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.codec.decode.ReceiptParser; +import org.fisco.bcos.sdk.transaction.manager.TransactionProcessor; +import org.fisco.bcos.sdk.transaction.manager.TransactionProcessorFactory; +import org.fisco.bcos.sdk.transaction.model.dto.CallRequest; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Contract { + protected static Logger logger = LoggerFactory.getLogger(Contract.class); + protected final String contractBinary; + protected String contractAddress; + // transactionReceipt after deploying the contract + protected TransactionReceipt deployReceipt; + protected final TransactionProcessor transactionProcessor; + protected final Client client; + public static final String FUNC_DEPLOY = "deploy"; + protected final FunctionEncoder functionEncoder; + protected final CryptoKeyPair credential; + protected final CryptoSuite cryptoSuite; + protected final EventEncoder eventEncoder; + private final EventSubscribe eventSubscribe; + protected static String LATEST_BLOCK = "latest"; + + protected Contract( + String contractBinary, + String contractAddress, + Client client, + CryptoKeyPair credential, + TransactionProcessor transactionProcessor) { + this.contractBinary = contractBinary; + this.contractAddress = contractAddress; + this.client = client; + this.transactionProcessor = transactionProcessor; + this.credential = credential; + this.cryptoSuite = client.getCryptoSuite(); + this.functionEncoder = new FunctionEncoder(client.getCryptoSuite()); + this.eventEncoder = new EventEncoder(client.getCryptoSuite()); + // create eventSubscribe + this.eventSubscribe = + EventSubscribe.build( + client.getGroupManagerService(), + client.getEventResource(), + client.getGroupId()); + } + + protected Contract( + String contractBinary, + String contractAddress, + Client client, + CryptoKeyPair credential) { + this( + contractBinary, + contractAddress, + client, + credential, + TransactionProcessorFactory.createTransactionManager(client, credential)); + } + + protected static T deploy( + Class type, + Client client, + CryptoKeyPair credential, + TransactionProcessor transactionManager, + String binary, + String encodedConstructor) + throws ContractException { + try { + Constructor constructor = + type.getDeclaredConstructor(String.class, Client.class, CryptoKeyPair.class); + constructor.setAccessible(true); + T contract = constructor.newInstance(null, client, credential); + return create(contract, binary, encodedConstructor); + } catch (InstantiationException + | InvocationTargetException + | NoSuchMethodException + | IllegalAccessException e) { + throw new ContractException("deploy contract failed, error info: " + e.getMessage()); + } + } + + protected static T deploy( + Class type, + Client client, + CryptoKeyPair credential, + String binary, + String encodedConstructor) + throws ContractException { + return deploy( + type, + client, + credential, + TransactionProcessorFactory.createTransactionManager(client, credential), + binary, + encodedConstructor); + } + + private static T create( + T contract, String binary, String encodedConstructor) throws ContractException { + TransactionReceipt transactionReceipt = + contract.executeTransaction(binary + encodedConstructor, FUNC_DEPLOY); + + String contractAddress = transactionReceipt.getContractAddress(); + if (contractAddress == null) { + // parse the receipt + RetCode retCode = ReceiptParser.parseTransactionReceipt(transactionReceipt); + throw new ContractException( + "Deploy contract failed, error message: " + retCode.getMessage()); + } + contract.setContractAddress(contractAddress); + contract.setDeployReceipt(transactionReceipt); + return contract; + } + + public String getContractAddress() { + return contractAddress; + } + + public void setContractAddress(String contractAddress) { + this.contractAddress = contractAddress; + } + + public TransactionReceipt getDeployReceipt() { + return deployReceipt; + } + + public void setDeployReceipt(TransactionReceipt deployReceipt) { + this.deployReceipt = deployReceipt; + } + + private List executeCall(Function function) throws ContractException { + + String encodedFunctionData = functionEncoder.encode(function); + CallRequest callRequest = + new CallRequest(credential.getAddress(), contractAddress, encodedFunctionData); + Call response = transactionProcessor.executeCall(callRequest); + // get value from the response + String callResult = response.getCallResult().getOutput(); + if (!response.getCallResult().getStatus().equals("0x0")) { + ContractException contractException = + new ContractException( + "execute " + + function.getName() + + " failed for non-zero status " + + response.getCallResult().getStatus(), + response.getCallResult()); + logger.warn( + "status of executeCall is non-success, status: {}, callResult: {}", + response.getCallResult().getStatus(), + response.getCallResult().toString()); + throw ReceiptParser.parseExceptionCall(contractException); + } + try { + return FunctionReturnDecoder.decode(callResult, function.getOutputParameters()); + } catch (Exception e) { + throw new ContractException( + "decode callResult failed, error info:" + e.getMessage(), + e, + response.getCallResult()); + } + } + + protected T executeCallWithSingleValueReturn(Function function) + throws ContractException { + List values = executeCall(function); + if (!values.isEmpty()) { + return (T) values.get(0); + } else { + throw new ContractException( + "executeCall for function " + + function.getName() + + " failed for empty returned value from the contract " + + contractAddress); + } + } + + protected R executeCallWithSingleValueReturn( + Function function, Class returnType) throws ContractException { + T result = executeCallWithSingleValueReturn(function); + // cast the value into returnType + Object value = result.getValue(); + if (returnType.isAssignableFrom(value.getClass())) { + return (R) value; + } else if (result.getClass().equals(Address.class) && returnType.equals(String.class)) { + return (R) result.toString(); // cast isn't necessary + } else { + throw new ContractException( + "Unable convert response " + + value + + " to expected type " + + returnType.getSimpleName()); + } + } + + protected List executeCallWithMultipleValueReturn(Function function) + throws ContractException { + return executeCall(function); + } + + protected void asyncExecuteTransaction( + String data, String funName, TransactionCallback callback) { + transactionProcessor.sendTransactionAsync(contractAddress, data, credential, callback); + } + + protected void asyncExecuteTransaction(Function function, TransactionCallback callback) { + asyncExecuteTransaction(functionEncoder.encode(function), function.getName(), callback); + } + + protected TransactionReceipt executeTransaction(Function function) { + return executeTransaction(functionEncoder.encode(function), function.getName()); + } + + protected TransactionReceipt executeTransaction(String data, String functionName) { + return transactionProcessor.sendTransactionAndGetReceipt(contractAddress, data, credential); + } + + /** Adds a log field to {@link EventValues}. */ + public static class EventValuesWithLog { + private final EventValues eventValues; + private final TransactionReceipt.Logs log; + + private EventValuesWithLog(EventValues eventValues, TransactionReceipt.Logs log) { + this.eventValues = eventValues; + this.log = log; + } + + public List getIndexedValues() { + return eventValues.getIndexedValues(); + } + + public List getNonIndexedValues() { + return eventValues.getNonIndexedValues(); + } + + public TransactionReceipt.Logs getLog() { + return log; + } + } + + protected String createSignedTransaction(Function function) { + return createSignedTransaction(contractAddress, this.functionEncoder.encode(function)); + } + + protected String createSignedTransaction(String to, String data) { + return transactionProcessor.createSignedTransaction(to, data, credential); + } + + public void subscribeEvent(EventLogParams params, EventCallback callback) { + this.eventSubscribe.subscribeEvent(params, callback); + } + + public void subscribeEvent(String abi, String bin, String topic0, EventCallback callback) { + subscribeEvent( + abi, bin, topic0, LATEST_BLOCK, LATEST_BLOCK, new ArrayList(), callback); + } + + public void subscribeEvent( + String abi, + String bin, + String topic0, + String fromBlock, + String toBlock, + List otherTopics, + EventCallback callback) { + + EventLogParams filter = new EventLogParams(); + filter.setFromBlock(fromBlock); + filter.setToBlock(toBlock); + + List addresses = new ArrayList(); + addresses.add(getContractAddress()); + filter.setAddresses(addresses); + + List topics = new ArrayList(); + topics.add(topic0); + if (otherTopics != null) { + for (Object obj : otherTopics) { + topics.add(obj); + } + } + filter.setTopics(topics); + this.subscribeEvent(filter, callback); + } + + public static EventValues staticExtractEventParameters( + EventEncoder eventEncoder, Event event, TransactionReceipt.Logs log) { + List topics = log.getTopics(); + String encodedEventSignature = eventEncoder.encode(event); + if (!topics.get(0).equals(encodedEventSignature)) { + return null; + } + + List indexedValues = new ArrayList<>(); + List nonIndexedValues = + FunctionReturnDecoder.decode(log.getData(), event.getNonIndexedParameters()); + + List> indexedParameters = event.getIndexedParameters(); + for (int i = 0; i < indexedParameters.size(); i++) { + Type value = + FunctionReturnDecoder.decodeIndexedValue( + topics.get(i + 1), indexedParameters.get(i)); + indexedValues.add(value); + } + return new EventValues(indexedValues, nonIndexedValues); + } + + protected EventValues extractEventParameters(Event event, TransactionReceipt.Logs log) { + return staticExtractEventParameters(eventEncoder, event, log); + } + + protected List extractEventParameters( + Event event, TransactionReceipt transactionReceipt) { + return transactionReceipt + .getLogs() + .stream() + .map(log -> extractEventParameters(event, log)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + protected EventValuesWithLog extractEventParametersWithLog( + Event event, TransactionReceipt.Logs log) { + final EventValues eventValues = extractEventParameters(event, log); + return (eventValues == null) ? null : new EventValuesWithLog(eventValues, log); + } + + protected List extractEventParametersWithLog( + Event event, TransactionReceipt transactionReceipt) { + return transactionReceipt + .getLogs() + .stream() + .map(log -> extractEventParametersWithLog(event, log)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + protected List extractEventParametersWithLog( + Event event, List logs) { + return logs.stream() + .map(log -> extractEventParametersWithLog(event, log)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + @SuppressWarnings("unchecked") + public static List convertToNative(List arr) { + List out = new ArrayList(); + for (Iterator it = arr.iterator(); it.hasNext(); ) { + out.add((T) it.next().getValue()); + } + return out; + } + + public TransactionProcessor getTransactionProcessor() { + return this.transactionProcessor; + } + + public String getCurrentExternalAccountAddress() { + return this.credential.getAddress(); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/callback/PrecompiledCallback.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/callback/PrecompiledCallback.java new file mode 100644 index 000000000..3fee18af7 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/callback/PrecompiledCallback.java @@ -0,0 +1,21 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.contract.precompiled.callback; + +import org.fisco.bcos.sdk.model.RetCode; + +public interface PrecompiledCallback { + public void onResponse(RetCode retCode); +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/cns/CNSPrecompiled.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/cns/CNSPrecompiled.java new file mode 100644 index 000000000..59eaae583 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/cns/CNSPrecompiled.java @@ -0,0 +1,170 @@ +package org.fisco.bcos.sdk.contract.precompiled.cns; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.abi.FunctionReturnDecoder; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.datatypes.Address; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Uint256; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple1; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple4; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.Contract; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; + +@SuppressWarnings("unchecked") +public class CNSPrecompiled extends Contract { + public static final String[] BINARY_ARRAY = {}; + + public static final String BINARY = String.join("", BINARY_ARRAY); + + public static final String[] SM_BINARY_ARRAY = {}; + + public static final String SM_BINARY = String.join("", SM_BINARY_ARRAY); + + public static final String[] ABI_ARRAY = { + "[{\"constant\":true,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"}],\"name\":\"selectByName\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"}],\"name\":\"selectByNameAndVersion\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"addr\",\"type\":\"string\"},{\"name\":\"abi\",\"type\":\"string\"}],\"name\":\"insert\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"}],\"name\":\"getContractAddress\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" + }; + + public static final String ABI = String.join("", ABI_ARRAY); + + public static final String FUNC_SELECTBYNAME = "selectByName"; + + public static final String FUNC_SELECTBYNAMEANDVERSION = "selectByNameAndVersion"; + + public static final String FUNC_INSERT = "insert"; + + public static final String FUNC_GETCONTRACTADDRESS = "getContractAddress"; + + protected CNSPrecompiled(String contractAddress, Client client, CryptoKeyPair credential) { + super(getBinary(client.getCryptoSuite()), contractAddress, client, credential); + } + + public static String getBinary(CryptoSuite cryptoSuite) { + return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY); + } + + public String selectByName(String name) throws ContractException { + final Function function = + new Function( + FUNC_SELECTBYNAME, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name)), + Arrays.>asList(new TypeReference() {})); + return executeCallWithSingleValueReturn(function, String.class); + } + + public String selectByNameAndVersion(String name, String version) throws ContractException { + final Function function = + new Function( + FUNC_SELECTBYNAMEANDVERSION, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(version)), + Arrays.>asList(new TypeReference() {})); + return executeCallWithSingleValueReturn(function, String.class); + } + + public TransactionReceipt insert(String name, String version, String addr, String abi) { + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(version), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(addr), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(abi)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void insert( + String name, String version, String addr, String abi, TransactionCallback callback) { + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(version), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(addr), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(abi)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForInsert( + String name, String version, String addr, String abi) { + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(version), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(addr), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(abi)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple4 getInsertInput( + TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {}, + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple4( + (String) results.get(0).getValue(), + (String) results.get(1).getValue(), + (String) results.get(2).getValue(), + (String) results.get(3).getValue()); + } + + public Tuple1 getInsertOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public String getContractAddress(String name, String version) throws ContractException { + final Function function = + new Function( + FUNC_GETCONTRACTADDRESS, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(name), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(version)), + Arrays.>asList(new TypeReference
() {})); + return executeCallWithSingleValueReturn(function, String.class); + } + + public static CNSPrecompiled load( + String contractAddress, Client client, CryptoKeyPair credential) { + return new CNSPrecompiled(contractAddress, client, credential); + } + + public static CNSPrecompiled deploy(Client client, CryptoKeyPair credential) + throws ContractException { + return deploy( + CNSPrecompiled.class, client, credential, getBinary(client.getCryptoSuite()), ""); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/cns/CnsInfo.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/cns/CnsInfo.java new file mode 100644 index 000000000..40997c5ac --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/cns/CnsInfo.java @@ -0,0 +1,92 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.contract.precompiled.cns; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.Objects; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class CnsInfo { + private String name; + private String version; + private String address; + private String abi; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getAbi() { + return abi; + } + + public void setAbi(String abi) { + this.abi = abi; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CnsInfo cnsInfo = (CnsInfo) o; + return Objects.equals(name, cnsInfo.name) + && Objects.equals(version, cnsInfo.version) + && Objects.equals(address, cnsInfo.address) + && Objects.equals(abi, cnsInfo.abi); + } + + @Override + public int hashCode() { + return Objects.hash(name, version, address, abi); + } + + @Override + public String toString() { + return "CnsInfo{" + + "name='" + + name + + '\'' + + ", version='" + + version + + '\'' + + ", address='" + + address + + '\'' + + ", abi='" + + abi + + '\'' + + '}'; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/cns/CnsService.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/cns/CnsService.java new file mode 100644 index 000000000..576d7f5ba --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/cns/CnsService.java @@ -0,0 +1,94 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.contract.precompiled.cns; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import java.util.List; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.precompiled.model.PrecompiledAddress; +import org.fisco.bcos.sdk.contract.precompiled.model.PrecompiledVersionCheck; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.PrecompiledConstant; +import org.fisco.bcos.sdk.model.PrecompiledRetCode; +import org.fisco.bcos.sdk.model.RetCode; +import org.fisco.bcos.sdk.transaction.codec.decode.ReceiptParser; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; + +public class CnsService { + private final CNSPrecompiled cnsPrecompiled; + private String currentVersion; + + public CnsService(Client client, CryptoKeyPair credential) { + this.cnsPrecompiled = + CNSPrecompiled.load(PrecompiledAddress.CNS_PRECOMPILED_ADDRESS, client, credential); + this.currentVersion = client.getClientNodeVersion().getNodeVersion().getSupportedVersion(); + } + + public RetCode registerCNS( + String contractName, String contractVersion, String contractAddress, String abiData) + throws ContractException { + // check the length of the contractVersion + if (contractVersion.length() > PrecompiledConstant.CNS_MAX_VERSION_LENGTH) { + throw new ContractException(PrecompiledRetCode.OVER_CONTRACT_VERSION_LEN_LIMIT); + } + return ReceiptParser.parseTransactionReceipt( + cnsPrecompiled.insert(contractName, contractVersion, contractAddress, abiData)); + } + + public List selectByName(String contractName) throws ContractException { + try { + String cnsInfo = cnsPrecompiled.selectByName(contractName); + return ObjectMapperFactory.getObjectMapper() + .readValue(cnsInfo, new TypeReference>() {}); + } catch (JsonProcessingException e) { + throw new ContractException( + "CnsService: failed to call selectByName interface, error message: " + + e.getMessage()); + } catch (ContractException e) { + throw ReceiptParser.parseExceptionCall(e); + } + } + + public List selectByNameAndVersion(String contractName, String contractVersion) + throws ContractException { + String cnsInfo = null; + try { + cnsInfo = cnsPrecompiled.selectByNameAndVersion(contractName, contractVersion); + return ObjectMapperFactory.getObjectMapper() + .readValue(cnsInfo, new TypeReference>() {}); + } catch (JsonProcessingException e) { + throw new ContractException( + "CnsService: failed to call selectByNameAndVersion interface, error message: " + + e.getMessage() + + ", return cnsInfo: " + + cnsInfo); + } catch (ContractException e) { + throw ReceiptParser.parseExceptionCall(e); + } + } + + public String getContractAddress(String contractName, String contractVersion) + throws ContractException { + try { + PrecompiledVersionCheck.CNS_GET_CONTRACT_ADDRESS_PRECOMPILED_VERSION.checkVersion( + currentVersion); + return cnsPrecompiled.getContractAddress(contractName, contractVersion); + } catch (ContractException e) { + throw ReceiptParser.parseExceptionCall(e); + } + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/consensus/ConsensusPrecompiled.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/consensus/ConsensusPrecompiled.java new file mode 100644 index 000000000..0e21fe2f8 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/consensus/ConsensusPrecompiled.java @@ -0,0 +1,224 @@ +package org.fisco.bcos.sdk.contract.precompiled.consensus; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.abi.FunctionReturnDecoder; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Int256; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple1; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.Contract; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; + +@SuppressWarnings("unchecked") +public class ConsensusPrecompiled extends Contract { + public static final String[] BINARY_ARRAY = {}; + + public static final String BINARY = String.join("", BINARY_ARRAY); + + public static final String[] SM_BINARY_ARRAY = {}; + + public static final String SM_BINARY = String.join("", SM_BINARY_ARRAY); + + public static final String[] ABI_ARRAY = { + "[{\"constant\":false,\"inputs\":[{\"name\":\"\",\"type\":\"string\"}],\"name\":\"addObserver\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"\",\"type\":\"string\"}],\"name\":\"remove\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"\",\"type\":\"string\"}],\"name\":\"addSealer\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" + }; + + public static final String ABI = String.join("", ABI_ARRAY); + + public static final String FUNC_ADDOBSERVER = "addObserver"; + + public static final String FUNC_REMOVE = "remove"; + + public static final String FUNC_ADDSEALER = "addSealer"; + + protected ConsensusPrecompiled( + String contractAddress, Client client, CryptoKeyPair credential) { + super(getBinary(client.getCryptoSuite()), contractAddress, client, credential); + } + + public static String getBinary(CryptoSuite cryptoSuite) { + return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY); + } + + public TransactionReceipt addObserver(String param0) { + final Function function = + new Function( + FUNC_ADDOBSERVER, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param0)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void addObserver(String param0, TransactionCallback callback) { + final Function function = + new Function( + FUNC_ADDOBSERVER, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param0)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForAddObserver(String param0) { + final Function function = + new Function( + FUNC_ADDOBSERVER, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param0)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple1 getAddObserverInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_ADDOBSERVER, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((String) results.get(0).getValue()); + } + + public Tuple1 getAddObserverOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_ADDOBSERVER, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public TransactionReceipt remove(String param0) { + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param0)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void remove(String param0, TransactionCallback callback) { + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param0)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForRemove(String param0) { + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param0)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple1 getRemoveInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((String) results.get(0).getValue()); + } + + public Tuple1 getRemoveOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public TransactionReceipt addSealer(String param0) { + final Function function = + new Function( + FUNC_ADDSEALER, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param0)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void addSealer(String param0, TransactionCallback callback) { + final Function function = + new Function( + FUNC_ADDSEALER, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param0)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForAddSealer(String param0) { + final Function function = + new Function( + FUNC_ADDSEALER, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param0)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple1 getAddSealerInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_ADDSEALER, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((String) results.get(0).getValue()); + } + + public Tuple1 getAddSealerOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_ADDSEALER, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public static ConsensusPrecompiled load( + String contractAddress, Client client, CryptoKeyPair credential) { + return new ConsensusPrecompiled(contractAddress, client, credential); + } + + public static ConsensusPrecompiled deploy(Client client, CryptoKeyPair credential) + throws ContractException { + return deploy( + ConsensusPrecompiled.class, + client, + credential, + getBinary(client.getCryptoSuite()), + ""); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/consensus/ConsensusService.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/consensus/ConsensusService.java new file mode 100644 index 000000000..22cc8d495 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/consensus/ConsensusService.java @@ -0,0 +1,72 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.contract.precompiled.consensus; + +import java.util.List; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.precompiled.model.PrecompiledAddress; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.PrecompiledRetCode; +import org.fisco.bcos.sdk.model.RetCode; +import org.fisco.bcos.sdk.transaction.codec.decode.ReceiptParser; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; + +public class ConsensusService { + private final ConsensusPrecompiled consensusPrecompiled; + private final Client client; + + public ConsensusService(Client client, CryptoKeyPair credential) { + this.client = client; + // load the ConsensusPrecompiled + this.consensusPrecompiled = + ConsensusPrecompiled.load( + PrecompiledAddress.CONSENSUS_PRECOMPILED_ADDRESS, client, credential); + } + + private boolean existsInNodeList(String nodeId) { + List nodeIdList = client.getNodeIDList().getNodeIDList(); + return nodeIdList.contains(nodeId); + } + + public RetCode addSealer(String nodeId) throws ContractException { + // check the nodeId exists in the nodeList or not + if (!existsInNodeList(nodeId)) { + throw new ContractException(PrecompiledRetCode.MUST_EXIST_IN_NODE_LIST); + } + // check the node exists in the sealerList or not + List sealerList = client.getSealerList().getResult(); + if (sealerList.contains(nodeId)) { + throw new ContractException(PrecompiledRetCode.ALREADY_EXISTS_IN_SEALER_LIST); + } + return ReceiptParser.parseTransactionReceipt(consensusPrecompiled.addSealer(nodeId)); + } + + public RetCode addObserver(String nodeId) throws ContractException { + List observerList = client.getObserverList().getResult(); + if (observerList.contains(nodeId)) { + throw new ContractException(PrecompiledRetCode.ALREADY_EXISTS_IN_OBSERVER_LIST); + } + return ReceiptParser.parseTransactionReceipt(consensusPrecompiled.addObserver(nodeId)); + } + + public RetCode removeNode(String nodeId) throws ContractException { + List sealerList = client.getSealerList().getResult(); + List observerList = client.getObserverList().getResult(); + if (!sealerList.contains(nodeId) && !observerList.contains(nodeId)) { + throw new ContractException(PrecompiledRetCode.ALREADY_REMOVED_FROM_THE_GROUP); + } + return ReceiptParser.parseTransactionReceipt(consensusPrecompiled.remove(nodeId)); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/contractmgr/ContractLifeCyclePrecompiled.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/contractmgr/ContractLifeCyclePrecompiled.java new file mode 100644 index 000000000..570ec707a --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/contractmgr/ContractLifeCyclePrecompiled.java @@ -0,0 +1,257 @@ +package org.fisco.bcos.sdk.contract.precompiled.contractmgr; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.abi.FunctionReturnDecoder; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.datatypes.Address; +import org.fisco.bcos.sdk.abi.datatypes.DynamicArray; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Int256; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple1; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.Contract; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; + +@SuppressWarnings("unchecked") +public class ContractLifeCyclePrecompiled extends Contract { + public static final String[] BINARY_ARRAY = {}; + + public static final String BINARY = String.join("", BINARY_ARRAY); + + public static final String[] SM_BINARY_ARRAY = {}; + + public static final String SM_BINARY = String.join("", SM_BINARY_ARRAY); + + public static final String[] ABI_ARRAY = { + "[{\"constant\":true,\"inputs\":[{\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getStatus\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"},{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"unfreeze\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"freeze\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"contractAddr\",\"type\":\"address\"},{\"name\":\"userAddr\",\"type\":\"address\"}],\"name\":\"grantManager\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"listManager\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"},{\"name\":\"\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" + }; + + public static final String ABI = String.join("", ABI_ARRAY); + + public static final String FUNC_GETSTATUS = "getStatus"; + + public static final String FUNC_UNFREEZE = "unfreeze"; + + public static final String FUNC_FREEZE = "freeze"; + + public static final String FUNC_GRANTMANAGER = "grantManager"; + + public static final String FUNC_LISTMANAGER = "listManager"; + + protected ContractLifeCyclePrecompiled( + String contractAddress, Client client, CryptoKeyPair credential) { + super(getBinary(client.getCryptoSuite()), contractAddress, client, credential); + } + + public static String getBinary(CryptoSuite cryptoSuite) { + return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY); + } + + public Tuple2 getStatus(String addr) throws ContractException { + final Function function = + new Function( + FUNC_GETSTATUS, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(addr)), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {})); + List results = executeCallWithMultipleValueReturn(function); + return new Tuple2( + (BigInteger) results.get(0).getValue(), (String) results.get(1).getValue()); + } + + public TransactionReceipt unfreeze(String addr) { + final Function function = + new Function( + FUNC_UNFREEZE, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(addr)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void unfreeze(String addr, TransactionCallback callback) { + final Function function = + new Function( + FUNC_UNFREEZE, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(addr)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForUnfreeze(String addr) { + final Function function = + new Function( + FUNC_UNFREEZE, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(addr)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple1 getUnfreezeInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_UNFREEZE, + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((String) results.get(0).getValue()); + } + + public Tuple1 getUnfreezeOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_UNFREEZE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public TransactionReceipt freeze(String addr) { + final Function function = + new Function( + FUNC_FREEZE, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(addr)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void freeze(String addr, TransactionCallback callback) { + final Function function = + new Function( + FUNC_FREEZE, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(addr)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForFreeze(String addr) { + final Function function = + new Function( + FUNC_FREEZE, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(addr)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple1 getFreezeInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_FREEZE, + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((String) results.get(0).getValue()); + } + + public Tuple1 getFreezeOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_FREEZE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public TransactionReceipt grantManager(String contractAddr, String userAddr) { + final Function function = + new Function( + FUNC_GRANTMANAGER, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Address(contractAddr), + new org.fisco.bcos.sdk.abi.datatypes.Address(userAddr)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void grantManager(String contractAddr, String userAddr, TransactionCallback callback) { + final Function function = + new Function( + FUNC_GRANTMANAGER, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Address(contractAddr), + new org.fisco.bcos.sdk.abi.datatypes.Address(userAddr)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForGrantManager(String contractAddr, String userAddr) { + final Function function = + new Function( + FUNC_GRANTMANAGER, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Address(contractAddr), + new org.fisco.bcos.sdk.abi.datatypes.Address(userAddr)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple2 getGrantManagerInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_GRANTMANAGER, + Arrays.asList(), + Arrays.>asList( + new TypeReference
() {}, new TypeReference
() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple2( + (String) results.get(0).getValue(), (String) results.get(1).getValue()); + } + + public Tuple1 getGrantManagerOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_GRANTMANAGER, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public Tuple2> listManager(String addr) throws ContractException { + final Function function = + new Function( + FUNC_LISTMANAGER, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(addr)), + Arrays.>asList( + new TypeReference() {}, + new TypeReference>() {})); + List results = executeCallWithMultipleValueReturn(function); + return new Tuple2>( + (BigInteger) results.get(0).getValue(), + convertToNative((List
) results.get(1).getValue())); + } + + public static ContractLifeCyclePrecompiled load( + String contractAddress, Client client, CryptoKeyPair credential) { + return new ContractLifeCyclePrecompiled(contractAddress, client, credential); + } + + public static ContractLifeCyclePrecompiled deploy(Client client, CryptoKeyPair credential) + throws ContractException { + return deploy( + ContractLifeCyclePrecompiled.class, + client, + credential, + getBinary(client.getCryptoSuite()), + ""); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/contractmgr/ContractLifeCycleService.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/contractmgr/ContractLifeCycleService.java new file mode 100644 index 000000000..5e889eac8 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/contractmgr/ContractLifeCycleService.java @@ -0,0 +1,114 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.contract.precompiled.contractmgr; + +import java.math.BigInteger; +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.precompiled.model.PrecompiledAddress; +import org.fisco.bcos.sdk.contract.precompiled.model.PrecompiledVersionCheck; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.PrecompiledRetCode; +import org.fisco.bcos.sdk.model.RetCode; +import org.fisco.bcos.sdk.transaction.codec.decode.ReceiptParser; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; + +public class ContractLifeCycleService { + private final ContractLifeCyclePrecompiled contractLifeCyclePrecompiled; + private final String currentVersion; + + public ContractLifeCycleService(Client client, CryptoKeyPair credential) { + this.contractLifeCyclePrecompiled = + ContractLifeCyclePrecompiled.load( + PrecompiledAddress.CONTRACT_LIFECYCLE_PRECOMPILED_ADDRESS, + client, + credential); + this.currentVersion = client.getClientNodeVersion().getNodeVersion().getSupportedVersion(); + } + + public RetCode freeze(String contractAddress) throws ContractException { + PrecompiledVersionCheck.CONTRACT_LIFE_CYCLE_PRECOMPILED_VERSION.checkVersion( + currentVersion); + return ReceiptParser.parseTransactionReceipt( + this.contractLifeCyclePrecompiled.freeze(contractAddress)); + } + + public RetCode unfreeze(String contractAddress) throws ContractException { + PrecompiledVersionCheck.CONTRACT_LIFE_CYCLE_PRECOMPILED_VERSION.checkVersion( + currentVersion); + return ReceiptParser.parseTransactionReceipt( + this.contractLifeCyclePrecompiled.unfreeze(contractAddress)); + } + + public RetCode grantManager(String contractAddress, String userAddress) + throws ContractException { + PrecompiledVersionCheck.CONTRACT_LIFE_CYCLE_PRECOMPILED_VERSION.checkVersion( + currentVersion); + return ReceiptParser.parseTransactionReceipt( + this.contractLifeCyclePrecompiled.grantManager(contractAddress, userAddress)); + } + + public String getContractStatus(String contractAddress) throws ContractException { + PrecompiledVersionCheck.CONTRACT_LIFE_CYCLE_PRECOMPILED_VERSION.checkVersion( + currentVersion); + try { + Tuple2 result = + this.contractLifeCyclePrecompiled.getStatus(contractAddress); + if (result.getValue1().intValue() != PrecompiledRetCode.CODE_SUCCESS.getCode()) { + return PrecompiledRetCode.getPrecompiledResponse( + result.getValue1().intValue(), result.getValue2()) + .getMessage(); + } + return result.getValue2(); + } catch (ContractException e) { + throw new ContractException( + "ContractLifCycleService: getContractStatus for " + + contractAddress + + " failed, error info:" + + e.getMessage(), + e); + } + } + + public List listManager(String contractAddress) throws ContractException { + PrecompiledVersionCheck.CONTRACT_LIFE_CYCLE_PRECOMPILED_VERSION.checkVersion( + currentVersion); + try { + Tuple2> result = + this.contractLifeCyclePrecompiled.listManager(contractAddress); + if (result.getValue1().intValue() != PrecompiledRetCode.CODE_SUCCESS.getCode()) { + String errorMessage = + PrecompiledRetCode.getPrecompiledResponse( + result.getValue1().intValue(), + result.getValue2().toString()) + .getMessage(); + throw new ContractException( + "contractLifCycleService: listManager for " + + contractAddress + + " failed, reason:" + + errorMessage); + } + return result.getValue2(); + } catch (ContractException e) { + throw new ContractException( + "ContractLifCycleService: listManager for " + + contractAddress + + " failed, error info: " + + e.getMessage(), + e); + } + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/crud/CRUD.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/crud/CRUD.java new file mode 100644 index 000000000..c5e6d06bf --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/crud/CRUD.java @@ -0,0 +1,331 @@ +package org.fisco.bcos.sdk.contract.precompiled.crud; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.abi.FunctionReturnDecoder; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Int256; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple1; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple4; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple5; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.Contract; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; + +@SuppressWarnings("unchecked") +public class CRUD extends Contract { + public static final String[] BINARY_ARRAY = {}; + + public static final String BINARY = String.join("", BINARY_ARRAY); + + public static final String[] SM_BINARY_ARRAY = {}; + + public static final String SM_BINARY = String.join("", SM_BINARY_ARRAY); + + public static final String[] ABI_ARRAY = { + "[{\"constant\":false,\"inputs\":[{\"name\":\"tableName\",\"type\":\"string\"},{\"name\":\"key\",\"type\":\"string\"},{\"name\":\"entry\",\"type\":\"string\"},{\"name\":\"condition\",\"type\":\"string\"},{\"name\":\"\",\"type\":\"string\"}],\"name\":\"update\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tableName\",\"type\":\"string\"}],\"name\":\"desc\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"},{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tableName\",\"type\":\"string\"},{\"name\":\"key\",\"type\":\"string\"},{\"name\":\"condition\",\"type\":\"string\"},{\"name\":\"\",\"type\":\"string\"}],\"name\":\"select\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"tableName\",\"type\":\"string\"},{\"name\":\"key\",\"type\":\"string\"},{\"name\":\"entry\",\"type\":\"string\"},{\"name\":\"\",\"type\":\"string\"}],\"name\":\"insert\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"tableName\",\"type\":\"string\"},{\"name\":\"key\",\"type\":\"string\"},{\"name\":\"condition\",\"type\":\"string\"},{\"name\":\"\",\"type\":\"string\"}],\"name\":\"remove\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" + }; + + public static final String ABI = String.join("", ABI_ARRAY); + + public static final String FUNC_UPDATE = "update"; + + public static final String FUNC_DESC = "desc"; + + public static final String FUNC_SELECT = "select"; + + public static final String FUNC_INSERT = "insert"; + + public static final String FUNC_REMOVE = "remove"; + + protected CRUD(String contractAddress, Client client, CryptoKeyPair credential) { + super(getBinary(client.getCryptoSuite()), contractAddress, client, credential); + } + + public static String getBinary(CryptoSuite cryptoSuite) { + return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY); + } + + public TransactionReceipt update( + String tableName, String key, String entry, String condition, String param4) { + final Function function = + new Function( + FUNC_UPDATE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(tableName), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(key), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(entry), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(condition), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param4)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void update( + String tableName, + String key, + String entry, + String condition, + String param4, + TransactionCallback callback) { + final Function function = + new Function( + FUNC_UPDATE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(tableName), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(key), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(entry), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(condition), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param4)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForUpdate( + String tableName, String key, String entry, String condition, String param4) { + final Function function = + new Function( + FUNC_UPDATE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(tableName), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(key), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(entry), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(condition), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param4)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple5 getUpdateInput( + TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_UPDATE, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {}, + new TypeReference() {}, + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple5( + (String) results.get(0).getValue(), + (String) results.get(1).getValue(), + (String) results.get(2).getValue(), + (String) results.get(3).getValue(), + (String) results.get(4).getValue()); + } + + public Tuple1 getUpdateOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_UPDATE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public Tuple2 desc(String tableName) throws ContractException { + final Function function = + new Function( + FUNC_DESC, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(tableName)), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {})); + List results = executeCallWithMultipleValueReturn(function); + return new Tuple2( + (String) results.get(0).getValue(), (String) results.get(1).getValue()); + } + + public String select(String tableName, String key, String condition, String param3) + throws ContractException { + final Function function = + new Function( + FUNC_SELECT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(tableName), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(key), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(condition), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param3)), + Arrays.>asList(new TypeReference() {})); + return executeCallWithSingleValueReturn(function, String.class); + } + + public TransactionReceipt insert(String tableName, String key, String entry, String param3) { + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(tableName), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(key), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(entry), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param3)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void insert( + String tableName, + String key, + String entry, + String param3, + TransactionCallback callback) { + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(tableName), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(key), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(entry), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param3)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForInsert( + String tableName, String key, String entry, String param3) { + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(tableName), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(key), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(entry), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param3)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple4 getInsertInput( + TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {}, + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple4( + (String) results.get(0).getValue(), + (String) results.get(1).getValue(), + (String) results.get(2).getValue(), + (String) results.get(3).getValue()); + } + + public Tuple1 getInsertOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public TransactionReceipt remove( + String tableName, String key, String condition, String param3) { + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(tableName), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(key), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(condition), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param3)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void remove( + String tableName, + String key, + String condition, + String param3, + TransactionCallback callback) { + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(tableName), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(key), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(condition), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param3)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForRemove( + String tableName, String key, String condition, String param3) { + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(tableName), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(key), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(condition), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param3)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple4 getRemoveInput( + TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {}, + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple4( + (String) results.get(0).getValue(), + (String) results.get(1).getValue(), + (String) results.get(2).getValue(), + (String) results.get(3).getValue()); + } + + public Tuple1 getRemoveOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public static CRUD load(String contractAddress, Client client, CryptoKeyPair credential) { + return new CRUD(contractAddress, client, credential); + } + + public static CRUD deploy(Client client, CryptoKeyPair credential) throws ContractException { + return deploy(CRUD.class, client, credential, getBinary(client.getCryptoSuite()), ""); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/crud/TableCRUDService.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/crud/TableCRUDService.java new file mode 100644 index 000000000..6d728898c --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/crud/TableCRUDService.java @@ -0,0 +1,324 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.contract.precompiled.crud; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2; +import org.fisco.bcos.sdk.channel.model.ChannelPrococolExceiption; +import org.fisco.bcos.sdk.channel.model.EnumNodeVersion; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.precompiled.callback.PrecompiledCallback; +import org.fisco.bcos.sdk.contract.precompiled.crud.common.Condition; +import org.fisco.bcos.sdk.contract.precompiled.crud.common.Entry; +import org.fisco.bcos.sdk.contract.precompiled.crud.table.TableFactory; +import org.fisco.bcos.sdk.contract.precompiled.model.PrecompiledAddress; +import org.fisco.bcos.sdk.contract.precompiled.model.PrecompiledVersionCheck; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.NodeVersion; +import org.fisco.bcos.sdk.model.PrecompiledConstant; +import org.fisco.bcos.sdk.model.PrecompiledRetCode; +import org.fisco.bcos.sdk.model.RetCode; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.codec.decode.ReceiptParser; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; +import org.fisco.bcos.sdk.utils.StringUtils; + +public class TableCRUDService { + private final Client client; + private final CRUD crudService; + private final TableFactory tableFactory; + private static final String ValueFieldsDelimiter = ","; + private final String currentVersion; + + public TableCRUDService(Client client, CryptoKeyPair credential) { + this.client = client; + this.crudService = + CRUD.load(PrecompiledAddress.CRUD_PRECOMPILED_ADDRESS, client, credential); + this.tableFactory = + TableFactory.load( + PrecompiledAddress.TABLEFACTORY_PRECOMPILED_ADDRESS, client, credential); + this.currentVersion = client.getClientNodeVersion().getNodeVersion().getSupportedVersion(); + } + + public static String convertValueFieldsToString(List valueFields) { + return StringUtils.join(valueFields, ValueFieldsDelimiter); + } + + public void checkKey(String key) throws ContractException { + if (key.length() > PrecompiledConstant.TABLE_KEY_MAX_LENGTH) { + throw new ContractException(PrecompiledRetCode.OVER_TABLE_KEY_LENGTH_LIMIT); + } + } + + public RetCode createTable(String tableName, String keyFieldName, List valueFields) + throws ContractException { + PrecompiledVersionCheck.TABLE_CRUD_PRECOMPILED_VERSION.checkVersion(currentVersion); + checkKey(keyFieldName); + String valueFieldsString = convertValueFieldsToString(valueFields); + return ReceiptParser.parseTransactionReceipt( + tableFactory.createTable(tableName, keyFieldName, valueFieldsString)); + } + + public RetCode insert(String tableName, String key, Entry fieldNameToValue) + throws ContractException { + PrecompiledVersionCheck.TABLE_CRUD_PRECOMPILED_VERSION.checkVersion(currentVersion); + checkKey(key); + try { + String fieldNameToValueStr = + ObjectMapperFactory.getObjectMapper() + .writeValueAsString(fieldNameToValue.getFieldNameToValue()); + return ReceiptParser.parseTransactionReceipt( + crudService.insert(tableName, key, fieldNameToValueStr, "")); + } catch (JsonProcessingException e) { + throw new ContractException( + "insert " + + fieldNameToValue.toString() + + " to " + + tableName + + " failed, error info:" + + e.getMessage(), + e); + } + } + + public RetCode update(String tableName, String key, Entry fieldNameToValue, Condition condition) + throws ContractException { + PrecompiledVersionCheck.TABLE_CRUD_PRECOMPILED_VERSION.checkVersion(currentVersion); + checkKey(key); + try { + String fieldNameToValueStr = + ObjectMapperFactory.getObjectMapper() + .writeValueAsString(fieldNameToValue.getFieldNameToValue()); + String conditionStr = encodeCondition(condition); + return ReceiptParser.parseTransactionReceipt( + crudService.update(tableName, key, fieldNameToValueStr, conditionStr, "")); + } catch (JsonProcessingException e) { + throw new ContractException( + "update " + + fieldNameToValue.toString() + + " to " + + tableName + + " failed, error info:" + + e.getMessage(), + e); + } + } + + private String encodeCondition(Condition condition) throws JsonProcessingException { + if (condition == null) { + condition = new Condition(); + } + return ObjectMapperFactory.getObjectMapper().writeValueAsString(condition.getConditions()); + } + + public RetCode remove(String tableName, String key, Condition condition) + throws ContractException { + PrecompiledVersionCheck.TABLE_CRUD_PRECOMPILED_VERSION.checkVersion(currentVersion); + checkKey(key); + try { + String conditionStr = encodeCondition(condition); + return ReceiptParser.parseTransactionReceipt( + crudService.remove(tableName, key, conditionStr, "")); + } catch (JsonProcessingException e) { + throw new ContractException( + "remove " + key + " with condition from " + tableName + " failed"); + } + } + + public List> select(String tableName, String key, Condition condition) + throws ContractException { + PrecompiledVersionCheck.TABLE_CRUD_PRECOMPILED_VERSION.checkVersion(currentVersion); + checkKey(key); + try { + String conditionStr = encodeCondition(condition); + return parseSelectResult(crudService.select(tableName, key, conditionStr, "")); + } catch (ContractException e) { + throw ReceiptParser.parseExceptionCall(e); + } catch (JsonProcessingException e) { + throw new ContractException( + "select " + + key + + " with condition from " + + tableName + + " failed, error info:" + + e.getMessage(), + e); + } + } + + public static List> parseSelectResult(String selectResult) + throws JsonProcessingException { + ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(); + return objectMapper.readValue( + selectResult, + objectMapper.getTypeFactory().constructCollectionType(List.class, Map.class)); + } + + private List> getTableDescLessThan230Version( + EnumNodeVersion.Version enumNodeVersion, String tableName) throws ContractException { + List> tableDesc = new ArrayList<>(); + if (enumNodeVersion.getMajor() == 2 && enumNodeVersion.getMinor() < 2) { + tableDesc = + select( + PrecompiledConstant.SYS_TABLE, + PrecompiledConstant.USER_TABLE_PREFIX + tableName, + new Condition()); + } else { + tableDesc = + select( + PrecompiledConstant.SYS_TABLE, + PrecompiledConstant.USER_TABLE_PREFIX_2_2_0_VERSION + tableName, + new Condition()); + } + for (Map item : tableDesc) { + if (item.containsKey(PrecompiledConstant.TABLE_NAME_FIELD)) { + item.remove(PrecompiledConstant.TABLE_NAME_FIELD); + } + } + return tableDesc; + } + + private List> getTableDesc(String tableName) throws ContractException { + Tuple2 tableDesc = crudService.desc(tableName); + List> tableDescList = new ArrayList<>(1); + Map keyToValue = new HashMap<>(); + keyToValue.put(PrecompiledConstant.KEY_FIELD_NAME, tableDesc.getValue1()); + keyToValue.put(PrecompiledConstant.VALUE_FIELD_NAME, tableDesc.getValue2()); + tableDescList.add(0, keyToValue); + return tableDescList; + } + + public List> desc(String tableName) throws ContractException { + PrecompiledVersionCheck.TABLE_CRUD_PRECOMPILED_VERSION.checkVersion(currentVersion); + try { + NodeVersion nodeVersion = client.getClientNodeVersion(); + EnumNodeVersion.Version enumNodeVersion = + EnumNodeVersion.getClassVersion( + nodeVersion.getNodeVersion().getSupportedVersion()); + if (enumNodeVersion.getMajor() == 2 && enumNodeVersion.getMinor() <= 3) { + return getTableDescLessThan230Version(enumNodeVersion, tableName); + } + return getTableDesc(tableName); + } catch (ChannelPrococolExceiption e) { + throw new ContractException( + "Obtain description for " + + tableName + + " failed, error info: " + + e.getMessage(), + e); + } catch (ContractException e) { + throw ReceiptParser.parseExceptionCall(e); + } + } + + private TransactionCallback createTransactionCallback(PrecompiledCallback callback) { + return new TransactionCallback() { + @Override + public void onResponse(TransactionReceipt receipt) { + RetCode retCode = null; + try { + retCode = ReceiptParser.parseTransactionReceipt(receipt); + + } catch (ContractException e) { + retCode.setCode(e.getErrorCode()); + retCode.setMessage(e.getMessage()); + retCode.setTransactionReceipt(receipt); + } + callback.onResponse(retCode); + } + }; + } + + public void asyncInsert( + String tableName, String key, Entry fieldNameToValue, PrecompiledCallback callback) + throws ContractException { + PrecompiledVersionCheck.TABLE_CRUD_PRECOMPILED_VERSION.checkVersion(currentVersion); + checkKey(key); + try { + String fieldNameToValueStr = + ObjectMapperFactory.getObjectMapper() + .writeValueAsString(fieldNameToValue.getFieldNameToValue()); + this.crudService.insert( + tableName, key, fieldNameToValueStr, "", createTransactionCallback(callback)); + } catch (JsonProcessingException e) { + throw new ContractException( + "asyncInsert " + + fieldNameToValue.toString() + + " to " + + tableName + + " failed, error info:" + + e.getMessage(), + e); + } + } + + public void asyncUpdate( + String tableName, + String key, + Entry fieldNameToValue, + Condition condition, + PrecompiledCallback callback) + throws ContractException { + PrecompiledVersionCheck.TABLE_CRUD_PRECOMPILED_VERSION.checkVersion(currentVersion); + checkKey(key); + try { + String fieldNameToValueStr = + ObjectMapperFactory.getObjectMapper() + .writeValueAsString(fieldNameToValue.getFieldNameToValue()); + String conditionStr = encodeCondition(condition); + this.crudService.update( + tableName, + key, + fieldNameToValueStr, + conditionStr, + "", + createTransactionCallback(callback)); + } catch (JsonProcessingException e) { + throw new ContractException( + "asyncUpdate " + + fieldNameToValue.toString() + + " to " + + tableName + + " failed, error info:" + + e.getMessage(), + e); + } + } + + public void asyncRemove( + String tableName, String key, Condition condition, PrecompiledCallback callback) + throws ContractException { + PrecompiledVersionCheck.TABLE_CRUD_PRECOMPILED_VERSION.checkVersion(currentVersion); + checkKey(key); + try { + this.crudService.remove( + tableName, + key, + encodeCondition(condition), + "", + createTransactionCallback(callback)); + } catch (JsonProcessingException e) { + throw new ContractException( + "asyncRemove " + key + " with condition from " + tableName + " failed"); + } + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/crud/common/Condition.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/crud/common/Condition.java new file mode 100644 index 000000000..1c713817e --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/crud/common/Condition.java @@ -0,0 +1,87 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.contract.precompiled.crud.common; + +import java.util.HashMap; +import java.util.Map; + +public class Condition { + + private Map> conditions; + + public Condition() { + conditions = new HashMap<>(); + } + + public void EQ(String key, String value) { + HashMap map = new HashMap(); + map.put(ConditionOperator.eq, value); + conditions.put(key, map); + } + + public void NE(String key, String value) { + HashMap map = new HashMap(); + map.put(ConditionOperator.ne, value); + conditions.put(key, map); + } + + public void GT(String key, String value) { + HashMap map = new HashMap(); + map.put(ConditionOperator.gt, value); + conditions.put(key, map); + } + + public void GE(String key, String value) { + HashMap map = new HashMap(); + map.put(ConditionOperator.ge, value); + conditions.put(key, map); + } + + public void LT(String key, String value) { + HashMap map = new HashMap(); + map.put(ConditionOperator.lt, value); + conditions.put(key, map); + } + + public void LE(String key, String value) { + HashMap map = new HashMap(); + map.put(ConditionOperator.le, value); + conditions.put(key, map); + } + + public void Limit(int count) { + Limit(0, count); + } + + public void Limit(int offset, int count) { + HashMap map = new HashMap(); + if (offset < 0) { + offset = 0; + } + if (count < 0) { + count = 0; + } + map.put(ConditionOperator.limit, offset + "," + count); + conditions.put("limit", map); + } + + public Map> getConditions() { + return conditions; + } + + public void setConditions(Map> conditions) { + this.conditions = conditions; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/crud/common/ConditionOperator.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/crud/common/ConditionOperator.java new file mode 100644 index 000000000..db2a6ffdb --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/crud/common/ConditionOperator.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.contract.precompiled.crud.common; + +public enum ConditionOperator { + eq, + ne, + gt, + ge, + lt, + le, + limit; +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/crud/common/Entry.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/crud/common/Entry.java new file mode 100644 index 000000000..0c184daec --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/crud/common/Entry.java @@ -0,0 +1,36 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.contract.precompiled.crud.common; + +import java.util.HashMap; +import java.util.Map; + +public class Entry { + private Map fieldNameToValue = new HashMap<>(); + + public Entry() {} + + public Entry(Map fieldNameToValue) { + this.fieldNameToValue = fieldNameToValue; + } + + public Map getFieldNameToValue() { + return fieldNameToValue; + } + + public void setFieldNameToValue(Map fieldNameToValue) { + this.fieldNameToValue = fieldNameToValue; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/crud/table/TableFactory.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/crud/table/TableFactory.java new file mode 100644 index 000000000..9b48a99e1 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/crud/table/TableFactory.java @@ -0,0 +1,139 @@ +package org.fisco.bcos.sdk.contract.precompiled.crud.table; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.abi.FunctionReturnDecoder; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.datatypes.Address; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Int256; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple1; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple3; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.Contract; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; + +@SuppressWarnings("unchecked") +public class TableFactory extends Contract { + public static final String[] BINARY_ARRAY = {}; + + public static final String BINARY = String.join("", BINARY_ARRAY); + + public static final String[] SM_BINARY_ARRAY = {}; + + public static final String SM_BINARY = String.join("", SM_BINARY_ARRAY); + + public static final String[] ABI_ARRAY = { + "[{\"constant\":false,\"inputs\":[{\"name\":\"\",\"type\":\"string\"},{\"name\":\"\",\"type\":\"string\"},{\"name\":\"\",\"type\":\"string\"}],\"name\":\"createTable\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"string\"}],\"name\":\"openTable\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" + }; + + public static final String ABI = String.join("", ABI_ARRAY); + + public static final String FUNC_CREATETABLE = "createTable"; + + public static final String FUNC_OPENTABLE = "openTable"; + + protected TableFactory(String contractAddress, Client client, CryptoKeyPair credential) { + super(getBinary(client.getCryptoSuite()), contractAddress, client, credential); + } + + public static String getBinary(CryptoSuite cryptoSuite) { + return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY); + } + + public TransactionReceipt createTable(String param0, String param1, String param2) { + final Function function = + new Function( + FUNC_CREATETABLE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param0), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param1), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param2)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void createTable( + String param0, String param1, String param2, TransactionCallback callback) { + final Function function = + new Function( + FUNC_CREATETABLE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param0), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param1), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param2)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForCreateTable(String param0, String param1, String param2) { + final Function function = + new Function( + FUNC_CREATETABLE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param0), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param1), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param2)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple3 getCreateTableInput( + TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_CREATETABLE, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple3( + (String) results.get(0).getValue(), + (String) results.get(1).getValue(), + (String) results.get(2).getValue()); + } + + public Tuple1 getCreateTableOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_CREATETABLE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public String openTable(String param0) throws ContractException { + final Function function = + new Function( + FUNC_OPENTABLE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(param0)), + Arrays.>asList(new TypeReference
() {})); + return executeCallWithSingleValueReturn(function, String.class); + } + + public static TableFactory load( + String contractAddress, Client client, CryptoKeyPair credential) { + return new TableFactory(contractAddress, client, credential); + } + + public static TableFactory deploy(Client client, CryptoKeyPair credential) + throws ContractException { + return deploy( + TableFactory.class, client, credential, getBinary(client.getCryptoSuite()), ""); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/model/PrecompiledAddress.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/model/PrecompiledAddress.java new file mode 100644 index 000000000..635fada0a --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/model/PrecompiledAddress.java @@ -0,0 +1,38 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.contract.precompiled.model; + +public class PrecompiledAddress { + public static final String SYSCONFIG_PRECOMPILED_ADDRESS = + "0x0000000000000000000000000000000000001000"; + public static final String TABLEFACTORY_PRECOMPILED_ADDRESS = + "0x0000000000000000000000000000000000001001"; + public static final String CRUD_PRECOMPILED_ADDRESS = + "0x0000000000000000000000000000000000001002"; + public static final String CONSENSUS_PRECOMPILED_ADDRESS = + "0x0000000000000000000000000000000000001003"; + public static final String CNS_PRECOMPILED_ADDRESS = + "0x0000000000000000000000000000000000001004"; + public static final String PERMISSION_PRECOMPILED_ADDRESS = + "0x0000000000000000000000000000000000001005"; + public static final String CONTRACT_LIFECYCLE_PRECOMPILED_ADDRESS = + "0x0000000000000000000000000000000000001007"; + public static final String CHAINGOVERNANCE_PRECOMPILED_ADDRESS = + "0x0000000000000000000000000000000000001008"; + public static final String KVTABLEFACTORY_PRECOMPILED_ADDRESS = + "0x0000000000000000000000000000000000001010"; + + private PrecompiledAddress() {} +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/model/PrecompiledResponse.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/model/PrecompiledResponse.java new file mode 100644 index 000000000..ada4ea617 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/model/PrecompiledResponse.java @@ -0,0 +1,56 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.contract.precompiled.model; + +import java.util.Objects; + +public class PrecompiledResponse { + public int code; + private String msg; + + public PrecompiledResponse(int code, String msg) { + this.code = code; + this.msg = msg; + } + + public final int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PrecompiledResponse that = (PrecompiledResponse) o; + return code == that.code && Objects.equals(msg, that.msg); + } + + @Override + public int hashCode() { + return Objects.hash(code, msg); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/model/PrecompiledVersionCheck.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/model/PrecompiledVersionCheck.java new file mode 100644 index 000000000..40627507b --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/model/PrecompiledVersionCheck.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.contract.precompiled.model; + +public class PrecompiledVersionCheck { + public static final Version CNS_GET_CONTRACT_ADDRESS_PRECOMPILED_VERSION = + new Version("getContractAddress", "2.3.0"); + public static final Version CONTRACT_LIFE_CYCLE_PRECOMPILED_VERSION = + new Version("ContractLifeCycle", "2.3.0"); + public static final Version TABLE_CRUD_PRECOMPILED_VERSION = new Version("CRUD", "2.0.0-rc3"); + public static final Version CHAIN_GOVERNANCE_PRECOMPILED_VERSION = + new Version("ChainGovernance", "2.5.0"); + public static final Version TABLE_PERMISSION_PRECOMPILED_VERSION = + new Version("Permission", "2.0.0-rc3"); + public static final Version GRANT_WRITE_PERMISSION_PRECOMPILED_VERSION = + new Version("grantWrite", "2.3.0"); + public static final Version REVOKE_WRITE_PERMISSION_PRECOMPILED_VERSION = + new Version("revokeWrite", "2.3.0"); + public static final Version QUERY_WRITE_PERMISSION_PRECOMPILED_VERSION = + new Version("queryPermission", "2.3.0"); +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/model/Version.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/model/Version.java new file mode 100644 index 000000000..055c1052f --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/model/Version.java @@ -0,0 +1,110 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.contract.precompiled.model; + +import org.fisco.bcos.sdk.channel.model.ChannelPrococolExceiption; +import org.fisco.bcos.sdk.channel.model.EnumNodeVersion; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Version { + private static Logger logger = LoggerFactory.getLogger(Version.class); + private final String minVersion; + private String maxVersion; + private String interfaceName; + + public Version(String interfaceName, String minVersion) { + this.interfaceName = interfaceName; + this.minVersion = minVersion; + } + + public void checkVersion(String currentVersion) throws ContractException { + try { + EnumNodeVersion.Version minSupportVersion = EnumNodeVersion.getClassVersion(minVersion); + EnumNodeVersion.Version supportedVersion = + EnumNodeVersion.getClassVersion(currentVersion); + String errorMessage = + "The fisco bcos node with supported_version lower than " + + minSupportVersion.toVersionString() + + " does not support the interface " + + interfaceName + + ", current fisco-bcos supported_version:" + + supportedVersion.toVersionString(); + + if (supportedVersion.getMajor() < minSupportVersion.getMajor()) { + logger.error(errorMessage); + throw new ContractException(errorMessage); + } + if (supportedVersion.getMajor() == minSupportVersion.getMajor() + && supportedVersion.getMinor() < minSupportVersion.getMinor()) { + logger.error(errorMessage); + throw new ContractException(errorMessage); + } + if (maxVersion == null || maxVersion.equals("")) { + return; + } + // check maxVersion + EnumNodeVersion.Version maxSupportedVersion = + EnumNodeVersion.getClassVersion(maxVersion); + errorMessage = + "The fisco bcos node with supported_version larger than " + + maxSupportedVersion.toVersionString() + + " does not support the interface " + + interfaceName + + ", current fisco-bcos supported_version:" + + supportedVersion.toVersionString(); + if (supportedVersion.getMajor() > maxSupportedVersion.getMajor()) { + throw new ContractException(errorMessage); + } + if (supportedVersion.getMajor() == maxSupportedVersion.getMajor() + && supportedVersion.getMinor() > maxSupportedVersion.getMinor()) { + throw new ContractException(errorMessage); + } + } catch (ChannelPrococolExceiption e) { + logger.error( + "checkVersion for interface " + + interfaceName + + " failed, error info: " + + e.getMessage()); + throw new ContractException( + "checkVersion for interface " + + interfaceName + + " failed, error info: " + + e.getMessage()); + } + } + + public String getMinVersion() { + return minVersion; + } + + public String getMaxVersion() { + return maxVersion; + } + + public void setMaxVersion(String maxVersion) { + this.maxVersion = maxVersion; + } + + public String getInterfaceName() { + return interfaceName; + } + + public void setInterfaceName(String interfaceName) { + this.interfaceName = interfaceName; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/permission/ChainGovernancePrecompiled.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/permission/ChainGovernancePrecompiled.java new file mode 100644 index 000000000..a264eb696 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/permission/ChainGovernancePrecompiled.java @@ -0,0 +1,548 @@ +package org.fisco.bcos.sdk.contract.precompiled.permission; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.abi.FunctionReturnDecoder; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.datatypes.Address; +import org.fisco.bcos.sdk.abi.datatypes.Bool; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Int256; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple1; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.Contract; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; + +@SuppressWarnings("unchecked") +public class ChainGovernancePrecompiled extends Contract { + public static final String[] BINARY_ARRAY = {}; + + public static final String BINARY = String.join("", BINARY_ARRAY); + + public static final String[] SM_BINARY_ARRAY = {}; + + public static final String SM_BINARY = String.join("", SM_BINARY_ARRAY); + + public static final String[] ABI_ARRAY = { + "[{\"constant\":true,\"inputs\":[],\"name\":\"listOperators\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"user\",\"type\":\"address\"},{\"name\":\"weight\",\"type\":\"int256\"}],\"name\":\"updateCommitteeMemberWeight\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"queryThreshold\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"user\",\"type\":\"address\"}],\"name\":\"queryCommitteeMemberWeight\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"},{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"user\",\"type\":\"address\"}],\"name\":\"grantCommitteeMember\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"account\",\"type\":\"address\"}],\"name\":\"unfreezeAccount\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"listCommitteeMembers\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"threshold\",\"type\":\"int256\"}],\"name\":\"updateThreshold\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"user\",\"type\":\"address\"}],\"name\":\"revokeCommitteeMember\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"user\",\"type\":\"address\"}],\"name\":\"grantOperator\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"account\",\"type\":\"address\"}],\"name\":\"freezeAccount\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"user\",\"type\":\"address\"}],\"name\":\"revokeOperator\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getAccountStatus\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" + }; + + public static final String ABI = String.join("", ABI_ARRAY); + + public static final String FUNC_LISTOPERATORS = "listOperators"; + + public static final String FUNC_UPDATECOMMITTEEMEMBERWEIGHT = "updateCommitteeMemberWeight"; + + public static final String FUNC_QUERYTHRESHOLD = "queryThreshold"; + + public static final String FUNC_QUERYCOMMITTEEMEMBERWEIGHT = "queryCommitteeMemberWeight"; + + public static final String FUNC_GRANTCOMMITTEEMEMBER = "grantCommitteeMember"; + + public static final String FUNC_UNFREEZEACCOUNT = "unfreezeAccount"; + + public static final String FUNC_LISTCOMMITTEEMEMBERS = "listCommitteeMembers"; + + public static final String FUNC_UPDATETHRESHOLD = "updateThreshold"; + + public static final String FUNC_REVOKECOMMITTEEMEMBER = "revokeCommitteeMember"; + + public static final String FUNC_GRANTOPERATOR = "grantOperator"; + + public static final String FUNC_FREEZEACCOUNT = "freezeAccount"; + + public static final String FUNC_REVOKEOPERATOR = "revokeOperator"; + + public static final String FUNC_GETACCOUNTSTATUS = "getAccountStatus"; + + protected ChainGovernancePrecompiled( + String contractAddress, Client client, CryptoKeyPair credential) { + super(getBinary(client.getCryptoSuite()), contractAddress, client, credential); + } + + public static String getBinary(CryptoSuite cryptoSuite) { + return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY); + } + + public String listOperators() throws ContractException { + final Function function = + new Function( + FUNC_LISTOPERATORS, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + return executeCallWithSingleValueReturn(function, String.class); + } + + public TransactionReceipt updateCommitteeMemberWeight(String user, BigInteger weight) { + final Function function = + new Function( + FUNC_UPDATECOMMITTEEMEMBERWEIGHT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Address(user), + new org.fisco.bcos.sdk.abi.datatypes.generated.Int256(weight)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void updateCommitteeMemberWeight( + String user, BigInteger weight, TransactionCallback callback) { + final Function function = + new Function( + FUNC_UPDATECOMMITTEEMEMBERWEIGHT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Address(user), + new org.fisco.bcos.sdk.abi.datatypes.generated.Int256(weight)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForUpdateCommitteeMemberWeight( + String user, BigInteger weight) { + final Function function = + new Function( + FUNC_UPDATECOMMITTEEMEMBERWEIGHT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Address(user), + new org.fisco.bcos.sdk.abi.datatypes.generated.Int256(weight)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple2 getUpdateCommitteeMemberWeightInput( + TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_UPDATECOMMITTEEMEMBERWEIGHT, + Arrays.asList(), + Arrays.>asList( + new TypeReference
() {}, new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple2( + (String) results.get(0).getValue(), (BigInteger) results.get(1).getValue()); + } + + public Tuple1 getUpdateCommitteeMemberWeightOutput( + TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_UPDATECOMMITTEEMEMBERWEIGHT, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public BigInteger queryThreshold() throws ContractException { + final Function function = + new Function( + FUNC_QUERYTHRESHOLD, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + return executeCallWithSingleValueReturn(function, BigInteger.class); + } + + public Tuple2 queryCommitteeMemberWeight(String user) + throws ContractException { + final Function function = + new Function( + FUNC_QUERYCOMMITTEEMEMBERWEIGHT, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Arrays.>asList( + new TypeReference() {}, new TypeReference() {})); + List results = executeCallWithMultipleValueReturn(function); + return new Tuple2( + (Boolean) results.get(0).getValue(), (BigInteger) results.get(1).getValue()); + } + + public TransactionReceipt grantCommitteeMember(String user) { + final Function function = + new Function( + FUNC_GRANTCOMMITTEEMEMBER, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void grantCommitteeMember(String user, TransactionCallback callback) { + final Function function = + new Function( + FUNC_GRANTCOMMITTEEMEMBER, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForGrantCommitteeMember(String user) { + final Function function = + new Function( + FUNC_GRANTCOMMITTEEMEMBER, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple1 getGrantCommitteeMemberInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_GRANTCOMMITTEEMEMBER, + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((String) results.get(0).getValue()); + } + + public Tuple1 getGrantCommitteeMemberOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_GRANTCOMMITTEEMEMBER, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public TransactionReceipt unfreezeAccount(String account) { + final Function function = + new Function( + FUNC_UNFREEZEACCOUNT, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(account)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void unfreezeAccount(String account, TransactionCallback callback) { + final Function function = + new Function( + FUNC_UNFREEZEACCOUNT, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(account)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForUnfreezeAccount(String account) { + final Function function = + new Function( + FUNC_UNFREEZEACCOUNT, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(account)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple1 getUnfreezeAccountInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_UNFREEZEACCOUNT, + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((String) results.get(0).getValue()); + } + + public Tuple1 getUnfreezeAccountOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_UNFREEZEACCOUNT, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public String listCommitteeMembers() throws ContractException { + final Function function = + new Function( + FUNC_LISTCOMMITTEEMEMBERS, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + return executeCallWithSingleValueReturn(function, String.class); + } + + public TransactionReceipt updateThreshold(BigInteger threshold) { + final Function function = + new Function( + FUNC_UPDATETHRESHOLD, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.generated.Int256(threshold)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void updateThreshold(BigInteger threshold, TransactionCallback callback) { + final Function function = + new Function( + FUNC_UPDATETHRESHOLD, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.generated.Int256(threshold)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForUpdateThreshold(BigInteger threshold) { + final Function function = + new Function( + FUNC_UPDATETHRESHOLD, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.generated.Int256(threshold)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple1 getUpdateThresholdInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_UPDATETHRESHOLD, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public Tuple1 getUpdateThresholdOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_UPDATETHRESHOLD, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public TransactionReceipt revokeCommitteeMember(String user) { + final Function function = + new Function( + FUNC_REVOKECOMMITTEEMEMBER, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void revokeCommitteeMember(String user, TransactionCallback callback) { + final Function function = + new Function( + FUNC_REVOKECOMMITTEEMEMBER, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForRevokeCommitteeMember(String user) { + final Function function = + new Function( + FUNC_REVOKECOMMITTEEMEMBER, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple1 getRevokeCommitteeMemberInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_REVOKECOMMITTEEMEMBER, + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((String) results.get(0).getValue()); + } + + public Tuple1 getRevokeCommitteeMemberOutput( + TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_REVOKECOMMITTEEMEMBER, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public TransactionReceipt grantOperator(String user) { + final Function function = + new Function( + FUNC_GRANTOPERATOR, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void grantOperator(String user, TransactionCallback callback) { + final Function function = + new Function( + FUNC_GRANTOPERATOR, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForGrantOperator(String user) { + final Function function = + new Function( + FUNC_GRANTOPERATOR, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple1 getGrantOperatorInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_GRANTOPERATOR, + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((String) results.get(0).getValue()); + } + + public Tuple1 getGrantOperatorOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_GRANTOPERATOR, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public TransactionReceipt freezeAccount(String account) { + final Function function = + new Function( + FUNC_FREEZEACCOUNT, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(account)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void freezeAccount(String account, TransactionCallback callback) { + final Function function = + new Function( + FUNC_FREEZEACCOUNT, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(account)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForFreezeAccount(String account) { + final Function function = + new Function( + FUNC_FREEZEACCOUNT, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(account)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple1 getFreezeAccountInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_FREEZEACCOUNT, + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((String) results.get(0).getValue()); + } + + public Tuple1 getFreezeAccountOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_FREEZEACCOUNT, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public TransactionReceipt revokeOperator(String user) { + final Function function = + new Function( + FUNC_REVOKEOPERATOR, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void revokeOperator(String user, TransactionCallback callback) { + final Function function = + new Function( + FUNC_REVOKEOPERATOR, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForRevokeOperator(String user) { + final Function function = + new Function( + FUNC_REVOKEOPERATOR, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple1 getRevokeOperatorInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_REVOKEOPERATOR, + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((String) results.get(0).getValue()); + } + + public Tuple1 getRevokeOperatorOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_REVOKEOPERATOR, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public String getAccountStatus(String account) throws ContractException { + final Function function = + new Function( + FUNC_GETACCOUNTSTATUS, + Arrays.asList(new org.fisco.bcos.sdk.abi.datatypes.Address(account)), + Arrays.>asList(new TypeReference() {})); + return executeCallWithSingleValueReturn(function, String.class); + } + + public static ChainGovernancePrecompiled load( + String contractAddress, Client client, CryptoKeyPair credential) { + return new ChainGovernancePrecompiled(contractAddress, client, credential); + } + + public static ChainGovernancePrecompiled deploy(Client client, CryptoKeyPair credential) + throws ContractException { + return deploy( + ChainGovernancePrecompiled.class, + client, + credential, + getBinary(client.getCryptoSuite()), + ""); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/permission/ChainGovernanceService.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/permission/ChainGovernanceService.java new file mode 100644 index 000000000..d8affe513 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/permission/ChainGovernanceService.java @@ -0,0 +1,153 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.contract.precompiled.permission; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.math.BigInteger; +import java.util.List; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.precompiled.model.PrecompiledAddress; +import org.fisco.bcos.sdk.contract.precompiled.model.PrecompiledVersionCheck; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.PrecompiledRetCode; +import org.fisco.bcos.sdk.model.RetCode; +import org.fisco.bcos.sdk.transaction.codec.decode.ReceiptParser; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; + +public class ChainGovernanceService { + private final ChainGovernancePrecompiled chainGovernancePrecompiled; + private String currentVersion; + + public ChainGovernanceService(Client client, CryptoKeyPair credential) { + this.chainGovernancePrecompiled = + ChainGovernancePrecompiled.load( + PrecompiledAddress.CHAINGOVERNANCE_PRECOMPILED_ADDRESS, client, credential); + this.currentVersion = client.getClientNodeVersion().getNodeVersion().getSupportedVersion(); + } + + public RetCode grantCommitteeMember(String userAddress) throws ContractException { + PrecompiledVersionCheck.CHAIN_GOVERNANCE_PRECOMPILED_VERSION.checkVersion(currentVersion); + return ReceiptParser.parseTransactionReceipt( + this.chainGovernancePrecompiled.grantCommitteeMember(userAddress)); + } + + public RetCode revokeCommitteeMember(String userAddress) throws ContractException { + PrecompiledVersionCheck.CHAIN_GOVERNANCE_PRECOMPILED_VERSION.checkVersion(currentVersion); + return ReceiptParser.parseTransactionReceipt( + this.chainGovernancePrecompiled.revokeCommitteeMember(userAddress)); + } + + public List listCommitteeMembers() throws ContractException { + PrecompiledVersionCheck.CHAIN_GOVERNANCE_PRECOMPILED_VERSION.checkVersion(currentVersion); + try { + return PermissionService.parsePermissionInfo( + this.chainGovernancePrecompiled.listCommitteeMembers()); + } catch (JsonProcessingException e) { + throw new ContractException( + "listCommitteeMembers exceptioned, error info: " + e.getMessage(), e); + } catch (ContractException e) { + throw ReceiptParser.parseExceptionCall(e); + } + } + + public RetCode updateCommitteeMemberWeight(String userAddress, BigInteger weight) + throws ContractException { + PrecompiledVersionCheck.CHAIN_GOVERNANCE_PRECOMPILED_VERSION.checkVersion(currentVersion); + return ReceiptParser.parseTransactionReceipt( + this.chainGovernancePrecompiled.updateCommitteeMemberWeight(userAddress, weight)); + } + + public RetCode updateThreshold(BigInteger threshold) throws ContractException { + PrecompiledVersionCheck.CHAIN_GOVERNANCE_PRECOMPILED_VERSION.checkVersion(currentVersion); + return ReceiptParser.parseTransactionReceipt( + this.chainGovernancePrecompiled.updateThreshold(threshold)); + } + + public BigInteger queryThreshold() throws ContractException { + PrecompiledVersionCheck.CHAIN_GOVERNANCE_PRECOMPILED_VERSION.checkVersion(currentVersion); + try { + return this.chainGovernancePrecompiled.queryThreshold(); + } catch (ContractException e) { + throw ReceiptParser.parseExceptionCall(e); + } + } + + public BigInteger queryCommitteeMemberWeight(String userAddress) throws ContractException { + PrecompiledVersionCheck.CHAIN_GOVERNANCE_PRECOMPILED_VERSION.checkVersion(currentVersion); + try { + Tuple2 queryResult = + this.chainGovernancePrecompiled.queryCommitteeMemberWeight(userAddress); + if (queryResult.getValue1()) { + return queryResult.getValue2(); + } + // parse the error information + RetCode errorMessage = + PrecompiledRetCode.getPrecompiledResponse( + queryResult.getValue2().intValue(), queryResult.getValue2().toString()); + throw new ContractException( + "queryCommitteeMemberWeight failed, error info: " + errorMessage.getMessage(), + errorMessage.getCode()); + } catch (ContractException e) { + throw ReceiptParser.parseExceptionCall(e); + } + } + + public RetCode grantOperator(String userAddress) throws ContractException { + PrecompiledVersionCheck.CHAIN_GOVERNANCE_PRECOMPILED_VERSION.checkVersion(currentVersion); + return ReceiptParser.parseTransactionReceipt( + this.chainGovernancePrecompiled.grantOperator(userAddress)); + } + + public RetCode revokeOperator(String userAddress) throws ContractException { + PrecompiledVersionCheck.CHAIN_GOVERNANCE_PRECOMPILED_VERSION.checkVersion(currentVersion); + return ReceiptParser.parseTransactionReceipt( + this.chainGovernancePrecompiled.revokeOperator(userAddress)); + } + + public List listOperators() throws ContractException { + PrecompiledVersionCheck.CHAIN_GOVERNANCE_PRECOMPILED_VERSION.checkVersion(currentVersion); + try { + return PermissionService.parsePermissionInfo( + this.chainGovernancePrecompiled.listOperators()); + } catch (JsonProcessingException e) { + throw new ContractException( + "listOperators exceptioned, error info:" + e.getMessage(), e); + } catch (ContractException e) { + throw ReceiptParser.parseExceptionCall(e); + } + } + + public RetCode freezeAccount(String userAddress) throws ContractException { + PrecompiledVersionCheck.CHAIN_GOVERNANCE_PRECOMPILED_VERSION.checkVersion(currentVersion); + return ReceiptParser.parseTransactionReceipt( + this.chainGovernancePrecompiled.freezeAccount(userAddress)); + } + + public RetCode unfreezeAccount(String userAddress) throws ContractException { + PrecompiledVersionCheck.CHAIN_GOVERNANCE_PRECOMPILED_VERSION.checkVersion(currentVersion); + return ReceiptParser.parseTransactionReceipt( + this.chainGovernancePrecompiled.unfreezeAccount(userAddress)); + } + + public String getAccountStatus(String userAddress) throws ContractException { + PrecompiledVersionCheck.CHAIN_GOVERNANCE_PRECOMPILED_VERSION.checkVersion(currentVersion); + try { + return this.chainGovernancePrecompiled.getAccountStatus(userAddress); + } catch (ContractException e) { + throw ReceiptParser.parseExceptionCall(e); + } + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/permission/PermissionInfo.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/permission/PermissionInfo.java new file mode 100644 index 000000000..83aaa7351 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/permission/PermissionInfo.java @@ -0,0 +1,82 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.contract.precompiled.permission; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Objects; + +public class PermissionInfo { + @JsonProperty("table_name") + private String tableName; + + private String address; + + @JsonProperty("enable_num") + private String enableNum; + + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getEnableNum() { + return enableNum; + } + + public void setEnableNum(String enableNum) { + this.enableNum = enableNum; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PermissionInfo that = (PermissionInfo) o; + return Objects.equals(tableName, that.tableName) + && Objects.equals(address, that.address) + && Objects.equals(enableNum, that.enableNum); + } + + @Override + public int hashCode() { + return Objects.hash(tableName, address, enableNum); + } + + @Override + public String toString() { + return "PermissionInfo{" + + "tableName='" + + tableName + + '\'' + + ", address='" + + address + + '\'' + + ", enableNum='" + + enableNum + + '\'' + + '}'; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/permission/PermissionPrecompiled.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/permission/PermissionPrecompiled.java new file mode 100644 index 000000000..d04caa083 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/permission/PermissionPrecompiled.java @@ -0,0 +1,326 @@ +package org.fisco.bcos.sdk.contract.precompiled.permission; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.abi.FunctionReturnDecoder; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.datatypes.Address; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Int256; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple1; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.Contract; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; + +@SuppressWarnings("unchecked") +public class PermissionPrecompiled extends Contract { + public static final String[] BINARY_ARRAY = {}; + + public static final String BINARY = String.join("", BINARY_ARRAY); + + public static final String[] SM_BINARY_ARRAY = {}; + + public static final String SM_BINARY = String.join("", SM_BINARY_ARRAY); + + public static final String[] ABI_ARRAY = { + "[{\"constant\":false,\"inputs\":[{\"name\":\"table_name\",\"type\":\"string\"},{\"name\":\"addr\",\"type\":\"string\"}],\"name\":\"insert\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"table_name\",\"type\":\"string\"}],\"name\":\"queryByName\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"table_name\",\"type\":\"string\"},{\"name\":\"addr\",\"type\":\"string\"}],\"name\":\"remove\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"contractAddr\",\"type\":\"address\"}],\"name\":\"queryPermission\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"contractAddr\",\"type\":\"address\"},{\"name\":\"user\",\"type\":\"address\"}],\"name\":\"grantWrite\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"contractAddr\",\"type\":\"address\"},{\"name\":\"user\",\"type\":\"address\"}],\"name\":\"revokeWrite\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" + }; + + public static final String ABI = String.join("", ABI_ARRAY); + + public static final String FUNC_INSERT = "insert"; + + public static final String FUNC_QUERYBYNAME = "queryByName"; + + public static final String FUNC_REMOVE = "remove"; + + public static final String FUNC_QUERYPERMISSION = "queryPermission"; + + public static final String FUNC_GRANTWRITE = "grantWrite"; + + public static final String FUNC_REVOKEWRITE = "revokeWrite"; + + protected PermissionPrecompiled( + String contractAddress, Client client, CryptoKeyPair credential) { + super(getBinary(client.getCryptoSuite()), contractAddress, client, credential); + } + + public static String getBinary(CryptoSuite cryptoSuite) { + return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY); + } + + public TransactionReceipt insert(String table_name, String addr) { + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(table_name), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(addr)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void insert(String table_name, String addr, TransactionCallback callback) { + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(table_name), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(addr)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForInsert(String table_name, String addr) { + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(table_name), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(addr)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple2 getInsertInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple2( + (String) results.get(0).getValue(), (String) results.get(1).getValue()); + } + + public Tuple1 getInsertOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_INSERT, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public String queryByName(String table_name) throws ContractException { + final Function function = + new Function( + FUNC_QUERYBYNAME, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(table_name)), + Arrays.>asList(new TypeReference() {})); + return executeCallWithSingleValueReturn(function, String.class); + } + + public TransactionReceipt remove(String table_name, String addr) { + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(table_name), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(addr)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void remove(String table_name, String addr, TransactionCallback callback) { + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(table_name), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(addr)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForRemove(String table_name, String addr) { + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(table_name), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(addr)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple2 getRemoveInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple2( + (String) results.get(0).getValue(), (String) results.get(1).getValue()); + } + + public Tuple1 getRemoveOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_REMOVE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public String queryPermission(String contractAddr) throws ContractException { + final Function function = + new Function( + FUNC_QUERYPERMISSION, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Address(contractAddr)), + Arrays.>asList(new TypeReference() {})); + return executeCallWithSingleValueReturn(function, String.class); + } + + public TransactionReceipt grantWrite(String contractAddr, String user) { + final Function function = + new Function( + FUNC_GRANTWRITE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Address(contractAddr), + new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void grantWrite(String contractAddr, String user, TransactionCallback callback) { + final Function function = + new Function( + FUNC_GRANTWRITE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Address(contractAddr), + new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForGrantWrite(String contractAddr, String user) { + final Function function = + new Function( + FUNC_GRANTWRITE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Address(contractAddr), + new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple2 getGrantWriteInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_GRANTWRITE, + Arrays.asList(), + Arrays.>asList( + new TypeReference
() {}, new TypeReference
() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple2( + (String) results.get(0).getValue(), (String) results.get(1).getValue()); + } + + public Tuple1 getGrantWriteOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_GRANTWRITE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public TransactionReceipt revokeWrite(String contractAddr, String user) { + final Function function = + new Function( + FUNC_REVOKEWRITE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Address(contractAddr), + new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void revokeWrite(String contractAddr, String user, TransactionCallback callback) { + final Function function = + new Function( + FUNC_REVOKEWRITE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Address(contractAddr), + new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForRevokeWrite(String contractAddr, String user) { + final Function function = + new Function( + FUNC_REVOKEWRITE, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Address(contractAddr), + new org.fisco.bcos.sdk.abi.datatypes.Address(user)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple2 getRevokeWriteInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_REVOKEWRITE, + Arrays.asList(), + Arrays.>asList( + new TypeReference
() {}, new TypeReference
() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple2( + (String) results.get(0).getValue(), (String) results.get(1).getValue()); + } + + public Tuple1 getRevokeWriteOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_REVOKEWRITE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public static PermissionPrecompiled load( + String contractAddress, Client client, CryptoKeyPair credential) { + return new PermissionPrecompiled(contractAddress, client, credential); + } + + public static PermissionPrecompiled deploy(Client client, CryptoKeyPair credential) + throws ContractException { + return deploy( + PermissionPrecompiled.class, + client, + credential, + getBinary(client.getCryptoSuite()), + ""); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/permission/PermissionService.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/permission/PermissionService.java new file mode 100644 index 000000000..dfa565477 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/permission/PermissionService.java @@ -0,0 +1,187 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.contract.precompiled.permission; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.precompiled.model.PrecompiledAddress; +import org.fisco.bcos.sdk.contract.precompiled.model.PrecompiledVersionCheck; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.PrecompiledConstant; +import org.fisco.bcos.sdk.model.RetCode; +import org.fisco.bcos.sdk.transaction.codec.decode.ReceiptParser; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; + +public class PermissionService { + private final PermissionPrecompiled permissionPrecompiled; + private final String currentVersion; + + public PermissionService(Client client, CryptoKeyPair credential) { + this.permissionPrecompiled = + PermissionPrecompiled.load( + PrecompiledAddress.PERMISSION_PRECOMPILED_ADDRESS, client, credential); + this.currentVersion = client.getClientNodeVersion().getNodeVersion().getSupportedVersion(); + } + + public RetCode grantPermission(String tableName, String userAddress) throws ContractException { + PrecompiledVersionCheck.TABLE_PERMISSION_PRECOMPILED_VERSION.checkVersion(currentVersion); + return ReceiptParser.parseTransactionReceipt( + this.permissionPrecompiled.insert(tableName, userAddress)); + } + + public RetCode revokePermission(String tableName, String userAddress) throws ContractException { + PrecompiledVersionCheck.TABLE_PERMISSION_PRECOMPILED_VERSION.checkVersion(currentVersion); + return ReceiptParser.parseTransactionReceipt( + this.permissionPrecompiled.remove(tableName, userAddress)); + } + + public static List parsePermissionInfo(String permissionInfo) + throws JsonProcessingException { + ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(); + return objectMapper.readValue( + permissionInfo, + objectMapper + .getTypeFactory() + .constructCollectionType(List.class, PermissionInfo.class)); + } + + public List queryPermission(String contractAddress) throws ContractException { + PrecompiledVersionCheck.QUERY_WRITE_PERMISSION_PRECOMPILED_VERSION.checkVersion( + currentVersion); + try { + String permissionInfo = this.permissionPrecompiled.queryPermission(contractAddress); + return parsePermissionInfo(permissionInfo); + } catch (JsonProcessingException e) { + throw new ContractException( + "Query permission for " + + contractAddress + + " failed, error info: " + + e.getMessage(), + e); + } catch (ContractException e) { + throw ReceiptParser.parseExceptionCall(e); + } + } + + public RetCode grantWrite(String contractAddress, String userAddress) throws ContractException { + PrecompiledVersionCheck.GRANT_WRITE_PERMISSION_PRECOMPILED_VERSION.checkVersion( + currentVersion); + return ReceiptParser.parseTransactionReceipt( + this.permissionPrecompiled.grantWrite(contractAddress, userAddress)); + } + + public RetCode revokeWrite(String contractAddress, String userAddress) + throws ContractException { + PrecompiledVersionCheck.REVOKE_WRITE_PERMISSION_PRECOMPILED_VERSION.checkVersion( + currentVersion); + return ReceiptParser.parseTransactionReceipt( + this.permissionPrecompiled.revokeWrite(contractAddress, userAddress)); + } + + public List queryPermissionByTableName(String tableName) + throws ContractException { + PrecompiledVersionCheck.TABLE_PERMISSION_PRECOMPILED_VERSION.checkVersion(currentVersion); + try { + String permissionInfo = this.permissionPrecompiled.queryByName(tableName); + return parsePermissionInfo(permissionInfo); + } catch (JsonProcessingException e) { + throw new ContractException( + "Query permission for " + tableName + " failed, error info: " + e.getMessage(), + e); + } catch (ContractException e) { + throw ReceiptParser.parseExceptionCall(e); + } + } + + // permission interfaces for _sys_table_ + public RetCode grantDeployAndCreateManager(String userAddress) throws ContractException { + PrecompiledVersionCheck.TABLE_PERMISSION_PRECOMPILED_VERSION.checkVersion(currentVersion); + return grantPermission(PrecompiledConstant.SYS_TABLE, userAddress); + } + + public RetCode revokeDeployAndCreateManager(String userAddress) throws ContractException { + PrecompiledVersionCheck.TABLE_PERMISSION_PRECOMPILED_VERSION.checkVersion(currentVersion); + return revokePermission(PrecompiledConstant.SYS_TABLE, userAddress); + } + + public List listDeployAndCreateManager() throws ContractException { + PrecompiledVersionCheck.TABLE_PERMISSION_PRECOMPILED_VERSION.checkVersion(currentVersion); + return queryPermissionByTableName(PrecompiledConstant.SYS_TABLE); + } + // permission interfaces for _sys_table_access_ + public RetCode grantPermissionManager(String userAddress) throws ContractException { + PrecompiledVersionCheck.TABLE_PERMISSION_PRECOMPILED_VERSION.checkVersion(currentVersion); + return grantPermission(PrecompiledConstant.SYS_TABLE_ACCESS, userAddress); + } + + public RetCode revokePermissionManager(String userAddress) throws ContractException { + PrecompiledVersionCheck.TABLE_PERMISSION_PRECOMPILED_VERSION.checkVersion(currentVersion); + return revokePermission(PrecompiledConstant.SYS_TABLE_ACCESS, userAddress); + } + + public List listPermissionManager() throws ContractException { + PrecompiledVersionCheck.TABLE_PERMISSION_PRECOMPILED_VERSION.checkVersion(currentVersion); + return queryPermissionByTableName(PrecompiledConstant.SYS_TABLE_ACCESS); + } + + // permission interfaces for _sys_consensus_ + public RetCode grantNodeManager(String userAddress) throws ContractException { + PrecompiledVersionCheck.TABLE_PERMISSION_PRECOMPILED_VERSION.checkVersion(currentVersion); + return grantPermission(PrecompiledConstant.SYS_CONSENSUS, userAddress); + } + + public RetCode revokeNodeManager(String userAddress) throws ContractException { + PrecompiledVersionCheck.TABLE_PERMISSION_PRECOMPILED_VERSION.checkVersion(currentVersion); + return revokePermission(PrecompiledConstant.SYS_CONSENSUS, userAddress); + } + + public List listNodeManager() throws ContractException { + PrecompiledVersionCheck.TABLE_PERMISSION_PRECOMPILED_VERSION.checkVersion(currentVersion); + return queryPermissionByTableName(PrecompiledConstant.SYS_CONSENSUS); + } + // permission interfaces for _sys_cns_ + public RetCode grantCNSManager(String userAddress) throws ContractException { + PrecompiledVersionCheck.TABLE_PERMISSION_PRECOMPILED_VERSION.checkVersion(currentVersion); + return grantPermission(PrecompiledConstant.SYS_CNS, userAddress); + } + + public RetCode revokeCNSManager(String userAddress) throws ContractException { + PrecompiledVersionCheck.TABLE_PERMISSION_PRECOMPILED_VERSION.checkVersion(currentVersion); + return revokePermission(PrecompiledConstant.SYS_CNS, userAddress); + } + + public List listCNSManager() throws ContractException { + PrecompiledVersionCheck.TABLE_PERMISSION_PRECOMPILED_VERSION.checkVersion(currentVersion); + return queryPermissionByTableName(PrecompiledConstant.SYS_CNS); + } + // permission interfaces for _sys_config_ + public RetCode grantSysConfigManager(String userAddress) throws ContractException { + PrecompiledVersionCheck.TABLE_PERMISSION_PRECOMPILED_VERSION.checkVersion(currentVersion); + return grantPermission(PrecompiledConstant.SYS_CONFIG, userAddress); + } + + public RetCode revokeSysConfigManager(String userAddress) throws ContractException { + PrecompiledVersionCheck.TABLE_PERMISSION_PRECOMPILED_VERSION.checkVersion(currentVersion); + return revokePermission(PrecompiledConstant.SYS_CONFIG, userAddress); + } + + public List listSysConfigManager() throws ContractException { + PrecompiledVersionCheck.TABLE_PERMISSION_PRECOMPILED_VERSION.checkVersion(currentVersion); + return queryPermissionByTableName(PrecompiledConstant.SYS_CONFIG); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/CNSPrecompiled.sol b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/CNSPrecompiled.sol new file mode 100644 index 000000000..b1ede87e7 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/CNSPrecompiled.sol @@ -0,0 +1,10 @@ +pragma solidity ^0.4.24; + +contract CNSPrecompiled +{ + function insert(string name, string version, string addr, string abi) public returns(uint256); + function selectByName(string name) public constant returns(string); + function selectByNameAndVersion(string name, string version) public constant returns(string); + function getContractAddress(string name, string version) public constant returns(address); +} + diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/CRUD.sol b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/CRUD.sol new file mode 100644 index 000000000..ff88a97bb --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/CRUD.sol @@ -0,0 +1,23 @@ +pragma solidity ^0.4.2; + +contract CRUD +{ + function insert(string tableName, string key, string entry, string) + public + returns (int256); + function remove(string tableName, string key, string condition, string) + public + returns (int256); + function select(string tableName, string key, string condition, string) + public + view + returns (string); + function desc(string tableName) public view returns (string, string); + function update( + string tableName, + string key, + string entry, + string condition, + string + ) public returns (int256); +} \ No newline at end of file diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/CRUDPrecompiled.sol b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/CRUDPrecompiled.sol new file mode 100644 index 000000000..11d7838e9 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/CRUDPrecompiled.sol @@ -0,0 +1,22 @@ +pragma solidity ^0.4.24; + +contract CRUDPrecompiled { + function insert(string tableName, string key, string entry, string) + public + returns (int256); + function remove(string tableName, string key, string condition, string) + public + returns (int256); + function select(string tableName, string key, string condition, string) + public + view + returns (string); + function desc(string tableName) public view returns (string, string); + function update( + string tableName, + string key, + string entry, + string condition, + string + ) public returns (int256); +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/ChainGovernancePrecompiled.sol b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/ChainGovernancePrecompiled.sol new file mode 100644 index 000000000..1ae3e33de --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/ChainGovernancePrecompiled.sol @@ -0,0 +1,37 @@ +pragma solidity ^0.4.24; + + +contract ChainGovernancePrecompiled { + function grantCommitteeMember(address user) public returns (int256); + + function revokeCommitteeMember(address user) public returns (int256); + + function listCommitteeMembers() public view returns (string); + + function queryCommitteeMemberWeight(address user) + public + view + returns (bool, int256); + + function updateCommitteeMemberWeight(address user, int256 weight) + public + returns (int256); + + // threshold [0,100) + function updateThreshold(int256 threshold) public returns (int256); + + function queryThreshold() public view returns (int256); + + function grantOperator(address user) public returns (int256); + + function revokeOperator(address user) public returns (int256); + + function listOperators() public view returns (string); + + // account life cycle + function freezeAccount(address account) public returns (int256); + + function unfreezeAccount(address account) public returns (int256); + + function getAccountStatus(address account) public view returns (string); +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/ConsensusPrecompiled.sol b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/ConsensusPrecompiled.sol new file mode 100644 index 000000000..c27d7210c --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/ConsensusPrecompiled.sol @@ -0,0 +1,7 @@ +pragma solidity ^0.4.24; + +contract ConsensusPrecompiled { + function addSealer(string) public returns (int256); + function addObserver(string) public returns (int256); + function remove(string) public returns (int256); +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/ContractLifeCyclePrecompiled.sol b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/ContractLifeCyclePrecompiled.sol new file mode 100644 index 000000000..a445be9fb --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/ContractLifeCyclePrecompiled.sol @@ -0,0 +1,9 @@ +pragma solidity ^0.4.24; + +contract ContractLifeCyclePrecompiled { + function freeze(address addr) public returns(int); + function unfreeze(address addr) public returns(int); + function grantManager(address contractAddr, address userAddr) public returns(int); + function getStatus(address addr) public constant returns(int,string); + function listManager(address addr) public constant returns(int,address[]); +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/ParallelConfigPrecompiled.sol b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/ParallelConfigPrecompiled.sol new file mode 100644 index 000000000..c3057aa8d --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/ParallelConfigPrecompiled.sol @@ -0,0 +1,10 @@ +pragma solidity ^0.4.24; + +contract ParallelConfigPrecompiled { + function registerParallelFunctionInternal(address, string, uint256) + public + returns (int256); + function unregisterParallelFunctionInternal(address, string) + public + returns (int256); +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/PermissionPrecompiled.sol b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/PermissionPrecompiled.sol new file mode 100644 index 000000000..adc4e6d29 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/PermissionPrecompiled.sol @@ -0,0 +1,15 @@ +pragma solidity ^0.4.24; + +contract PermissionPrecompiled { + function insert(string table_name, string addr) public returns (int256); + function remove(string table_name, string addr) public returns (int256); + function queryByName(string table_name) public view returns (string); + + function grantWrite(address contractAddr, address user) + public + returns (int256); + function revokeWrite(address contractAddr, address user) + public + returns (int256); + function queryPermission(address contractAddr) public view returns (string); +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/SystemConfigPrecompiled.sol b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/SystemConfigPrecompiled.sol new file mode 100644 index 000000000..d9e7df607 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/SystemConfigPrecompiled.sol @@ -0,0 +1,6 @@ +pragma solidity ^0.4.24; + +contract SystemConfigPrecompiled +{ + function setValueByKey(string key, string value) public returns(int256); +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/TableFactory.sol b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/TableFactory.sol new file mode 100644 index 000000000..7d3c0c3f2 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sol/TableFactory.sol @@ -0,0 +1,7 @@ +pragma solidity ^0.4.2; +import "./Table.sol"; + +contract TableFactory { + function openTable(string) public view returns (Table); //open table + function createTable(string, string, string) public returns (int256); //create table +} \ No newline at end of file diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sysconfig/SystemConfigPrecompiled.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sysconfig/SystemConfigPrecompiled.java new file mode 100644 index 000000000..acce33980 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sysconfig/SystemConfigPrecompiled.java @@ -0,0 +1,123 @@ +package org.fisco.bcos.sdk.contract.precompiled.sysconfig; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.abi.FunctionReturnDecoder; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.Int256; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple1; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.Contract; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.CryptoType; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; + +@SuppressWarnings("unchecked") +public class SystemConfigPrecompiled extends Contract { + public static final String[] BINARY_ARRAY = {}; + + public static final String BINARY = String.join("", BINARY_ARRAY); + + public static final String[] SM_BINARY_ARRAY = {}; + + public static final String SM_BINARY = String.join("", SM_BINARY_ARRAY); + + public static final String[] ABI_ARRAY = { + "[{\"constant\":false,\"inputs\":[{\"name\":\"key\",\"type\":\"string\"},{\"name\":\"value\",\"type\":\"string\"}],\"name\":\"setValueByKey\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" + }; + + public static final String ABI = String.join("", ABI_ARRAY); + + public static final String FUNC_SETVALUEBYKEY = "setValueByKey"; + + protected SystemConfigPrecompiled( + String contractAddress, Client client, CryptoKeyPair credential) { + super(getBinary(client.getCryptoSuite()), contractAddress, client, credential); + } + + public static String getBinary(CryptoSuite cryptoSuite) { + return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY); + } + + public TransactionReceipt setValueByKey(String key, String value) { + final Function function = + new Function( + FUNC_SETVALUEBYKEY, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(key), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(value)), + Collections.>emptyList()); + return executeTransaction(function); + } + + public void setValueByKey(String key, String value, TransactionCallback callback) { + final Function function = + new Function( + FUNC_SETVALUEBYKEY, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(key), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(value)), + Collections.>emptyList()); + asyncExecuteTransaction(function, callback); + } + + public String getSignedTransactionForSetValueByKey(String key, String value) { + final Function function = + new Function( + FUNC_SETVALUEBYKEY, + Arrays.asList( + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(key), + new org.fisco.bcos.sdk.abi.datatypes.Utf8String(value)), + Collections.>emptyList()); + return createSignedTransaction(function); + } + + public Tuple2 getSetValueByKeyInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = + new Function( + FUNC_SETVALUEBYKEY, + Arrays.asList(), + Arrays.>asList( + new TypeReference() {}, + new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple2( + (String) results.get(0).getValue(), (String) results.get(1).getValue()); + } + + public Tuple1 getSetValueByKeyOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = + new Function( + FUNC_SETVALUEBYKEY, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1((BigInteger) results.get(0).getValue()); + } + + public static SystemConfigPrecompiled load( + String contractAddress, Client client, CryptoKeyPair credential) { + return new SystemConfigPrecompiled(contractAddress, client, credential); + } + + public static SystemConfigPrecompiled deploy(Client client, CryptoKeyPair credential) + throws ContractException { + return deploy( + SystemConfigPrecompiled.class, + client, + credential, + getBinary(client.getCryptoSuite()), + ""); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sysconfig/SystemConfigService.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sysconfig/SystemConfigService.java new file mode 100644 index 000000000..387d09660 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/contract/precompiled/sysconfig/SystemConfigService.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.contract.precompiled.sysconfig; + +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.contract.precompiled.model.PrecompiledAddress; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.RetCode; +import org.fisco.bcos.sdk.transaction.codec.decode.ReceiptParser; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; + +public class SystemConfigService { + private final SystemConfigPrecompiled systemConfigPrecompiled; + + public SystemConfigService(Client client, CryptoKeyPair credential) { + this.systemConfigPrecompiled = + SystemConfigPrecompiled.load( + PrecompiledAddress.SYSCONFIG_PRECOMPILED_ADDRESS, client, credential); + } + + public RetCode setValueByKey(String key, String value) throws ContractException { + return ReceiptParser.parseTransactionReceipt( + systemConfigPrecompiled.setValueByKey(key, value)); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/builder/TransactionBuilderInterface.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/builder/TransactionBuilderInterface.java new file mode 100644 index 000000000..cd34ef16e --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/builder/TransactionBuilderInterface.java @@ -0,0 +1,46 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.builder; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.transaction.model.po.RawTransaction; + +/** + * TransactionBuilderInterface @Description: TransactionBuilderInterface + * + * @author maojiayu + */ +public interface TransactionBuilderInterface { + + public RawTransaction createTransaction( + BigInteger gasPrice, + BigInteger gasLimit, + String to, + String data, + BigInteger value, + BigInteger chainId, + BigInteger groupId, + String extraData); + + /** + * Create fisco bcos transaction for short + * + * @param to target address + * @param data encoded data + * @param groupId the group that need create transaction + * @return RawTransaction the created transaction + */ + public RawTransaction createTransaction(String to, String data, BigInteger groupId); +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/builder/TransactionBuilderService.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/builder/TransactionBuilderService.java new file mode 100644 index 000000000..8c656f889 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/builder/TransactionBuilderService.java @@ -0,0 +1,86 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.builder; + +import java.math.BigInteger; +import java.security.SecureRandom; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.transaction.model.gas.DefaultGasProvider; +import org.fisco.bcos.sdk.transaction.model.po.RawTransaction; + +public class TransactionBuilderService implements TransactionBuilderInterface { + + private SecureRandom secureRandom = new SecureRandom(); + private Client client; + + /** + * create TransactionBuilderService + * + * @param client the client object + */ + public TransactionBuilderService(Client client) { + super(); + this.client = client; + } + + @Override + public RawTransaction createTransaction( + BigInteger gasPrice, + BigInteger gasLimit, + String to, + String data, + BigInteger value, + BigInteger chainId, + BigInteger groupId, + String extraData) { + BigInteger randomId = new BigInteger(250, secureRandom); + BigInteger blockLimit = client.getBlockLimit(); + return RawTransaction.createTransaction( + randomId, + gasPrice, + gasLimit, + blockLimit, + to, + value, + data, + chainId, + groupId, + extraData); + } + + @Override + public RawTransaction createTransaction(String to, String data, BigInteger groupId) { + + return createTransaction( + DefaultGasProvider.GAS_PRICE, + DefaultGasProvider.GAS_LIMIT, + to, + data, + BigInteger.ZERO, + BigInteger.ONE, + groupId, + null); + } + + /** @return the client */ + public Client getClient() { + return client; + } + + /** @param client the client to set */ + public void setClient(Client client) { + this.client = client; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/decode/ReceiptParser.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/decode/ReceiptParser.java new file mode 100644 index 000000000..af7849c1b --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/decode/ReceiptParser.java @@ -0,0 +1,124 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.codec.decode; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2; +import org.fisco.bcos.sdk.client.protocol.response.Call; +import org.fisco.bcos.sdk.model.PrecompiledRetCode; +import org.fisco.bcos.sdk.model.RetCode; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.TransactionReceiptStatus; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; +import org.fisco.bcos.sdk.utils.Numeric; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ReceiptParser { + private static final Logger logger = LoggerFactory.getLogger(ReceiptParser.class); + + private ReceiptParser() {} + + public static RetCode parseTransactionReceipt(TransactionReceipt receipt) + throws ContractException { + RetCode retCode = new RetCode(); + try { + String status = receipt.getStatus(); + if (!"0x0".equals(status)) { + retCode = TransactionReceiptStatus.getStatusMessage(status, receipt.getMessage()); + Tuple2 errorOutput = + RevertMessageParser.tryResolveRevertMessage(receipt); + if (errorOutput.getValue1()) { + throw new ContractException( + errorOutput.getValue2(), retCode.getCode(), receipt); + } + throw new ContractException(retCode.getMessage(), retCode.getCode(), receipt); + } else { + String output = receipt.getOutput(); + if (output.equals("0x")) { + return PrecompiledRetCode.CODE_SUCCESS; + } + try { + int statusValue = + new BigInteger(output.substring(2, output.length()), 16).intValue(); + if (receipt.getMessage() == null || receipt.getMessage().equals("")) { + receipt.setMessage(PrecompiledRetCode.CODE_SUCCESS.getMessage()); + } + retCode = + PrecompiledRetCode.getPrecompiledResponse( + statusValue, receipt.getMessage()); + retCode.setTransactionReceipt(receipt); + return retCode; + } catch (Exception e) { + logger.debug( + "try to parse the output failed, output: {}, status: {}, exception: {}", + output, + receipt.getStatus(), + e.getMessage()); + retCode = PrecompiledRetCode.CODE_SUCCESS; + retCode.setTransactionReceipt(receipt); + return retCode; + } + } + } catch (NumberFormatException e) { + throw new ContractException( + "NumberFormatException when parse receipt, receipt info: " + + receipt.toString() + + ", error info: " + + e.getMessage()); + } + } + + public static ContractException parseExceptionCall(ContractException exception) { + Call.CallOutput callResult = exception.getResponseOutput(); + if (callResult == null) { + return new ContractException(exception.getMessage(), exception); + } + RetCode retCode = parseCallOutput(callResult, exception.getMessage()); + return new ContractException(retCode.getMessage(), retCode.getCode()); + } + + public static RetCode parseCallOutput(Call.CallOutput callResult, String message) { + if (!callResult.getStatus().equals("0x0")) { + Tuple2 errorOutput = + RevertMessageParser.tryResolveRevertMessage( + callResult.getStatus(), callResult.getOutput()); + if (errorOutput.getValue1()) { + return new RetCode( + Numeric.decodeQuantity(callResult.getStatus()).intValue(), + errorOutput.getValue2()); + } + return TransactionReceiptStatus.getStatusMessage(callResult.getStatus(), message); + } + try { + if (callResult.getOutput().equals("0x")) { + return PrecompiledRetCode.CODE_SUCCESS; + } + int statusValue = + new BigInteger( + callResult + .getOutput() + .substring(2, callResult.getOutput().length()), + 16) + .intValue(); + RetCode ret = + PrecompiledRetCode.getPrecompiledResponse( + statusValue, PrecompiledRetCode.CODE_SUCCESS.getMessage()); + return new RetCode(ret.getCode(), ret.getMessage()); + } catch (Exception e) { + return PrecompiledRetCode.CODE_SUCCESS; + } + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/decode/RevertMessageParser.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/decode/RevertMessageParser.java new file mode 100644 index 000000000..50d03c4e3 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/decode/RevertMessageParser.java @@ -0,0 +1,126 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.codec.decode; + +/* +pragma solidity ^0.4.25; +contract Revert { + function Error(string memory s) public {} +} + +"08c379a0": "Error(string)" // Not SM Method +"c703cb12": "Error(string)" // SM Method +*/ + +import java.math.BigInteger; +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.abi.FunctionReturnDecoder; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; +import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.utils.Numeric; +import org.fisco.bcos.sdk.utils.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RevertMessageParser { + + private static final Logger logger = LoggerFactory.getLogger(RevertMessageParser.class); + + public static final String RevertMethod = "08c379a0"; + public static final String RevertMethodWithHexPrefix = "0x08c379a0"; + + public static final String SMRevertMethod = "c703cb12"; + public static final String SMRevertMethodWithHexPrefix = "0xc703cb12"; + + // Error(String) + public static final Function revertFunction = + new Function( + "Error", + Collections.emptyList(), + Collections.singletonList(new TypeReference() {})); + + /** + * Does output start with the code of the Revert method, If so, the output may be error message + * + * @param output the string of output + * @return true/false + */ + public static boolean isOutputStartWithRevertMethod(String output) { + return output.startsWith(RevertMethodWithHexPrefix) + || output.startsWith(SMRevertMethodWithHexPrefix) + || (output.startsWith(RevertMethod) || output.startsWith(SMRevertMethod)); + } + + /** + * @param status the status of the receipt + * @param output the output of the receipt + * @return true/false + */ + public static boolean hasRevertMessage(String status, String output) { + if (StringUtils.isEmpty(status) || StringUtils.isEmpty(output)) { + return false; + } + try { + BigInteger statusQuantity = Numeric.decodeQuantity(status); + return !BigInteger.ZERO.equals(statusQuantity) && isOutputStartWithRevertMethod(output); + } catch (Exception e) { + return false; + } + } + + /** + * @param status the transaction receipt status + * @param output the output of the transaction receipt + * @return the resolved revert message information + */ + public static Tuple2 tryResolveRevertMessage(String status, String output) { + if (!hasRevertMessage(status, output)) { + return new Tuple2<>(false, null); + } + + try { + String rawOutput = + Numeric.containsHexPrefix(output) + ? output.substring(RevertMethodWithHexPrefix.length()) + : output.substring(RevertMethod.length()); + List result = + FunctionReturnDecoder.decode(rawOutput, revertFunction.getOutputParameters()); + if (result.get(0) instanceof Utf8String) { + String message = ((Utf8String) result.get(0)).getValue(); + if (logger.isDebugEnabled()) { + logger.debug(" ABI: {} , RevertMessage: {}", output, message); + } + return new Tuple2<>(true, message); + } + } catch (Exception e) { + logger.warn(" ABI: {}, e: {}", output, e); + } + + return new Tuple2<>(false, null); + } + + /** + * @param receipt the receipt need to be parsed + * @return the resolved revert message information + */ + public static Tuple2 tryResolveRevertMessage(TransactionReceipt receipt) { + return tryResolveRevertMessage(receipt.getStatus(), receipt.getOutput()); + } +} 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 new file mode 100644 index 000000000..5f3d8c4a3 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/decode/TransactionDecoderInterface.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.codec.decode; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import org.fisco.bcos.sdk.abi.ABICodecException; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.TransactionReceipt.Logs; +import org.fisco.bcos.sdk.transaction.model.dto.TransactionResponse; +import org.fisco.bcos.sdk.transaction.model.exception.TransactionException; + +/** + * TransactionDecoderInterface @Description: TransactionDecoderInterface + * + * @author maojiayu + */ +public interface TransactionDecoderInterface { + + public String decodeReceiptMessage(String input); + + public TransactionResponse decodeReceiptStatus(TransactionReceipt receipt); + + public TransactionResponse decodeReceiptWithValues( + String abi, String functionName, TransactionReceipt receipt) + throws JsonProcessingException, TransactionException, IOException, ABICodecException; + + public TransactionResponse decodeReceiptWithoutValues( + String abi, TransactionReceipt transactionReceipt) + throws TransactionException, IOException, ABICodecException; + + public Map> decodeEvents(String abi, List logs) + throws ABICodecException; +} 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 new file mode 100644 index 000000000..24ad678f6 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/decode/TransactionDecoderService.java @@ -0,0 +1,174 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.codec.decode; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.fisco.bcos.sdk.abi.ABICodec; +import org.fisco.bcos.sdk.abi.ABICodecException; +import org.fisco.bcos.sdk.abi.EventEncoder; +import org.fisco.bcos.sdk.abi.wrapper.ABICodecObject; +import org.fisco.bcos.sdk.abi.wrapper.ABIDefinition; +import org.fisco.bcos.sdk.abi.wrapper.ABIDefinition.NamedType; +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.RetCode; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.TransactionReceipt.Logs; +import org.fisco.bcos.sdk.transaction.model.dto.TransactionResponse; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; +import org.fisco.bcos.sdk.transaction.model.exception.TransactionException; +import org.fisco.bcos.sdk.transaction.tools.JsonUtils; +import org.fisco.bcos.sdk.transaction.tools.ReceiptStatusUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TransactionDecoderService implements TransactionDecoderInterface { + protected static Logger logger = LoggerFactory.getLogger(TransactionDecoderService.class); + + private CryptoSuite cryptoSuite; + private final ABICodec abiCodec; + private EventEncoder eventEncoder; + + /** + * create TransactionDecoderService + * + * @param cryptoSuite the cryptoSuite used to calculate hash and signatures + */ + public TransactionDecoderService(CryptoSuite cryptoSuite) { + super(); + this.cryptoSuite = cryptoSuite; + this.abiCodec = new ABICodec(cryptoSuite); + this.eventEncoder = new EventEncoder(cryptoSuite); + } + + @Override + public String decodeReceiptMessage(String output) { + return ReceiptStatusUtil.decodeReceiptMessage(output); + } + + @Override + public TransactionResponse decodeReceiptWithValues( + String abi, String functionName, TransactionReceipt transactionReceipt) + throws IOException, ABICodecException, TransactionException { + TransactionResponse response = decodeReceiptWithoutValues(abi, transactionReceipt); + // only successful tx has return values. + if (transactionReceipt.getStatus().equals("0x0")) { + String values = + JsonUtils.toJson( + abiCodec.decodeMethod( + abi, functionName, transactionReceipt.getOutput())); + response.setValues(values); + } + return response; + } + + @Override + public TransactionResponse decodeReceiptWithoutValues( + String abi, TransactionReceipt transactionReceipt) + throws TransactionException, IOException, ABICodecException { + TransactionResponse response = decodeReceiptStatus(transactionReceipt); + String events = JsonUtils.toJson(decodeEvents(abi, transactionReceipt.getLogs())); + response.setTransactionReceipt(transactionReceipt); + response.setEvents(events); + response.setContractAddress(transactionReceipt.getContractAddress()); + return response; + } + + @Override + public TransactionResponse decodeReceiptStatus(TransactionReceipt receipt) { + TransactionResponse response = new TransactionResponse(); + try { + RetCode retCode = ReceiptParser.parseTransactionReceipt(receipt); + response.setReturnCode(retCode.getCode()); + response.setReceiptMessages(retCode.getMessage()); + response.setReturnMessage(retCode.getMessage()); + } catch (ContractException e) { + response.setReturnCode(e.getErrorCode()); + response.setReceiptMessages(e.getMessage()); + response.setReturnMessage(e.getMessage()); + } + return response; + } + + @SuppressWarnings("static-access") + @Override + public Map> decodeEvents(String abi, List logs) + throws ABICodecException { + ABIDefinitionFactory abiDefinitionFactory = new ABIDefinitionFactory(cryptoSuite); + ContractABIDefinition contractABIDefinition = abiDefinitionFactory.loadABI(abi); + Map> eventsMap = contractABIDefinition.getEvents(); + Map> result = new HashMap<>(); + eventsMap.forEach( + (name, events) -> { + for (ABIDefinition abiDefinition : events) { + ABIObjectFactory abiObjectFactory = new ABIObjectFactory(); + ABIObject outputObject = abiObjectFactory.createInputObject(abiDefinition); + ABICodecObject abiCodecObject = new ABICodecObject(); + for (Logs log : logs) { + String eventSignature = + eventEncoder.buildEventSignature( + decodeMethodSign(abiDefinition)); + if (log.getTopics().isEmpty() + || !log.getTopics().contains(eventSignature)) { + continue; + } + try { + List list = + abiCodecObject.decodeJavaObject( + outputObject, log.getData()); + if (result.containsKey(name)) { + result.get("name").addAll(list); + } else { + result.put(name, list); + } + } catch (Exception e) { + logger.error( + " exception in decodeEventToObject : {}", e.getMessage()); + } + } + } + }); + return result; + } + + private String decodeMethodSign(ABIDefinition ABIDefinition) { + List inputTypes = ABIDefinition.getInputs(); + StringBuilder methodSign = new StringBuilder(); + methodSign.append(ABIDefinition.getName()); + methodSign.append("("); + String params = + inputTypes.stream().map(NamedType::getType).collect(Collectors.joining(",")); + methodSign.append(params); + methodSign.append(")"); + return methodSign.toString(); + } + + /** @return the cryptoSuite */ + public CryptoSuite getCryptoSuite() { + return cryptoSuite; + } + + /** @param cryptoSuite the cryptoSuite to set */ + public void setCryptoSuite(CryptoSuite cryptoSuite) { + this.cryptoSuite = cryptoSuite; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/encode/TransactionEncoderInterface.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/encode/TransactionEncoderInterface.java new file mode 100644 index 000000000..852b01a6c --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/encode/TransactionEncoderInterface.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.codec.encode; + +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.crypto.signature.SignatureResult; +import org.fisco.bcos.sdk.transaction.model.po.RawTransaction; + +/** + * TransactionEncoderInterface @Description: TransactionEncoderInterface + * + * @author maojiayu + */ +public interface TransactionEncoderInterface { + + byte[] encode(RawTransaction transaction, SignatureResult signature); + + byte[] encodeAndSignBytes(RawTransaction rawTransaction, CryptoKeyPair cryptoKeyPair); + + String encodeAndSign(RawTransaction rawTransaction, CryptoKeyPair cryptoKeyPair); +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/encode/TransactionEncoderService.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/encode/TransactionEncoderService.java new file mode 100644 index 000000000..9c41d6954 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/codec/encode/TransactionEncoderService.java @@ -0,0 +1,111 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.codec.encode; + +import java.util.ArrayList; +import java.util.List; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.crypto.signature.Signature; +import org.fisco.bcos.sdk.crypto.signature.SignatureResult; +import org.fisco.bcos.sdk.rlp.RlpEncoder; +import org.fisco.bcos.sdk.rlp.RlpList; +import org.fisco.bcos.sdk.rlp.RlpString; +import org.fisco.bcos.sdk.rlp.RlpType; +import org.fisco.bcos.sdk.transaction.model.po.RawTransaction; +import org.fisco.bcos.sdk.transaction.signer.TransactionSignerInterface; +import org.fisco.bcos.sdk.transaction.signer.TransactionSignerServcie; +import org.fisco.bcos.sdk.utils.Hex; +import org.fisco.bcos.sdk.utils.Numeric; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TransactionEncoderService implements TransactionEncoderInterface { + protected static Logger logger = LoggerFactory.getLogger(TransactionEncoderService.class); + private final Signature signature; + private final TransactionSignerInterface transactionSignerService; + private final CryptoSuite cryptoSuite; + + public TransactionEncoderService(CryptoSuite cryptoSuite) { + super(); + this.cryptoSuite = cryptoSuite; + this.signature = cryptoSuite.getSignatureImpl(); + this.transactionSignerService = new TransactionSignerServcie(signature); + } + + @Override + public String encodeAndSign(RawTransaction rawTransaction, CryptoKeyPair cryptoKeyPair) { + return Numeric.toHexString(encodeAndSignBytes(rawTransaction, cryptoKeyPair)); + } + + @Override + public byte[] encodeAndSignBytes(RawTransaction rawTransaction, CryptoKeyPair cryptoKeyPair) { + byte[] encodedTransaction = encode(rawTransaction, null); + byte[] hash = cryptoSuite.hash(encodedTransaction); + SignatureResult result = + transactionSignerService.sign(Hex.toHexString(hash), cryptoKeyPair); + return encode(rawTransaction, result); + } + + @Override + public byte[] encode(RawTransaction transaction, SignatureResult signature) { + List values = asRlpValues(transaction, signature); + RlpList rlpList = new RlpList(values); + return RlpEncoder.encode(rlpList); + } + + public static List asRlpValues( + RawTransaction rawTransaction, SignatureResult signatureResult) { + List result = new ArrayList<>(); + result.add(RlpString.create(rawTransaction.getRandomid())); + result.add(RlpString.create(rawTransaction.getGasPrice())); + result.add(RlpString.create(rawTransaction.getGasLimit())); + result.add(RlpString.create(rawTransaction.getBlockLimit())); + // an empty to address (contract creation) should not be encoded as a numeric 0 value + String to = rawTransaction.getTo(); + if (to != null && to.length() > 0) { + // addresses that start with zeros should be encoded with the zeros included, not + // as numeric values + result.add(RlpString.create(Numeric.hexStringToByteArray(to))); + } else { + result.add(RlpString.create("")); + } + + result.add(RlpString.create(rawTransaction.getValue())); + + // value field will already be hex encoded, so we need to convert into binary first + byte[] data = Numeric.hexStringToByteArray(rawTransaction.getData()); + result.add(RlpString.create(data)); + + // add extra data!!! + result.add(RlpString.create(rawTransaction.getFiscoChainId())); + result.add(RlpString.create(rawTransaction.getGroupId())); + if (rawTransaction.getExtraData() == null) { + result.add(RlpString.create("")); + } else { + result.add( + RlpString.create(Numeric.hexStringToByteArray(rawTransaction.getExtraData()))); + } + if (signatureResult != null) { + result.addAll(signatureResult.encode()); + } + return result; + } + + /** @return the signature */ + public Signature getSignature() { + return signature; + } +} 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 new file mode 100644 index 000000000..b794b4c0c --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/manager/AssembleTransactionProcessor.java @@ -0,0 +1,325 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.manager; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.fisco.bcos.sdk.abi.ABICodec; +import org.fisco.bcos.sdk.abi.ABICodecException; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.client.protocol.response.Call; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.PrecompiledRetCode; +import org.fisco.bcos.sdk.model.RetCode; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.codec.decode.ReceiptParser; +import org.fisco.bcos.sdk.transaction.codec.decode.TransactionDecoderInterface; +import org.fisco.bcos.sdk.transaction.codec.decode.TransactionDecoderService; +import org.fisco.bcos.sdk.transaction.model.dto.CallRequest; +import org.fisco.bcos.sdk.transaction.model.dto.CallResponse; +import org.fisco.bcos.sdk.transaction.model.dto.ResultCodeEnum; +import org.fisco.bcos.sdk.transaction.model.dto.TransactionResponse; +import org.fisco.bcos.sdk.transaction.model.exception.NoSuchTransactionFileException; +import org.fisco.bcos.sdk.transaction.model.exception.TransactionBaseException; +import org.fisco.bcos.sdk.transaction.model.exception.TransactionException; +import org.fisco.bcos.sdk.transaction.pusher.TransactionPusherInterface; +import org.fisco.bcos.sdk.transaction.pusher.TransactionPusherService; +import org.fisco.bcos.sdk.transaction.tools.ContractLoader; +import org.fisco.bcos.sdk.transaction.tools.JsonUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ContractlessTransactionManager @Description: ContractlessTransactionManager + * + * @author maojiayu + */ +public class AssembleTransactionProcessor extends TransactionProcessor + implements AssembleTransactionProcessorInterface { + protected static Logger log = LoggerFactory.getLogger(AssembleTransactionProcessor.class); + protected final TransactionDecoderInterface transactionDecoder; + protected final TransactionPusherInterface transactionPusher; + protected final ABICodec abiCodec; + private ContractLoader contractLoader; + + public AssembleTransactionProcessor( + Client client, + CryptoKeyPair cryptoKeyPair, + Integer groupId, + String chainId, + ContractLoader contractLoader) { + super(client, cryptoKeyPair, groupId, chainId); + this.transactionDecoder = new TransactionDecoderService(cryptoSuite); + this.transactionPusher = new TransactionPusherService(client); + this.abiCodec = new ABICodec(cryptoSuite); + this.contractLoader = contractLoader; + } + + @Override + public void deployOnly(String abi, String bin, List params) throws ABICodecException { + transactionPusher.pushOnly(createSignedConstructor(abi, bin, params)); + } + + @Override + public TransactionReceipt deployAndGetReceipt(String data) { + String signedData = createSignedTransaction(null, data, this.cryptoKeyPair); + return transactionPusher.push(signedData); + } + + @Override + public TransactionResponse deployAndGetResponse(String abi, String signedData) { + TransactionReceipt receipt = transactionPusher.push(signedData); + try { + return transactionDecoder.decodeReceiptWithoutValues(abi, receipt); + } catch (TransactionException | IOException | ABICodecException e) { + log.error("deploy exception: {}", e.getMessage()); + return new TransactionResponse( + receipt, ResultCodeEnum.EXCEPTION_OCCUR.getCode(), e.getMessage()); + } + } + + @Override + public TransactionResponse deployAndGetResponse(String abi, String bin, List params) + throws ABICodecException { + return deployAndGetResponse(abi, createSignedConstructor(abi, bin, params)); + } + + @Override + public TransactionResponse deployAndGetResponseWithStringParams( + String abi, String bin, List params) throws ABICodecException { + return deployAndGetResponse( + abi, + createSignedTransaction( + null, + abiCodec.encodeConstructorFromString(abi, bin, params), + this.cryptoKeyPair)); + } + + @Override + public void deployAsync( + String abi, String bin, List params, TransactionCallback callback) + throws ABICodecException { + transactionPusher.pushAsync(createSignedConstructor(abi, bin, params), callback); + } + + @Override + public CompletableFuture deployAsync( + String abi, String bin, List params) throws ABICodecException { + return transactionPusher.pushAsync(createSignedConstructor(abi, bin, params)); + } + + /** + * Deploy by bin and abi files. Should init with contractLoader. + * + * @param contractName the contract name + * @param args the params when deploy a contract + * @return the transaction response + * @throws TransactionBaseException send transaction exceptioned + * @throws ABICodecException abi encode exceptioned + * @throws NoSuchTransactionFileException Files related to abi codec were not found + */ + @Override + public TransactionResponse deployByContractLoader(String contractName, List args) + throws ABICodecException, TransactionBaseException { + return deployAndGetResponse( + contractLoader.getABIByContractName(contractName), + contractLoader.getBinaryByContractName(contractName), + args); + } + + @Override + public void deployByContractLoaderAsync( + String contractName, List args, TransactionCallback callback) + throws ABICodecException, NoSuchTransactionFileException { + deployAsync( + contractLoader.getABIByContractName(contractName), + contractLoader.getBinaryByContractName(contractName), + args, + callback); + } + + @Override + public void sendTransactionOnly(String signedData) { + this.transactionPusher.pushOnly(signedData); + } + + @Override + public TransactionResponse sendTransactionAndGetResponse( + String to, String abi, String functionName, String data) + throws TransactionBaseException, ABICodecException { + String signedData = createSignedTransaction(to, data, this.cryptoKeyPair); + TransactionReceipt receipt = this.transactionPusher.push(signedData); + try { + return transactionDecoder.decodeReceiptWithValues(abi, functionName, receipt); + } catch (TransactionException | IOException e) { + log.error("sendTransaction exception: {}", e.getMessage()); + return new TransactionResponse( + receipt, ResultCodeEnum.EXCEPTION_OCCUR.getCode(), e.getMessage()); + } + } + + @Override + public TransactionResponse sendTransactionAndGetResponse( + String to, String abi, String functionName, List params) + throws ABICodecException, TransactionBaseException { + String data = encodeFunction(abi, functionName, params); + return sendTransactionAndGetResponse(to, abi, functionName, data); + } + + @Override + public TransactionResponse sendTransactionWithStringParamsAndGetResponse( + String to, String abi, String functionName, List params) + throws ABICodecException, TransactionBaseException { + String data = abiCodec.encodeMethodFromString(abi, functionName, params); + return sendTransactionAndGetResponse(to, abi, functionName, data); + } + + @Override + public TransactionReceipt sendTransactionAndGetReceiptByContractLoader( + String contractName, String contractAddress, String functionName, List args) + throws ABICodecException, TransactionBaseException { + String data = + abiCodec.encodeMethod( + contractLoader.getABIByContractName(contractName), functionName, args); + return sendTransactionAndGetReceipt(contractAddress, data, cryptoKeyPair); + } + + @Override + public TransactionResponse sendTransactionAndGetResponseByContractLoader( + String contractName, + String contractAddress, + String functionName, + List funcParams) + throws ABICodecException, TransactionBaseException { + return sendTransactionAndGetResponse( + contractAddress, + contractLoader.getABIByContractName(contractName), + functionName, + funcParams); + } + + @Override + public void sendTransactionAsync(String signedTransaction, TransactionCallback callback) { + transactionPusher.pushAsync(signedTransaction, callback); + } + + @Override + public void sendTransactionAsync( + String to, + String abi, + String functionName, + List params, + TransactionCallback callback) + throws TransactionBaseException, ABICodecException { + String data = encodeFunction(abi, functionName, params); + sendTransactionAsync(to, data, this.cryptoKeyPair, callback); + } + + @Override + public CompletableFuture sendTransactionAsync(String signedData) { + return transactionPusher.pushAsync(signedData); + } + + @Override + public void sendTransactionAndGetReceiptByContractLoaderAsync( + String contractName, + String contractAddress, + String functionName, + List args, + TransactionCallback callback) + throws ABICodecException, TransactionBaseException { + String data = + abiCodec.encodeMethod( + contractLoader.getABIByContractName(contractName), functionName, args); + sendTransactionAsync(contractAddress, data, this.cryptoKeyPair, callback); + } + + @Override + public CallResponse sendCallByContractLoader( + String contractName, String contractAddress, String functionName, List args) + throws TransactionBaseException, ABICodecException { + return sendCall( + this.cryptoKeyPair.getAddress(), + contractAddress, + contractLoader.getABIByContractName(contractName), + functionName, + args); + } + + @Override + public CallResponse sendCall( + String from, String to, String abi, String functionName, List paramsList) + throws TransactionBaseException, ABICodecException { + String data = abiCodec.encodeMethod(abi, functionName, paramsList); + return callAndGetResponse(from, to, abi, functionName, data); + } + + @Override + public CallResponse sendCall(CallRequest callRequest) + throws TransactionBaseException, ABICodecException { + Call call = executeCall(callRequest); + CallResponse callResponse = parseCallResponseStatus(call.getCallResult()); + String callOutput = call.getCallResult().getOutput(); + List results = abiCodec.decodeMethod(callRequest.getAbi(), callOutput); + callResponse.setValues(JsonUtils.toJson(results)); + return callResponse; + } + + @Override + public CallResponse sendCallWithStringParams( + String from, String to, String abi, String functionName, List paramsList) + throws TransactionBaseException, ABICodecException { + String data = abiCodec.encodeMethodFromString(abi, functionName, paramsList); + return callAndGetResponse(from, to, abi, functionName, data); + } + + public CallResponse callAndGetResponse( + String from, String to, String abi, String functionName, String data) + throws ABICodecException, TransactionBaseException { + Call call = executeCall(from, to, data); + CallResponse callResponse = parseCallResponseStatus(call.getCallResult()); + List results = + abiCodec.decodeMethod(abi, functionName, call.getCallResult().getOutput()); + callResponse.setValues(JsonUtils.toJson(results)); + return callResponse; + } + + @Override + public String createSignedConstructor(String abi, String bin, List params) + throws ABICodecException { + return createSignedTransaction( + null, abiCodec.encodeConstructor(abi, bin, params), this.cryptoKeyPair); + } + + @Override + public String encodeFunction(String abi, String functionName, List params) + throws ABICodecException { + return abiCodec.encodeMethod(abi, functionName, params); + } + + private CallResponse parseCallResponseStatus(Call.CallOutput callOutput) + throws TransactionBaseException { + CallResponse callResponse = new CallResponse(); + RetCode retCode = ReceiptParser.parseCallOutput(callOutput, ""); + callResponse.setReturnCode(retCode.getCode()); + callResponse.setReturnMessage(retCode.getMessage()); + if (!retCode.getMessage().equals(PrecompiledRetCode.CODE_SUCCESS.getMessage())) { + throw new TransactionBaseException(retCode); + } + return callResponse; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/manager/AssembleTransactionProcessorInterface.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/manager/AssembleTransactionProcessorInterface.java new file mode 100644 index 000000000..b96176249 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/manager/AssembleTransactionProcessorInterface.java @@ -0,0 +1,121 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.manager; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.fisco.bcos.sdk.abi.ABICodecException; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.model.dto.CallRequest; +import org.fisco.bcos.sdk.transaction.model.dto.CallResponse; +import org.fisco.bcos.sdk.transaction.model.dto.TransactionResponse; +import org.fisco.bcos.sdk.transaction.model.exception.NoSuchTransactionFileException; +import org.fisco.bcos.sdk.transaction.model.exception.TransactionBaseException; + +public interface AssembleTransactionProcessorInterface { + + public TransactionReceipt deployAndGetReceipt(String data); + + public void deployOnly(String abi, String bin, List params) throws ABICodecException; + + public TransactionResponse deployAndGetResponse(String abi, String signedData); + + public TransactionResponse deployAndGetResponse(String abi, String bin, List params) + throws ABICodecException; + + public TransactionResponse deployAndGetResponseWithStringParams( + String abi, String bin, List params) throws ABICodecException; + + public void deployAsync( + String abi, String bin, List params, TransactionCallback callback) + throws ABICodecException; + + public CompletableFuture deployAsync( + String abi, String bin, List params) throws ABICodecException; + + public TransactionResponse deployByContractLoader(String contractName, List params) + throws ABICodecException, TransactionBaseException; + + public void deployByContractLoaderAsync( + String contractName, List args, TransactionCallback callback) + throws ABICodecException, NoSuchTransactionFileException; + + public void sendTransactionOnly(String signedData); + + public TransactionReceipt sendTransactionAndGetReceiptByContractLoader( + String contractName, String contractAddress, String functionName, List params) + throws ABICodecException, TransactionBaseException; + + public TransactionResponse sendTransactionAndGetResponse( + String to, String abi, String functionName, String data) + throws TransactionBaseException, ABICodecException; + + public TransactionResponse sendTransactionAndGetResponse( + String to, String abi, String functionName, List params) + throws ABICodecException, TransactionBaseException; + + public TransactionResponse sendTransactionWithStringParamsAndGetResponse( + String to, String abi, String functionName, List params) + throws ABICodecException, TransactionBaseException; + + public void sendTransactionAsync(String signedTransaction, TransactionCallback callback); + + public void sendTransactionAsync( + String to, + String abi, + String functionName, + List params, + TransactionCallback callback) + throws TransactionBaseException, ABICodecException; + + public CompletableFuture sendTransactionAsync(String signedData); + + public void sendTransactionAndGetReceiptByContractLoaderAsync( + String contractName, + String contractAddress, + String functionName, + List args, + TransactionCallback callback) + throws ABICodecException, TransactionBaseException; + + public TransactionResponse sendTransactionAndGetResponseByContractLoader( + String contractName, + String contractAddress, + String functionName, + List funcParams) + throws ABICodecException, TransactionBaseException; + + public CallResponse sendCallByContractLoader( + String contractName, String contractAddress, String functionName, List params) + throws TransactionBaseException, ABICodecException; + + public CallResponse sendCall( + String from, String to, String abi, String functionName, List args) + throws TransactionBaseException, ABICodecException; + + public CallResponse sendCall(CallRequest callRequest) + throws ABICodecException, TransactionBaseException; + + public CallResponse sendCallWithStringParams( + String from, String to, String abi, String functionName, List paramsList) + throws TransactionBaseException, ABICodecException; + + public String createSignedConstructor(String abi, String bin, List params) + throws ABICodecException; + + public String encodeFunction(String abi, String functionName, List params) + throws ABICodecException; +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/manager/TransactionProcessor.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/manager/TransactionProcessor.java new file mode 100644 index 000000000..ff6f27697 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/manager/TransactionProcessor.java @@ -0,0 +1,95 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.manager; + +import java.math.BigInteger; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.client.protocol.request.Transaction; +import org.fisco.bcos.sdk.client.protocol.response.Call; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.builder.TransactionBuilderInterface; +import org.fisco.bcos.sdk.transaction.builder.TransactionBuilderService; +import org.fisco.bcos.sdk.transaction.codec.encode.TransactionEncoderInterface; +import org.fisco.bcos.sdk.transaction.codec.encode.TransactionEncoderService; +import org.fisco.bcos.sdk.transaction.model.dto.CallRequest; +import org.fisco.bcos.sdk.transaction.model.gas.DefaultGasProvider; +import org.fisco.bcos.sdk.transaction.model.po.RawTransaction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TransactionProcessor implements TransactionProcessorInterface { + protected static Logger log = LoggerFactory.getLogger(TransactionProcessor.class); + protected final CryptoSuite cryptoSuite; + protected final CryptoKeyPair cryptoKeyPair; + protected final Client client; + protected final Integer groupId; + protected final String chainId; + protected final TransactionBuilderInterface transactionBuilder; + protected final TransactionEncoderInterface transactionEncoder; + + public TransactionProcessor( + Client client, CryptoKeyPair cryptoKeyPair, Integer groupId, String chainId) { + this.cryptoSuite = client.getCryptoSuite(); + this.cryptoKeyPair = cryptoKeyPair; + this.client = client; + this.groupId = groupId; + this.chainId = chainId; + this.transactionBuilder = new TransactionBuilderService(client); + this.transactionEncoder = new TransactionEncoderService(client.getCryptoSuite()); + } + + @Override + public TransactionReceipt sendTransactionAndGetReceipt( + String to, String data, CryptoKeyPair cryptoKeyPair) { + String signedData = createSignedTransaction(to, data, cryptoKeyPair); + return this.client.sendRawTransactionAndGetReceipt(signedData); + } + + @Override + public void sendTransactionAsync( + String to, String data, CryptoKeyPair cryptoKeyPair, TransactionCallback callback) { + String signedData = createSignedTransaction(to, data, cryptoKeyPair); + client.sendRawTransactionAndGetReceiptAsync(signedData, callback); + } + + @Override + public Call executeCall(CallRequest callRequest) { + return executeCall( + callRequest.getFrom(), callRequest.getTo(), callRequest.getEncodedFunction()); + } + + @Override + public Call executeCall(String from, String to, String encodedFunction) { + return client.call(new Transaction(from, to, encodedFunction)); + } + + @Override + public String createSignedTransaction(String to, String data, CryptoKeyPair cryptoKeyPair) { + RawTransaction rawTransaction = + transactionBuilder.createTransaction( + DefaultGasProvider.GAS_PRICE, + DefaultGasProvider.GAS_LIMIT, + to, + data, + BigInteger.ZERO, + new BigInteger(this.chainId), + BigInteger.valueOf(this.groupId), + ""); + return transactionEncoder.encodeAndSign(rawTransaction, cryptoKeyPair); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/manager/TransactionProcessorFactory.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/manager/TransactionProcessorFactory.java new file mode 100644 index 000000000..c302c23a6 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/manager/TransactionProcessorFactory.java @@ -0,0 +1,77 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.manager; + +import org.apache.commons.lang3.tuple.Pair; +import org.fisco.bcos.sdk.channel.model.EnumNodeVersion; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.NodeVersion; +import org.fisco.bcos.sdk.transaction.tools.ContractLoader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TransactionProcessorFactory { + private static final Logger logger = LoggerFactory.getLogger(TransactionProcessorFactory.class); + + @SuppressWarnings("unlikely-arg-type") + public static Pair getChainIdAndGroupId(Client client) { + NodeVersion version = client.getClientNodeVersion(); + String binaryVersion = version.getNodeVersion().getVersion(); + String supportedVersion = version.getNodeVersion().getSupportedVersion(); + logger.debug( + "getNodeVersion before createTransactionManager, binaryVerison: {}, supportedVersion:{}", + binaryVersion, + supportedVersion); + // transaction manager for rc1 transaction (without groupId and chainId) + if (EnumNodeVersion.BCOS_2_0_0_RC1.equals(binaryVersion) + || EnumNodeVersion.BCOS_2_0_0_RC1.equals(supportedVersion)) { + logger.debug("createTransactionManager for rc1 node"); + return Pair.of(null, null); + } else { + // get chainId + String chainId = version.getNodeVersion().getChainId(); + // get groupId + Integer groupId = client.getGroupId(); + logger.debug( + "createTransactionManager for >=rc2 node, chainId: {}, groupId: {}", + chainId, + groupId); + return Pair.of(chainId, groupId); + } + } + + public static TransactionProcessor createTransactionManager( + Client client, CryptoKeyPair cryptoKeyPair) { + Pair pair = getChainIdAndGroupId(client); + return new TransactionProcessor(client, cryptoKeyPair, pair.getRight(), pair.getLeft()); + } + + public static AssembleTransactionProcessor createAssembleTransactionProcessor( + Client client, CryptoKeyPair cryptoKeyPair) throws Exception { + Pair pair = getChainIdAndGroupId(client); + return new AssembleTransactionProcessor( + client, cryptoKeyPair, pair.getRight(), pair.getLeft(), null); + } + + public static AssembleTransactionProcessor createAssembleTransactionProcessor( + Client client, CryptoKeyPair cryptoKeyPair, String abiFilePath, String binFilePath) + throws Exception { + Pair pair = getChainIdAndGroupId(client); + ContractLoader contractLoader = new ContractLoader(abiFilePath, binFilePath); + return new AssembleTransactionProcessor( + client, cryptoKeyPair, pair.getRight(), pair.getLeft(), contractLoader); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/manager/TransactionProcessorInterface.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/manager/TransactionProcessorInterface.java new file mode 100644 index 000000000..6a6bc9274 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/manager/TransactionProcessorInterface.java @@ -0,0 +1,41 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.manager; + +import org.fisco.bcos.sdk.client.protocol.response.Call; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.model.dto.CallRequest; + +/** + * TransactionManagerInterface @Description: TransactionManagerInterface + * + * @author maojiayu + */ +public interface TransactionProcessorInterface { + + public TransactionReceipt sendTransactionAndGetReceipt( + String to, String data, CryptoKeyPair cryptoKeyPair); + + public void sendTransactionAsync( + String to, String data, CryptoKeyPair cryptoKeyPair, TransactionCallback callback); + + public Call executeCall(CallRequest callRequest); + + public Call executeCall(String from, String to, String encodedFunction); + + public String createSignedTransaction(String to, String data, CryptoKeyPair cryptoKeyPair); +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/CommonConstant.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/CommonConstant.java new file mode 100644 index 000000000..990889c14 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/CommonConstant.java @@ -0,0 +1,9 @@ +package org.fisco.bcos.sdk.transaction.model; + +public class CommonConstant { + public static final String BIN = "binary"; + public static final String ABI = "abi"; + + public static final String ABI_CONSTRUCTOR = "constructor"; + public static final String ABI_FUNCTION = "function"; +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/bo/AbiInfo.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/bo/AbiInfo.java new file mode 100644 index 000000000..7d552260d --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/bo/AbiInfo.java @@ -0,0 +1,38 @@ +package org.fisco.bcos.sdk.transaction.model.bo; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import org.fisco.bcos.sdk.abi.wrapper.ABIDefinition; + +public class AbiInfo { + + private Map> contractFuncAbis; + private Map contractConstructAbi; + + /** + * create the AbiInfo object + * + * @param contractFuncAbis maps between the contract name and the contract abi + * @param contractConstructAbi maps between the contract name and the constructor abi + */ + public AbiInfo( + Map> contractFuncAbis, + Map contractConstructAbi) { + super(); + this.contractFuncAbis = contractFuncAbis; + this.contractConstructAbi = contractConstructAbi; + } + + public List findFuncAbis(String contractName) { + List abis = contractFuncAbis.get(contractName); + if (abis == null) { + throw new RuntimeException("No such contract abi " + contractName); + } + return Collections.unmodifiableList(abis); + } + + public ABIDefinition findConstructor(String contractName) { + return contractConstructAbi.get(contractName); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/bo/BinInfo.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/bo/BinInfo.java new file mode 100644 index 000000000..bfdcadcaf --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/bo/BinInfo.java @@ -0,0 +1,22 @@ +package org.fisco.bcos.sdk.transaction.model.bo; + +import java.util.Map; + +public class BinInfo { + private Map bins; + + /** @param bins */ + /** + * the binary information of the contracts + * + * @param bins maps between contract name and the binary + */ + public BinInfo(Map bins) { + super(); + this.bins = bins; + } + + public String getBin(String contract) { + return this.bins.get(contract); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/dto/CallRequest.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/dto/CallRequest.java new file mode 100644 index 000000000..7060469cc --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/dto/CallRequest.java @@ -0,0 +1,86 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.model.dto; + +import org.fisco.bcos.sdk.abi.wrapper.ABIDefinition; + +/** + * CallRequest @Description: CallRequest + * + * @author maojiayu + */ +public class CallRequest { + private String from; + private String to; + private String encodedFunction; + private ABIDefinition abi; + + public CallRequest(String from, String to, String encodedFunction) { + this.from = from; + this.to = to; + this.encodedFunction = encodedFunction; + } + + /** + * @param from the transaction sender + * @param to the contract address + * @param encodedFunction the encoded methods and params + * @param abi the abi definition of the function + */ + public CallRequest(String from, String to, String encodedFunction, ABIDefinition abi) { + this(from, to, encodedFunction); + this.abi = abi; + } + + /** @return the from */ + public String getFrom() { + return from; + } + + /** @param from the from to set */ + public void setFrom(String from) { + this.from = from; + } + + /** @return the to */ + public String getTo() { + return to; + } + + /** @param to the to to set */ + public void setTo(String to) { + this.to = to; + } + + /** @return the encodedFunction */ + public String getEncodedFunction() { + return encodedFunction; + } + + /** @param encodedFunction the encodedFunction to set */ + public void setEncodedFunction(String encodedFunction) { + this.encodedFunction = encodedFunction; + } + + /** @return the abi */ + public ABIDefinition getAbi() { + return abi; + } + + /** @param abi the abi to set */ + public void setAbi(ABIDefinition abi) { + this.abi = abi; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/dto/CallResponse.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/dto/CallResponse.java new file mode 100644 index 000000000..f12fc7a97 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/dto/CallResponse.java @@ -0,0 +1,34 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.model.dto; + +/** + * CallResponse @Description: CallResponse + * + * @author maojiayu + */ +public class CallResponse extends CommonResponse { + private String values; + + /** @return the values */ + public String getValues() { + return values; + } + + /** @param values the values to set */ + public void setValues(String values) { + this.values = values; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/dto/CommonResponse.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/dto/CommonResponse.java new file mode 100644 index 000000000..32ac334a6 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/dto/CommonResponse.java @@ -0,0 +1,59 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.model.dto; + +/** + * CommonResponse @Description: CommonResponse + * + * @author maojiayu + */ +public class CommonResponse { + private int returnCode = 0; + private String returnMessage = ""; + + public CommonResponse() { + super(); + } + + /** + * @param returnCode the return code of the response + * @param returnMessage the return message of the response + */ + public CommonResponse(int returnCode, String returnMessage) { + super(); + this.returnCode = returnCode; + this.returnMessage = returnMessage; + } + + /** @return the returnCode */ + public int getReturnCode() { + return returnCode; + } + + /** @param returnCode the returnCode to set */ + public void setReturnCode(int returnCode) { + this.returnCode = returnCode; + } + + /** @return the returnMessage */ + public String getReturnMessage() { + return returnMessage; + } + + /** @param returnMessage the returnMessage to set */ + public void setReturnMessage(String returnMessage) { + this.returnMessage = returnMessage; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/dto/ResultCodeEnum.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/dto/ResultCodeEnum.java new file mode 100644 index 000000000..1dace9cc3 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/dto/ResultCodeEnum.java @@ -0,0 +1,58 @@ +/** + * Copyright 2014-2019 the original author or authors. + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.transaction.model.dto; + +/** + * ResultCodeEnum @Description: ResultCodeEnum + * + * @author maojiayu + */ +public enum ResultCodeEnum { + SUCCESS(0, "success"), + EXECUTE_ERROR(1, "execute error"), + RESULT_EMPTY(2, "empty result"), + UNKNOWN(3, "unknown exception"), + EVM_ERROR(4, "evm error"), + EXCEPTION_OCCUR(5, "exception occur"), + PARAMETER_ERROR(6, "param error"), + PARSE_ERROR(7, "parse error"); + + private int code; + private String message; + + ResultCodeEnum(int code, String message) { + this.code = code; + this.message = message; + } + + /** @return the code */ + public int getCode() { + return code; + } + + /** @param code the code to set */ + public void setCode(int code) { + this.code = code; + } + + /** @return the message */ + public String getMessage() { + return message; + } + + /** @param message the message to set */ + public void setMessage(String message) { + this.message = message; + } +} 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 new file mode 100644 index 000000000..7fc4d292f --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/dto/TransactionResponse.java @@ -0,0 +1,116 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.model.dto; + +import com.fasterxml.jackson.core.type.TypeReference; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.transaction.tools.JsonUtils; + +/** + * TransactionResponse @Description: TransactionResponse + * + * @author maojiayu + */ +public class TransactionResponse extends CommonResponse { + private TransactionReceipt transactionReceipt; + private String contractAddress; + private String values; + private String events; + private String receiptMessages; + + public TransactionResponse() { + super(); + } + + /** + * @param returnCode the return code of the receipt + * @param returnMessage the return message of the receipt + */ + public TransactionResponse(int returnCode, String returnMessage) { + super(returnCode, returnMessage); + } + + public TransactionResponse(TransactionReceipt tr, int returnCode, String returnMessage) { + super(returnCode, returnMessage); + this.transactionReceipt = tr; + } + + /** @return the bcosTransactionReceipt */ + public TransactionReceipt getTransactionReceipt() { + return transactionReceipt; + } + + /** @param transactionReceipt the transactionReceipt to set */ + public void setTransactionReceipt(TransactionReceipt transactionReceipt) { + this.transactionReceipt = transactionReceipt; + } + + /** @return the contractAddress */ + public String getContractAddress() { + return contractAddress; + } + + /** @param contractAddress the contractAddress to set */ + public void setContractAddress(String contractAddress) { + this.contractAddress = contractAddress; + } + + /** @return the values */ + public String getValues() { + return values; + } + + public List getValuesList() { + if (StringUtils.isEmpty(values)) { + return null; + } + return JsonUtils.fromJson(values, new TypeReference>() {}); + } + + /** @param values the values to set */ + public void setValues(String values) { + this.values = values; + } + + /** @return the events */ + public String getEvents() { + return events; + } + + public Map> getEventResultMap() { + if (StringUtils.isEmpty(events)) { + return null; + } + return JsonUtils.fromJson(events, new TypeReference>>() {}); + } + + /** @param events the events to set */ + public void setEvents(String events) { + this.events = events; + } + + /** @return the receiptMessages */ + public String getReceiptMessages() { + return receiptMessages; + } + + /** @param receiptMessages the receiptMessages to set */ + public void setReceiptMessages(String receiptMessages) { + this.receiptMessages = receiptMessages; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/exception/ContractException.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/exception/ContractException.java new file mode 100644 index 000000000..6e2667c0f --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/exception/ContractException.java @@ -0,0 +1,100 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.transaction.model.exception; + +import java.util.Objects; +import org.fisco.bcos.sdk.client.protocol.response.Call; +import org.fisco.bcos.sdk.model.TransactionReceipt; + +public class ContractException extends Exception { + private Call.CallOutput responseOutput = null; + private int errorCode; + private TransactionReceipt receipt; + + public ContractException(String errorMessage, int errorCode) { + super(errorMessage); + this.errorCode = errorCode; + } + + public ContractException(String errorMessage, int errorCode, TransactionReceipt receipt) { + super(errorMessage); + this.errorCode = errorCode; + this.receipt = receipt; + } + + public ContractException(String message) { + super(message); + } + + public ContractException(String message, Throwable cause) { + super(message, cause); + } + + public ContractException(String message, Throwable cause, Call.CallOutput responseOutput) { + super(message, cause); + this.responseOutput = responseOutput; + } + + public ContractException(String message, Call.CallOutput responseOutput) { + super(message); + this.responseOutput = responseOutput; + } + + public Call.CallOutput getResponseOutput() { + return this.responseOutput; + } + + public int getErrorCode() { + return errorCode; + } + + public void setErrorCode(int errorCode) { + this.errorCode = errorCode; + } + + public void setResponseOutput(Call.CallOutput responseOutput) { + this.responseOutput = responseOutput; + } + + public TransactionReceipt getReceipt() { + return receipt; + } + + public void setReceipt(TransactionReceipt receipt) { + this.receipt = receipt; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ContractException that = (ContractException) o; + return errorCode == that.errorCode && Objects.equals(responseOutput, that.responseOutput); + } + + @Override + public int hashCode() { + return Objects.hash(responseOutput, errorCode); + } + + @Override + public String toString() { + return "ContractException{" + + "responseOutput=" + + (responseOutput == null ? "null" : responseOutput.toString()) + + ", errorCode=" + + errorCode + + '}'; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/exception/JsonException.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/exception/JsonException.java new file mode 100644 index 000000000..4bedc872c --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/exception/JsonException.java @@ -0,0 +1,40 @@ +/** + * Copyright 2014-2019 the original author or authors. + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.transaction.model.exception; + +/** + * JacksonException @Description: JacksonException + * + * @author maojiayu + */ +public class JsonException extends RuntimeException { + + private static final long serialVersionUID = -3313868940376241665L; + + public JsonException() { + super(); + } + + public JsonException(String message, Throwable cause) { + super(message, cause); + } + + public JsonException(String message) { + super(message); + } + + public JsonException(Throwable cause) { + super(cause); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/exception/NoSuchTransactionFileException.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/exception/NoSuchTransactionFileException.java new file mode 100644 index 000000000..1d0bf3207 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/exception/NoSuchTransactionFileException.java @@ -0,0 +1,34 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.model.exception; + +import org.fisco.bcos.sdk.model.RetCode; + +/** + * NoSuchTransactionFileException @Description: NoSuchTransactionFileException + * + * @author maojiayu + */ +public class NoSuchTransactionFileException extends TransactionBaseException { + private static final long serialVersionUID = -3082997842343754327L; + + public NoSuchTransactionFileException(int code, String msg) { + super(code, msg); + } + + public NoSuchTransactionFileException(RetCode retCode) { + this(retCode.getCode(), retCode.getMessage()); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/exception/TransactionBaseException.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/exception/TransactionBaseException.java new file mode 100644 index 000000000..f524b16f7 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/exception/TransactionBaseException.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.fisco.bcos.sdk.transaction.model.exception; + +import org.fisco.bcos.sdk.model.RetCode; + +/** BaseException. */ +public class TransactionBaseException extends Exception { + + private static final long serialVersionUID = 1L; + private RetCode retCode; + + public TransactionBaseException(RetCode retCode) { + super(retCode.getMessage()); + this.retCode = retCode; + } + + public TransactionBaseException(int code, String msg) { + super(msg); + this.retCode = new RetCode(code, msg); + } + + public RetCode getRetCode() { + return retCode; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/exception/TransactionException.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/exception/TransactionException.java new file mode 100644 index 000000000..f10647863 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/exception/TransactionException.java @@ -0,0 +1,61 @@ +package org.fisco.bcos.sdk.transaction.model.exception; + +import java.math.BigInteger; +import java.util.Optional; + +public class TransactionException extends Exception { + private static final long serialVersionUID = -2204228001512046284L; + private Optional transactionHash = Optional.empty(); + private String status; + private BigInteger gasUsed; + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public BigInteger getGasUsed() { + return gasUsed; + } + + public void setGasUsed(BigInteger gasUsed) { + this.gasUsed = gasUsed; + } + + public void setTransactionHash(Optional transactionHash) { + this.transactionHash = transactionHash; + } + + public TransactionException(String message) { + super(message); + } + + public TransactionException(String message, String transactionHash) { + super(message); + this.transactionHash = Optional.ofNullable(transactionHash); + } + + public TransactionException( + String message, String status, BigInteger gasUsed, String transactionHash) { + super(message); + this.status = status; + this.gasUsed = gasUsed; + this.transactionHash = Optional.ofNullable(transactionHash); + } + + public TransactionException(Throwable cause) { + super(cause); + } + + /** + * Obtain the transaction hash . + * + * @return optional transaction hash . + */ + public Optional getTransactionHash() { + return transactionHash; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/exception/TransactionRetCodeConstants.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/exception/TransactionRetCodeConstants.java new file mode 100644 index 000000000..51b7629e3 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/exception/TransactionRetCodeConstants.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.model.exception; + +import org.fisco.bcos.sdk.model.RetCode; + +/** + * TransactionRetCode @Description: TransactionRetCode + * + * @author maojiayu + */ +public class TransactionRetCodeConstants { + + public static final RetCode CODE_SUCCESS = new RetCode(0, "Success"); + + // internal error(for example: params check failed, etc.): -22299~-22400 + public static final RetCode NO_SUCH_BINARY_FILE = + new RetCode(-22301, "No such binary file in config path."); + public static final RetCode NO_SUCH_ABI_FILE = + new RetCode(-22302, "No such abi file in config path."); +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/gas/ContractGasProvider.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/gas/ContractGasProvider.java new file mode 100644 index 000000000..53ce109fd --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/gas/ContractGasProvider.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.transaction.model.gas; + +import java.math.BigInteger; + +public interface ContractGasProvider { + BigInteger getGasPrice(); + + BigInteger getGasLimit(); +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/gas/DefaultGasProvider.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/gas/DefaultGasProvider.java new file mode 100644 index 000000000..21935b048 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/gas/DefaultGasProvider.java @@ -0,0 +1,32 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.model.gas; + +import java.math.BigInteger; + +public class DefaultGasProvider implements ContractGasProvider { + public static final BigInteger GAS_LIMIT = BigInteger.valueOf(4_300_000); + public static final BigInteger GAS_PRICE = BigInteger.valueOf(22_000_000_000L); + + @Override + public BigInteger getGasPrice() { + return GAS_PRICE; + } + + @Override + public BigInteger getGasLimit() { + return GAS_LIMIT; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/po/RawTransaction.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/po/RawTransaction.java new file mode 100644 index 000000000..a10598216 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/model/po/RawTransaction.java @@ -0,0 +1,158 @@ +package org.fisco.bcos.sdk.transaction.model.po; + +import java.io.Serializable; +import java.math.BigInteger; +import org.fisco.bcos.sdk.utils.Numeric; + +/** + * Transaction class used for signing transactions locally.
+ * For the specification, refer to p4 of the yellow + * paper. + */ +public class RawTransaction implements Serializable { + + private static final long serialVersionUID = -5580814755985097996L; + private BigInteger randomid; + private BigInteger gasPrice; + private BigInteger gasLimit; + private BigInteger blockLimit; + private String to; + private BigInteger value; + private String data; + private BigInteger fiscoChainId; + private BigInteger groupId; + private String extraData; + // private BigInteger version = TransactionConstant.version; + // TODO + private BigInteger version; + + protected RawTransaction( + BigInteger randomid, + BigInteger gasPrice, + BigInteger gasLimit, + BigInteger blockLimit, + String to, + BigInteger value, + String data, + BigInteger fiscoChainId, + BigInteger groupId, + String extraData) { + this.randomid = randomid; + this.gasPrice = gasPrice; + this.gasLimit = gasLimit; + this.blockLimit = blockLimit; + this.fiscoChainId = fiscoChainId; + this.groupId = groupId; + this.extraData = extraData; + this.to = to; + this.value = value; + if (data != null) { + this.data = Numeric.cleanHexPrefix(data); + } + } + + public static RawTransaction createContractTransaction( + BigInteger randomid, + BigInteger gasPrice, + BigInteger gasLimit, + BigInteger blockLimit, + BigInteger value, + String init, + BigInteger chainId, + BigInteger groupId, + String extraData) { + + return new RawTransaction( + randomid, + gasPrice, + gasLimit, + blockLimit, + "", + value, + init, + chainId, + groupId, + extraData); + } + + public static RawTransaction createTransaction( + BigInteger randomid, + BigInteger gasPrice, + BigInteger gasLimit, + BigInteger blockLimit, + String to, + BigInteger value, + String data, + BigInteger chainId, + BigInteger groupId, + String extraData) { + + return new RawTransaction( + randomid, + gasPrice, + gasLimit, + blockLimit, + to, + value, + data, + chainId, + groupId, + extraData); + } + + public BigInteger getRandomid() { + return randomid; + } + + public BigInteger getGasPrice() { + return gasPrice; + } + + public BigInteger getGasLimit() { + return gasLimit; + } + + public BigInteger getBlockLimit() { + return blockLimit; + } + + public String getTo() { + return to; + } + + public BigInteger getValue() { + return value; + } + + public String getData() { + return data; + } + + public BigInteger getVersion() { + return version; + } + + public BigInteger getGroupId() { + return groupId; + } + + public void setGroupId(BigInteger groupId) { + this.groupId = groupId; + } + + public String getExtraData() { + return extraData; + } + + public void setExtraData(String extraData) { + this.extraData = extraData; + } + + public BigInteger getFiscoChainId() { + return fiscoChainId; + } + + public void setFiscoChainId(BigInteger fiscoChainId) { + this.fiscoChainId = fiscoChainId; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/pusher/TransactionPusherInterface.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/pusher/TransactionPusherInterface.java new file mode 100644 index 000000000..b539cc1d5 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/pusher/TransactionPusherInterface.java @@ -0,0 +1,38 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.pusher; + +import java.util.concurrent.CompletableFuture; +import org.fisco.bcos.sdk.client.protocol.response.Call; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; + +/** + * TransactionPusher @Description: TransactionPusherInterface + * + * @author maojiayu + */ +public interface TransactionPusherInterface { + + public void pushOnly(String signedTransaction); + + public TransactionReceipt push(String signedTransaction); + + public Call push(String from, String to, String encodedFunction); + + public CompletableFuture pushAsync(String signedTransaction); + + public void pushAsync(String signedTransaction, TransactionCallback callback); +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/pusher/TransactionPusherService.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/pusher/TransactionPusherService.java new file mode 100644 index 000000000..3e150bc42 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/pusher/TransactionPusherService.java @@ -0,0 +1,75 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.pusher; + +import java.util.concurrent.CompletableFuture; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.client.protocol.request.Transaction; +import org.fisco.bcos.sdk.client.protocol.response.Call; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; + +public class TransactionPusherService implements TransactionPusherInterface { + + private Client client; + + /** + * create the TransactionPusherService + * + * @param client the client object responsible for send transaction + */ + public TransactionPusherService(Client client) { + super(); + this.client = client; + } + + @Override + public void pushOnly(String signedTransaction) { + client.sendRawTransactionAndGetReceiptAsync(signedTransaction, null); + } + + @Override + public Call push(String from, String to, String encodedFunction) { + Transaction transaction = new Transaction(from, to, encodedFunction); + return client.call(transaction); + } + + @Override + public TransactionReceipt push(String signedTransaction) { + return client.sendRawTransactionAndGetReceipt(signedTransaction); + } + + @Override + public void pushAsync(String signedTransactionData, TransactionCallback callback) { + client.sendRawTransactionAndGetReceiptAsync(signedTransactionData, callback); + } + + @Override + public CompletableFuture pushAsync(String signedTransaction) { + CompletableFuture future = + CompletableFuture.supplyAsync(() -> push(signedTransaction)); + return future; + } + + /** @return the client */ + public Client getClient() { + return client; + } + + /** @param client the client to set */ + public void setClient(Client client) { + this.client = client; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/signer/TransactionSignerInterface.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/signer/TransactionSignerInterface.java new file mode 100644 index 000000000..120c9da48 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/signer/TransactionSignerInterface.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.signer; + +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.crypto.signature.SignatureResult; + +/** + * TransactionSignerInterface @Description: TransactionSignerInterface + * + * @author maojiayu + */ +public interface TransactionSignerInterface { + public SignatureResult sign(String hash, CryptoKeyPair cryptoKeyPair); +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/signer/TransactionSignerServcie.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/signer/TransactionSignerServcie.java new file mode 100644 index 000000000..c6158c82c --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/signer/TransactionSignerServcie.java @@ -0,0 +1,47 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.signer; + +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.crypto.signature.Signature; +import org.fisco.bcos.sdk.crypto.signature.SignatureResult; + +public class TransactionSignerServcie implements TransactionSignerInterface { + private Signature signature; + /** + * create the TransactionSignerService according the the given signature + * + * @param signature the signature + */ + public TransactionSignerServcie(Signature signature) { + super(); + this.signature = signature; + } + + @Override + public SignatureResult sign(String hash, CryptoKeyPair cryptoKeyPair) { + return signature.sign(hash, cryptoKeyPair); + } + + /** @return the signature */ + public Signature getSignature() { + return signature; + } + + /** @param signature the signature to set */ + public void setSignature(Signature signature) { + this.signature = signature; + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/tools/ContractLoader.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/tools/ContractLoader.java new file mode 100644 index 000000000..3ebb80d9a --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/tools/ContractLoader.java @@ -0,0 +1,152 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.tools; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.fisco.bcos.sdk.abi.tools.ContractAbiUtil; +import org.fisco.bcos.sdk.abi.wrapper.ABIDefinition; +import org.fisco.bcos.sdk.transaction.model.CommonConstant; +import org.fisco.bcos.sdk.transaction.model.bo.AbiInfo; +import org.fisco.bcos.sdk.transaction.model.bo.BinInfo; +import org.fisco.bcos.sdk.transaction.model.exception.NoSuchTransactionFileException; +import org.fisco.bcos.sdk.transaction.model.exception.TransactionRetCodeConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ContractLoader @Description: ContractLoader + * + * @author maojiayu + */ +public class ContractLoader { + private static final Logger log = LoggerFactory.getLogger(ContractLoader.class); + private Map> contractFuncAbis; + private Map contractConstructorAbi; + private Map contractBinMap; + private Map contractAbiMap; + + public ContractLoader(String abiFilePath, String binaryFilePath) throws Exception { + this.binInfo(binaryFilePath); + this.abiInfo(abiFilePath); + } + + public BinInfo binInfo(String binaryFilePath) throws IOException { + String[] s = {"bin"}; + Collection fileCollection = FileUtils.listFiles(new File(binaryFilePath), s, true); + if (fileCollection.isEmpty()) { + log.warn("No bin found, cannot deploy any contract"); + return new BinInfo(Collections.emptyMap()); + } + this.contractBinMap = new HashMap<>(); + for (File file : fileCollection) { + String contract = parseContractName(file); + String bin = FileUtils.readFileToString(file); + contractBinMap.put(contract, bin); + } + return new BinInfo(contractBinMap); + } + + public AbiInfo abiInfo(String abiFilePath) throws Exception { + String[] s = {"abi"}; + Collection fileCollection = FileUtils.listFiles(new File(abiFilePath), s, true); + this.contractFuncAbis = new HashMap<>(); + this.contractConstructorAbi = new HashMap<>(); + this.contractAbiMap = new HashMap<>(); + for (File file : fileCollection) { + String contract = parseContractName(file); + List abiList = parseAbiBody(file); + ABIDefinition constructorAbi = selectConstructor(abiList); + contractFuncAbis.put(contract, abiList); + contractConstructorAbi.put(contract, constructorAbi); + contractAbiMap.put(contract, FileUtils.readFileToString(file)); + } + return new AbiInfo(contractFuncAbis, contractConstructorAbi); + } + + public static ABIDefinition selectConstructor(List abiList) { + for (ABIDefinition ABIDefinition : abiList) { + if (ABIDefinition.getType().equals(CommonConstant.ABI_CONSTRUCTOR)) { + return ABIDefinition; + } + } + // The case where the sol file does not define constructor + return null; + } + + private String parseContractName(File file) { + String fileName = file.getName(); + return StringUtils.substringBefore(fileName, "."); + } + + private List parseAbiBody(File file) throws Exception { + String abiStr = FileUtils.readFileToString(file); + return ContractAbiUtil.getFuncABIDefinition(abiStr); + } + + public String getABIByContractName(String contractName) throws NoSuchTransactionFileException { + if (contractAbiMap.get(contractName) == null) { + log.error("Contract {} not found.", contractName); + throw new NoSuchTransactionFileException(TransactionRetCodeConstants.NO_SUCH_ABI_FILE); + } + return contractAbiMap.get(contractName); + } + + public String getBinaryByContractName(String contractName) + throws NoSuchTransactionFileException { + if (contractBinMap.get(contractName) == null) { + log.error("Contract {} not found.", contractName); + throw new NoSuchTransactionFileException( + TransactionRetCodeConstants.NO_SUCH_BINARY_FILE); + } + return contractBinMap.get(contractName); + } + + public Pair getABIAndBinaryByContractName(String contractName) + throws NoSuchTransactionFileException { + if (contractAbiMap.get(contractName) == null) { + log.error("Contract {} not found.", contractName); + throw new NoSuchTransactionFileException(TransactionRetCodeConstants.NO_SUCH_ABI_FILE); + } + if (contractBinMap.get(contractName) == null) { + log.error("Contract {} not found.", contractName); + throw new NoSuchTransactionFileException( + TransactionRetCodeConstants.NO_SUCH_BINARY_FILE); + } + return Pair.of(contractAbiMap.get(contractName), contractBinMap.get(contractName)); + } + + public ABIDefinition getConstructorABIByContractName(String contractName) + throws NoSuchTransactionFileException { + return selectConstructor(getFunctionABIListByContractName(contractName)); + } + + public List getFunctionABIListByContractName(String contractName) + throws NoSuchTransactionFileException { + if (contractFuncAbis.get(contractName) == null) { + log.error("Contract {} not found.", contractName); + throw new NoSuchTransactionFileException(TransactionRetCodeConstants.NO_SUCH_ABI_FILE); + } + return contractFuncAbis.get(contractName); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/tools/JsonUtils.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/tools/JsonUtils.java new file mode 100644 index 000000000..9895fd4c7 --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/tools/JsonUtils.java @@ -0,0 +1,143 @@ +/** + * Copyright 2014-2019 the original author or authors. + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.transaction.tools; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.fisco.bcos.sdk.transaction.model.exception.JsonException; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * a useful toolkit of json based on Jackson. + * + * @author maojiayu + */ +public class JsonUtils { + protected static Logger log = LoggerFactory.getLogger(JsonUtils.class); + + private static ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(); + + public static T fromJson(String json, Class clazz) { + try { + return fromJsonWithException(json, clazz); + } catch (Exception e) { + log.error("json is: " + json, e); + return null; + } + } + + @SuppressWarnings("rawtypes") + public static T fromJson(String json, Class c, Class... t) { + try { + return fromJsonWithException(json, c, t); + } catch (IOException e) { + throw new JsonException(e); + } + } + + public static T fromJson(String json, JavaType type) { + try { + return fromJsonWithException(json, type); + } catch (IOException e) { + throw new JsonException(e); + } + } + + public static T fromJson(String json, TypeReference typeReference) { + try { + return objectMapper.readValue(json, typeReference); + } catch (Exception e) { + log.error("json is: " + json, e); + return null; + } + } + + public static T fromJsonWithException(String json, Class clazz) + throws JsonParseException, JsonMappingException, IOException { + return objectMapper.readValue(json, clazz); + } + + @SuppressWarnings("rawtypes") + public static T fromJsonWithException(String json, Class c, Class... t) + throws JsonParseException, JsonMappingException, IOException { + JavaType javaType = objectMapper.getTypeFactory().constructParametricType(c, t); + return objectMapper.readValue(json, javaType); + } + + @SuppressWarnings("unchecked") + public static T fromJsonWithException(String json, JavaType type) + throws JsonParseException, JsonMappingException, IOException { + T ret = (T) objectMapper.readValue(json, type); + return ret; + } + + public static List fromJsonList(String json, Class c) { + try { + return fromJsonListWithException(json, c); + } catch (IOException e) { + throw new JsonException(e); + } + } + + @SuppressWarnings("unchecked") + public static List fromJsonListWithException(String json, Class c) + throws IOException { + JavaType type = getCollectionType(ArrayList.class, c); + return (List) objectMapper.readValue(json, type); + } + + public static JavaType getCollectionType(Class collectionClass, Class... elementClasses) { + return objectMapper + .getTypeFactory() + .constructParametricType(collectionClass, elementClasses); + } + + public static String toJsonWithException(Object o) throws JsonProcessingException { + return objectMapper.writeValueAsString(o); + } + + public static String toJson(Object o) { + try { + return toJsonWithException(o); + } catch (Exception e) { + throw new JsonException(e); + } + } + + public static Map convertValue( + Object req, Class keyClazz, Class valueClazz) { + Map ret = + objectMapper.convertValue( + req, + objectMapper + .getTypeFactory() + .constructMapType(Map.class, keyClazz, valueClazz)); + return ret; + } + + @SuppressWarnings("rawtypes") + public static T convertMap(Map map, Class retClazz) { + return objectMapper.convertValue(map, retClazz); + } +} diff --git a/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/tools/ReceiptStatusUtil.java b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/tools/ReceiptStatusUtil.java new file mode 100644 index 000000000..9b71b47dd --- /dev/null +++ b/sdk-transaction/src/main/java/org/fisco/bcos/sdk/transaction/tools/ReceiptStatusUtil.java @@ -0,0 +1,47 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.tools; + +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.abi.FunctionReturnDecoder; +import org.fisco.bcos.sdk.abi.TypeReference; +import org.fisco.bcos.sdk.abi.datatypes.Function; +import org.fisco.bcos.sdk.abi.datatypes.Type; +import org.fisco.bcos.sdk.abi.datatypes.Utf8String; + +/** + * ReceiptStatusUtil @Description: ReceiptStatusUtil + * + * @author maojiayu + */ +public class ReceiptStatusUtil { + + public static String decodeReceiptMessage(String output) { + if (output.length() <= 10) { + return null; + } else { + Function function = + new Function( + "Error", + Collections.emptyList(), + Collections.singletonList(new TypeReference() {})); + List r = + FunctionReturnDecoder.decode( + output.substring(10), function.getOutputParameters()); + return ((Type) r.get(0)).toString(); + } + } +} diff --git a/sdk-transaction/src/test/java/org/fisco/bcos/sdk/tx/tools/UtilsTest.java b/sdk-transaction/src/test/java/org/fisco/bcos/sdk/tx/tools/UtilsTest.java new file mode 100644 index 000000000..d9816665e --- /dev/null +++ b/sdk-transaction/src/test/java/org/fisco/bcos/sdk/tx/tools/UtilsTest.java @@ -0,0 +1,22 @@ +package org.fisco.bcos.sdk.tx.tools; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import org.fisco.bcos.sdk.abi.Utils; +import org.fisco.bcos.sdk.abi.datatypes.generated.Uint256; +import org.junit.Assert; +import org.junit.Test; + +public class UtilsTest { + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Test + public void utilsExtTest() { + Class destType = Uint256.class; + List input = new ArrayList(); + input.add(BigInteger.ONE); + List output = Utils.typeMap(input, destType); + Assert.assertEquals(new Uint256(BigInteger.ONE), output.get(0)); + } +} diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 000000000..4c604b73c --- /dev/null +++ b/settings.gradle @@ -0,0 +1,11 @@ +rootProject.name = "java-sdk" + +// submodules +include "sdk-core" +include "sdk-abi" +include "sdk-crypto" +include "sdk-amop" +include "sdk-service" +include "sdk-transaction" +include "sdk-codegen" +include "sdk-demo" diff --git a/src/integration-test/java/org/fisco/bcos/sdk/BcosSDKTest.java b/src/integration-test/java/org/fisco/bcos/sdk/BcosSDKTest.java new file mode 100644 index 000000000..0bf8df802 --- /dev/null +++ b/src/integration-test/java/org/fisco/bcos/sdk/BcosSDKTest.java @@ -0,0 +1,290 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk; + +import java.math.BigInteger; +import java.util.List; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.client.exceptions.ClientException; +import org.fisco.bcos.sdk.client.protocol.response.BcosBlock; +import org.fisco.bcos.sdk.client.protocol.response.BcosBlockHeader; +import org.fisco.bcos.sdk.client.protocol.response.BlockHash; +import org.fisco.bcos.sdk.client.protocol.response.BlockNumber; +import org.fisco.bcos.sdk.client.protocol.response.ConsensusStatus; +import org.fisco.bcos.sdk.client.protocol.response.GroupList; +import org.fisco.bcos.sdk.client.protocol.response.Peers; +import org.fisco.bcos.sdk.client.protocol.response.PendingTransactions; +import org.fisco.bcos.sdk.client.protocol.response.PendingTxSize; +import org.fisco.bcos.sdk.client.protocol.response.SealerList; +import org.fisco.bcos.sdk.client.protocol.response.SyncStatus; +import org.fisco.bcos.sdk.config.exceptions.ConfigException; +import org.fisco.bcos.sdk.demo.contract.HelloWorld; +import org.fisco.bcos.sdk.model.ConstantConfig; +import org.fisco.bcos.sdk.model.NodeVersion; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.service.GroupManagerService; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; +import org.fisco.bcos.sdk.utils.Numeric; +import org.junit.Assert; +import org.junit.Test; + +public class BcosSDKTest { + private static final String configFile = + BcosSDKTest.class + .getClassLoader() + .getResource(ConstantConfig.CONFIG_FILE_NAME) + .getPath(); + + @Test + public void testClient() throws ConfigException { + BcosSDK sdk = BcosSDK.build(configFile); + // check groupList + Assert.assertTrue(sdk.getChannel().getAvailablePeer().size() >= 1); + for (String endPoint : sdk.getChannel().getAvailablePeer()) { + List groupInfo = sdk.getGroupManagerService().getGroupInfoByNodeInfo(endPoint); + if (groupInfo.size() > 0) { + Assert.assertEquals(1, groupInfo.size()); + Assert.assertEquals("1", groupInfo.get(0)); + } + } + // get the client + Client client = sdk.getClient(Integer.valueOf(1)); + + // test getBlockNumber + BlockNumber blockNumber = client.getBlockNumber(); + + // test getBlockByNumber + BcosBlock block = client.getBlockByNumber(BigInteger.ZERO, false); + Assert.assertEquals(BigInteger.ZERO, block.getBlock().getNumber()); + // the genesis block with zero transactions + Assert.assertEquals(0, block.getBlock().getTransactions().size()); + // the genesis block with 0 sealer + Assert.assertEquals(0, block.getBlock().getSealerList().size()); + Assert.assertEquals("0x0", block.getBlock().getSealer()); + Assert.assertEquals( + "0x0000000000000000000000000000000000000000000000000000000000000000", + block.getBlock().getParentHash()); + Assert.assertEquals( + "0x0000000000000000000000000000000000000000000000000000000000000000", + block.getBlock().getDbHash()); + Assert.assertEquals( + "0x0000000000000000000000000000000000000000000000000000000000000000", + block.getBlock().getStateRoot()); + + // test getBlockByHash + BcosBlock block2 = client.getBlockByHash(block.getBlock().getHash(), false); + Assert.assertEquals(block2.getBlock().getHash(), block.getBlock().getHash()); + + // get blockHash + BlockHash blockHash = client.getBlockHashByNumber(BigInteger.ZERO); + Assert.assertEquals(blockHash.getBlockHashByNumber(), block.getBlock().getHash()); + + try { + // Note: FISCO BCOS supported_version >= v2.6.0 has this RPC interface + // get blockHeader + BcosBlockHeader blockHeader = + client.getBlockHeaderByHash(blockHash.getBlockHashByNumber(), true); + if (blockHeader.getError() == null) { + Assert.assertEquals(BigInteger.ZERO, blockHeader.getBlockHeader().getNumber()); + Assert.assertEquals( + block.getBlock().getHash(), blockHeader.getBlockHeader().getHash()); + + BcosBlockHeader blockHeader2 = client.getBlockHeaderByNumber(BigInteger.ZERO, true); + Assert.assertEquals(blockHeader.getBlockHeader(), blockHeader2.getBlockHeader()); + } + } catch (ClientException e) { + System.out.println("getBlockHeaderByHash failed, error information: " + e.getMessage()); + } + + // get SealerList + SealerList sealerList = client.getSealerList(); + Assert.assertTrue(sealerList.getSealerList().size() > 0); + + // get observerList + client.getObserverList(); + + // getPeers + Peers peers = client.getPeers(); + Assert.assertTrue(peers.getPeers().get(0).getAgency() != null); + + // get NodeVersion + NodeVersion nodeVersion = client.getNodeVersion(); + Assert.assertTrue(nodeVersion.getNodeVersion() != null); + + // getSystemConfig + client.getSystemConfigByKey("tx_count_limit"); + client.getSystemConfigByKey("tx_gas_limit"); + + // get groupPeers + client.getGroupPeers(); + // get PendingTxSize + PendingTxSize pendingTxSize = client.getPendingTxSize(); + Assert.assertEquals(BigInteger.valueOf(0), pendingTxSize.getPendingTxSize()); + + // get pendingTransactions + PendingTransactions pendingTransactions = client.getPendingTransaction(); + Assert.assertEquals(0, pendingTransactions.getPendingTransactions().size()); + + // get pbftView + client.getPbftView(); + + // getSyncStatus + BlockHash latestHash = client.getBlockHashByNumber(blockNumber.getBlockNumber()); + SyncStatus syncStatus = client.getSyncStatus(); + Assert.assertEquals("0", syncStatus.getSyncStatus().getTxPoolSize()); + Assert.assertEquals( + latestHash.getBlockHashByNumber(), + "0x" + syncStatus.getSyncStatus().getLatestHash()); + Assert.assertEquals( + blockHash.getBlockHashByNumber(), + "0x" + syncStatus.getSyncStatus().getGenesisHash()); + Assert.assertEquals( + latestHash.getBlockHashByNumber(), + "0x" + syncStatus.getSyncStatus().getKnownLatestHash()); + Assert.assertEquals( + blockNumber.getBlockNumber(), + new BigInteger(syncStatus.getSyncStatus().getKnownHighestNumber())); + + BigInteger blockLimit = client.getBlockLimit(); + Assert.assertEquals( + blockNumber.getBlockNumber().add(GroupManagerService.BLOCK_LIMIT), blockLimit); + + // test getGroupList + GroupList groupList = client.getGroupList(); + Assert.assertEquals(1, groupList.getGroupList().size()); + Assert.assertEquals("1", groupList.getGroupList().get(0)); + + // test getConsensusStatus + ConsensusStatus consensusStatus = client.getConsensusStatus(); + Assert.assertTrue(consensusStatus.getConsensusStatus().getViewInfos().size() > 0); + + for (String sealer : + consensusStatus.getConsensusStatus().getBaseConsensusInfo().getSealerList()) { + Assert.assertTrue(sealerList.getResult().contains(sealer)); + } + Assert.assertEquals( + "true", + consensusStatus.getConsensusStatus().getBaseConsensusInfo().getAllowFutureBlocks()); + Assert.assertEquals( + "true", + consensusStatus.getConsensusStatus().getBaseConsensusInfo().getOmitEmptyBlock()); + Assert.assertEquals( + blockNumber.getBlockNumber(), + new BigInteger( + consensusStatus + .getConsensusStatus() + .getBaseConsensusInfo() + .getHighestblockNumber())); + Assert.assertEquals( + latestHash.getBlockHashByNumber(), + consensusStatus.getConsensusStatus().getBaseConsensusInfo().getHighestblockHash()); + } + + private void checkReceipt( + HelloWorld helloWorld, + Client client, + BigInteger expectedBlockNumber, + TransactionReceipt receipt, + boolean checkTo) { + // check block number + System.out.println("blockNumber: " + Numeric.decodeQuantity(receipt.getBlockNumber())); + System.out.println("expected: " + expectedBlockNumber); + Assert.assertTrue( + Numeric.decodeQuantity(receipt.getBlockNumber()).compareTo(expectedBlockNumber) + >= 0); + // check hash + // Assert.assertTrue(receipt.getBlockHash().equals(client.getBlockHashByNumber(expectedBlockNumber).getBlockHashByNumber())); + Assert.assertEquals(null, receipt.getReceiptProof()); + Assert.assertEquals(null, receipt.getTxProof()); + System.out.println( + "getCurrentExternalAccountAddress: " + + helloWorld.getCurrentExternalAccountAddress() + + ", receipt.getFrom()" + + receipt.getFrom()); + Assert.assertEquals(helloWorld.getCurrentExternalAccountAddress(), receipt.getFrom()); + if (checkTo) { + Assert.assertEquals(helloWorld.getContractAddress(), receipt.getTo()); + } + } + + @Test + public void testSendTransactions() throws ConfigException, ContractException { + try { + BcosSDK sdk = BcosSDK.build(configFile); + Integer groupId = Integer.valueOf(1); + Client client = sdk.getClient(groupId); + BigInteger blockLimit = sdk.getGroupManagerService().getBlockLimitByGroup(groupId); + BigInteger blockNumber = client.getBlockNumber().getBlockNumber(); + // deploy the HelloWorld contract + HelloWorld helloWorld = + HelloWorld.deploy(client, client.getCryptoSuite().getCryptoKeyPair()); + checkReceipt( + helloWorld, + client, + blockNumber.add(BigInteger.ONE), + helloWorld.getDeployReceipt(), + false); + + // check the blockLimit has been modified + // wait the block number notification + Thread.sleep(1000); + Assert.assertTrue( + sdk.getGroupManagerService() + .getBlockLimitByGroup(groupId) + .compareTo(blockLimit.add(BigInteger.ONE)) + >= 0); + Assert.assertTrue(helloWorld != null); + Assert.assertTrue(helloWorld.getContractAddress() != null); + + // send transaction + String settedString = "Hello, FISCO"; + TransactionReceipt receipt = helloWorld.set(settedString); + Assert.assertTrue(receipt != null); + checkReceipt(helloWorld, client, blockNumber.add(BigInteger.valueOf(2)), receipt, true); + // wait the blocknumber notification + Thread.sleep(1000); + System.out.println( + sdk.getGroupManagerService().getBlockLimitByGroup(groupId) + + " " + + blockLimit.add(BigInteger.valueOf(2))); + Assert.assertTrue( + sdk.getGroupManagerService() + .getBlockLimitByGroup(groupId) + .compareTo(blockLimit.add(BigInteger.valueOf(2))) + >= 0); + // get the modified value + String getValue = helloWorld.get(); + Assert.assertTrue(getValue.equals(settedString)); + + // load contract from the contract address + HelloWorld helloWorld2 = + HelloWorld.load( + helloWorld.getContractAddress(), + client, + client.getCryptoSuite().getCryptoKeyPair()); + Assert.assertTrue( + helloWorld2.getContractAddress().equals(helloWorld.getContractAddress())); + settedString = "Hello, Fisco2"; + TransactionReceipt receipt2 = helloWorld2.set(settedString); + checkReceipt( + helloWorld2, client, blockNumber.add(BigInteger.valueOf(3)), receipt2, true); + Assert.assertTrue(helloWorld.get().equals(settedString)); + Assert.assertTrue(helloWorld2.get().equals(settedString)); + } catch (ContractException | ClientException | InterruptedException e) { + System.out.println("testSendTransactions exceptioned, error info:" + e.getMessage()); + } + } +} diff --git a/src/integration-test/java/org/fisco/bcos/sdk/amop/PrivateTopicVerifyTest.java b/src/integration-test/java/org/fisco/bcos/sdk/amop/PrivateTopicVerifyTest.java new file mode 100644 index 000000000..1d69c34fc --- /dev/null +++ b/src/integration-test/java/org/fisco/bcos/sdk/amop/PrivateTopicVerifyTest.java @@ -0,0 +1,144 @@ +package org.fisco.bcos.sdk.amop; + +import java.util.concurrent.Semaphore; +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.amop.topic.AmopMsgIn; +import org.fisco.bcos.sdk.amop.topic.TopicType; +import org.fisco.bcos.sdk.channel.ResponseCallback; +import org.fisco.bcos.sdk.model.Response; +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PrivateTopicVerifyTest { + private static Logger logger = LoggerFactory.getLogger(PrivateTopicVerifyTest.class); + private static final String senderConfig = + PrivateTopicVerifyTest.class + .getClassLoader() + .getResource("amop/config-publisher-for-test.toml") + .getPath(); + private static final String subscriberConfig = + PrivateTopicVerifyTest.class + .getClassLoader() + .getResource("amop/config-subscriber-for-test.toml") + .getPath(); + private Amop sender; + private Amop subscriber; + + @Test + public void testSendMsg() throws InterruptedException { + prepareEnv(); + Thread.sleep(3000); + AmopMsgOut out = new AmopMsgOut(); + out.setTimeout(2000); + out.setTopic("test"); + out.setType(TopicType.NORMAL_TOPIC); + out.setContent("Tell you th.".getBytes()); + class TestResponseCb extends ResponseCallback { + public transient Semaphore semaphore = new Semaphore(1, true); + + public TestResponseCb() { + try { + semaphore.acquire(1); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + @Override + public void onResponse(Response response) { + semaphore.release(); + Assert.assertEquals("Yes, I received.", response.getContent().substring(5)); + } + } + TestResponseCb cb = new TestResponseCb(); + sender.sendAmopMsg(out, cb); + try { + cb.semaphore.acquire(1); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + @Test + public void addPrivateTopic() throws InterruptedException { + prepareEnv(); + logger.trace("Start private topic test"); + Thread.sleep(4000); + AmopMsgOut out = new AmopMsgOut(); + out.setTimeout(10000); + out.setContent("send private msg".getBytes()); + out.setType(TopicType.PRIVATE_TOPIC); + out.setTopic("privTopic"); + final String[] content = new String[1]; + + class TestResponseCb extends ResponseCallback { + public transient Semaphore semaphore = new Semaphore(1, true); + + public TestResponseCb() { + try { + semaphore.acquire(1); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + @Override + public void onResponse(Response response) { + logger.trace( + "Receive response, seq:{} error:{} error msg: {} content:{}", + response.getMessageID(), + response.getErrorCode(), + response.getErrorMessage(), + response.getContent()); + content[0] = response.getContent(); + semaphore.release(); + } + } + TestResponseCb cb = new TestResponseCb(); + sender.sendAmopMsg(out, cb); + try { + cb.semaphore.acquire(1); + if (content[0].length() > 29) { + Assert.assertEquals("Yes, I received.", content[0].substring(29)); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + private void prepareEnv() throws InterruptedException { + BcosSDK sdk2 = BcosSDK.build(subscriberConfig); + Assert.assertTrue(sdk2.getChannel().getAvailablePeer().size() >= 1); + + BcosSDK sdk1 = BcosSDK.build(senderConfig); + Assert.assertTrue(sdk1.getChannel().getAvailablePeer().size() >= 1); + Thread.sleep(2000); + sender = sdk1.getAmop(); + subscriber = sdk2.getAmop(); + TestAmopCallback defaultCb = + new TestAmopCallback("#!$TopicNeedVerify_privTopic", "send private msg"); + subscriber.setCallback(defaultCb); + subscriber.subscribeTopic("test", new TestAmopCallback("test", "Tell you th.")); + } + + public class TestAmopCallback extends AmopCallback { + private String topic; + private String content; + + public TestAmopCallback(String topic, String content) { + this.topic = topic; + this.content = content; + } + + @Override + public byte[] receiveAmopMsg(AmopMsgIn msg) { + // Assert.assertEquals(topic,msg.getTopic()); + // Assert.assertEquals(content,new String(msg.getContent())); + System.out.println("on subscribed topic msg"); + + return "Yes, I received.".getBytes(); + } + } +} diff --git a/src/integration-test/java/org/fisco/bcos/sdk/channel/ChannelTest.java b/src/integration-test/java/org/fisco/bcos/sdk/channel/ChannelTest.java new file mode 100644 index 000000000..7b7c4613f --- /dev/null +++ b/src/integration-test/java/org/fisco/bcos/sdk/channel/ChannelTest.java @@ -0,0 +1,136 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.channel; + +import static org.junit.Assert.fail; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.netty.channel.ChannelHandlerContext; +import java.util.List; +import org.fisco.bcos.sdk.channel.model.EnumChannelProtocolVersion; +import org.fisco.bcos.sdk.channel.model.HeartBeatParser; +import org.fisco.bcos.sdk.channel.model.NodeHeartbeat; +import org.fisco.bcos.sdk.channel.model.Options; +import org.fisco.bcos.sdk.config.Config; +import org.fisco.bcos.sdk.config.ConfigOption; +import org.fisco.bcos.sdk.config.exceptions.ConfigException; +import org.fisco.bcos.sdk.model.ConstantConfig; +import org.fisco.bcos.sdk.model.Message; +import org.fisco.bcos.sdk.model.MsgType; +import org.fisco.bcos.sdk.model.Response; +import org.fisco.bcos.sdk.network.MsgHandler; +import org.fisco.bcos.sdk.utils.ChannelUtils; +import org.fisco.bcos.sdk.utils.ObjectMapperFactory; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ChannelTest { + private Logger logger = LoggerFactory.getLogger(ChannelImp.class); + private Channel channel; + + @Test + public void testConnect() throws ConfigException { + ConfigOption configOption = + Config.load("src/integration-test/resources/" + ConstantConfig.CONFIG_FILE_NAME); + channel = Channel.build(configOption); + class TestMsgHandler implements MsgHandler { + @Override + public void onConnect(ChannelHandlerContext ctx) { + logger.info("OnConnect in ChannelTest called: " + ctx.channel().remoteAddress()); + } + + @Override + public void onMessage(ChannelHandlerContext ctx, Message msg) { + logger.info("onMessage in ChannelTest called: " + ctx.channel().remoteAddress()); + } + + @Override + public void onDisconnect(ChannelHandlerContext ctx) { + logger.info("onDisconnect in ChannelTest called: " + ctx.channel().remoteAddress()); + } + } + TestMsgHandler testMsgHandler = new TestMsgHandler(); + channel.addConnectHandler(testMsgHandler); + channel.addMessageHandler(MsgType.CHANNEL_RPC_REQUEST, testMsgHandler); + channel.addDisconnectHandler(testMsgHandler); + try { + channel.start(); + sendMessage(); + Thread.sleep(10000); + channel.stop(); + } catch (Exception e) { + System.out.println("testConnect failed, error info: " + e.getMessage()); + fail("Exception is not expected"); + } + } + + // use heart beat for case to send + private void sendMessage() { + List peers = channel.getAvailablePeer(); + if (peers.size() == 0) { + fail("Empty available peer"); + } + String host = peers.get(0); + Message message = new Message(); + try { + message.setSeq(ChannelUtils.newSeq()); + message.setResult(0); + message.setType(Short.valueOf((short) MsgType.CLIENT_HEARTBEAT.getType())); + HeartBeatParser heartBeatParser = + new HeartBeatParser(EnumChannelProtocolVersion.VERSION_1); + message.setData(heartBeatParser.encode("0")); + logger.trace( + "encodeHeartbeatToMessage, seq: {}, content: {}, messageType: {}", + message.getSeq(), + heartBeatParser.toString(), + message.getType()); + } catch (JsonProcessingException e) { + logger.error( + "sendHeartbeatMessage failed for decode the message exception, errorMessage: {}", + e.getMessage()); + return; + } + + ResponseCallback callback = + new ResponseCallback() { + @Override + public void onResponse(Response response) { + try { + NodeHeartbeat nodeHeartbeat = + ObjectMapperFactory.getObjectMapper() + .readValue(response.getContent(), NodeHeartbeat.class); + int heartBeat = nodeHeartbeat.getHeartBeat(); + logger.trace( + " heartbeat packet in ChannelTest, heartbeat is {} ", + heartBeat); + if (heartBeat != 1) { + fail("heartbeat packet in ChannelTest fail"); + } + } catch (Exception e) { + fail( + " channel protocol heartbeat failed, exception: " + + e.getMessage()); + } + } + }; + + logger.info(" test sendToPeer"); + channel.sendToPeer(message, host); + logger.info(" test asyncSendToPeer"); + channel.asyncSendToPeer(message, host, callback, new Options()); + } +} diff --git a/src/integration-test/java/org/fisco/bcos/sdk/eventsub/SubscribeTest.java b/src/integration-test/java/org/fisco/bcos/sdk/eventsub/SubscribeTest.java new file mode 100644 index 000000000..f9c4a6825 --- /dev/null +++ b/src/integration-test/java/org/fisco/bcos/sdk/eventsub/SubscribeTest.java @@ -0,0 +1,180 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.eventsub; + +import com.google.common.collect.Lists; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Semaphore; +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.abi.ABICodec; +import org.fisco.bcos.sdk.abi.ABICodecException; +import org.fisco.bcos.sdk.abi.tools.TopicTools; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.model.ConstantConfig; +import org.fisco.bcos.sdk.model.EventLog; +import org.fisco.bcos.sdk.transaction.manager.AssembleTransactionProcessor; +import org.fisco.bcos.sdk.transaction.manager.TransactionProcessorFactory; +import org.fisco.bcos.sdk.transaction.model.dto.TransactionResponse; +import org.fisco.bcos.sdk.transaction.tools.JsonUtils; +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SubscribeTest { + private static final String configFile = + SubscribeTest.class + .getClassLoader() + .getResource(ConstantConfig.CONFIG_FILE_NAME) + .getPath(); + private static final Logger logger = LoggerFactory.getLogger(SubscribeTest.class); + private static final String abiFile = "src/integration-test/resources/abi/"; + private static final String binFile = "src/integration-test/resources/bin/"; + private static final String abi = + "[{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"_addrDArray\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"_addr\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getUint256\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"v\",\"type\":\"uint256\"}],\"name\":\"incrementUint256\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"_bytesV\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"_s\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"getSArray\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"bytesArray\",\"type\":\"bytes1[]\"}],\"name\":\"setBytesMapping\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b\",\"type\":\"bytes\"}],\"name\":\"setBytes\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i\",\"type\":\"int256\"},{\"name\":\"a\",\"type\":\"address[]\"},{\"name\":\"s\",\"type\":\"string\"}],\"name\":\"setValues\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"b\",\"type\":\"bytes1\"}],\"name\":\"getByBytes\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes1[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"_intV\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"emptyArgs\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"i\",\"type\":\"int256\"},{\"name\":\"s\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"LogIncrement\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"s\",\"type\":\"string\"}],\"name\":\"LogInit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"i\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"a\",\"type\":\"address[]\"},{\"indexed\":false,\"name\":\"s\",\"type\":\"string\"}],\"name\":\"LogSetValues\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"o\",\"type\":\"bytes\"},{\"indexed\":false,\"name\":\"b\",\"type\":\"bytes\"}],\"name\":\"LogSetBytes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"o\",\"type\":\"uint256[2]\"},{\"indexed\":false,\"name\":\"n\",\"type\":\"uint256[2]\"}],\"name\":\"LogSetSArray\",\"type\":\"event\"}]"; + + @Test + public void testEventSubModule() { + // Init event subscribe module. + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + EventSubscribe eventSubscribe = sdk.getEventSubscribe(client.getGroupId()); + eventSubscribe.start(); + String contractAddress = ""; + try { + AssembleTransactionProcessor manager = + TransactionProcessorFactory.createAssembleTransactionProcessor( + client, client.getCryptoSuite().createKeyPair(), abiFile, binFile); + // deploy + List params = Lists.newArrayList(); + params.add(1); + params.add("test"); + TransactionResponse response = manager.deployByContractLoader("ComplexSol", params); + if (!response.getTransactionReceipt().getStatus().equals("0x0")) { + return; + } + contractAddress = response.getContractAddress(); + + // call function with event + List paramsSetValues = Lists.newArrayList(20); + String[] o = {"0x1", "0x2", "0x3"}; + List a = Arrays.asList(o); + paramsSetValues.add(a); + paramsSetValues.add("test"); + TransactionResponse transactionResponse = + manager.sendTransactionAndGetResponse( + contractAddress, abi, "setValues", paramsSetValues); + logger.info("transaction response : " + JsonUtils.toJson(transactionResponse)); + } catch (Exception e) { + logger.error("exception:", e); + } + + EventLogParams eventLogParams1 = new EventLogParams(); + eventLogParams1.setFromBlock("latest"); + eventLogParams1.setToBlock("latest"); + eventLogParams1.setAddresses(new ArrayList<>()); + ArrayList topics = new ArrayList<>(); + CryptoSuite invalidCryptoSuite = + new CryptoSuite(client.getCryptoSuite().getCryptoTypeConfig()); + TopicTools topicTools = new TopicTools(invalidCryptoSuite); + topics.add(topicTools.stringToTopic("LogSetValues(int256,address[],string)")); + eventLogParams1.setTopics(topics); + + class SubscribeCallback implements EventCallback { + public transient Semaphore semaphore = new Semaphore(1, true); + + SubscribeCallback() { + try { + semaphore.acquire(1); + } catch (InterruptedException e) { + logger.error("error :", e); + Thread.currentThread().interrupt(); + } + } + + @Override + public void onReceiveLog(int status, List logs) { + Assert.assertEquals(status, 0); + String str = "status in onReceiveLog : " + status; + logger.debug(str); + semaphore.release(); + if (logs != null) { + for (EventLog log : logs) { + logger.debug( + " blockNumber:" + + log.getBlockNumber() + + ",txIndex:" + + log.getTransactionIndex() + + " data:" + + log.getData()); + ABICodec abiCodec = new ABICodec(client.getCryptoSuite()); + try { + List list = abiCodec.decodeEvent(abi, "LogSetValues", log); + logger.debug("decode event log content, " + list); + Assert.assertEquals("20", list.get(0).toString()); + Assert.assertEquals("test", list.get(2).toString()); + List list1 = + abiCodec.decodeEventByInterface( + abi, "LogSetValues(int256,address[],string)", log); + Assert.assertEquals(3, list1.size()); + } catch (ABICodecException e) { + logger.error("decode event log error, " + e.getMessage()); + } + } + } + } + } + + logger.info(" start to subscribe event"); + SubscribeCallback subscribeEventCallback1 = new SubscribeCallback(); + String registerId1 = + eventSubscribe.subscribeEvent(eventLogParams1, subscribeEventCallback1); + try { + subscribeEventCallback1.semaphore.acquire(1); + subscribeEventCallback1.semaphore.release(); + logger.info("subscribe successful, registerId is " + registerId1); + } catch (InterruptedException e) { + logger.error("system error:", e); + Thread.currentThread().interrupt(); + } + + // FISCO BCOS node v2.7.0 + try { + Thread.sleep(3000); + } catch (Exception e) { + logger.error("exception:", e); + } + + // FISCO BCOS node v2.7.0 + /*logger.info(" start to unregister event"); + SubscribeCallback subscribeEventCallback2 = new SubscribeCallback(); + eventSubscribe.unsubscribeEvent(registerId1, subscribeEventCallback2); + try { + subscribeEventCallback2.semaphore.acquire(1); + subscribeEventCallback2.semaphore.release(); + logger.info("unregister event successful"); + } catch (InterruptedException e) { + logger.error("system error:", e); + Thread.currentThread().interrupt(); + }*/ + + eventSubscribe.stop(); + sdk.getChannel().stop(); + } +} diff --git a/src/integration-test/java/org/fisco/bcos/sdk/network/ConnectTest.java b/src/integration-test/java/org/fisco/bcos/sdk/network/ConnectTest.java new file mode 100644 index 000000000..173ff5310 --- /dev/null +++ b/src/integration-test/java/org/fisco/bcos/sdk/network/ConnectTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.network; + +import static org.junit.Assert.fail; + +import io.netty.channel.ChannelHandlerContext; +import org.fisco.bcos.sdk.config.Config; +import org.fisco.bcos.sdk.config.ConfigOption; +import org.fisco.bcos.sdk.config.exceptions.ConfigException; +import org.fisco.bcos.sdk.model.ConstantConfig; +import org.fisco.bcos.sdk.model.Message; +import org.junit.Test; + +public class ConnectTest { + @Test + public void testConnect() throws ConfigException { + class TestMsgHandler implements MsgHandler { + + @Override + public void onConnect(ChannelHandlerContext ctx) { + System.out.println("OnConnect called: " + ctx.channel().remoteAddress()); + } + + @Override + public void onMessage(ChannelHandlerContext ctx, Message msg) {} + + @Override + public void onDisconnect(ChannelHandlerContext ctx) {} + } + ConfigOption configOption = + Config.load("src/integration-test/resources/" + ConstantConfig.CONFIG_FILE_NAME); + Network network = Network.build(configOption, new TestMsgHandler()); + try { + network.start(); + Thread.sleep(3000); + } catch (Exception e) { + System.out.println("testConnect failed, error message:" + e.getMessage()); + fail("Exception is not expected"); + } + } +} diff --git a/src/integration-test/java/org/fisco/bcos/sdk/precompiled/PrecompiledTest.java b/src/integration-test/java/org/fisco/bcos/sdk/precompiled/PrecompiledTest.java new file mode 100644 index 000000000..9cc155261 --- /dev/null +++ b/src/integration-test/java/org/fisco/bcos/sdk/precompiled/PrecompiledTest.java @@ -0,0 +1,612 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.fisco.bcos.sdk.precompiled; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicLong; +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.BcosSDKTest; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.client.exceptions.ClientException; +import org.fisco.bcos.sdk.config.exceptions.ConfigException; +import org.fisco.bcos.sdk.contract.precompiled.callback.PrecompiledCallback; +import org.fisco.bcos.sdk.contract.precompiled.cns.CnsInfo; +import org.fisco.bcos.sdk.contract.precompiled.cns.CnsService; +import org.fisco.bcos.sdk.contract.precompiled.consensus.ConsensusService; +import org.fisco.bcos.sdk.contract.precompiled.contractmgr.ContractLifeCycleService; +import org.fisco.bcos.sdk.contract.precompiled.crud.TableCRUDService; +import org.fisco.bcos.sdk.contract.precompiled.crud.common.Entry; +import org.fisco.bcos.sdk.contract.precompiled.permission.ChainGovernanceService; +import org.fisco.bcos.sdk.contract.precompiled.permission.PermissionInfo; +import org.fisco.bcos.sdk.contract.precompiled.permission.PermissionService; +import org.fisco.bcos.sdk.contract.precompiled.sysconfig.SystemConfigService; +import org.fisco.bcos.sdk.crypto.CryptoSuite; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.demo.contract.HelloWorld; +import org.fisco.bcos.sdk.model.ConstantConfig; +import org.fisco.bcos.sdk.model.PrecompiledRetCode; +import org.fisco.bcos.sdk.model.RetCode; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.transaction.model.exception.ContractException; +import org.fisco.bcos.sdk.utils.ThreadPoolService; +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class PrecompiledTest { + private static final String configFile = + BcosSDKTest.class + .getClassLoader() + .getResource(ConstantConfig.CONFIG_FILE_NAME) + .getPath(); + public AtomicLong receiptCount = new AtomicLong(); + + @Test + public void test1ConsensusService() throws ConfigException, ContractException { + try { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair(); + ConsensusService consensusService = new ConsensusService(client, cryptoKeyPair); + // get the current sealerList + List sealerList = client.getSealerList().getResult(); + + // select the node to operate + String selectedNode = sealerList.get(0); + + // addSealer + Assert.assertTrue( + PrecompiledRetCode.ALREADY_EXISTS_IN_SEALER_LIST.equals( + consensusService.addSealer(selectedNode))); + + // add the sealer to the observerList + RetCode retCode = consensusService.addObserver(selectedNode); + // query the observerList + if (retCode.getCode() == PrecompiledRetCode.CODE_SUCCESS.getCode()) { + List observerList = client.getObserverList().getResult(); + Assert.assertTrue(observerList.contains(selectedNode)); + // query the sealerList + sealerList = client.getSealerList().getResult(); + Assert.assertTrue(!sealerList.contains(selectedNode)); + // add the node to the observerList again + Assert.assertTrue( + consensusService + .addObserver(selectedNode) + .equals(PrecompiledRetCode.ALREADY_EXISTS_IN_OBSERVER_LIST)); + } + // add the node to the sealerList again + retCode = consensusService.addSealer(selectedNode); + + if (retCode.getCode() == PrecompiledRetCode.CODE_SUCCESS.getCode()) { + Assert.assertTrue(client.getSealerList().getResult().contains(selectedNode)); + Assert.assertTrue(!client.getObserverList().getResult().contains(selectedNode)); + } + + // removeNode + retCode = consensusService.removeNode(selectedNode); + if (retCode.getCode() == PrecompiledRetCode.CODE_SUCCESS.getCode()) { + Assert.assertTrue(!client.getObserverList().getResult().contains(selectedNode)); + Assert.assertTrue(!client.getSealerList().getResult().contains(selectedNode)); + } + + // add the node to observerList again + retCode = consensusService.addObserver(selectedNode); + if (retCode.getCode() == PrecompiledRetCode.CODE_SUCCESS.getCode()) { + Assert.assertTrue(client.getObserverList().getResult().contains(selectedNode)); + Assert.assertTrue(!client.getSealerList().getResult().contains(selectedNode)); + } + + // add the node to the sealerList again + retCode = consensusService.addSealer(selectedNode); + if (retCode.getCode() == PrecompiledRetCode.CODE_SUCCESS.getCode()) { + Assert.assertTrue(client.getSealerList().getResult().contains(selectedNode)); + Assert.assertTrue(!client.getObserverList().getResult().contains(selectedNode)); + } + } catch (ClientException | ContractException e) { + System.out.println( + "testConsensusPrecompiled exceptioned, error info:" + e.getMessage()); + } + } + + @Test + public void test2CnsService() throws ConfigException { + try { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair(); + HelloWorld helloWorld = HelloWorld.deploy(client, cryptoKeyPair); + String contractAddress = helloWorld.getContractAddress(); + String contractName = "HelloWorld"; + String contractVersion = "1.0"; + CnsService cnsService = new CnsService(client, cryptoKeyPair); + RetCode retCode = + cnsService.registerCNS(contractName, contractVersion, contractAddress, ""); + // query the cns information + List cnsInfos = cnsService.selectByName(contractName); + Assert.assertTrue(cnsInfos.get(0).getAbi().equals("")); + Assert.assertTrue(cnsInfos.get(0).getVersion().equals(contractVersion)); + + if (retCode.getCode() == PrecompiledRetCode.CODE_SUCCESS.getCode()) { + boolean containContractAddress = false; + for (CnsInfo cnsInfo : cnsInfos) { + if (cnsInfo.getAddress().equals(contractAddress)) { + containContractAddress = true; + } + } + Assert.assertTrue(containContractAddress); + } + Assert.assertTrue(cnsInfos.get(0).getName().equals(contractName)); + + // query contractAddress + cnsService.getContractAddress(contractName, contractVersion); + // insert another cns info + String contractVersion2 = "2.0"; + retCode = cnsService.registerCNS(contractName, contractVersion2, contractAddress, ""); + + if (retCode.getCode() == PrecompiledRetCode.CODE_SUCCESS.getCode()) { + List cnsInfos2 = cnsService.selectByName(contractName); + Assert.assertTrue(cnsInfos2.size() == cnsInfos.size() + 1); + Assert.assertTrue( + cnsService + .getContractAddress(contractName, contractVersion) + .equals(contractAddress)); + Assert.assertTrue( + cnsService + .getContractAddress(contractName, contractVersion2) + .equals(contractAddress)); + } + // insert anther cns for other contract + HelloWorld helloWorld2 = HelloWorld.deploy(client, cryptoKeyPair); + String contractAddress2 = helloWorld2.getContractAddress(); + String contractName2 = "hello"; + retCode = cnsService.registerCNS(contractName2, contractVersion, contractAddress2, ""); + if (retCode.getCode() == PrecompiledRetCode.CODE_SUCCESS.getCode()) { + Assert.assertTrue(cnsService.getContractAddress(contractName, "abc").equals("")); + Assert.assertTrue( + cnsService + .getContractAddress(contractName2, contractVersion) + .equals(contractAddress2)); + Assert.assertTrue( + cnsService + .getContractAddress(contractName, contractVersion) + .equals(contractAddress)); + } + } catch (ContractException e) { + System.out.println("testCnsPrecompiled failed for " + e.getMessage()); + } + } + + @Test + public void test3SystemConfigService() throws ConfigException, ContractException { + try { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair(); + SystemConfigService systemConfigService = + new SystemConfigService(client, cryptoKeyPair); + testSystemConfigService(client, systemConfigService, "tx_count_limit"); + testSystemConfigService(client, systemConfigService, "tx_gas_limit"); + } catch (ClientException | ContractException e) { + System.out.println( + "testSystemConfigPrecompiled exceptioned, error inforamtion:" + e.getMessage()); + } + } + + private void testSystemConfigService( + Client client, SystemConfigService systemConfigService, String key) + throws ContractException { + BigInteger value = new BigInteger(client.getSystemConfigByKey(key).getSystemConfig()); + BigInteger updatedValue = value.add(BigInteger.valueOf(1000)); + String updatedValueStr = String.valueOf(updatedValue); + systemConfigService.setValueByKey(key, updatedValueStr); + + BigInteger queriedValue = + new BigInteger(client.getSystemConfigByKey(key).getSystemConfig()); + System.out.println("queriedValue: " + queriedValue); + // Assert.assertTrue(queriedValue.equals(updatedValue)); + // Assert.assertTrue(queriedValue.equals(value.add(BigInteger.valueOf(1000)))); + } + // Note: Please make sure that the ut is before the permission-related ut + @Test + public void test5CRUDService() throws ConfigException, ContractException { + try { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair(); + TableCRUDService tableCRUDService = new TableCRUDService(client, cryptoKeyPair); + // create a user table + String tableName = "test"; + String key = "key"; + List valueFields = new ArrayList<>(5); + for (int i = 0; i < 5; i++) { + valueFields.add(i, "field" + i); + } + tableCRUDService.createTable(tableName, key, valueFields); + + // insert + Map fieldNameToValue = new HashMap<>(); + for (int i = 0; i < valueFields.size(); i++) { + fieldNameToValue.put("field" + i, "value" + i); + } + Entry fieldNameToValueEntry = new Entry(fieldNameToValue); + tableCRUDService.insert(tableName, key, fieldNameToValueEntry); + // select + List> result = tableCRUDService.select(tableName, key, null); + // field value result + key result + if (result.size() > 0) { + Assert.assertTrue(result.get(0).size() == fieldNameToValue.size() + 1); + } + System.out.println("tableCRUDService select result: " + result.toString()); + // update + fieldNameToValue.clear(); + fieldNameToValueEntry.setFieldNameToValue(fieldNameToValue); + tableCRUDService.update(tableName, key, fieldNameToValueEntry, null); + result = tableCRUDService.select(tableName, key, null); + if (result.size() > 0) { + Assert.assertTrue(result.get(0).size() == valueFields.size() + 1); + } + System.out.println("tableCRUDService select result: " + result.toString()); + + // remove + tableCRUDService.remove(tableName, key, null); + result = tableCRUDService.select(tableName, key, null); + // Assert.assertTrue(result.size() == 0); + System.out.println( + "testCRUDPrecompiled tableCRUDService.remove size : " + result.size()); + + // desc + tableCRUDService.desc(tableName); + } catch (ContractException e) { + System.out.println("testCRUDPrecompiled exceptioned, error info: " + e.getMessage()); + } + } + + // Note: Please make sure that the ut is before the permission-related ut + @Test + public void test51SyncCRUDService() throws ConfigException { + try { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair(); + TableCRUDService crudService = new TableCRUDService(client, cryptoKeyPair); + String tableName = "test_sync"; + List valueFiled = new ArrayList<>(); + valueFiled.add("field"); + RetCode retCode = crudService.createTable(tableName, "key", valueFiled); + System.out.println( + "createResult: " + retCode.getCode() + ", message: " + retCode.getMessage()); + // create a thread pool to parallel insert and select + ExecutorService threadPool = Executors.newFixedThreadPool(50); + + BigInteger orgTxCount = + new BigInteger( + client.getTotalTransactionCount() + .getTotalTransactionCount() + .getTxSum() + .substring(2), + 16); + for (int i = 0; i < 100; i++) { + final Integer index = i; + threadPool.execute( + new Runnable() { + @Override + public void run() { + try { + Map value = new HashMap<>(); + value.put("field", "field" + index); + String valueOfKey = "key_value" + index; + // insert + crudService.insert(tableName, valueOfKey, new Entry(value)); + // select + crudService.select(tableName, valueOfKey, null); + // update + value.clear(); + value.put("field", "field" + index + 100); + crudService.update( + tableName, valueOfKey, new Entry(value), null); + // remove + crudService.remove(tableName, valueOfKey, null); + } catch (ContractException e) { + System.out.println( + "call crudService failed, error information: " + + e.getMessage()); + } + } + }); + } + ThreadPoolService.stopThreadPool(threadPool); + BigInteger currentTxCount = + new BigInteger( + client.getTotalTransactionCount() + .getTotalTransactionCount() + .getTxSum() + .substring(2), + 16); + System.out.println("orgTxCount: " + orgTxCount + ", currentTxCount:" + currentTxCount); + Assert.assertTrue( + currentTxCount.compareTo(orgTxCount.add(BigInteger.valueOf(300))) >= 0); + } catch (ContractException e) { + System.out.println("test9SyncCRUDService failed, error info: " + e.getMessage()); + } + } + + class FakeTransactionCallback implements PrecompiledCallback { + public TransactionReceipt receipt; + // wait until get the transactionReceipt + @Override + public void onResponse(RetCode retCode) { + this.receipt = retCode.getTransactionReceipt(); + receiptCount.addAndGet(1); + } + } + + @Test + public void test52AsyncCRUDService() { + try { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair(); + TableCRUDService crudService = new TableCRUDService(client, cryptoKeyPair); + // create table + String tableName = "send_async"; + List valueFiled = new ArrayList<>(); + valueFiled.add("field"); + String key = "key"; + crudService.createTable(tableName, key, valueFiled); + // create a thread pool to parallel insert and select + ExecutorService threadPool = Executors.newFixedThreadPool(50); + BigInteger orgTxCount = + new BigInteger( + client.getTotalTransactionCount() + .getTotalTransactionCount() + .getTxSum() + .substring(2), + 16); + for (int i = 0; i < 100; i++) { + final Integer index = i; + threadPool.execute( + new Runnable() { + @Override + public void run() { + try { + Map value = new HashMap<>(); + value.put("field", "field" + index); + String valueOfKey = "key_value" + index; + // insert + FakeTransactionCallback callback = + new FakeTransactionCallback(); + crudService.asyncInsert( + tableName, valueOfKey, new Entry(value), callback); + // update + value.clear(); + value.put("field", "field" + index + 100); + FakeTransactionCallback callback2 = + new FakeTransactionCallback(); + crudService.asyncUpdate( + tableName, + valueOfKey, + new Entry(value), + null, + callback2); + // remove + FakeTransactionCallback callback3 = + new FakeTransactionCallback(); + crudService.asyncRemove(tableName, valueOfKey, null, callback3); + } catch (ContractException e) { + System.out.println( + "call crudService failed, error information: " + + e.getMessage()); + } + } + }); + } + while (receiptCount.get() != 300) { + Thread.sleep(1000); + } + ThreadPoolService.stopThreadPool(threadPool); + BigInteger currentTxCount = + new BigInteger( + client.getTotalTransactionCount() + .getTotalTransactionCount() + .getTxSum() + .substring(2), + 16); + System.out.println("orgTxCount: " + orgTxCount + ", currentTxCount:" + currentTxCount); + Assert.assertTrue( + currentTxCount.compareTo(orgTxCount.add(BigInteger.valueOf(300))) >= 0); + } catch (ContractException | InterruptedException e) { + System.out.println("test10AsyncCRUDService failed, error info: " + e.getMessage()); + } + } + + @Test + public void test6PermissionService() throws ConfigException, ContractException { + try { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair(); + PermissionService permissionService = new PermissionService(client, cryptoKeyPair); + + String tableName = "test"; + permissionService.grantPermission(tableName, cryptoKeyPair.getAddress()); + + // insert data to the table with the account without permission + CryptoSuite invalidCryptoSuite = + new CryptoSuite(client.getCryptoSuite().getCryptoTypeConfig()); + TableCRUDService tableCRUDService = + new TableCRUDService(client, invalidCryptoSuite.createKeyPair()); + String key = "key2"; + Map value = new HashMap<>(5); + for (int i = 0; i < 5; i++) { + value.put("field" + i, "value2" + i); + } + RetCode retCode = tableCRUDService.insert(tableName, key, new Entry(value)); + Assert.assertTrue(retCode.getCode() == PrecompiledRetCode.CODE_NO_AUTHORIZED.getCode()); + Assert.assertTrue( + retCode.getMessage() == PrecompiledRetCode.CODE_NO_AUTHORIZED.getMessage()); + + // insert data to the table with the account with permission + TableCRUDService tableCRUDService2 = new TableCRUDService(client, cryptoKeyPair); + retCode = tableCRUDService2.insert(tableName, key, new Entry(value)); + Assert.assertTrue(retCode.getCode() == 1); + + // revoke permission + permissionService.revokePermission(tableName, cryptoKeyPair.getAddress()); + retCode = tableCRUDService.insert(tableName, key, new Entry(value)); + Assert.assertTrue(retCode.getCode() == 1); + } catch (ContractException e) { + System.out.println( + "testPermissionPrecompiled exceptioned, error info: " + e.getMessage()); + } + } + + @Test + public void test7ContractLifeCycleService() throws ConfigException { + try { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair(); + ContractLifeCycleService contractLifeCycleService = + new ContractLifeCycleService(client, cryptoKeyPair); + // deploy a helloWorld + HelloWorld helloWorld = HelloWorld.deploy(client, cryptoKeyPair); + String orgValue = helloWorld.get(); + contractLifeCycleService.freeze(helloWorld.getContractAddress()); + // call the contract + TransactionReceipt receipt = helloWorld.set("Hello, Fisco"); + BigInteger status = new BigInteger(receipt.getStatus().substring(2), 16); + Assert.assertTrue(status.equals(BigInteger.valueOf(30))); + + // get contract status + contractLifeCycleService.getContractStatus(helloWorld.getContractAddress()); + + // unfreeze the contract + contractLifeCycleService.unfreeze(helloWorld.getContractAddress()); + String value = helloWorld.get(); + Assert.assertTrue(value.equals(orgValue)); + + helloWorld.set("Hello, Fisco1"); + value = helloWorld.get(); + System.out.println("==== after set: " + value); + // Assert.assertTrue("Hello, Fisco1".equals(value)); + // grant Manager + CryptoSuite cryptoSuite1 = + new CryptoSuite(client.getCryptoSuite().getCryptoTypeConfig()); + CryptoKeyPair cryptoKeyPair1 = cryptoSuite1.createKeyPair(); + ContractLifeCycleService contractLifeCycleService1 = + new ContractLifeCycleService(client, cryptoKeyPair1); + // freeze contract without grant manager + RetCode retCode = contractLifeCycleService1.freeze(helloWorld.getContractAddress()); + Assert.assertTrue(retCode.equals(PrecompiledRetCode.CODE_INVALID_NO_AUTHORIZED)); + // grant manager + contractLifeCycleService.grantManager( + helloWorld.getContractAddress(), cryptoKeyPair1.getAddress()); + // freeze the contract + retCode = contractLifeCycleService1.freeze(helloWorld.getContractAddress()); + receipt = helloWorld.set("Hello, fisco2"); + Assert.assertTrue( + new BigInteger(receipt.getStatus().substring(2), 16) + .equals(BigInteger.valueOf(30))); + + // unfreeze the contract + contractLifeCycleService1.unfreeze(helloWorld.getContractAddress()); + helloWorld.set("Hello, fisco3"); + Assert.assertTrue("Hello, fisco3".equals(helloWorld.get())); + } catch (ContractException | ClientException e) { + System.out.println("testContractLifeCycleService failed, error info:" + e.getMessage()); + } + } + + @Test + public void test8GovernanceService() throws ConfigException { + try { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair(); + ChainGovernanceService chainGovernanceService = + new ChainGovernanceService(client, cryptoKeyPair); + + List orgPermissionInfos = chainGovernanceService.listCommitteeMembers(); + chainGovernanceService.grantCommitteeMember(cryptoKeyPair.getAddress()); + List permissionInfos = chainGovernanceService.listCommitteeMembers(); + // Assert.assertTrue(permissionInfos.size() == orgPermissionInfos.size() + 1); + System.out.println("permissionInfos size: " + permissionInfos.size()); + + Assert.assertTrue( + chainGovernanceService + .queryCommitteeMemberWeight(cryptoKeyPair.getAddress()) + .equals(BigInteger.valueOf(1))); + + RetCode retCode = chainGovernanceService.grantOperator(cryptoKeyPair.getAddress()); + Assert.assertTrue( + retCode.equals(PrecompiledRetCode.CODE_COMMITTEE_MEMBER_CANNOT_BE_OPERATOR)); + + // create a new account and grantOperator + int orgOperatorSize = chainGovernanceService.listOperators().size(); + CryptoSuite cryptoSuite1 = + new CryptoSuite(client.getCryptoSuite().getCryptoTypeConfig()); + CryptoKeyPair cryptoKeyPair1 = cryptoSuite1.createKeyPair(); + chainGovernanceService.grantOperator(cryptoKeyPair.getAddress()); + // Assert.assertTrue(chainGovernanceService.listOperators().size() == orgOperatorSize + + // 1); + System.out.println( + "listOperators size:" + + chainGovernanceService.listOperators().size() + + ", orgOperatorSize: " + + orgOperatorSize); + + // only the committeeMember can freeze account + CryptoKeyPair cryptoKeyPair2 = + new CryptoSuite(client.getCryptoSuite().getCryptoTypeConfig()).createKeyPair(); + chainGovernanceService.grantOperator(cryptoKeyPair2.getAddress()); + // create the account + HelloWorld helloWorld = HelloWorld.deploy(client, cryptoKeyPair2); + TransactionReceipt receipt = helloWorld.set("test"); + Assert.assertTrue(receipt.getStatus().equals("0x0")); + // the operator freeze account failed + ChainGovernanceService chainGovernanceService1 = + new ChainGovernanceService(client, cryptoKeyPair1); + retCode = chainGovernanceService1.freezeAccount(cryptoKeyPair2.getAddress()); + Assert.assertTrue(retCode.equals(PrecompiledRetCode.CODE_NO_AUTHORIZED)); + + // the committeeMember freeze account succ + chainGovernanceService.freezeAccount(cryptoKeyPair2.getAddress()); + receipt = helloWorld.set("test_freeze"); + // account frozen: status is 31 + Assert.assertTrue(receipt.getStatus().equals("0x1f")); + + // unfreeze the account + chainGovernanceService.unfreezeAccount(cryptoKeyPair2.getAddress()); + receipt = helloWorld.set("test_unfreeze"); + Assert.assertTrue(receipt.getStatus().equals("0x0")); + // Assert.assertTrue("test_unfreeze".equals(helloWorld.get())); + + // revoke the committeeMember + chainGovernanceService.revokeCommitteeMember(cryptoKeyPair.getAddress()); + Assert.assertTrue(chainGovernanceService.listCommitteeMembers().size() == 0); + } catch (ContractException e) { + System.out.println("test8GovernanceService failed, error info:" + e.getMessage()); + } + } +} diff --git a/src/integration-test/java/org/fisco/bcos/sdk/transaction/decoder/EventDecodeTest.java b/src/integration-test/java/org/fisco/bcos/sdk/transaction/decoder/EventDecodeTest.java new file mode 100644 index 000000000..280efe612 --- /dev/null +++ b/src/integration-test/java/org/fisco/bcos/sdk/transaction/decoder/EventDecodeTest.java @@ -0,0 +1,73 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.decoder; + +import com.google.common.collect.Lists; +import java.util.List; +import java.util.Map; +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.abi.ABICodec; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.model.ConstantConfig; +import org.fisco.bcos.sdk.model.EventLog; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.transaction.manager.AssembleTransactionProcessor; +import org.fisco.bcos.sdk.transaction.manager.TransactionProcessorFactory; +import org.fisco.bcos.sdk.transaction.model.dto.TransactionResponse; +import org.junit.Assert; +import org.junit.Test; + +/** + * EventDecodeTest @Description: EventDecodeTest + * + * @author maojiayu + * @data Aug 28, 2020 10:50:53 PM + */ +public class EventDecodeTest { + + private static final String configFile = + "src/integration-test/resources/" + ConstantConfig.CONFIG_FILE_NAME; + private static final String abiFile = "src/integration-test/resources/abi/"; + private static final String binFile = "src/integration-test/resources/bin/"; + private final String abi = + "[{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"_addrDArray\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"_addr\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getUint256\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"v\",\"type\":\"uint256\"}],\"name\":\"incrementUint256\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"_bytesV\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"_s\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"getSArray\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"bytesArray\",\"type\":\"bytes1[]\"}],\"name\":\"setBytesMapping\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b\",\"type\":\"bytes\"}],\"name\":\"setBytes\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i\",\"type\":\"int256\"},{\"name\":\"a\",\"type\":\"address[]\"},{\"name\":\"s\",\"type\":\"string\"}],\"name\":\"setValues\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"b\",\"type\":\"bytes1\"}],\"name\":\"getByBytes\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes1[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"_intV\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"emptyArgs\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"i\",\"type\":\"int256\"},{\"name\":\"s\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"LogIncrement\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"s\",\"type\":\"string\"}],\"name\":\"LogInit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"i\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"a\",\"type\":\"address[]\"},{\"indexed\":false,\"name\":\"s\",\"type\":\"string\"}],\"name\":\"LogSetValues\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"o\",\"type\":\"bytes\"},{\"indexed\":false,\"name\":\"b\",\"type\":\"bytes\"}],\"name\":\"LogSetBytes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"o\",\"type\":\"uint256[2]\"},{\"indexed\":false,\"name\":\"n\",\"type\":\"uint256[2]\"}],\"name\":\"LogSetSArray\",\"type\":\"event\"}]"; + + @Test + public void testDecode() throws Exception { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + // System.out.println(cryptoInterface.getCryptoKeyPair().getAddress()); + AssembleTransactionProcessor manager = + TransactionProcessorFactory.createAssembleTransactionProcessor( + client, client.getCryptoSuite().createKeyPair(), abiFile, binFile); + ABICodec abiCodec = new ABICodec(client.getCryptoSuite()); + // deploy + List params = Lists.newArrayList(); + params.add(1); + params.add("test2"); + TransactionResponse response = manager.deployByContractLoader("ComplexSol", params); + if (!response.getTransactionReceipt().getStatus().equals("0x0")) { + System.out.println(response.getReturnMessage()); + return; + } + + TransactionReceipt.Logs log = response.getTransactionReceipt().getLogs().get(0); + EventLog eventLog = new EventLog(log.getData(), log.getTopics()); + List list = abiCodec.decodeEvent(abi, "LogInit", eventLog); + Assert.assertEquals("test2", list.get(1)); + Map> map = response.getEventResultMap(); + Assert.assertEquals("test2", map.get("LogInit").get(1)); + } +} 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 new file mode 100644 index 000000000..e384a77b9 --- /dev/null +++ b/src/integration-test/java/org/fisco/bcos/sdk/transaction/decoder/TransactionDecoderServiceTest.java @@ -0,0 +1,96 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.decoder; + +import com.google.common.collect.Lists; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.model.ConstantConfig; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.transaction.codec.decode.TransactionDecoderInterface; +import org.fisco.bcos.sdk.transaction.codec.decode.TransactionDecoderService; +import org.fisco.bcos.sdk.transaction.manager.AssembleTransactionProcessor; +import org.fisco.bcos.sdk.transaction.manager.TransactionProcessorFactory; +import org.fisco.bcos.sdk.transaction.model.dto.TransactionResponse; +import org.fisco.bcos.sdk.transaction.tools.ContractLoader; +import org.fisco.bcos.sdk.transaction.tools.JsonUtils; +import org.junit.Assert; +import org.junit.Test; + +/** + * TransactionDecoderServiceTest @Description: TransactionDecoderServiceTest + * + * @author maojiayu + * @data Sep 17, 2020 10:36:56 AM + */ +public class TransactionDecoderServiceTest { + private static final String configFile = + "src/integration-test/resources/" + ConstantConfig.CONFIG_FILE_NAME; + private static final String abiFile = "src/integration-test/resources/abi/"; + private static final String binFile = "src/integration-test/resources/bin/"; + private static final String contractName = "ComplexSol"; + + @Test + public void testDecode() throws Exception { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + TransactionDecoderInterface decoder = + new TransactionDecoderService(client.getCryptoSuite()); + ContractLoader contractLoader = new ContractLoader(abiFile, binFile); + String abi = contractLoader.getABIByContractName(contractName); + AssembleTransactionProcessor manager = + TransactionProcessorFactory.createAssembleTransactionProcessor( + client, client.getCryptoSuite().createKeyPair(), abiFile, binFile); + // deploy + List params = Lists.newArrayList(); + params.add(1); + params.add("test2"); + TransactionResponse response = manager.deployByContractLoader(contractName, params); + if (!response.getTransactionReceipt().getStatus().equals("0x0")) { + return; + } + String contractAddress = response.getContractAddress(); + + // increment + TransactionReceipt transactionReceipt = + manager.sendTransactionAndGetReceiptByContractLoader( + contractName, + contractAddress, + "incrementUint256", + Lists.newArrayList(BigInteger.valueOf(1))); + TransactionResponse transactionResponseWithoutValues = + decoder.decodeReceiptWithoutValues(abi, transactionReceipt); + System.out.println(JsonUtils.toJson(transactionResponseWithoutValues)); + TransactionResponse transactionResponseWithValues = + decoder.decodeReceiptWithValues(abi, "incrementUint256", transactionReceipt); + Assert.assertEquals("Success", transactionResponseWithValues.getReceiptMessages()); + Map> events = decoder.decodeEvents(abi, transactionReceipt.getLogs()); + Assert.assertEquals(1, events.size()); + // setBytes + List s = Lists.newArrayList("2".getBytes()); + List paramsSetBytes = new ArrayList(); + paramsSetBytes.add(s); + TransactionReceipt transactionReceipt2 = + manager.sendTransactionAndGetReceiptByContractLoader( + contractName, contractAddress, "setBytesMapping", paramsSetBytes); + // decode receipt + TransactionResponse transactionResponse2 = decoder.decodeReceiptStatus(transactionReceipt2); + Assert.assertEquals(22, transactionResponse2.getReturnCode()); + } +} 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 new file mode 100644 index 000000000..c94c2e8af --- /dev/null +++ b/src/integration-test/java/org/fisco/bcos/sdk/transaction/manager/AssembleTransactionProcessorTest.java @@ -0,0 +1,382 @@ +/* + * Copyright 2014-2020 [fisco-dev] + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + */ +package org.fisco.bcos.sdk.transaction.manager; + +import com.google.common.collect.Lists; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import org.apache.commons.collections4.ListUtils; +import org.apache.commons.lang3.StringUtils; +import org.bouncycastle.util.encoders.Base64; +import org.fisco.bcos.sdk.BcosSDK; +import org.fisco.bcos.sdk.abi.ABICodecException; +import org.fisco.bcos.sdk.client.Client; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.model.ConstantConfig; +import org.fisco.bcos.sdk.model.PrecompiledRetCode; +import org.fisco.bcos.sdk.model.TransactionReceipt; +import org.fisco.bcos.sdk.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.transaction.model.dto.CallResponse; +import org.fisco.bcos.sdk.transaction.model.dto.TransactionResponse; +import org.fisco.bcos.sdk.transaction.model.exception.TransactionBaseException; +import org.fisco.bcos.sdk.transaction.tools.JsonUtils; +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * TransactionProcessorTest @Description: TransactionProcessorTest + * + * @author maojiayu + * @data Aug 13, 2020 8:00:11 PM + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class AssembleTransactionProcessorTest { + private static final String configFile = + "src/integration-test/resources/" + ConstantConfig.CONFIG_FILE_NAME; + private static final String abiFile = "src/integration-test/resources/abi/"; + private static final String binFile = "src/integration-test/resources/bin/"; + private final String abi = + "[{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"_addrDArray\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"_addr\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getUint256\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"v\",\"type\":\"uint256\"}],\"name\":\"incrementUint256\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"_bytesV\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"_s\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"getSArray\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"bytesArray\",\"type\":\"bytes1[]\"}],\"name\":\"setBytesMapping\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b\",\"type\":\"bytes\"}],\"name\":\"setBytes\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i\",\"type\":\"int256\"},{\"name\":\"a\",\"type\":\"address[]\"},{\"name\":\"s\",\"type\":\"string\"}],\"name\":\"setValues\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"b\",\"type\":\"bytes1\"}],\"name\":\"getByBytes\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes1[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"_intV\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"emptyArgs\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"i\",\"type\":\"int256\"},{\"name\":\"s\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"LogIncrement\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"s\",\"type\":\"string\"}],\"name\":\"LogInit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"i\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"a\",\"type\":\"address[]\"},{\"indexed\":false,\"name\":\"s\",\"type\":\"string\"}],\"name\":\"LogSetValues\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"o\",\"type\":\"bytes\"},{\"indexed\":false,\"name\":\"b\",\"type\":\"bytes\"}],\"name\":\"LogSetBytes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"o\",\"type\":\"uint256[2]\"},{\"indexed\":false,\"name\":\"n\",\"type\":\"uint256[2]\"}],\"name\":\"LogSetSArray\",\"type\":\"event\"}]"; + + @Test + public void test1HelloWorld() throws Exception { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + // System.out.println(cryptoInterface.getCryptoKeyPair().getAddress()); + CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair(); + AssembleTransactionProcessor transactionProcessor = + TransactionProcessorFactory.createAssembleTransactionProcessor( + client, cryptoKeyPair, abiFile, binFile); + // deploy + TransactionResponse response = + transactionProcessor.deployByContractLoader("HelloWorld", new ArrayList<>()); + // System.out.println(JsonUtils.toJson(response)); + if (!response.getTransactionReceipt().getStatus().equals("0x0")) { + return; + } + Assert.assertTrue(response.getReturnCode() == 0); + Assert.assertEquals("0x0", response.getTransactionReceipt().getStatus()); + String helloWorldAddrss = response.getContractAddress(); + Assert.assertTrue( + StringUtils.isNotBlank(response.getContractAddress()) + && !StringUtils.equalsIgnoreCase( + helloWorldAddrss, + "0x0000000000000000000000000000000000000000000000000000000000000000")); + // call + CallResponse callResponse1 = + transactionProcessor.sendCallByContractLoader( + "HelloWorld", helloWorldAddrss, "name", new ArrayList<>()); + // System.out.println(JsonUtils.toJson(callResponse1)); + List l = JsonUtils.fromJsonList(callResponse1.getValues(), Object.class); + Assert.assertEquals(l.size(), 1); + Assert.assertEquals(l.get(0), "Hello, World!"); + // send transaction + List params = new ArrayList<>(); + params.add("test"); + TransactionReceipt tr = + transactionProcessor.sendTransactionAndGetReceiptByContractLoader( + "HelloWorld", helloWorldAddrss, "set", params); + Assert.assertEquals("0x0", tr.getStatus()); + // System.out.println(JsonUtils.toJson(tr)); + TransactionResponse res = + transactionProcessor.sendTransactionAndGetResponseByContractLoader( + "HelloWorld", helloWorldAddrss, "set", params); + Assert.assertEquals("0x0", res.getTransactionReceipt().getStatus()); + // System.out.println(JsonUtils.toJson(res)); + + // call + CallResponse callResponse2 = + transactionProcessor.sendCallByContractLoader( + "HelloWorld", helloWorldAddrss, "name", new ArrayList<>()); + // System.out.println(JsonUtils.toJson(callResponse2)); + l = JsonUtils.fromJsonList(callResponse2.getValues(), Object.class); + Assert.assertEquals(l.size(), 1); + Assert.assertEquals(l.get(0), "test"); + } + + @Test + public void test2ComplexDeploy() throws Exception { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + // System.out.println(cryptoInterface.getCryptoKeyPair().getAddress()); + CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair(); + 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); + // System.out.println(JsonUtils.toJson(response)); + if (!response.getTransactionReceipt().getStatus().equals("0x0")) { + System.out.println(response.getReturnMessage()); + return; + } + Assert.assertTrue(response.getReturnCode() == 0); + Assert.assertEquals("0x0", response.getTransactionReceipt().getStatus()); + String contractAddress = response.getContractAddress(); + Assert.assertTrue( + StringUtils.isNotBlank(response.getContractAddress()) + && !StringUtils.equalsIgnoreCase( + contractAddress, + "0x0000000000000000000000000000000000000000000000000000000000000000")); + // System.out.println(JsonUtils.toJson(response)); + Map> map = response.getEventResultMap(); + Assert.assertEquals("test2", map.get("LogInit").get(1)); + } + + @Test + public void test3ComplexQuery() throws Exception { + try { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + // System.out.println(cryptoInterface.getCryptoKeyPair().getAddress()); + CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair(); + 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; + } + String contractAddress = response.getContractAddress(); + // query i and s + CallResponse callResponse1 = + transactionProcessor.sendCallByContractLoader( + "ComplexSol", contractAddress, "_intV", new ArrayList<>()); + // System.out.println(JsonUtils.toJson(callResponse1)); + // System.out.println("callResponse1 : " + callResponse1.getReturnMessage()); + if (callResponse1.getReturnCode() == PrecompiledRetCode.CODE_SUCCESS.getCode()) { + List entities = + JsonUtils.fromJsonList(callResponse1.getValues(), Object.class); + Assert.assertEquals(entities.size(), 1); + Assert.assertEquals(entities.get(0), 1); + } + CallResponse callResponse2 = + transactionProcessor.sendCallByContractLoader( + "ComplexSol", contractAddress, "_s", new ArrayList<>()); + // System.out.println("callResponse2 : " + callResponse2.getReturnMessage()); + if (callResponse2.getReturnCode() == PrecompiledRetCode.CODE_SUCCESS.getCode()) { + // System.out.println(JsonUtils.toJson(callResponse2)); + List entities2 = + JsonUtils.fromJsonList(callResponse2.getValues(), Object.class); + Assert.assertEquals(entities2.size(), 1); + Assert.assertEquals(entities2.get(0), "test2"); + } + } catch (TransactionBaseException e) { + System.out.println("test3ComplexQuery exception, RetCode: " + e.getRetCode()); + } + } + + @Test + public void test4ComplexEmptyTx() throws Exception { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + // System.out.println(cryptoInterface.getCryptoKeyPair().getAddress()); + CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair(); + 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; + } + String contractAddress = response.getContractAddress(); + // send empty tx + TransactionReceipt tr = + transactionProcessor.sendTransactionAndGetReceiptByContractLoader( + "ComplexSol", contractAddress, "emptyArgs", ListUtils.emptyIfNull(null)); + Assert.assertEquals("0x0", tr.getStatus()); + } + + @Test + public void test5ComplexIncrement() throws Exception { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + // System.out.println(cryptoInterface.getCryptoKeyPair().getAddress()); + CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair(); + 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; + } + String contractAddress = response.getContractAddress(); + // increment v + transactionProcessor.sendTransactionAsync( + contractAddress, + abi, + "incrementUint256", + Lists.newArrayList(BigInteger.valueOf(10)), + new TransactionCallback() { + @Override + public void onResponse(TransactionReceipt receipt) { + Assert.assertEquals("0x0", receipt.getStatus()); + // getV + CallResponse callResponse3; + try { + callResponse3 = + transactionProcessor.sendCall( + cryptoKeyPair.getAddress(), + contractAddress, + abi, + "getUint256", + Lists.newArrayList()); + // System.out.println(JsonUtils.toJson(callResponse3)); + Assert.assertEquals("Success", callResponse3.getReturnMessage()); + } catch (TransactionBaseException | ABICodecException e) { + System.out.println(e.getMessage()); + } + } + }); + } + + @Test + public void test6ComplexSetValues() throws Exception { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + // System.out.println(cryptoInterface.getCryptoKeyPair().getAddress()); + CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair(); + 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; + } + String contractAddress = response.getContractAddress(); + // set values + List paramsSetValues = Lists.newArrayList(20); + String[] o = {"0x1", "0x2", "0x3"}; + List a = Arrays.asList(o); + paramsSetValues.add(a); + 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(2)); + } + + @Test + public void test7ComplexSetBytes() throws Exception { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + // System.out.println(cryptoInterface.getCryptoKeyPair().getAddress()); + CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair(); + 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; + } + String contractAddress = response.getContractAddress(); + // setBytes + List paramsSetBytes = + Lists.newArrayList(Base64.toBase64String("set bytes test".getBytes())); + TransactionResponse transactionResponse3 = + transactionProcessor.sendTransactionWithStringParamsAndGetResponse( + contractAddress, abi, "setBytes", paramsSetBytes); + // System.out.println(JsonUtils.toJson(transactionResponse3)); + Assert.assertEquals(transactionResponse3.getValuesList().size(), 1); + Assert.assertEquals(transactionResponse3.getValuesList().get(0), "set bytes test"); + + Map> eventsMap3 = transactionResponse3.getEventResultMap(); + // System.out.println(JsonUtils.toJson(eventsMap3)); + Assert.assertEquals(1, eventsMap3.size()); + Assert.assertEquals("set bytes test", eventsMap3.get("LogSetBytes").get(1)); + + // getBytes + CallResponse callResponse4 = + transactionProcessor.sendCall( + cryptoKeyPair.getAddress(), + contractAddress, + abi, + "_bytesV", + Lists.newArrayList()); + Assert.assertEquals(0, callResponse4.getReturnCode()); + List resultEntityList4 = + JsonUtils.fromJsonList(callResponse4.getValues(), Object.class); + Assert.assertEquals("set bytes test", resultEntityList4.get(0)); + } + + @Test + public void test8ComplexSetBytesFuture() throws Exception { + BcosSDK sdk = BcosSDK.build(configFile); + Client client = sdk.getClient(Integer.valueOf(1)); + // System.out.println(cryptoInterface.getCryptoKeyPair().getAddress()); + CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair(); + 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; + } + String contractAddress = response.getContractAddress(); + List paramsSetBytes = Lists.newArrayList("2".getBytes()); + String data = transactionProcessor.encodeFunction(abi, "setBytes", paramsSetBytes); + String signedData = + transactionProcessor.createSignedTransaction(contractAddress, data, cryptoKeyPair); + CompletableFuture future = + transactionProcessor.sendTransactionAsync(signedData); + future.thenAccept( + r -> { + Assert.assertEquals("0x0", response.getTransactionReceipt().getStatus()); + }); + } +} diff --git a/src/test/resources/amop/config-publisher-for-test.toml b/src/test/resources/amop/config-publisher-for-test.toml new file mode 100644 index 000000000..ceb34741a --- /dev/null +++ b/src/test/resources/amop/config-publisher-for-test.toml @@ -0,0 +1,44 @@ +# This is a config file for amop test + +[cryptoMaterial] +certPath = "conf" +# CA cert file path +# caCert = "conf/ca.crt" +# SSL cert file path +# sslCert = "conf/sdk.crt" +# SSL key file path +# sslKey = "conf/sdk.key" +# enSslCert = "conf/gm/gmensdk.crt" +# enSslKey = "conf/gm/gmensdk.key" + +[network] +# The peer list to connect +peers=["127.0.0.1:20200", "127.0.0.1:20201"] + +# Configure a "need verify AMOP topic" as a topic message sender. +[[amop]] +topicName = "privTopic" +# Public keys of the nodes that you want to send AMOP message of this topic to. +publicKeys = [ "conf/amop/consumer_public_key_1.pem"] + + +[account] +# The directory where the account private key file is placed in +keyStoreDir = "account" +# The account file path(Default load account from keyStoreDir directory when accountFilePath is not configured) +# accountFilePath = "" +# The storage format of the account, support pem and p12, default is pem +accountFileFormat = "pem" +# The address of the account used to send transactions +# When it's empty, use a randomly generated account to send transactions, +# and the randomly generated account information is stored in tmp sub-directory of keyStoreDir +# accountAddress = "" +# The password used to load the account private key file +# password = "" + +[threadPool] +# The size of the thread pool used to process the callback of the channel +channelProcessorThreadSize = "16" +# The size of the thread pool used to process the transaction receipt notification +receiptProcessorThreadSize = "16" + diff --git a/src/test/resources/amop/config-subscriber-for-test.toml b/src/test/resources/amop/config-subscriber-for-test.toml new file mode 100644 index 000000000..1ffd63fdd --- /dev/null +++ b/src/test/resources/amop/config-subscriber-for-test.toml @@ -0,0 +1,46 @@ +# This is a config file for amop test + +[cryptoMaterial] +certPath = "conf" +# CA cert file path +# caCert = "conf/ca.crt" +# SSL cert file path +# sslCert = "conf/sdk.crt" +# SSL key file path +# sslKey = "conf/sdk.key" +# enSslCert = "conf/gm/gmensdk.crt" +# enSslKey = "conf/gm/gmensdk.key" + +[network] +# The peer list to connect +peers=["127.0.0.1:20202", "127.0.0.1:20203"] + +# Configure a private topic as a topic message sender. +[[amop]] +topicName = "privTopic" +# Your private key that used to subscriber verification. +privateKey = "conf/amop/consumer_private_key.p12" +password = "123456" + + +[account] +# The directory where the account private key file is placed in +keyStoreDir = "account" +# The account file path(Default load account from keyStoreDir directory when accountFilePath is not configured) +# accountFilePath = "" +# The storage format of the account, support pem and p12, default is pem +accountFileFormat = "pem" +# The address of the account used to send transactions +# When it's empty, use a randomly generated account to send transactions, +# and the randomly generated account information is stored in tmp sub-directory of keyStoreDir +# accountAddress = "" +# The password used to load the account private key file +# password = "" + + +[threadPool] +# The size of the thread pool used to process the callback of the channel +channelProcessorThreadSize = "16" +# The size of the thread pool used to process the transaction receipt notification +receiptProcessorThreadSize = "16" + diff --git a/src/test/resources/amop/consumer_private_key.p12 b/src/test/resources/amop/consumer_private_key.p12 new file mode 100644 index 000000000..09388e9a7 Binary files /dev/null and b/src/test/resources/amop/consumer_private_key.p12 differ diff --git a/src/test/resources/amop/consumer_public_key_1.pem b/src/test/resources/amop/consumer_public_key_1.pem new file mode 100644 index 000000000..0b6ef051e --- /dev/null +++ b/src/test/resources/amop/consumer_public_key_1.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE17ngD1bT95MFNZ+i19sWYCHnMIa9zS56 +KNbtJzReHy3ez4XbdDjoRX/UdO+cTOuJq7fV+mCiLykC7CbcpSrV5Q== +-----END PUBLIC KEY----- diff --git a/src/test/resources/applicationContext-sample.xml b/src/test/resources/applicationContext-sample.xml new file mode 100644 index 000000000..a4684aec2 --- /dev/null +++ b/src/test/resources/applicationContext-sample.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + 127.0.0.1:20200 + 127.0.0.1:20201 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/config-example.toml b/src/test/resources/config-example.toml new file mode 100644 index 000000000..037bceb5f --- /dev/null +++ b/src/test/resources/config-example.toml @@ -0,0 +1,54 @@ +[cryptoMaterial] + +certPath = "conf" # The certification path + +# The following configurations take the certPath by default if commented +# caCert = "conf/ca.crt" # CA cert file path + # If connect to the GM node, default CA cert path is ${certPath}/gm/gmca.crt + +# sslCert = "conf/sdk.crt" # SSL cert file path + # If connect to the GM node, the default SDK cert path is ${certPath}/gm/gmsdk.crt + +# sslKey = "conf/sdk.key" # SSL key file path + # If connect to the GM node, the default SDK privateKey path is ${certPath}/gm/gmsdk.key + +# enSslCert = "conf/gm/gmensdk.crt" # GM encryption cert file path + # default load the GM SSL encryption cert from ${certPath}/gm/gmensdk.crt + +# enSslKey = "conf/gm/gmensdk.key" # GM ssl cert file path + # default load the GM SSL encryption privateKey from ${certPath}/gm/gmensdk.key + +[network] +peers=["127.0.0.1:20200", "127.0.0.1:20201"] # The peer list to connect + +# Configure a private topic as a topic message sender. +# [[amop]] +# topicName = "PrivateTopic1" +# publicKeys = [ "conf/amop/consumer_public_key_1.pem" ] # Public keys of the nodes that you want to send AMOP message of this topic to. + +# Configure a private topic as a topic subscriber. +# [[amop]] +# topicName = "PrivateTopic2" +# privateKey = "conf/amop/consumer_private_key.p12" # Your private key that used to subscriber verification. +# password = "123456" + +[account] +keyStoreDir = "account" # The directory to load/store the account file, default is "account" +# accountFilePath = "" # The account file path (default load from the path specified by the keyStoreDir) +accountFileFormat = "pem" # The storage format of account file (Default is "pem", "p12" as an option) + +# accountAddress = "" # The transactions sending account address + # Default is a randomly generated account + # The randomly generated account is stored in the path specified by the keyStoreDir + +# password = "" # The password used to load the account file + +[threadPool] +# channelProcessorThreadSize = "16" # The size of the thread pool to process channel callback + # Default is the number of cpu cores + +# receiptProcessorThreadSize = "16" # The size of the thread pool to process transaction receipt notification + # Default is the number of cpu cores + +maxBlockingQueueSize = "102400" # The max blocking queue size of the thread pool + diff --git a/src/test/resources/config/ca.crt b/src/test/resources/config/ca.crt new file mode 100644 index 000000000..d02981796 --- /dev/null +++ b/src/test/resources/config/ca.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSzCCAjOgAwIBAgIUKsk+1UNeCOqmiha4AtNbK2HRtWUwDQYJKoZIhvcNAQEL +BQAwNTEOMAwGA1UEAwwFY2hhaW4xEzARBgNVBAoMCmZpc2NvLWJjb3MxDjAMBgNV +BAsMBWNoYWluMB4XDTIwMDcyMDA3MzY0NVoXDTMwMDcxODA3MzY0NVowNTEOMAwG +A1UEAwwFY2hhaW4xEzARBgNVBAoMCmZpc2NvLWJjb3MxDjAMBgNVBAsMBWNoYWlu +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo5zrDCq69OAtMMrHv9yb +fcV95GzEAXNxhvqR2rVcP9M5OMrhQ8TXz39GMpTHHYYy/DKKwpYykAR752FTEFbo +ky4JNMxGvO1SV3NrwY/pQyeuCyRo2Iry+sYPtxBAMg/fCRdMzSjMrZXWmnOYx2uW +4IVVtVZBJ5WFCp3R6ZTz505hZzXyxTr/5jIztmtIi29I/q88bFFQtmayj8J+qZZu +BiN5qSs9xG7GbmfxeQEFzftThK5rQ5KUBUe56jAeJbNInB1kFiIyB119wsY+QTnP +I7OCm3vQ58RMPUXk9RuT7WBE2/ORRWGu5EBCI0gOK4bNzIcfUeF+i2Yo0N0+MASN +zwIDAQABo1MwUTAdBgNVHQ4EFgQU1pXn7uKZL73JAgYhN57V8w3juGUwHwYDVR0j +BBgwFoAU1pXn7uKZL73JAgYhN57V8w3juGUwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQsFAAOCAQEAicxdWl3msjRDI/JCoL3EMRtPGa7haQbBsBPl+iS5gCXm +QWPxPSbt8WCZWYuAg786XDlrblA6gMEKwFpi1V4kVwOWYdrom2a+ljdc8OO6de2K +8ZKKYzj/LEIwPkdp0xHvo1St3vT/9qHKiM6OtpQxlbrPsHZNviJh1vuYqLxcoU2N +F6cdDv8DfVF0Xh3Q/1zjLOfS9ayuCIPHoaIm4Px9DjrwU6KG1BwJCdO/do5sopYS +PPL3IekgpkMKFlCm6jKYLEPuj3hSMkZipnYlrfe231pwOjo1aDkH5ud5rvUx6uUy ++6hms09chOK+Bx5LMclyNd/MX7YCmwPnxllkQvT3AA== +-----END CERTIFICATE----- diff --git a/src/test/resources/config/sdk.crt b/src/test/resources/config/sdk.crt new file mode 100644 index 000000000..267207fc4 --- /dev/null +++ b/src/test/resources/config/sdk.crt @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIICQjCCASqgAwIBAgIURDhyND2WYBEQPWE+TFUHbI3T+14wDQYJKoZIhvcNAQEL +BQAwNzEPMA0GA1UEAwwGYWdlbmN5MRMwEQYDVQQKDApmaXNjby1iY29zMQ8wDQYD +VQQLDAZhZ2VuY3kwHhcNMjAwNzIwMDczNjQ2WhcNMzAwNzE4MDczNjQ2WjAxMQww +CgYDVQQDDANzZGsxEzARBgNVBAoMCmZpc2NvLWJjb3MxDDAKBgNVBAsMA3NkazBW +MBAGByqGSM49AgEGBSuBBAAKA0IABAakRi6hjdXt3Eh3XNdS0IxMqOIQMYPk1ixf +DhR/KM6ODDbXp+PNelp7J/2zxjW9gv8ll25dG/Wzg4Pl8EUJVj6jGjAYMAkGA1Ud +EwQCMAAwCwYDVR0PBAQDAgXgMA0GCSqGSIb3DQEBCwUAA4IBAQAmByQEn4c+OP2v +iJe3Z7RW8l8+InsXWBebEbiAhOImGAQ2XfLAmR+lhVQ7A7iInnKmEBK7oNn9vgcG +NiXarKAHsEE6LV7uqAZYVX7+Xp8u/DD7utE3+tw++k0ysxzxLlsW47yhU04nw2wf +IJoWsEGvkpnMDo2soLV3RPSWzBKUudSCtYdH9xP5j1umBElnPfTx0Jw2CQZS21cK +7NPI23aU7CDRsKO4MNdrhddBzDyWlOtoGkiFrBxBL26Wk2BPkc/v9ip/g7Tw+1Og +awky+4T4RGPIxmsrwVzrqrbl/efMMcmeG4CrbiWuE/9nHtLbM+ZVnPXTYB5U2Wot +NNi033ff +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDCjCCAfKgAwIBAgIUBnXphpxPBgeogKUldLgxFq1rbe8wDQYJKoZIhvcNAQEL +BQAwNTEOMAwGA1UEAwwFY2hhaW4xEzARBgNVBAoMCmZpc2NvLWJjb3MxDjAMBgNV +BAsMBWNoYWluMB4XDTIwMDcyMDA3MzY0NVoXDTMwMDcxODA3MzY0NVowNzEPMA0G +A1UEAwwGYWdlbmN5MRMwEQYDVQQKDApmaXNjby1iY29zMQ8wDQYDVQQLDAZhZ2Vu +Y3kwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDcarpuKChCkoQAJGFT +30L9WbFmCnS9szy1FfnzoPs7h5qJBuyTOFGgtnQOfuUd1g7ZDoAtf5tfAxhXlCyl +YlE8epuDmRJQBZAC2NSdC6IaBVNjgX7QotJ8FW5ylFmlIt8OkOjB+/k7jL7yTjIc +R+mTUr3Qn1DG9kQ9bg+XjyoqDQ5FVx2TywwmzuptRnUBXgoVH/69AQKLpC/LQE61 +dnVbnobrq2u6inwX3kfAoWm41rmn2gksQpSHqQFgTIVqaCpIrXq/gmNWwNZT0PqY +yqiOGe0+V5Nz7Jfj96vTRsLjVnzrp8XmP035nGA4tZiw0B+HfgN1WPtm7cqeP0Vj +XTgZAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAF/R +xpld6ETAHPowbFxdGtAL0QZ/lPn4trFNAZrKveM1TlZef1AxrG1wzLrVqsBNANXv +Nhsxk71yGDc8RAhiOIAosjQI7EV8MoDDVl7TUPmCVN0xAe8wrGikca+9YtO0PgYQ +9vmemam/rnRr35ZJJxYwEOGqGj6FP/XsNt68ysdBFmOYtXq5EA4KVXfYYStLrPqJ +qJsqvtFCtURfWf1CJWrLsk+iVGl30a0NlDEimwOQZ8nAMSvwdoM3cyi815N+rRy5 +7idf7sbtuzKhI6vbOHFDtuvTVW7vjFvDnTpGI4+wiVBDSpxNbKmm+PbcP+bW4C2s +v2BsJbum3UlIGRBP9uA= +-----END CERTIFICATE----- diff --git a/src/test/resources/config/sdk.key b/src/test/resources/config/sdk.key new file mode 100644 index 000000000..be516180a --- /dev/null +++ b/src/test/resources/config/sdk.key @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgngMq1bsP9e0JLYTO7t+L +CKEHoEKP+6lcVU8Ml00miIWhRANCAAQGpEYuoY3V7dxId1zXUtCMTKjiEDGD5NYs +Xw4UfyjOjgw216fjzXpaeyf9s8Y1vYL/JZduXRv1s4OD5fBFCVY+ +-----END PRIVATE KEY----- diff --git a/src/test/resources/contracts/ComplexSol.sol b/src/test/resources/contracts/ComplexSol.sol new file mode 100644 index 000000000..f864e8df9 --- /dev/null +++ b/src/test/resources/contracts/ComplexSol.sol @@ -0,0 +1,70 @@ +pragma solidity ^0.4.25; +pragma experimental ABIEncoderV2; + +contract ComplexSol{ + + uint256 private _uint256V; + int public _intV; + address public _addr; + string public _s; + bytes public _bytesV; + uint256[2] _uint8SArray; + address[] public _addrDArray; + mapping(bytes => bytes[]) _bytesMapping; + + event LogIncrement(address sender, uint256 a); + event LogInit(address sender, string s); + event LogSetValues(int i, address[] a, string s); + event LogSetBytes(bytes o, bytes b); + event LogSetSArray(uint256[2] o, uint256[2] n); + + constructor(int i, string s) public { + _addr = msg.sender; + _intV = i; + _s = s; + emit LogInit(msg.sender, s); + } + + function emptyArgs() public {} + + + function incrementUint256(uint256 v) public returns(uint256){ + _uint256V = v + 1 ; + emit LogIncrement(msg.sender, v); + return _uint256V; + } + + function getUint256() public view returns(uint256){ + return _uint256V; + } + + function setValues(int i, address[] a, string s) public { + _intV = i; + _addrDArray = a; + _s = s; + emit LogSetValues(i, a, s); + } + + + function setBytes(bytes b) public returns (bytes) { + emit LogSetBytes(_bytesV, b); + _bytesV = b; + return b; + } + + function setBytesMapping(bytes[] bytesArray) public returns (bool) { + require(bytesArray.length>1, "Bytes array is less than 2"); + _bytesMapping[bytesArray[0]] = bytesArray; + return true; + } + + function getByBytes(bytes b) public view returns (bytes[]) { + return _bytesMapping[b]; + } + + function getSArray() public returns (uint256[2]){ + uint256[2] memory arr = [uint256(1),2]; + emit LogSetSArray(arr, _uint8SArray); + return arr; + } +} diff --git a/src/test/resources/contracts/HelloWorld.sol b/src/test/resources/contracts/HelloWorld.sol new file mode 100644 index 000000000..28b00ba49 --- /dev/null +++ b/src/test/resources/contracts/HelloWorld.sol @@ -0,0 +1,12 @@ +pragma solidity ^0.4.25; + +contract HelloWorld{ + string public name; + constructor() public{ + name = "Hello, World!"; + } + + function set(string n) public{ + name = n; + } +} \ No newline at end of file diff --git a/src/test/resources/ecdsa/abi/ComplexSol.abi b/src/test/resources/ecdsa/abi/ComplexSol.abi new file mode 100644 index 000000000..5cc9376b1 --- /dev/null +++ b/src/test/resources/ecdsa/abi/ComplexSol.abi @@ -0,0 +1 @@ +[{"constant":true,"inputs":[{"name":"b","type":"bytes"}],"name":"getByBytes","outputs":[{"name":"","type":"bytes[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"bytesArray","type":"bytes[]"}],"name":"setBytesMapping","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"_addrDArray","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_addr","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getUint256","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"v","type":"uint256"}],"name":"incrementUint256","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"_bytesV","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_s","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"getSArray","outputs":[{"name":"","type":"uint256[2]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"b","type":"bytes"}],"name":"setBytes","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"i","type":"int256"},{"name":"a","type":"address[]"},{"name":"s","type":"string"}],"name":"setValues","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"_intV","outputs":[{"name":"","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"emptyArgs","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"i","type":"int256"},{"name":"s","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"a","type":"uint256"}],"name":"LogIncrement","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"s","type":"string"}],"name":"LogInit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"int256"},{"indexed":false,"name":"a","type":"address[]"},{"indexed":false,"name":"s","type":"string"}],"name":"LogSetValues","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"o","type":"bytes"},{"indexed":false,"name":"b","type":"bytes"}],"name":"LogSetBytes","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"o","type":"uint256[2]"},{"indexed":false,"name":"n","type":"uint256[2]"}],"name":"LogSetSArray","type":"event"}] \ No newline at end of file diff --git a/src/test/resources/ecdsa/abi/HelloWorld.abi b/src/test/resources/ecdsa/abi/HelloWorld.abi new file mode 100644 index 000000000..68f2ce200 --- /dev/null +++ b/src/test/resources/ecdsa/abi/HelloWorld.abi @@ -0,0 +1 @@ +[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"n","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}] \ No newline at end of file diff --git a/src/test/resources/ecdsa/bin/ComplexSol.bin b/src/test/resources/ecdsa/bin/ComplexSol.bin new file mode 100644 index 000000000..0f4f38b96 --- /dev/null +++ b/src/test/resources/ecdsa/bin/ComplexSol.bin @@ -0,0 +1 @@ +60806040523480156200001157600080fd5b5060405162001b3a38038062001b3a8339810180604052620000379190810190620001fe565b33600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600181905550806003908051906020019062000097929190620000db565b507f96cbce3c2f7574181c59fe1f42ee3733c5ebb6ff910ad138ec2877995da00b883382604051620000cb929190620002a5565b60405180910390a15050620003b0565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200011e57805160ff19168380011785556200014f565b828001600101855582156200014f579182015b828111156200014e57825182559160200191906001019062000131565b5b5090506200015e919062000162565b5090565b6200018791905b808211156200018357600081600090555060010162000169565b5090565b90565b60006200019882516200035f565b905092915050565b600082601f8301121515620001b457600080fd5b8151620001cb620001c58262000307565b620002d9565b91508082526020830160208301858383011115620001e857600080fd5b620001f583828462000369565b50505092915050565b600080604083850312156200021257600080fd5b600062000222858286016200018a565b925050602083015167ffffffffffffffff8111156200024057600080fd5b6200024e85828601620001a0565b9150509250929050565b62000263816200033f565b82525050565b6000620002768262000334565b8084526200028c81602086016020860162000369565b62000297816200039f565b602085010191505092915050565b6000604082019050620002bc600083018562000258565b8181036020830152620002d0818462000269565b90509392505050565b6000604051905081810181811067ffffffffffffffff82111715620002fd57600080fd5b8060405250919050565b600067ffffffffffffffff8211156200031f57600080fd5b601f19601f8301169050602081019050919050565b600081519050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60005b83811015620003895780820151818401526020810190506200036c565b8381111562000399576000848401525b50505050565b6000601f19601f8301169050919050565b61177a80620003c06000396000f3006080604052600436106100c5576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633d3b51e2146100ca578063479ba9a3146101075780635c803d921461014457806362ab1a771461018157806368895979146101ac5780637c1bf3c5146101d7578063806a0b7214610214578063ae638e061461023f578063bb39513a1461026a578063da359dc814610295578063df94431c146102d2578063f5a12f98146102fb578063f9ce95fe14610326575b600080fd5b3480156100d657600080fd5b506100f160048036036100ec9190810190610e96565b61033d565b6040516100fe91906112f3565b60405180910390f35b34801561011357600080fd5b5061012e60048036036101299190810190610e55565b610491565b60405161013b9190611359565b60405180910390f35b34801561015057600080fd5b5061016b60048036036101669190810190610f56565b61057a565b60405161017891906112af565b60405180910390f35b34801561018d57600080fd5b506101966105b8565b6040516101a391906112af565b60405180910390f35b3480156101b857600080fd5b506101c16105de565b6040516101ce9190611491565b60405180910390f35b3480156101e357600080fd5b506101fe60048036036101f99190810190610f56565b6105e7565b60405161020b9190611491565b60405180910390f35b34801561022057600080fd5b50610229610636565b6040516102369190611374565b60405180910390f35b34801561024b57600080fd5b506102546106d4565b604051610261919061144f565b60405180910390f35b34801561027657600080fd5b5061027f610772565b60405161028c9190611315565b60405180910390f35b3480156102a157600080fd5b506102bc60048036036102b79190810190610e96565b6107dc565b6040516102c99190611396565b60405180910390f35b3480156102de57600080fd5b506102f960048036036102f49190810190610ed7565b610837565b005b34801561030757600080fd5b506103106108ac565b60405161031d91906113ef565b60405180910390f35b34801561033257600080fd5b5061033b6108b2565b005b60606008826040518082805190602001908083835b6020831015156103775780518252602082019150602081019050602083039250610352565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020805480602002602001604051908101604052809291908181526020016000905b82821015610486578382906000526020600020018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156104725780601f1061044757610100808354040283529160200191610472565b820191906000526020600020905b81548152906001019060200180831161045557829003601f168201915b5050505050815260200190600101906103ca565b505050509050919050565b6000600182511115156104d9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104d090611471565b60405180910390fd5b8160088360008151811015156104eb57fe5b906020019060200201516040518082805190602001908083835b60208310151561052a5780518252602082019150602081019050602083039250610505565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902090805190602001906105709291906108b4565b5060019050919050565b60078181548110151561058957fe5b906000526020600020016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054905090565b6000600182016000819055507faca9a02cfe513f3f88c54a860469369849c8fa0a2119a8d1f3f75c67ac0c954733836040516106249291906112ca565b60405180910390a16000549050919050565b60048054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156106cc5780601f106106a1576101008083540402835291602001916106cc565b820191906000526020600020905b8154815290600101906020018083116106af57829003601f168201915b505050505081565b60038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561076a5780601f1061073f5761010080835404028352916020019161076a565b820191906000526020600020905b81548152906001019060200180831161074d57829003601f168201915b505050505081565b61077a610914565b610782610914565b604080519081016040528060018152602001600281525090507f84712d7e2b783e5ec8a0f0f50d302da0b15d078ac64968245cfc91e5b7481c988160056040516107cd929190611330565b60405180910390a18091505090565b60607fa0f5dc8c800a837e0a7c88af15df4a194b8cf2b9a1e0d4e1a28013471713ae136004836040516108109291906113b8565b60405180910390a1816004908051906020019061082e929190610936565b50819050919050565b8260018190555081600790805190602001906108549291906109b6565b50806003908051906020019061086b929190610a40565b507f487b33fb5d5ff951b71eea40323f9d8dac61f7aefb4bc9c23399aa9cd900ba2683838360405161089f9392919061140a565b60405180910390a1505050565b60015481565b565b828054828255906000526020600020908101928215610903579160200282015b828111156109025782518290805190602001906108f2929190610ac0565b50916020019190600101906108d4565b5b5090506109109190610b40565b5090565b6040805190810160405280600290602082028038833980820191505090505090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061097757805160ff19168380011785556109a5565b828001600101855582156109a5579182015b828111156109a4578251825591602001919060010190610989565b5b5090506109b29190610b6c565b5090565b828054828255906000526020600020908101928215610a2f579160200282015b82811115610a2e5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550916020019190600101906109d6565b5b509050610a3c9190610b91565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10610a8157805160ff1916838001178555610aaf565b82800160010185558215610aaf579182015b82811115610aae578251825591602001919060010190610a93565b5b509050610abc9190610b6c565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10610b0157805160ff1916838001178555610b2f565b82800160010185558215610b2f579182015b82811115610b2e578251825591602001919060010190610b13565b5b509050610b3c9190610b6c565b5090565b610b6991905b80821115610b655760008181610b5c9190610bd4565b50600101610b46565b5090565b90565b610b8e91905b80821115610b8a576000816000905550600101610b72565b5090565b90565b610bd191905b80821115610bcd57600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600101610b97565b5090565b90565b50805460018160011615610100020316600290046000825580601f10610bfa5750610c19565b601f016020900490600052602060002090810190610c189190610b6c565b5b50565b6000610c2882356116b9565b905092915050565b600082601f8301121515610c4357600080fd5b8135610c56610c51826114d9565b6114ac565b91508181835260208401935060208101905083856020840282011115610c7b57600080fd5b60005b83811015610cab5781610c918882610c1c565b845260208401935060208301925050600181019050610c7e565b5050505092915050565b600082601f8301121515610cc857600080fd5b8135610cdb610cd682611501565b6114ac565b9150818183526020840193506020810190508360005b83811015610d215781358601610d078882610d2b565b845260208401935060208301925050600181019050610cf1565b5050505092915050565b600082601f8301121515610d3e57600080fd5b8135610d51610d4c82611529565b6114ac565b91508082526020830160208301858383011115610d6d57600080fd5b610d788382846116ed565b50505092915050565b600082601f8301121515610d9457600080fd5b8135610da7610da282611555565b6114ac565b91508082526020830160208301858383011115610dc357600080fd5b610dce8382846116ed565b50505092915050565b6000610de382356116d9565b905092915050565b600082601f8301121515610dfe57600080fd5b8135610e11610e0c82611581565b6114ac565b91508082526020830160208301858383011115610e2d57600080fd5b610e388382846116ed565b50505092915050565b6000610e4d82356116e3565b905092915050565b600060208284031215610e6757600080fd5b600082013567ffffffffffffffff811115610e8157600080fd5b610e8d84828501610cb5565b91505092915050565b600060208284031215610ea857600080fd5b600082013567ffffffffffffffff811115610ec257600080fd5b610ece84828501610d81565b91505092915050565b600080600060608486031215610eec57600080fd5b6000610efa86828701610dd7565b935050602084013567ffffffffffffffff811115610f1757600080fd5b610f2386828701610c30565b925050604084013567ffffffffffffffff811115610f4057600080fd5b610f4c86828701610deb565b9150509250925092565b600060208284031215610f6857600080fd5b6000610f7684828501610e41565b91505092915050565b610f8881611679565b82525050565b6000610f99826115ed565b808452602084019350610fab836115ad565b60005b82811015610fdd57610fc1868351610f7f565b610fca82611645565b9150602086019550600181019050610fae565b50849250505092915050565b6000610ff4826115f8565b8084526020840193508360208202850161100d856115ba565b60005b84811015611046578383038852611028838351611132565b925061103382611652565b9150602088019750600181019050611010565b508196508694505050505092915050565b61106081611603565b611069826115c7565b60005b8281101561109b5761107f8583516112a0565b6110888261165f565b915060208501945060018101905061106c565b5050505050565b6110ab8161160e565b6110b4826115d1565b60005b828110156110e6576110ca8583546112a0565b6110d38261166c565b91506020850194506001810190506110b7565b5050505050565b6110f681611699565b82525050565b600061110782611624565b80845261111b8160208601602086016116fc565b6111248161172f565b602085010191505092915050565b600061113d82611619565b8084526111518160208601602086016116fc565b61115a8161172f565b602085010191505092915050565b60008154600181166000811461118557600181146111a5576111e6565b607f600283041680865260ff1983166020870152604086019350506111e6565b600282048086526020860195506111bb856115db565b60005b828110156111dd578154818901526001820191506020810190506111be565b80880195505050505b505092915050565b6111f7816116a5565b82525050565b60006112088261163a565b80845261121c8160208601602086016116fc565b6112258161172f565b602085010191505092915050565b600061123e8261162f565b8084526112528160208601602086016116fc565b61125b8161172f565b602085010191505092915050565b6000601a82527f4279746573206172726179206973206c657373207468616e20320000000000006020830152604082019050919050565b6112a9816116af565b82525050565b60006020820190506112c46000830184610f7f565b92915050565b60006040820190506112df6000830185610f7f565b6112ec60208301846112a0565b9392505050565b6000602082019050818103600083015261130d8184610fe9565b905092915050565b600060408201905061132a6000830184611057565b92915050565b60006080820190506113456000830185611057565b61135260408301846110a2565b9392505050565b600060208201905061136e60008301846110ed565b92915050565b6000602082019050818103600083015261138e8184611132565b905092915050565b600060208201905081810360008301526113b081846110fc565b905092915050565b600060408201905081810360008301526113d28185611168565b905081810360208301526113e681846110fc565b90509392505050565b600060208201905061140460008301846111ee565b92915050565b600060608201905061141f60008301866111ee565b81810360208301526114318185610f8e565b9050818103604083015261144581846111fd565b9050949350505050565b600060208201905081810360008301526114698184611233565b905092915050565b6000602082019050818103600083015261148a81611269565b9050919050565b60006020820190506114a660008301846112a0565b92915050565b6000604051905081810181811067ffffffffffffffff821117156114cf57600080fd5b8060405250919050565b600067ffffffffffffffff8211156114f057600080fd5b602082029050602081019050919050565b600067ffffffffffffffff82111561151857600080fd5b602082029050602081019050919050565b600067ffffffffffffffff82111561154057600080fd5b601f19601f8301169050602081019050919050565b600067ffffffffffffffff82111561156c57600080fd5b601f19601f8301169050602081019050919050565b600067ffffffffffffffff82111561159857600080fd5b601f19601f8301169050602081019050919050565b6000602082019050919050565b6000602082019050919050565b6000819050919050565b6000819050919050565b60008160005260206000209050919050565b600081519050919050565b600081519050919050565b600060029050919050565b600060029050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000600182019050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60008115159050919050565b6000819050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b6000819050919050565b82818337600083830152505050565b60005b8381101561171a5780820151818401526020810190506116ff565b83811115611729576000848401525b50505050565b6000601f19601f83011690509190505600a265627a7a723058205c6daaac747c436743c1b9e0037ff84f35d449ad70c0745fa9218e3a5744e2c36c6578706572696d656e74616cf50037 \ No newline at end of file diff --git a/src/test/resources/ecdsa/bin/HelloWorld.bin b/src/test/resources/ecdsa/bin/HelloWorld.bin new file mode 100644 index 000000000..8367a2507 --- /dev/null +++ b/src/test/resources/ecdsa/bin/HelloWorld.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b506040805190810160405280600d81526020017f48656c6c6f2c20576f726c6421000000000000000000000000000000000000008152506000908051906020019061005c929190610062565b50610107565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100a357805160ff19168380011785556100d1565b828001600101855582156100d1579182015b828111156100d05782518255916020019190600101906100b5565b5b5090506100de91906100e2565b5090565b61010491905b808211156101005760008160009055506001016100e8565b5090565b90565b6102d3806101166000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100515780634ed3885e146100e1575b600080fd5b34801561005d57600080fd5b5061006661014a565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100a657808201518184015260208101905061008b565b50505050905090810190601f1680156100d35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156100ed57600080fd5b50610148600480360381019080803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506101e8565b005b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101e05780601f106101b5576101008083540402835291602001916101e0565b820191906000526020600020905b8154815290600101906020018083116101c357829003601f168201915b505050505081565b80600090805190602001906101fe929190610202565b5050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061024357805160ff1916838001178555610271565b82800160010185558215610271579182015b82811115610270578251825591602001919060010190610255565b5b50905061027e9190610282565b5090565b6102a491905b808211156102a0576000816000905550600101610288565b5090565b905600a165627a7a72305820f320e5eb2a59c810c188f5c3a74faacbea80ffac8d31427bdd05c71b2c51cec10029 \ No newline at end of file diff --git a/src/test/resources/gm/abi/ComplexSol.abi b/src/test/resources/gm/abi/ComplexSol.abi new file mode 100644 index 000000000..d19f506cd --- /dev/null +++ b/src/test/resources/gm/abi/ComplexSol.abi @@ -0,0 +1 @@ +[{"constant":true,"inputs":[],"name":"_intV","outputs":[{"name":"","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"bytesArray","type":"bytes[]"}],"name":"setBytesMapping","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"i","type":"int256"},{"name":"a","type":"address[]"},{"name":"s","type":"string"}],"name":"setValues","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"b","type":"bytes"}],"name":"getByBytes","outputs":[{"name":"","type":"bytes[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_s","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_addr","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_bytesV","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"emptyArgs","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"getSArray","outputs":[{"name":"","type":"uint256[2]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getUint256","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"b","type":"bytes"}],"name":"setBytes","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"v","type":"uint256"}],"name":"incrementUint256","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"_addrDArray","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"i","type":"int256"},{"name":"s","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"a","type":"uint256"}],"name":"LogIncrement","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"s","type":"string"}],"name":"LogInit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"int256"},{"indexed":false,"name":"a","type":"address[]"},{"indexed":false,"name":"s","type":"string"}],"name":"LogSetValues","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"o","type":"bytes"},{"indexed":false,"name":"b","type":"bytes"}],"name":"LogSetBytes","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"o","type":"uint256[2]"},{"indexed":false,"name":"n","type":"uint256[2]"}],"name":"LogSetSArray","type":"event"}] \ No newline at end of file diff --git a/src/test/resources/gm/abi/HelloWorld.abi b/src/test/resources/gm/abi/HelloWorld.abi new file mode 100644 index 000000000..426703568 --- /dev/null +++ b/src/test/resources/gm/abi/HelloWorld.abi @@ -0,0 +1 @@ +[{"constant":false,"inputs":[{"name":"n","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}] \ No newline at end of file diff --git a/src/test/resources/gm/bin/ComplexSol.bin b/src/test/resources/gm/bin/ComplexSol.bin new file mode 100644 index 000000000..02ffa2bb1 --- /dev/null +++ b/src/test/resources/gm/bin/ComplexSol.bin @@ -0,0 +1 @@ +60806040523480156200001157600080fd5b5060405162001b3a38038062001b3a8339810180604052620000379190810190620001fe565b33600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600181905550806003908051906020019062000097929190620000db565b507f5d67838bb61a80e683a1c6ad9a5858348ad1f14d2ae9bb06983da6458c6b67ea3382604051620000cb929190620002a5565b60405180910390a15050620003b0565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200011e57805160ff19168380011785556200014f565b828001600101855582156200014f579182015b828111156200014e57825182559160200191906001019062000131565b5b5090506200015e919062000162565b5090565b6200018791905b808211156200018357600081600090555060010162000169565b5090565b90565b60006200019882516200035f565b905092915050565b600082601f8301121515620001b457600080fd5b8151620001cb620001c58262000307565b620002d9565b91508082526020830160208301858383011115620001e857600080fd5b620001f583828462000369565b50505092915050565b600080604083850312156200021257600080fd5b600062000222858286016200018a565b925050602083015167ffffffffffffffff8111156200024057600080fd5b6200024e85828601620001a0565b9150509250929050565b62000263816200033f565b82525050565b6000620002768262000334565b8084526200028c81602086016020860162000369565b62000297816200039f565b602085010191505092915050565b6000604082019050620002bc600083018562000258565b8181036020830152620002d0818462000269565b90509392505050565b6000604051905081810181811067ffffffffffffffff82111715620002fd57600080fd5b8060405250919050565b600067ffffffffffffffff8211156200031f57600080fd5b601f19601f8301169050602081019050919050565b600081519050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60005b83811015620003895780820151818401526020810190506200036c565b8381111562000399576000848401525b50505050565b6000601f19601f8301169050919050565b61177a80620003c06000396000f3006080604052600436106100c5576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063121a5478146100ca57806342ce53ee146100f557806347e2106a146101325780636a52c3241461015b578063792e0e55146101985780638fbede04146101c3578063ad598ae8146101ee578063b021bd8914610219578063b05d32c714610230578063bd1801da1461025b578063c5b4f92514610286578063f9350e5f146102c3578063fee3907014610300575b600080fd5b3480156100d657600080fd5b506100df61033d565b6040516100ec91906113ef565b60405180910390f35b34801561010157600080fd5b5061011c60048036036101179190810190610e55565b610343565b6040516101299190611359565b60405180910390f35b34801561013e57600080fd5b5061015960048036036101549190810190610ed7565b61042c565b005b34801561016757600080fd5b50610182600480360361017d9190810190610e96565b6104a1565b60405161018f91906112f3565b60405180910390f35b3480156101a457600080fd5b506101ad6105f5565b6040516101ba919061144f565b60405180910390f35b3480156101cf57600080fd5b506101d8610693565b6040516101e591906112af565b60405180910390f35b3480156101fa57600080fd5b506102036106b9565b6040516102109190611374565b60405180910390f35b34801561022557600080fd5b5061022e610757565b005b34801561023c57600080fd5b50610245610759565b6040516102529190611315565b60405180910390f35b34801561026757600080fd5b506102706107c3565b60405161027d9190611491565b60405180910390f35b34801561029257600080fd5b506102ad60048036036102a89190810190610e96565b6107cc565b6040516102ba9190611396565b60405180910390f35b3480156102cf57600080fd5b506102ea60048036036102e59190810190610f56565b610827565b6040516102f79190611491565b60405180910390f35b34801561030c57600080fd5b5061032760048036036103229190810190610f56565b610876565b60405161033491906112af565b60405180910390f35b60015481565b60006001825111151561038b576040517fc703cb1200000000000000000000000000000000000000000000000000000000815260040161038290611471565b60405180910390fd5b81600883600081518110151561039d57fe5b906020019060200201516040518082805190602001908083835b6020831015156103dc57805182526020820191506020810190506020830392506103b7565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902090805190602001906104229291906108b4565b5060019050919050565b826001819055508160079080519060200190610449929190610914565b50806003908051906020019061046092919061099e565b507fc26a0e0417d439eff54a52eee1dc2555f214da1cd78a1b4ff752ca2cb3c02ac98383836040516104949392919061140a565b60405180910390a1505050565b60606008826040518082805190602001908083835b6020831015156104db57805182526020820191506020810190506020830392506104b6565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020805480602002602001604051908101604052809291908181526020016000905b828210156105ea578382906000526020600020018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156105d65780601f106105ab576101008083540402835291602001916105d6565b820191906000526020600020905b8154815290600101906020018083116105b957829003601f168201915b50505050508152602001906001019061052e565b505050509050919050565b60038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561068b5780601f106106605761010080835404028352916020019161068b565b820191906000526020600020905b81548152906001019060200180831161066e57829003601f168201915b505050505081565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60048054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561074f5780601f106107245761010080835404028352916020019161074f565b820191906000526020600020905b81548152906001019060200180831161073257829003601f168201915b505050505081565b565b610761610a1e565b610769610a1e565b604080519081016040528060018152602001600281525090507f4635bf9eb40890fab230936d555e52f5f571a650c7e4b8f855398517bbf0607a8160056040516107b4929190611330565b60405180910390a18091505090565b60008054905090565b60607f01562154dafe58b5dcba0eba49f45309533857e2e909eec8f19ba560cf41fde76004836040516108009291906113b8565b60405180910390a1816004908051906020019061081e929190610a40565b50819050919050565b6000600182016000819055507f60103047da8b10d410fb500a0fed064ee8918a2edeef42b5056850a3ed4b347f33836040516108649291906112ca565b60405180910390a16000549050919050565b60078181548110151561088557fe5b906000526020600020016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b828054828255906000526020600020908101928215610903579160200282015b828111156109025782518290805190602001906108f2929190610ac0565b50916020019190600101906108d4565b5b5090506109109190610b40565b5090565b82805482825590600052602060002090810192821561098d579160200282015b8281111561098c5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555091602001919060010190610934565b5b50905061099a9190610b6c565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106109df57805160ff1916838001178555610a0d565b82800160010185558215610a0d579182015b82811115610a0c5782518255916020019190600101906109f1565b5b509050610a1a9190610baf565b5090565b6040805190810160405280600290602082028038833980820191505090505090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10610a8157805160ff1916838001178555610aaf565b82800160010185558215610aaf579182015b82811115610aae578251825591602001919060010190610a93565b5b509050610abc9190610baf565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10610b0157805160ff1916838001178555610b2f565b82800160010185558215610b2f579182015b82811115610b2e578251825591602001919060010190610b13565b5b509050610b3c9190610baf565b5090565b610b6991905b80821115610b655760008181610b5c9190610bd4565b50600101610b46565b5090565b90565b610bac91905b80821115610ba857600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600101610b72565b5090565b90565b610bd191905b80821115610bcd576000816000905550600101610bb5565b5090565b90565b50805460018160011615610100020316600290046000825580601f10610bfa5750610c19565b601f016020900490600052602060002090810190610c189190610baf565b5b50565b6000610c2882356116b9565b905092915050565b600082601f8301121515610c4357600080fd5b8135610c56610c51826114d9565b6114ac565b91508181835260208401935060208101905083856020840282011115610c7b57600080fd5b60005b83811015610cab5781610c918882610c1c565b845260208401935060208301925050600181019050610c7e565b5050505092915050565b600082601f8301121515610cc857600080fd5b8135610cdb610cd682611501565b6114ac565b9150818183526020840193506020810190508360005b83811015610d215781358601610d078882610d2b565b845260208401935060208301925050600181019050610cf1565b5050505092915050565b600082601f8301121515610d3e57600080fd5b8135610d51610d4c82611529565b6114ac565b91508082526020830160208301858383011115610d6d57600080fd5b610d788382846116ed565b50505092915050565b600082601f8301121515610d9457600080fd5b8135610da7610da282611555565b6114ac565b91508082526020830160208301858383011115610dc357600080fd5b610dce8382846116ed565b50505092915050565b6000610de382356116d9565b905092915050565b600082601f8301121515610dfe57600080fd5b8135610e11610e0c82611581565b6114ac565b91508082526020830160208301858383011115610e2d57600080fd5b610e388382846116ed565b50505092915050565b6000610e4d82356116e3565b905092915050565b600060208284031215610e6757600080fd5b600082013567ffffffffffffffff811115610e8157600080fd5b610e8d84828501610cb5565b91505092915050565b600060208284031215610ea857600080fd5b600082013567ffffffffffffffff811115610ec257600080fd5b610ece84828501610d81565b91505092915050565b600080600060608486031215610eec57600080fd5b6000610efa86828701610dd7565b935050602084013567ffffffffffffffff811115610f1757600080fd5b610f2386828701610c30565b925050604084013567ffffffffffffffff811115610f4057600080fd5b610f4c86828701610deb565b9150509250925092565b600060208284031215610f6857600080fd5b6000610f7684828501610e41565b91505092915050565b610f8881611679565b82525050565b6000610f99826115ed565b808452602084019350610fab836115ad565b60005b82811015610fdd57610fc1868351610f7f565b610fca82611645565b9150602086019550600181019050610fae565b50849250505092915050565b6000610ff4826115f8565b8084526020840193508360208202850161100d856115ba565b60005b84811015611046578383038852611028838351611132565b925061103382611652565b9150602088019750600181019050611010565b508196508694505050505092915050565b61106081611603565b611069826115c7565b60005b8281101561109b5761107f8583516112a0565b6110888261165f565b915060208501945060018101905061106c565b5050505050565b6110ab8161160e565b6110b4826115d1565b60005b828110156110e6576110ca8583546112a0565b6110d38261166c565b91506020850194506001810190506110b7565b5050505050565b6110f681611699565b82525050565b600061110782611624565b80845261111b8160208601602086016116fc565b6111248161172f565b602085010191505092915050565b600061113d82611619565b8084526111518160208601602086016116fc565b61115a8161172f565b602085010191505092915050565b60008154600181166000811461118557600181146111a5576111e6565b607f600283041680865260ff1983166020870152604086019350506111e6565b600282048086526020860195506111bb856115db565b60005b828110156111dd578154818901526001820191506020810190506111be565b80880195505050505b505092915050565b6111f7816116a5565b82525050565b60006112088261163a565b80845261121c8160208601602086016116fc565b6112258161172f565b602085010191505092915050565b600061123e8261162f565b8084526112528160208601602086016116fc565b61125b8161172f565b602085010191505092915050565b6000601a82527f4279746573206172726179206973206c657373207468616e20320000000000006020830152604082019050919050565b6112a9816116af565b82525050565b60006020820190506112c46000830184610f7f565b92915050565b60006040820190506112df6000830185610f7f565b6112ec60208301846112a0565b9392505050565b6000602082019050818103600083015261130d8184610fe9565b905092915050565b600060408201905061132a6000830184611057565b92915050565b60006080820190506113456000830185611057565b61135260408301846110a2565b9392505050565b600060208201905061136e60008301846110ed565b92915050565b6000602082019050818103600083015261138e8184611132565b905092915050565b600060208201905081810360008301526113b081846110fc565b905092915050565b600060408201905081810360008301526113d28185611168565b905081810360208301526113e681846110fc565b90509392505050565b600060208201905061140460008301846111ee565b92915050565b600060608201905061141f60008301866111ee565b81810360208301526114318185610f8e565b9050818103604083015261144581846111fd565b9050949350505050565b600060208201905081810360008301526114698184611233565b905092915050565b6000602082019050818103600083015261148a81611269565b9050919050565b60006020820190506114a660008301846112a0565b92915050565b6000604051905081810181811067ffffffffffffffff821117156114cf57600080fd5b8060405250919050565b600067ffffffffffffffff8211156114f057600080fd5b602082029050602081019050919050565b600067ffffffffffffffff82111561151857600080fd5b602082029050602081019050919050565b600067ffffffffffffffff82111561154057600080fd5b601f19601f8301169050602081019050919050565b600067ffffffffffffffff82111561156c57600080fd5b601f19601f8301169050602081019050919050565b600067ffffffffffffffff82111561159857600080fd5b601f19601f8301169050602081019050919050565b6000602082019050919050565b6000602082019050919050565b6000819050919050565b6000819050919050565b60008160005260206000209050919050565b600081519050919050565b600081519050919050565b600060029050919050565b600060029050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000600182019050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60008115159050919050565b6000819050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b6000819050919050565b82818337600083830152505050565b60005b8381101561171a5780820151818401526020810190506116ff565b83811115611729576000848401525b50505050565b6000601f19601f83011690509190505600a265627a7a72305820fb786828544a024d211cd90d158baa56ef91023746a8e321cd847043b090dbb36c6578706572696d656e74616cf50037 \ No newline at end of file diff --git a/src/test/resources/gm/bin/HelloWorld.bin b/src/test/resources/gm/bin/HelloWorld.bin new file mode 100644 index 000000000..105042d56 --- /dev/null +++ b/src/test/resources/gm/bin/HelloWorld.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b506040805190810160405280600d81526020017f48656c6c6f2c20576f726c6421000000000000000000000000000000000000008152506000908051906020019061005c929190610062565b50610107565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100a357805160ff19168380011785556100d1565b828001600101855582156100d1579182015b828111156100d05782518255916020019190600101906100b5565b5b5090506100de91906100e2565b5090565b61010491905b808211156101005760008160009055506001016100e8565b5090565b90565b6102d3806101166000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633590b49f14610051578063b11b6883146100ba575b600080fd5b34801561005d57600080fd5b506100b8600480360381019080803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061014a565b005b3480156100c657600080fd5b506100cf610164565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561010f5780820151818401526020810190506100f4565b50505050905090810190601f16801561013c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b8060009080519060200190610160929190610202565b5050565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101fa5780601f106101cf576101008083540402835291602001916101fa565b820191906000526020600020905b8154815290600101906020018083116101dd57829003601f168201915b505050505081565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061024357805160ff1916838001178555610271565b82800160010185558215610271579182015b82811115610270578251825591602001919060010190610255565b5b50905061027e9190610282565b5090565b6102a491905b808211156102a0576000816000905550600101610288565b5090565b905600a165627a7a723058209072782fc019ac745aa91b6fede6c358df1b03584b1bf5193a8c66d68a6880f30029 \ No newline at end of file diff --git a/src/test/resources/keystore/ecdsa/0x0fc3c4bb89bd90299db4c62be0174c4966286c00.pem b/src/test/resources/keystore/ecdsa/0x0fc3c4bb89bd90299db4c62be0174c4966286c00.pem new file mode 100644 index 000000000..b448c4cd7 --- /dev/null +++ b/src/test/resources/keystore/ecdsa/0x0fc3c4bb89bd90299db4c62be0174c4966286c00.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgvFFrJgDuw6IW9FfcFM+D +oB7SLQ/CFJ/JEdwuxIb+V6OhRANCAATbv+5PdvWjvD28LmEnxKH1C3YUv/QTikSn +mu09QvZ/nHqnBXAgX5tgpYiMZBW2qDABJne0QVp5zNFTP+VjeGHf +-----END PRIVATE KEY----- diff --git a/src/test/resources/keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.p12 b/src/test/resources/keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.p12 new file mode 100644 index 000000000..09388e9a7 Binary files /dev/null and b/src/test/resources/keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.p12 differ diff --git a/src/test/resources/keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.public.pem b/src/test/resources/keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.public.pem new file mode 100644 index 000000000..0b6ef051e --- /dev/null +++ b/src/test/resources/keystore/ecdsa/0x45e14c53197adbcb719d915fb93342c25600faaf.public.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE17ngD1bT95MFNZ+i19sWYCHnMIa9zS56 +KNbtJzReHy3ez4XbdDjoRX/UdO+cTOuJq7fV+mCiLykC7CbcpSrV5Q== +-----END PUBLIC KEY----- diff --git a/src/test/resources/keystore/ecdsa/invalid.p12 b/src/test/resources/keystore/ecdsa/invalid.p12 new file mode 100644 index 000000000..5e5138794 Binary files /dev/null and b/src/test/resources/keystore/ecdsa/invalid.p12 differ diff --git a/src/test/resources/keystore/ecdsa/invalid.pem b/src/test/resources/keystore/ecdsa/invalid.pem new file mode 100644 index 000000000..ecc335ea0 --- /dev/null +++ b/src/test/resources/keystore/ecdsa/invalid.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgvFFrJgDuw6IW9FfcFM+D +oB7SLQ/CFJ/JEdwuxIb+V6OhRANCAATbv+5PdvWjvD28LmEnxKH1C3YUv/QTikSn +mu09QvZ/nHqnBXAgX5tgpYiMZBW2qDABJne0QVp5zNFTP+VjeGf +-----END PRIVATE KEY----- diff --git a/src/test/resources/keystore/gm/0x40b3558746e8f9a47a474774e8c4a9e67d4e3174.pem b/src/test/resources/keystore/gm/0x40b3558746e8f9a47a474774e8c4a9e67d4e3174.pem new file mode 100644 index 000000000..f5395940b --- /dev/null +++ b/src/test/resources/keystore/gm/0x40b3558746e8f9a47a474774e8c4a9e67d4e3174.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgkBdEw04q3/yf1/sS +6Mui2Ip5qvVL6bThFmAVModInxOhRANCAAQ7cs0oJEyFbT2Jtn0cX/IuHyaDW6/N +Y+mkrTQkoqV/K3WRSfRsaW3wi52Uc2hmdfxtredE0Mgr3FWY11ngFf2W +-----END PRIVATE KEY----- diff --git a/src/test/resources/keystore/gm/0x6f68461309925093236df82b51df630a55d32377.p12 b/src/test/resources/keystore/gm/0x6f68461309925093236df82b51df630a55d32377.p12 new file mode 100644 index 000000000..367c17da1 Binary files /dev/null and b/src/test/resources/keystore/gm/0x6f68461309925093236df82b51df630a55d32377.p12 differ diff --git a/src/test/resources/keystore/gm/invalid.p12 b/src/test/resources/keystore/gm/invalid.p12 new file mode 100644 index 000000000..60862eb2f Binary files /dev/null and b/src/test/resources/keystore/gm/invalid.p12 differ diff --git a/src/test/resources/keystore/gm/invalid.pem b/src/test/resources/keystore/gm/invalid.pem new file mode 100644 index 000000000..d63a94f80 --- /dev/null +++ b/src/test/resources/keystore/gm/invalid.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgkBdEw04q3/yf1/sS +6Mui2Ip5qvVL6bThFmAVModInxOhRANCAAQ7cs0oJEyFbT2Jtn0cX/IuHyaDW6/N +Y+mkrTQkoqV/K3WRSfRsaW3wi52Uc2hmdfxtredE0Mgr3FWY11ngFf2 +-----END PRIVATE KEY----- diff --git a/src/test/resources/log4j.properties b/src/test/resources/log4j.properties new file mode 100644 index 000000000..55785c234 --- /dev/null +++ b/src/test/resources/log4j.properties @@ -0,0 +1,32 @@ +# +# Copyright 2014-2020 [fisco-dev] +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under the License +# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +# or implied. See the License for the specific language governing permissions and limitations under +# the License. +# +# + +### set log levels ### +log4j.rootLogger=DEBUG, file + +### output the log information to the file ### +log4j.appender.file=org.apache.log4j.DailyRollingFileAppender +log4j.appender.file.DatePattern='_'yyyyMMddHH'.log' +log4j.appender.file.File=./log/sdk.log +log4j.appender.file.Append=true +log4j.appender.file.filter.traceFilter=org.apache.log4j.varia.LevelRangeFilter +log4j.appender.file.layout=org.apache.log4j.PatternLayout +log4j.appender.file.layout.ConversionPattern=[%p] [%-d{yyyy-MM-dd HH:mm:ss}] %C{1}.%M(%L) | %m%n + +###output the log information to the console ### +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=[%p] [%-d{yyyy-MM-dd HH:mm:ss}] %C{1}.%M(%L) | %m%n