├── .ci ├── ci_check.sh └── ci_check_commit.sh ├── .codecov.yml ├── .github └── workflows │ ├── ci_check.yml │ └── publish_binaries.yml ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── Changelog.md ├── LICENSE ├── README.md ├── build.gradle ├── docs └── images │ └── menu_logo_wecross.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── release_note.txt ├── scripts └── start.sh ├── settings.gradle └── src ├── main ├── java │ └── com │ │ └── webank │ │ └── wecross │ │ └── console │ │ ├── Initializer.java │ │ ├── Shell.java │ │ ├── common │ │ ├── ConsoleUtils.java │ │ ├── FileUtils.java │ │ ├── Hash.java │ │ ├── HelpInfo.java │ │ ├── IgnoreCaseCompleter.java │ │ ├── JlineUtils.java │ │ ├── PrintUtils.java │ │ ├── TarUtils.java │ │ ├── TransactionInfo.java │ │ ├── Version.java │ │ └── WelcomeInfo.java │ │ ├── custom │ │ ├── BCOSCommand.java │ │ └── FabricCommand.java │ │ ├── exception │ │ ├── ErrorCode.java │ │ └── WeCrossConsoleException.java │ │ ├── mock │ │ ├── MockResource.java │ │ └── MockWeCross.java │ │ ├── routine │ │ ├── HTLCFace.java │ │ ├── HTLCImpl.java │ │ ├── XAFace.java │ │ └── XAImpl.java │ │ └── rpc │ │ ├── RPCFace.java │ │ └── RPCImpl.java └── resources │ ├── application-sample.toml │ ├── application.toml │ ├── contracts │ ├── chaincode │ │ ├── asset │ │ │ └── assetSample.go │ │ ├── evidence │ │ │ ├── evidenceSample.go │ │ │ └── policy.yaml │ │ ├── helloworld │ │ │ └── helloworld.go │ │ ├── htlc │ │ │ ├── htlc.go │ │ │ └── htlc_sample.go │ │ ├── interchain │ │ │ └── interchainSample.go │ │ ├── ledger │ │ │ └── ledger_sample.go │ │ └── sacc │ │ │ ├── policy.yaml │ │ │ └── sacc.go │ ├── liquid │ │ └── hello_world │ │ │ ├── .gitignore │ │ │ ├── .liquid │ │ │ └── abi_gen │ │ │ │ ├── Cargo.toml │ │ │ │ └── main.rs │ │ │ ├── Cargo.toml │ │ │ ├── hello_world.abi │ │ │ ├── hello_world.wasm │ │ │ ├── hello_world_gm.wasm │ │ │ └── src │ │ │ └── lib.rs │ └── solidity │ │ ├── AssetSample.sol │ │ ├── EvidenceSample.sol │ │ ├── HTLC.sol │ │ ├── HelloWeCross.sol │ │ ├── HelloWorld.sol │ │ ├── InterchainGetBlockSample.sol │ │ ├── InterchainSample.sol │ │ ├── LedgerSample.sol │ │ ├── LedgerSampleHTLC.sol │ │ ├── Sacc.sol │ │ └── WeCrossHub.sol │ └── log4j2.xml └── test ├── java └── com │ └── webank │ └── wecross │ └── console │ ├── ConsoleUtilsTest.java │ ├── FileUtilsTest.java │ └── TarUtilsTest.java └── resources ├── ContractTypeTest.sol └── TupleTest.sol /.ci/ci_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -r src/main/resources/contracts src/test/resources/ 4 | 5 | set -e 6 | 7 | ./gradlew verifyGoogleJavaFormat 8 | ./gradlew build 9 | ./gradlew test 10 | ./gradlew jacocoTestReport 11 | -------------------------------------------------------------------------------- /.ci/ci_check_commit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | scan_code_script="cobra/cobra.py -f json -o /tmp/report.json -t " 6 | ignore_files=(application-sample.yml application.yml HelpInfo.java) 7 | 8 | LOG_ERROR() { 9 | content=${1} 10 | echo -e "\033[31m${content}\033[0m" 11 | } 12 | 13 | LOG_INFO() { 14 | content=${1} 15 | echo -e "\033[32m${content}\033[0m" 16 | } 17 | 18 | should_ignore() { 19 | local file=${1} 20 | for ignore in ${ignore_files[*]}; do 21 | if echo ${file} | grep ${ignore} &>/dev/null; then 22 | echo "ignore ${file} ${ignore}" 23 | return 0 24 | fi 25 | done 26 | return 1 27 | } 28 | 29 | scan_code() { 30 | # Redirect output to stderr. 31 | exec 1>&2 32 | for file in $(git diff-index --name-status HEAD^ | awk '{print $2}'); do 33 | if should_ignore ${file}; then continue; fi 34 | if [ ! -f ${file} ]; then continue; fi 35 | LOG_INFO "check file ${file}" 36 | python ${scan_code_script} $file 37 | trigger_rules=$(jq -r '.' /tmp/report.json | grep 'trigger_rules' | awk '{print $2}' | sed 's/,//g') 38 | echo "trigger_rules is ${trigger_rules}" 39 | rm /tmp/report.json 40 | if [ ${trigger_rules} -ne 0 ]; then 41 | echo "######### ERROR: Scan code failed, please adjust them before commit" 42 | exit 1 43 | fi 44 | done 45 | } 46 | 47 | install_cobra() { 48 | git clone https://github.com/WhaleShark-Team/cobra.git 49 | pip install -r cobra/requirements.txt 50 | cp cobra/config.template cobra/config 51 | } 52 | 53 | install_cobra 54 | scan_code 55 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | target: 30% 6 | threshold: null 7 | if_not_found: success 8 | patch: 9 | default: 10 | enabled: no 11 | if_not_found: success 12 | changes: 13 | default: 14 | enabled: no 15 | if_not_found: success 16 | -------------------------------------------------------------------------------- /.github/workflows/ci_check.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Gradle 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle 3 | 4 | name: ci check 5 | 6 | on: pull_request 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Set up JDK 1.8 15 | uses: actions/setup-java@v1 16 | with: 17 | java-version: 1.8 18 | - name: run ci_check.sh 19 | run: bash .ci/ci_check.sh 20 | - name: upload coverage 21 | run: bash <(curl -s https://codecov.io/bash) 22 | -------------------------------------------------------------------------------- /.github/workflows/publish_binaries.yml: -------------------------------------------------------------------------------- 1 | name: Publish binaries 2 | 3 | on: 4 | release: 5 | types: [prereleased] 6 | 7 | jobs: 8 | build: 9 | name: Publish binaries 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v1 14 | - name: Set up JDK 1.8 15 | uses: actions/setup-java@v1 16 | with: 17 | java-version: 1.8 18 | - name: Build with Gradle 19 | run: ./gradlew assemble 20 | - name: Download scripts 21 | run: mkdir -p dist/conf/accounts && cd dist/conf/accounts && curl -LO https://raw.githubusercontent.com/FISCO-BCOS/console/master/tools/get_account.sh && curl -LO https://raw.githubusercontent.com/FISCO-BCOS/console/master/tools/get_gm_account.sh && chmod +x *.sh && cd - 22 | - name: Pack 23 | run: chmod +x dist/*.sh && mv dist WeCross-Console && tar -zcvf WeCross-Console.tar.gz WeCross-Console 24 | - name: Checksum 25 | run: md5sum WeCross-Console.tar.gz > WeCross-Console.tar.gz.md5 26 | - name: Upload binaries to release 27 | uses: svenstaro/upload-release-action@v1-release 28 | with: 29 | repo_token: ${{ secrets.GITHUB_TOKEN }} 30 | file: WeCross-Console.tar.gz 31 | asset_name: WeCross-Console.tar.gz 32 | tag: ${{ github.ref }} 33 | overwrite: true 34 | 35 | - name: Upload checksum to release 36 | uses: svenstaro/upload-release-action@v1-release 37 | with: 38 | repo_token: ${{ secrets.GITHUB_TOKEN }} 39 | file: WeCross-Console.tar.gz.md5 40 | asset_name: WeCross-Console.tar.gz.md5 41 | tag: ${{ github.ref }} 42 | overwrite: true 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Java template 3 | *.class 4 | 5 | # Package Files # 6 | *.war 7 | *.ear 8 | *.bin 9 | *.abi 10 | 11 | ### Gradle template 12 | .gradle 13 | build 14 | gradle.properties 15 | 16 | ### output 17 | dist 18 | logs 19 | 20 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 21 | !gradle-wrapper.jar 22 | 23 | # Cache of project 24 | .gradletasknamecache 25 | 26 | # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 27 | # gradle/wrapper/gradle-wrapper.properties 28 | 29 | .idea 30 | *.iml 31 | 32 | # OS X 33 | .DS_Store 34 | 35 | .settings/ 36 | .classpath 37 | .project 38 | src/main/resources/application.toml 39 | 40 | *.key 41 | *.crt 42 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # safelist 2 | branches: 3 | only: 4 | - /.*/ 5 | 6 | matrix: 7 | fast_finish: true 8 | include: 9 | - language: python 10 | python: 3.6 11 | dist: xenial 12 | before_cache: 13 | cache: 14 | before_install: 15 | script: | 16 | bash .ci/ci_check_commit.sh 17 | 18 | - language: java 19 | jdk: openjdk8 20 | os: linux 21 | dist: xenial 22 | sudo: required 23 | 24 | - language: java 25 | jdk: openjdk9 26 | os: linux 27 | dist: xenial 28 | sudo: required 29 | 30 | - language: java 31 | jdk: openjdk10 32 | os: linux 33 | dist: xenial 34 | sudo: required 35 | 36 | - language: java 37 | jdk: openjdk11 38 | os: linux 39 | dist: xenial 40 | sudo: required 41 | 42 | # - language: java 43 | # jdk: openjdk11 44 | # os: osx 45 | # before_install: 46 | # - brew install gradle && gradle wrapper 47 | 48 | before_cache: 49 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 50 | - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ 51 | cache: 52 | directories: 53 | - $HOME/.gradle/caches/ 54 | - $HOME/.gradle/wrapper/ 55 | before_install: 56 | - gradle wrapper 57 | script: | 58 | bash .ci/ci_check.sh 59 | 60 | after_success: 61 | - bash <(curl -s https://codecov.io/bash) -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # 贡献代码 2 | 3 | 非常感谢能有心为WeCross贡献代码! 4 | 5 | ## 分支策略 6 | 7 | 项目采用[git-flow](https://jeffkreeftmeijer.com/git-flow/)的分支策略。 8 | 9 | * master:最新的稳定分支 10 | * dev:待发布的稳定分支 11 | * feature-xxxx:一个正在开发xxxx特性分支 12 | * bugfix-xxxx:一个正在修bug xxxx的分支 13 | 14 | ## 贡献方法 15 | 16 | ### Issue 17 | 18 | 可直接去[issues page](https://github.com/WeBankBlockchain/WeCross-Console/issues)提issue。 19 | 20 | ### 修复bug 21 | 22 | 1. Fork本仓库到个人仓库 23 | 2. 从个人仓库的master分支拉出一个bugfix-xxxx分支 24 | 3. 在bugfix-xxxx上修复bug 25 | 4. 测试修复的bug 26 | 5. PR(Pull Request)到本仓库的dev分支 27 | 6. 等待社区review这个PR 28 | 7. PR合入,bug修复完成! 29 | 30 | ### 开发新特性 31 | 32 | 1. Fork本仓库到个人仓库 33 | 2. 从个人仓库的dev分支拉出一个feature-xxxx分支 34 | 3. 在feature-xxxx上进行特性开发 35 | 4. 不定期的从本仓库的dev分支pull最新的改动到feature-xxxx分支 36 | 5. 测试新特性 37 | 6. PR(Pull Request)到本参考的dev分支 38 | 7. 等待社区review这个PR 39 | 8. PR合入,特性开发完成! 40 | 41 | ## 代码格式化 42 | 43 | 代码格式化gradle插件[google-java-format-gradle-plugin](https://github.com/sherter/google-java-format-gradle-plugin). 44 | 45 | 执行任务 `googleJavaFormat`格式化java文件。 46 | ``` 47 | ./gradlew goJF 48 | ``` 49 | 执行任务 `verifyGoogleJavaFormat`验证java文件是否格式化完成 50 | ``` 51 | ./gradlew verGJF 52 | ``` 53 | -------------------------------------------------------------------------------- /Changelog.md: -------------------------------------------------------------------------------- 1 | ### v1.4.0 2 | 3 | (2024-03-01) 4 | 5 | **新增** 6 | 7 | - 增加获取区块的命令 `getBlock` https://github.com/WeBankBlockchain/WeCross-Console/pull/187 8 | - 增加跨链获取区块的示例合约 https://github.com/WeBankBlockchain/WeCross-Console/pull/188 9 | 10 | **更新** 11 | 12 | - 更新版本依赖,修复安全问题 https://github.com/WeBankBlockchain/WeCross-Console/pull/190 13 | 14 | ### v1.3.1 15 | 16 | (2023-07-31) 17 | 18 | **新增** 19 | 20 | * 支持FISCO BCOS 3.+ WASM执行版本,支持WASM合约部署、调用等功能。 21 | 22 | ### v1.3.0 23 | 24 | (2023-03-15) 25 | 26 | **新增** 27 | 28 | * 新增HelloWorld的Fabric chaincode #169,新增Sacc的Solidity合约 #170。 29 | * 新增单笔事务写交易接口 `autoCommitXATransaction` 30 | * 新增对FISCO BCOS 3.x 版本的支持 31 | 32 | **更改** 33 | 34 | * 优化Fabric交易接口。 #177 35 | * 更新commons-compress、log4j的版本号。 36 | 37 | ### v1.2.1 38 | 39 | (2021-12-15) 40 | 41 | **修复** 42 | 43 | * 修复log4j的漏洞,将其升级至2.15 44 | 45 | ### v1.2.0 46 | 47 | (2021-08-20) 48 | 49 | **新增** 50 | 51 | * 适配Fabric2.0类型的链账户 52 | 53 | ### v1.1.1 54 | 55 | (2021-04-02) 56 | 57 | **更改** 58 | 59 | * 启动时打印版本号 60 | * 升级wecross-java-sdk以支持Router的URL前缀可配 61 | * help 提示信息分类展示 62 | 63 | ### v1.1.0 64 | 65 | (2020-02-02) 66 | 67 | **更新** 68 | 69 | * 升级`groovy-all`版本,详情参考`build.gradle`修改 70 | * 修改`login`逻辑,参数加密以及`token`验证逻辑移植到`java-sdk`中 71 | 72 | **删除** 73 | 74 | * 删除`status`命令 75 | 76 | ### v1.0.1 77 | 78 | (2020-01-15) 79 | 80 | **功能** 81 | 82 | * 启动脚本添加参数,修复新版本JDK无法使用的问题 83 | 84 | ### v1.0.0 85 | 86 | (2020-12-17) 87 | 88 | **新增** 89 | 90 | * 账户相关命令:registerAccount、login、logout、addChainAccount、setDefaultAccount、listAccount 91 | * 新增事务命令:invoke,根据上下文自动选择发交易的方式 92 | * 新增合约: 桥接合约(WeCrossHub)、资产示例合约(AssetSample) 93 | * 文件名补全:部署相关命令支持文件名补全 94 | 95 | **更改** 96 | 97 | * 删除获取账户列表的命令:listAccounts 98 | * 资源调用相关命令参数列表去掉账户名 99 | * 部分事务命令重命名: 100 | * getTransactionIDs => getXATransaction 101 | * getTransactionIDs => listXATransactions 102 | 103 | ### v1.0.0-rc4 104 | 105 | (2020-08-18) 106 | 107 | **新增** 108 | 109 | * 资源部署命令 110 | * FISCO BCOS:bcosDeploy、bcosRegister 111 | * Fabric:fabricInstall、fabricInstantiate、fabricUpgrade 112 | * 2PC事务操作命令 113 | * 操作:startTransaction、execTransaction、callTransaction、commitTransaction、rollbackTransaction 114 | * 查询:getTransactionInfo、getTransactionIDs 115 | * 跨链资源集 116 | * 一般示例代码:HelloWorld.sol、sacc.go、fabcar.java 117 | * HTLC合约代码:HTLC.sol、htlc.go等 118 | * 两阶段示例:EvidenceSample.sol、EvidenceSample.go等 119 | 120 | ### v1.0.0-rc3 121 | 122 | (2020-06-15) 123 | 124 | **更改** 125 | 126 | * 适配v1.0.0-rc3的wecross-java-sdk 127 | * 下载脚本稳定性修复 128 | 129 | ### v1.0.0-rc2 130 | 131 | (2020-05-12) 132 | 133 | **新增** 134 | 135 | * 安全通讯:控制台和Router之间采用TLS协议通讯 136 | * 增加命令: 137 | * detail:查看资源详情信息 138 | * supportedStubs:查看连接Router支持的Stub插件列表 139 | * listAccounts:查看Router配置的账户列表 140 | * genSecretAndHash:跨链转账辅助命令,生成一个秘密和它的哈希 141 | * genTimelock:跨链转账辅助命令,生成两个合法的时间戳 142 | * newContract:创建一个基于哈希时间锁合约的跨链转账合同 143 | 144 | **更改** 145 | 146 | * 合约调用:合约调用需要指定签名的账户 147 | * 命令更新:合约调用不再需要指定返回值类型列表,因此删除了相关衍生命令 148 | * 配置文件:更新配置文件为toml格式,新增TLS配置项 149 | 150 | ### v1.0.0-rc1 151 | 152 | (2019-12-30) 153 | 154 | **功能** 155 | 156 | * 跨连控制台基本功能 157 | 158 | ``` 159 | ============================================================================================= 160 | Welcome to WeCross console(v1.0.0-rc1)! 161 | Type 'help' or 'h' for help. Type 'quit' or 'q' to quit console. 162 | 163 | ============================================================================================= 164 | [server1]> -h 165 | Error: unsupported command. 166 | 167 | [server1]> help 168 | --------------------------------------------------------------------------------------------- 169 | quit Quit console. 170 | currentServer Show currently connected WeCross server. 171 | listServers List all configured WeCross servers. 172 | switch Switch to a specific WeCross server. 173 | listLocalResources List local resources configured by WeCross server. 174 | listResources List all resources including remote resources. 175 | status Check if the resource exists. 176 | getData Get data from contract. 177 | setData Set data for contract. 178 | call Call constant method of smart contract. 179 | callInt Call constant method of smart contract with int returned. 180 | callIntArray Call constant method of smart contract with int array returned. 181 | callString Call constant method of smart contract with string returned. 182 | callStringArray Call constant method of smart contract with string array returned. 183 | sendTransaction Call non-constant method of smart contract. 184 | sendTransactionInt Call non-constant method of smart contract with int returned. 185 | sendTransactionIntArray Call non-constant method of smart contract with int array returned. 186 | sendTransactionString Call non-constant method of smart contract with string returned. 187 | sendTransactionStringArray Call non-constant method of smart contract with string array returned. 188 | WeCross.getResource Init resource by path, and assign it to a custom variable. 189 | [resource].[command] Equal to command: command [path]. 190 | 191 | --------------------------------------------------------------------------------------------- 192 | ``` 193 | 194 | **框架** 195 | 196 | * 适配WeCross跨连路由v1.0.0-rc1版本 197 | * 集成WeCross Java SDK v1.0.0-rc1版本 198 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](docs/images/menu_logo_wecross.png) 2 | 3 | # WeCross-Console 4 | 5 | [![CodeFactor](https://www.codefactor.io/repository/github/webankblockchain/WeCross-Console/badge)](https://www.codefactor.io/repository/github/webankblockchain/WeCross-Console) [![Build Status](https://travis-ci.org/WeBankBlockchain/WeCross-Console.svg?branch=dev)](https://travis-ci.org/WeBankBlockchain/WeCross-Console) [![Latest release](https://img.shields.io/github/release/WeBankBlockchain/WeCross-Console.svg)](https://github.com/WeBankBlockchain/WeCross-Console/releases/latest) 6 | [![License](https://img.shields.io/github/license/WeBankBlockchain/WeCross-Console)](https://www.apache.org/licenses/LICENSE-2.0) [![Language](https://img.shields.io/badge/Language-Java-blue.svg)](https://www.java.com) 7 | 8 | WeCross Console是[WeCross](https://github.com/WeBankBlockchain/WeCross)的重要交互式客户端工具。 9 | 10 | ## 关键特性 11 | 12 | - 支持交互式命令 13 | - 提供了针对跨链资源的操作命令 14 | 15 | ## 部署使用 16 | 17 | 可直接下载WeCross控制台压缩包,然后解压并使用,具体请参考[部署和使用文档](https://wecross.readthedocs.io/zh_CN/latest/docs/tutorial/networks.html#id7)。 18 | 19 | ## 源码编译 20 | 21 | **环境要求**: 22 | 23 | - [JDK8及以上](https://www.oracle.com/java/technologies/javase-downloads.html) 24 | - Gradle 5.0及以上 25 | 26 | **编译命令**: 27 | 28 | ```bash 29 | $ cd WeCross-Console 30 | $ ./gradlew assemble 31 | ``` 32 | 33 | 如果编译成功,将在当前目录的dist/apps目录下生成控制台jar包。 34 | 35 | ## 项目贡献 36 | 37 | 欢迎参与WeCross社区的维护和建设: 38 | 39 | - 提交代码(Pull requests),可参考[代码贡献流程](CONTRIBUTING.md)以及[wiki指南](https://github.com/WeBankBlockchain/WeCross/wiki/%E8%B4%A1%E7%8C%AE%E4%BB%A3%E7%A0%81) 40 | - [提问和提交BUG](https://github.com/WeBankBlockchain/WeCross/issues/new) 41 | 42 | 您将成为贡献者,感谢各位贡献者的付出: 43 | 44 | https://github.com/WeBankBlockchain/WeCross-Console/graphs/contributors 45 | 46 | ## 开源社区 47 | 48 | 参与meetup:[活动日历](https://github.com/WeBankBlockchain/WeCross/wiki#%E6%B4%BB%E5%8A%A8%E6%97%A5%E5%8E%86) 49 | 50 | 学习知识、讨论方案、开发新特性:[联系微信小助手,加入跨链兴趣小组(CC-SIG)](https://wecross.readthedocs.io/zh_CN/latest/docs/community/cc-sig.html#id3) 51 | 52 | ## License 53 | 54 | WeCross Console的开源协议为Apache License 2.0,详情参考[LICENSE](./LICENSE)。 55 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.github.sherter.google-java-format' version '0.8' 3 | id 'org.ajoberstar.grgit' version '4.0.1' 4 | } 5 | 6 | apply plugin: 'maven' 7 | apply plugin: 'idea' 8 | apply plugin: 'eclipse' 9 | apply plugin: 'java' 10 | apply plugin: 'jacoco' 11 | 12 | group = 'com.webank' 13 | version = '1.4.0' 14 | sourceCompatibility = '1.8' 15 | 16 | repositories { 17 | jcenter() 18 | maven { url "https://maven.aliyun.com/nexus/content/groups/public/" } 19 | maven { url "https://oss.sonatype.org/content/repositories/snapshots" } 20 | mavenCentral() 21 | } 22 | 23 | googleJavaFormat { 24 | options style: 'AOSP' 25 | source = sourceSets*.allJava 26 | include '**/*.java' 27 | exclude '**/temp/*.java' 28 | } 29 | 30 | verifyGoogleJavaFormat { 31 | source = sourceSets*.allJava 32 | include '**/*.java' 33 | exclude '**/temp/*.java' 34 | } 35 | 36 | def log4j_version = '2.22.1' 37 | List logger = [ 38 | "org.apache.logging.log4j:log4j-api:$log4j_version", 39 | "org.apache.logging.log4j:log4j-core:$log4j_version", 40 | "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version", 41 | //"org.apache.logging.log4j:log4j-to-slf4j:$log4j_version", 42 | //"org.apache.logging.log4j:log4j-web:$log4j_version", 43 | //"org.apache.logging.log4j:log4j-jul:$log4j_version" 44 | ] 45 | 46 | dependencies { 47 | compile logger 48 | compile 'org.jline:jline:3.15.0' 49 | compile 'org.codehaus.groovy:groovy-all:3.0.10' 50 | compile 'com.fasterxml.jackson.core:jackson-databind:2.14.3' 51 | compile 'com.webank:wecross-java-sdk:1.4.0' 52 | compile 'org.apache.commons:commons-compress:1.26.0' 53 | compile 'commons-io:commons-io:2.8.0' 54 | compile 'com.moandjiezana.toml:toml4j:0.7.2' 55 | compile 'com.google.code.gson:gson:2.8.9' 56 | // Use JUnit test framework 57 | testImplementation 'junit:junit:4.13.2' 58 | } 59 | 60 | sourceSets { 61 | main { 62 | resources { 63 | exclude 'contracts/*' 64 | } 65 | } 66 | } 67 | configurations.all { 68 | resolutionStrategy.cacheChangingModulesFor 0, 'seconds' 69 | exclude module: "testng" 70 | } 71 | 72 | jar { 73 | destinationDir file('dist/apps') 74 | archiveName project.name + "-" + project.version + '.jar' 75 | exclude '**/*.xml' 76 | exclude '**/*.toml' 77 | exclude '**/*.properties' 78 | exclude '**/*.yml' 79 | exclude '**/*.crt' 80 | exclude '**/*.key' 81 | 82 | manifest { 83 | try { 84 | def repo = grgit.open(dir: file('.').canonicalPath) 85 | if (repo != null) { 86 | def date = new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") 87 | def branch = repo.branch.getCurrent().getName() 88 | def commit = repo.head().getAbbreviatedId(40) 89 | 90 | attributes(["Implementation-Timestamp": date, 91 | "Git-Branch" : branch, 92 | "Git-Commit" : commit 93 | ]) 94 | 95 | logger.info(" Commit : ") 96 | logger.info(" => date: {}", date) 97 | logger.info(" => branch: {}", branch) 98 | logger.info(" => commit: {}", commit) 99 | } 100 | } catch (Exception e) { 101 | // logger.warn(' .git not exist, cannot found commit info') 102 | } 103 | } 104 | 105 | doLast { 106 | copy { 107 | from file('src/main/resources/') 108 | into 'dist/conf' 109 | } 110 | copy { 111 | from configurations.runtime 112 | into 'dist/lib' 113 | } 114 | copy { 115 | from file('.').listFiles().findAll { File f -> (f.name.endsWith('.sh') || f.name.endsWith('.env')) } 116 | into 'dist' 117 | } 118 | copy { 119 | from file('scripts/') 120 | into 'dist' 121 | } 122 | } 123 | } 124 | 125 | test { 126 | testLogging { 127 | showStandardStreams = false 128 | events 'passed', 'skipped', 'failed' 129 | } 130 | } 131 | 132 | jacocoTestReport { 133 | reports { 134 | xml.enabled true 135 | html.enabled false 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /docs/images/menu_logo_wecross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeBankBlockchain/WeCross-Console/d8b8f82c1cd49356d689f2c16288b8c8ebff434d/docs/images/menu_logo_wecross.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeBankBlockchain/WeCross-Console/d8b8f82c1cd49356d689f2c16288b8c8ebff434d/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin or MSYS, switch paths to Windows format before running java 129 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=$((i+1)) 158 | done 159 | case $i in 160 | (0) set -- ;; 161 | (1) set -- "$args0" ;; 162 | (2) set -- "$args0" "$args1" ;; 163 | (3) set -- "$args0" "$args1" "$args2" ;; 164 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=$(save "$@") 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 184 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 185 | cd "$(dirname "$0")" 186 | fi 187 | 188 | exec "$JAVACMD" "$@" 189 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /release_note.txt: -------------------------------------------------------------------------------- 1 | v1.4.0 -------------------------------------------------------------------------------- /scripts/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | dirpath="$(cd "$(dirname "$0")" && pwd)" 3 | cd ${dirpath} 4 | export LANG='zh_CN.utf8' 5 | 6 | APPS_FOLDER=$(pwd)/apps 7 | SECURIY_FILE='./.wecross.security' 8 | 9 | LOG_INFO() { 10 | echo -e "\033[32m$@\033[0m" 11 | } 12 | 13 | LOG_ERROR() { 14 | echo -e "\033[31m$@\033[0m" 15 | } 16 | 17 | create_jvm_security() { 18 | if [[ ! -f ${SECURIY_FILE} ]];then 19 | echo "jdk.disabled.namedCurves = " > ${SECURIY_FILE} 20 | # LOG_INFO "create new file ${SECURIY_FILE}" 21 | fi 22 | } 23 | 24 | show_version() { 25 | LOG_INFO "WeCross-Console version: [" $(ls ${APPS_FOLDER} |awk '{gsub(/.jar$/,""); print}') "]" 26 | } 27 | 28 | run_console() { 29 | if [ "$(uname)" == "Darwin" ]; then 30 | # Mac 31 | java -Dfile.encoding=UTF-8 -Djava.security.properties=${SECURIY_FILE} -Djdk.sunec.disableNative="false" -Djdk.tls.namedGroups="secp256k1,x25519,secp256r1,secp384r1,secp521r1,x448,ffdhe2048,ffdhe3072,ffdhe4096,ffdhe6144,ffdhe8192" -cp 'apps/*:lib/*:conf' com.webank.wecross.console.Shell 32 | elif [ "$(uname -s | grep MINGW | wc -l)" != "0" ]; then 33 | # Windows 34 | java -Dfile.encoding=UTF-8 -Djava.security.properties=${SECURIY_FILE} -Djdk.sunec.disableNative="false" -Djdk.tls.namedGroups="secp256k1,x25519,secp256r1,secp384r1,secp521r1,x448,ffdhe2048,ffdhe3072,ffdhe4096,ffdhe6144,ffdhe8192" -cp 'apps/*;lib/*;conf' com.webank.wecross.console.Shell 35 | else 36 | # GNU/Linux 37 | java -Dfile.encoding=UTF-8 -Djava.security.properties=${SECURIY_FILE} -Djdk.sunec.disableNative="false" -Djdk.tls.namedGroups="secp256k1,x25519,secp256r1,secp384r1,secp521r1,x448,ffdhe2048,ffdhe3072,ffdhe4096,ffdhe6144,ffdhe8192" -cp 'apps/*:lib/*:conf' -Djava.security.egd=file:/dev/./urandom com.webank.wecross.console.Shell 38 | fi 39 | } 40 | 41 | create_jvm_security 42 | show_version 43 | run_console 44 | 45 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'wecross-console' 2 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/Initializer.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console; 2 | 3 | import com.webank.wecross.console.custom.BCOSCommand; 4 | import com.webank.wecross.console.custom.FabricCommand; 5 | import com.webank.wecross.console.exception.ErrorCode; 6 | import com.webank.wecross.console.exception.WeCrossConsoleException; 7 | import com.webank.wecross.console.routine.HTLCFace; 8 | import com.webank.wecross.console.routine.HTLCImpl; 9 | import com.webank.wecross.console.routine.XAFace; 10 | import com.webank.wecross.console.routine.XAImpl; 11 | import com.webank.wecross.console.rpc.RPCFace; 12 | import com.webank.wecross.console.rpc.RPCImpl; 13 | import com.webank.wecrosssdk.exception.WeCrossSDKException; 14 | import com.webank.wecrosssdk.rpc.WeCrossRPC; 15 | import com.webank.wecrosssdk.rpc.WeCrossRPCFactory; 16 | import com.webank.wecrosssdk.rpc.service.WeCrossRPCService; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | public class Initializer { 21 | 22 | private Logger logger = LoggerFactory.getLogger(Initializer.class); 23 | 24 | private WeCrossRPC weCrossRPC; 25 | private RPCFace rpcFace; 26 | private XAFace xaFace; 27 | private HTLCFace htlcFace; 28 | private BCOSCommand bcosCommand; 29 | private FabricCommand fabricCommand; 30 | 31 | public void init() throws WeCrossConsoleException { 32 | WeCrossRPCService weCrossRPCService = new WeCrossRPCService(); 33 | try { 34 | weCrossRPC = WeCrossRPCFactory.build(weCrossRPCService); 35 | } catch (WeCrossSDKException e) { 36 | logger.error("init wecross service failed: {}", e.getMessage()); 37 | throw new WeCrossConsoleException(ErrorCode.INIT_WECROSS_SERVICE_ERROR, e.getMessage()); 38 | } 39 | rpcFace = new RPCImpl(); 40 | rpcFace.setWeCrossRPC(weCrossRPC); 41 | htlcFace = new HTLCImpl(); 42 | htlcFace.setWeCrossRPC(weCrossRPC); 43 | xaFace = new XAImpl(); 44 | xaFace.setWeCrossRPC(weCrossRPC); 45 | bcosCommand = new BCOSCommand(weCrossRPC); 46 | fabricCommand = new FabricCommand(weCrossRPC); 47 | } 48 | 49 | public WeCrossRPC getWeCrossRPC() { 50 | return weCrossRPC; 51 | } 52 | 53 | public void setWeCrossRPC(WeCrossRPC weCrossRPC) { 54 | this.weCrossRPC = weCrossRPC; 55 | } 56 | 57 | public RPCFace getRpcFace() { 58 | return rpcFace; 59 | } 60 | 61 | public void setRpcFace(RPCFace rpcFace) { 62 | this.rpcFace = rpcFace; 63 | } 64 | 65 | public HTLCFace getHtlcFace() { 66 | return htlcFace; 67 | } 68 | 69 | public void setHtlcFace(HTLCFace htlcFace) { 70 | this.htlcFace = htlcFace; 71 | } 72 | 73 | public XAFace getXaFace() { 74 | return xaFace; 75 | } 76 | 77 | public void setXaFace(XAFace xaFace) { 78 | this.xaFace = xaFace; 79 | } 80 | 81 | public BCOSCommand getBcosCommand() { 82 | return bcosCommand; 83 | } 84 | 85 | public void setBcosCommand(BCOSCommand bcosCommand) { 86 | this.bcosCommand = bcosCommand; 87 | } 88 | 89 | public FabricCommand getFabricCommand() { 90 | return fabricCommand; 91 | } 92 | 93 | public void setFabricCommand(FabricCommand fabricCommand) { 94 | this.fabricCommand = fabricCommand; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/common/ConsoleUtils.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.common; 2 | 3 | import com.google.common.collect.BiMap; 4 | import com.google.common.collect.HashBiMap; 5 | import com.webank.wecross.console.exception.ErrorCode; 6 | import com.webank.wecross.console.exception.WeCrossConsoleException; 7 | import java.net.URL; 8 | import java.util.*; 9 | import java.util.regex.Matcher; 10 | import java.util.regex.Pattern; 11 | import java.util.stream.Collectors; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | public class ConsoleUtils { 16 | public static ThreadLocal runtimeUsernameThreadLocal = new ThreadLocal<>(); 17 | public static ThreadLocal runtimePasswordThreadLocal = new ThreadLocal<>(); 18 | 19 | public static final String fabricType = "Fabric1.4"; 20 | public static final String fabricType2 = "Fabric2.0"; 21 | public static final String BCOSType = "BCOS2.0"; 22 | public static final String BCOSGMType = "GM_BCOS2.0"; 23 | public static final String BCOSType3 = "BCOS3_ECDSA_EVM"; 24 | public static final String BCOSGMType3 = "BCOS3_GM_EVM"; 25 | public static final String BCOSWASMType3 = "BCOS3_ECDSA_WASM"; 26 | public static final String BCOSWASMGMType3 = "BCOS3_GM_WASM"; 27 | public static final List bcosChainList = 28 | Arrays.asList( 29 | BCOSType, BCOSGMType, BCOSType3, BCOSGMType3, BCOSWASMType3, BCOSWASMGMType3); 30 | public static final List supportChainList = 31 | Arrays.asList( 32 | fabricType, 33 | BCOSType, 34 | BCOSGMType, 35 | fabricType2, 36 | BCOSType3, 37 | BCOSGMType3, 38 | BCOSWASMType3, 39 | BCOSWASMGMType3); 40 | private static final Logger logger = LoggerFactory.getLogger(ConsoleUtils.class); 41 | 42 | public static boolean isValidPath(String path) { 43 | if (path == null || path.length() == 0 || path.charAt(0) == '.' || path.endsWith(".")) { 44 | return false; 45 | } 46 | String[] unit = path.split("\\."); 47 | if (unit.length == 3) { 48 | String templateUrl = "http://127.0.0.1:8080/" + path.replace('.', '/'); 49 | try { 50 | new URL(templateUrl); 51 | } catch (Exception e) { 52 | return false; 53 | } 54 | return true; 55 | } 56 | return false; 57 | } 58 | 59 | public static boolean isValidPathVar(String path, Map pathMaps) { 60 | return pathMaps.containsKey(path); 61 | } 62 | 63 | public static boolean isNaturalInteger(String seq) { 64 | try { 65 | int s = Integer.parseInt(seq); 66 | return s >= 0; 67 | } catch (Exception e) { 68 | return false; 69 | } 70 | } 71 | 72 | public static boolean isNumeric(String str) { 73 | Pattern p = Pattern.compile("[0-9]*"); 74 | return p.matcher(str).matches(); 75 | } 76 | 77 | // parse variables and save path variables 78 | public static Boolean parseVars( 79 | String[] params, 80 | List resourceVars, 81 | List pathVars, 82 | Map pathMaps) { 83 | int length = params.length; 84 | if (length < 3 || params[0].contains("\"") || params[0].contains("'")) { 85 | return false; 86 | } 87 | if (params[1].equals("=")) { 88 | if (params[2].equals("WeCross.getResource")) { 89 | if (length != 4) { 90 | return false; 91 | } 92 | if (pathMaps.keySet().contains(params[3])) { 93 | resourceVars.add(params[0]); 94 | return true; 95 | } 96 | String path = parseString(params[3]); 97 | if (ConsoleUtils.isValidPath(path)) { 98 | pathVars.add(path); 99 | resourceVars.add(params[0]); 100 | return true; 101 | } 102 | } else { 103 | if (length != 3) { 104 | return false; 105 | } 106 | String path = parseString(params[2]); 107 | if (ConsoleUtils.isValidPath(path)) { 108 | pathVars.add(params[0]); 109 | pathMaps.put(params[0], path); 110 | return true; 111 | } 112 | } 113 | } 114 | return false; 115 | } 116 | 117 | // remove "" or '' of string 118 | public static String parseString(String input) { 119 | int len = input.length(); 120 | if (len < 2) { 121 | return input; 122 | } 123 | if (input.charAt(0) == '\"' && input.charAt(len - 1) == '\"' 124 | || input.charAt(0) == '\'' && input.charAt(len - 1) == '\'') { 125 | return input.substring(1, len - 1); 126 | } 127 | return input; 128 | } 129 | 130 | public static String[] parseArgs(String[] args) { 131 | String[] result = new String[args.length]; 132 | for (int i = 0; i < args.length; i++) { 133 | result[i] = parseString(args[i]); 134 | } 135 | return result; 136 | } 137 | 138 | public static void printJson(String jsonStr) { 139 | System.out.println(formatJson(jsonStr)); 140 | } 141 | 142 | public static String formatJson(String jsonStr) { 143 | if (null == jsonStr || "".equals(jsonStr)) { 144 | return ""; 145 | } 146 | jsonStr = jsonStr.replace("\\n", ""); 147 | StringBuilder sb = new StringBuilder(); 148 | char last = '\0'; 149 | char current = '\0'; 150 | int indent = 0; 151 | boolean isInQuotationMarks = false; 152 | for (int i = 0; i < jsonStr.length(); i++) { 153 | last = current; 154 | current = jsonStr.charAt(i); 155 | switch (current) { 156 | case '"': 157 | if (last != '\\') { 158 | isInQuotationMarks = !isInQuotationMarks; 159 | } 160 | sb.append(current); 161 | break; 162 | case '{': 163 | case '[': 164 | sb.append(current); 165 | if (!isInQuotationMarks) { 166 | sb.append('\n'); 167 | indent++; 168 | addIndentBlank(sb, indent); 169 | } 170 | break; 171 | case '}': 172 | case ']': 173 | if (!isInQuotationMarks) { 174 | sb.append('\n'); 175 | indent--; 176 | addIndentBlank(sb, indent); 177 | } 178 | sb.append(current); 179 | break; 180 | case ',': 181 | sb.append(current); 182 | if (last != '\\' && !isInQuotationMarks) { 183 | sb.append('\n'); 184 | addIndentBlank(sb, indent); 185 | } 186 | break; 187 | case ' ': 188 | if (',' != jsonStr.charAt(i - 1)) { 189 | sb.append(current); 190 | } 191 | break; 192 | case '\\': 193 | break; 194 | default: 195 | if (!(current == " ".charAt(0))) sb.append(current); 196 | } 197 | } 198 | return sb.toString(); 199 | } 200 | 201 | private static void addIndentBlank(StringBuilder sb, int indent) { 202 | for (int i = 0; i < indent; i++) { 203 | sb.append(" "); 204 | } 205 | } 206 | 207 | public static String parsePath(String[] params, Map pathMaps) { 208 | String path = parseString(params[1]); 209 | if (!isValidPath(path)) { 210 | if (!isValidPathVar(params[1], pathMaps)) { 211 | System.out.println("Please provide a valid path"); 212 | return null; 213 | } 214 | path = pathMaps.get(params[1]); 215 | } 216 | return path; 217 | } 218 | 219 | public static String[] tokenizeCommand(String line) { 220 | // example: callByCNS HelloWorld.sol set"Hello" parse [callByCNS, HelloWorld.sol, 221 | // set"Hello"] 222 | 223 | BiMap tokens = HashBiMap.create(); 224 | 225 | tokens.put('"', '"'); 226 | tokens.put('\'', '\''); 227 | tokens.put('{', '}'); 228 | tokens.put('[', ']'); 229 | tokens.put('(', ')'); 230 | 231 | String trimLine = line.trim(); 232 | 233 | LinkedList items = new LinkedList(); 234 | items.add(new StringBuffer()); 235 | 236 | boolean isEscape = false; 237 | Stack tokenStack = new Stack(); 238 | 239 | for (int i = 0; i < trimLine.length(); ++i) { 240 | Character c = trimLine.charAt(i); 241 | 242 | if (!isEscape) { 243 | if (c == '\\') { 244 | isEscape = true; 245 | continue; 246 | } 247 | 248 | if ((c == ' ' || c == '\t') && tokenStack.isEmpty()) { 249 | if (items.getLast().length() > 0) { 250 | items.add(new StringBuffer()); 251 | } 252 | 253 | continue; 254 | } 255 | 256 | Character token = tokens.get(c); 257 | if (token == null) { 258 | token = tokens.inverse().get(c); 259 | } 260 | 261 | if (token != null) { 262 | if (!tokenStack.isEmpty() && tokenStack.peek().equals(token)) { 263 | tokenStack.pop(); 264 | } else { 265 | tokenStack.add(c); 266 | } 267 | } 268 | } 269 | 270 | items.getLast().append(c); 271 | } 272 | 273 | return items.stream() 274 | .map(StringBuffer::toString) 275 | .collect(Collectors.toList()) 276 | .toArray(new String[] {}); 277 | } 278 | 279 | public static String parseCommand(String[] params) throws WeCrossConsoleException { 280 | StringBuilder result = new StringBuilder(); 281 | boolean isArgs = false; 282 | int length = params.length; 283 | int start = 0; 284 | if (length != 0) { 285 | if (params[0].endsWith(".call") || params[0].endsWith(".sendTransaction")) { 286 | isArgs = true; 287 | if (length < 2) { 288 | throw new WeCrossConsoleException( 289 | ErrorCode.METHOD_MISSING, "Method is missing"); 290 | } 291 | start = 1; 292 | result = new StringBuilder(params[0] + " "); 293 | } else if (params[0].endsWith(".status") || params[0].endsWith(".detail")) { 294 | if (length != 1) { 295 | throw new WeCrossConsoleException( 296 | ErrorCode.ILLEGAL_PARAM, "Redundant parameters"); 297 | } 298 | result = new StringBuilder(params[0] + "()"); 299 | return result.toString(); 300 | } else if (length > 3 && params[2].equals("WeCross.getResource")) { 301 | if (length != 4) { 302 | throw new WeCrossConsoleException( 303 | ErrorCode.ILLEGAL_PARAM, "Parameter:q error: [path]"); 304 | } 305 | result = new StringBuilder(params[0] + " " + params[1] + " " + params[2] + " "); 306 | String path = params[3]; 307 | if (ConsoleUtils.isValidPath(parseString(params[3]))) { 308 | path = "\"" + path + "\""; 309 | } 310 | result.append(path); 311 | return result.toString(); 312 | } 313 | for (; start < length; ++start) { 314 | String temp = parseString(params[start]); 315 | if (!isArgs && ConsoleUtils.isValidPath(temp)) { 316 | result.append("\"").append(temp).append("\"").append(" "); 317 | } else if (isArgs) { 318 | result.append("\"").append(parseString(params[start])).append("\"").append(","); 319 | } else { 320 | result.append(params[start]).append(" "); 321 | } 322 | } 323 | result = new StringBuilder(result.substring(0, result.length() - 1)); 324 | } 325 | // System.out.println(result); 326 | return result.toString(); 327 | } 328 | 329 | public static List parseArrayInParams(String params) { 330 | // pathString => paths[] 331 | List pathList = new ArrayList<>(); 332 | // [a.b.c] or [a.b.c,a.b.d] 333 | Pattern pattern = 334 | Pattern.compile( 335 | "^\\[(([\\u4e00-\\u9fa5\\w-]+\\.){2}[\\u4e00-\\u9fa5\\w-]+\\,){0,}(([\\u4e00-\\u9fa5\\w-]+\\.){2}[\\u4e00-\\u9fa5\\w-]+)\\]$"); 336 | Matcher matcher = pattern.matcher(params); 337 | if (matcher.find()) { 338 | String pathString = params.substring(1, params.length() - 1); 339 | pathString = pathString.replaceAll(" ", ""); 340 | Collections.addAll(pathList, pathString.split(",")); 341 | } 342 | return pathList; 343 | } 344 | 345 | public static void singleLine() { 346 | System.out.println( 347 | "---------------------------------------------------------------------------------------------"); 348 | } 349 | 350 | public static void doubleLine() { 351 | System.out.println( 352 | "============================================================================================="); 353 | } 354 | } 355 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/common/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.common; 2 | 3 | import com.moandjiezana.toml.Toml; 4 | import com.moandjiezana.toml.TomlWriter; 5 | import com.webank.wecross.console.exception.ErrorCode; 6 | import com.webank.wecross.console.exception.WeCrossConsoleException; 7 | import com.webank.wecross.console.routine.XAFace; 8 | import com.webank.wecrosssdk.rpc.common.TransactionContext; 9 | import java.io.File; 10 | import java.io.FileWriter; 11 | import java.io.IOException; 12 | import java.nio.charset.StandardCharsets; 13 | import java.nio.file.Files; 14 | import java.nio.file.Path; 15 | import java.nio.file.Paths; 16 | import java.util.Base64; 17 | import java.util.List; 18 | import java.util.Scanner; 19 | import java.util.Set; 20 | import java.util.regex.Matcher; 21 | import java.util.regex.Pattern; 22 | import org.jline.reader.Completer; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 26 | 27 | public class FileUtils { 28 | 29 | public static final String TRANSACTION_LOG_TOML = "transactionLog.toml"; 30 | public static final String CONF = "conf"; 31 | private static final Logger logger = LoggerFactory.getLogger(FileUtils.class); 32 | 33 | public static Toml getToml(String fileName) throws WeCrossConsoleException { 34 | try { 35 | Path path; 36 | if (fileName.indexOf("classpath:") != 0) { 37 | path = Paths.get(fileName); 38 | } else { 39 | PathMatchingResourcePatternResolver resolver = 40 | new PathMatchingResourcePatternResolver(); 41 | if (!resolver.getResource(fileName).exists()) { 42 | throw new WeCrossConsoleException( 43 | ErrorCode.TX_LOG_NOT_EXIST, 44 | TRANSACTION_LOG_TOML + " doesn't exist, clean transaction context."); 45 | } 46 | path = Paths.get(resolver.getResource(fileName).getURI()); 47 | } 48 | return new Toml().read(path.toFile()); 49 | } catch (IOException e) { 50 | throw new WeCrossConsoleException( 51 | ErrorCode.INTERNAL_ERROR, 52 | "Something wrong with parsing " + fileName + ": " + e); 53 | } 54 | } 55 | 56 | public static String mergeSource( 57 | String currentDir, 58 | String sourceFile, 59 | PathMatchingResourcePatternResolver resolver, 60 | Set dependencies) 61 | throws Exception { 62 | StringBuffer sourceBuffer = new StringBuffer(); 63 | 64 | String fullPath = currentDir + sourceFile; 65 | String dir = fullPath.substring(0, fullPath.lastIndexOf(File.separator)) + File.separator; 66 | 67 | org.springframework.core.io.Resource sourceResource = 68 | resolver.getResource("file:" + fullPath); 69 | if (!sourceResource.exists()) { 70 | logger.error("Source file: {} not found!", fullPath); 71 | 72 | throw new IOException("Source file:" + fullPath + " not found"); 73 | } 74 | 75 | Pattern pattern = Pattern.compile("^\\s*import\\s+[\"'](.+)[\"']\\s*;\\s*$"); 76 | try (Scanner scanner = new Scanner(sourceResource.getInputStream(), "UTF-8")) { 77 | while (scanner.hasNextLine()) { 78 | String line = scanner.nextLine(); 79 | if (line.contains("pragma experimental ABIEncoderV2;")) { 80 | if (!dependencies.contains("pragma experimental ABIEncoderV2;")) { 81 | dependencies.add("pragma experimental ABIEncoderV2;"); 82 | sourceBuffer.append(line); 83 | sourceBuffer.append(System.lineSeparator()); 84 | } 85 | continue; 86 | } 87 | 88 | Matcher matcher = pattern.matcher(line); 89 | if (matcher.find()) { 90 | String depSourcePath = matcher.group(1); 91 | String nextPath = dir + depSourcePath; 92 | if (!dependencies.contains(nextPath)) { 93 | dependencies.add(nextPath); 94 | sourceBuffer.append( 95 | mergeSource(dir, depSourcePath, resolver, dependencies)); 96 | } 97 | } else { 98 | sourceBuffer.append(line); 99 | sourceBuffer.append(System.lineSeparator()); 100 | } 101 | } 102 | } 103 | 104 | return sourceBuffer.toString(); 105 | } 106 | 107 | public static String readFileContent(String fileName) throws IOException { 108 | try { 109 | // to avoid path manipulation 110 | fileName = fileName.replace("..", ""); 111 | Path path; 112 | 113 | if (fileName.indexOf("classpath:") != 0) { 114 | path = Paths.get(fileName); 115 | } else { 116 | // Start with "classpath:" 117 | PathMatchingResourcePatternResolver resolver = 118 | new PathMatchingResourcePatternResolver(); 119 | path = Paths.get(resolver.getResource(fileName).getURI()); 120 | } 121 | return new String(Files.readAllBytes(path)); 122 | } catch (Exception e) { 123 | logger.error("Read file error: ", e); 124 | throw new IOException("Read file error: " + e); 125 | } 126 | } 127 | 128 | public static String readFileContentToHexString(String fileName) throws IOException { 129 | try { 130 | // to avoid path manipulation 131 | fileName = fileName.replace("..", ""); 132 | Path path; 133 | 134 | if (fileName.indexOf("classpath:") != 0) { 135 | path = Paths.get(fileName); 136 | } else { 137 | // Start with "classpath:" 138 | PathMatchingResourcePatternResolver resolver = 139 | new PathMatchingResourcePatternResolver(); 140 | path = Paths.get(resolver.getResource(fileName).getURI()); 141 | } 142 | return byteArrayToHex(Files.readAllBytes(path)); 143 | } catch (Exception e) { 144 | logger.error("Read file error: ", e); 145 | throw new IOException("Read file error: " + e); 146 | } 147 | } 148 | 149 | public static String readFileToBytesString(String filePath) throws Exception { 150 | String content = readFileContent(filePath); 151 | return Base64.getEncoder().encodeToString(content.getBytes(StandardCharsets.UTF_8)); 152 | } 153 | 154 | static String byteArrayToHex(byte[] bytes) { 155 | StringBuilder result = new StringBuilder(); 156 | for (int index = 0, len = bytes.length; index <= len - 1; index += 1) { 157 | int char1 = ((bytes[index] >> 4) & 0xF); 158 | char chara1 = Character.forDigit(char1, 16); 159 | int char2 = ((bytes[index]) & 0xF); 160 | char chara2 = Character.forDigit(char2, 16); 161 | result.append(chara1); 162 | result.append(chara2); 163 | } 164 | return result.toString(); 165 | } 166 | 167 | public static String getTransactionID(Toml toml) throws WeCrossConsoleException { 168 | String transactionID = toml.getString("transactionID"); 169 | if (transactionID == null) { 170 | String errorMessage = 171 | "Something wrong with parsing [transactionID], please check configuration"; 172 | throw new WeCrossConsoleException(ErrorCode.INVALID_TXID, errorMessage); 173 | } 174 | 175 | return transactionID; 176 | } 177 | 178 | public static List getTransactionPath(Toml toml) throws WeCrossConsoleException { 179 | List transactionPath = toml.getList("paths"); 180 | if (transactionPath == null) { 181 | String errorMessage = 182 | "Something wrong with parsing [paths], please check configuration"; 183 | throw new WeCrossConsoleException(ErrorCode.INVALID_PATH, errorMessage); 184 | } 185 | 186 | return transactionPath; 187 | } 188 | 189 | public static void loadTransactionLog(List completers, XAFace xaFace) { 190 | try { 191 | Toml toml = getToml("classpath:" + TRANSACTION_LOG_TOML); 192 | String transactionID = getTransactionID(toml); 193 | List transactionPath = getTransactionPath(toml); 194 | 195 | if (!xaFace.isTransactionInfoExist( 196 | transactionID, transactionPath.toArray(new String[0]))) { 197 | logger.error( 198 | "loadTransactionLog error: the transaction in toml file had already been committed/rollbacked or even doesn't exist."); 199 | FileUtils.cleanFile(FileUtils.CONF, FileUtils.TRANSACTION_LOG_TOML); 200 | return; 201 | } 202 | TransactionContext.txThreadLocal.set(transactionID); 203 | TransactionContext.pathInTransactionThreadLocal.set(transactionPath); 204 | } catch (WeCrossConsoleException e) { 205 | if (e.getErrorCode() == ErrorCode.TX_LOG_NOT_EXIST) { 206 | logger.info("Load transactionLog Toml file fail, {}", e.getMessage()); 207 | } else { 208 | logger.warn("Load transactionLog Toml file fail, error: {}.", e.getMessage()); 209 | } 210 | } catch (Exception e) { 211 | logger.warn("Load transactionLog Toml file fail, error: {}", e.getMessage()); 212 | } 213 | } 214 | 215 | public static void writeTransactionLog() { 216 | TomlWriter writer = new TomlWriter(); 217 | TransactionInfo transactionInfo = 218 | new TransactionInfo( 219 | TransactionContext.currentXATransactionID(), 220 | TransactionContext.pathInTransactionThreadLocal.get()); 221 | try { 222 | writer.write(transactionInfo, new File(CONF, TRANSACTION_LOG_TOML)); 223 | } catch (IOException e) { 224 | logger.error("Write TransactionLogTOML file error: {}", e.getMessage()); 225 | } 226 | } 227 | 228 | public static void cleanFile(String prefix, String filename) throws WeCrossConsoleException { 229 | File file = new File(prefix, filename); 230 | if (!file.exists()) { 231 | logger.error("Cannot find file: {}", filename); 232 | return; 233 | } 234 | if (!file.delete()) { 235 | logger.error("Cannot delete file: {}", filename); 236 | throw new WeCrossConsoleException( 237 | ErrorCode.INTERNAL_ERROR, "Cannot delete file: " + filename); 238 | } 239 | } 240 | 241 | public static void writeFile(String fileName, String content, boolean append) 242 | throws WeCrossConsoleException { 243 | try (FileWriter writer = new FileWriter(fileName, append)) { 244 | writer.write(content + "\n"); 245 | } catch (IOException e) { 246 | throw new WeCrossConsoleException( 247 | ErrorCode.INTERNAL_ERROR, "Load file " + fileName + " fail, error: " + e); 248 | } 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/common/Hash.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.common; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | import java.security.MessageDigest; 5 | import java.security.NoSuchAlgorithmException; 6 | import java.security.SecureRandom; 7 | 8 | public class Hash { 9 | public String getRandom(int numBytes) { 10 | SecureRandom random = new SecureRandom(); 11 | return bytesToHex(random.generateSeed(numBytes)); 12 | } 13 | 14 | public String sha256(String msg) throws NoSuchAlgorithmException { 15 | MessageDigest messageDigest; 16 | String encodestr; 17 | messageDigest = MessageDigest.getInstance("SHA-256"); 18 | messageDigest.update(msg.getBytes(StandardCharsets.UTF_8)); 19 | encodestr = bytesToHex(messageDigest.digest()); 20 | return encodestr; 21 | } 22 | 23 | private String bytesToHex(byte[] bytes) { 24 | StringBuilder stringBuffer = new StringBuilder(); 25 | String temp; 26 | for (int i = 0; i < bytes.length; i++) { 27 | temp = Integer.toHexString(bytes[i] & 0xFF); 28 | if (temp.length() == 1) { 29 | stringBuffer.append("0"); 30 | } 31 | stringBuffer.append(temp); 32 | } 33 | return stringBuffer.toString(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/common/IgnoreCaseCompleter.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.common; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Collection; 6 | import java.util.Iterator; 7 | import java.util.List; 8 | import org.jline.reader.Buffer; 9 | import org.jline.reader.Candidate; 10 | import org.jline.reader.Completer; 11 | import org.jline.reader.LineReader; 12 | import org.jline.reader.ParsedLine; 13 | import org.jline.utils.AttributedString; 14 | 15 | public class IgnoreCaseCompleter implements Completer { 16 | 17 | protected final Collection candidates = new ArrayList<>(); 18 | 19 | public IgnoreCaseCompleter() {} 20 | 21 | public IgnoreCaseCompleter(String... strings) { 22 | this(Arrays.asList(strings)); 23 | } 24 | 25 | public IgnoreCaseCompleter(Iterable strings) { 26 | assert strings != null; 27 | for (String string : strings) { 28 | candidates.add( 29 | new Candidate( 30 | AttributedString.stripAnsi(string), 31 | string, 32 | null, 33 | null, 34 | null, 35 | null, 36 | true)); 37 | } 38 | } 39 | 40 | public IgnoreCaseCompleter(Candidate... candidates) { 41 | assert candidates != null; 42 | this.candidates.addAll(Arrays.asList(candidates)); 43 | } 44 | 45 | public void complete( 46 | LineReader reader, final ParsedLine commandLine, final List candidates) { 47 | assert commandLine != null; 48 | assert candidates != null; 49 | 50 | Buffer buffer = reader.getBuffer(); 51 | String start = (buffer == null) ? "" : buffer.toString(); 52 | int index = start.lastIndexOf(" "); 53 | String tmp = start.substring(index + 1).toLowerCase(); 54 | 55 | for (Iterator iter = this.candidates.iterator(); iter.hasNext(); ) { 56 | Candidate candidate = iter.next(); 57 | String candidateStr = candidate.value().toLowerCase(); 58 | if (candidateStr.startsWith(tmp)) { 59 | candidates.add(candidate); 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/common/JlineUtils.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.common; 2 | 3 | import java.io.IOException; 4 | import java.nio.file.Paths; 5 | import java.util.*; 6 | import org.jline.builtins.Completers.DirectoriesCompleter; 7 | import org.jline.builtins.Completers.FilesCompleter; 8 | import org.jline.reader.Completer; 9 | import org.jline.reader.LineReader; 10 | import org.jline.reader.LineReaderBuilder; 11 | import org.jline.reader.impl.completer.AggregateCompleter; 12 | import org.jline.reader.impl.completer.ArgumentCompleter; 13 | import org.jline.reader.impl.completer.NullCompleter; 14 | import org.jline.reader.impl.completer.StringsCompleter; 15 | import org.jline.terminal.Attributes; 16 | import org.jline.terminal.Attributes.ControlChar; 17 | import org.jline.terminal.Terminal; 18 | import org.jline.terminal.TerminalBuilder; 19 | 20 | public class JlineUtils { 21 | 22 | private static Set paths = new HashSet<>(); 23 | private static Set pathVars = new HashSet<>(); 24 | private static Set resourceVars = new HashSet<>(); 25 | private static Set contractMethods = new HashSet<>(); 26 | private static Set orgs = new HashSet<>(); 27 | private static final List pathVarSupportedCommands = 28 | Arrays.asList("detail", "call", "sendTransaction"); 29 | 30 | private static final List callContractCommands = 31 | Arrays.asList("call", "sendTransaction"); 32 | 33 | private static final List pathVarNotSupportedCommands = 34 | Arrays.asList( 35 | "bcosDeploy", 36 | "bcosRegister", 37 | "fabricInstall", 38 | "fabricInstantiate", 39 | "fabricUpgrade", 40 | "login", 41 | "registerAccount", 42 | "logout", 43 | "addChainAccount", 44 | "setDefaultAccount"); 45 | 46 | private static final List fabricCommands = 47 | Arrays.asList("fabricInstall", "fabricInstantiate", "fabricUpgrade"); 48 | 49 | private static final List bcosCommands = Arrays.asList("bcosDeploy", "bcosRegister"); 50 | 51 | private static final List allCommands = 52 | Arrays.asList( 53 | "help", 54 | "quit", 55 | "supportedStubs", 56 | "listAccount", 57 | "listLocalResources", 58 | "listResources", 59 | "detail", 60 | "call", 61 | "invoke", 62 | "sendTransaction", 63 | "newHTLCProposal", 64 | "genTimelock", 65 | "checkTransferStatus", 66 | "genSecretAndHash", 67 | "callTransaction", 68 | "execTransaction", 69 | "startTransaction", 70 | "commitTransaction", 71 | "rollbackTransaction", 72 | "getXATransaction", 73 | "listXATransactions", 74 | "loadTransaction", 75 | "bcosDeploy", 76 | "bcosRegister", 77 | "fabricInstall", 78 | "fabricInstantiate", 79 | "fabricUpgrade", 80 | "login", 81 | "registerAccount", 82 | "logout", 83 | "getBlock", 84 | "addChainAccount", 85 | "setDefaultAccount", 86 | "setDefaultChainAccount", 87 | "getCurrentTransactionID"); 88 | 89 | public static void addCommandCompleters(List completers) { 90 | // commands 91 | for (String command : allCommands) { 92 | completers.add( 93 | new ArgumentCompleter( 94 | new IgnoreCaseCompleter(command), NullCompleter.INSTANCE)); 95 | } 96 | } 97 | 98 | public static List getNoAuthCompleters() { 99 | List completers = new ArrayList<>(); 100 | addCommandCompleters(completers); 101 | return completers; 102 | } 103 | 104 | public static void updateCompleters( 105 | List completers, 106 | Set paths, 107 | Set resourceVars, 108 | Set pathVars) { 109 | if (!completers.isEmpty()) { 110 | completers.clear(); 111 | } 112 | 113 | JlineUtils.paths.addAll(paths); 114 | JlineUtils.pathVars.addAll(pathVars); 115 | JlineUtils.resourceVars.addAll(resourceVars); 116 | 117 | addCommandCompleters(completers); 118 | addPathsCompleters(completers, paths); 119 | addVarsCompleters(completers, resourceVars, pathVars); 120 | 121 | ArgumentCompleter argumentCompleter1 = 122 | new ArgumentCompleter( 123 | new StringsCompleter(), 124 | new StringsCompleter("="), 125 | new StringsCompleter("WeCross.getResource"), 126 | NullCompleter.INSTANCE); 127 | argumentCompleter1.setStrict(false); 128 | completers.add(argumentCompleter1); 129 | 130 | ArgumentCompleter addChainAccountCompleter = 131 | new ArgumentCompleter( 132 | new StringsCompleter("addChainAccount"), 133 | new StringsCompleter(ConsoleUtils.supportChainList), 134 | new FilesCompleter(Paths.get(System.getProperty("user.dir")), true), 135 | new FilesCompleter(Paths.get(System.getProperty("user.dir")), true), 136 | NullCompleter.INSTANCE); 137 | completers.add(addChainAccountCompleter); 138 | 139 | ArgumentCompleter setDefaultAccountCompleter = 140 | new ArgumentCompleter( 141 | new StringsCompleter("setDefaultAccount"), 142 | new StringsCompleter(ConsoleUtils.supportChainList), 143 | NullCompleter.INSTANCE); 144 | completers.add(setDefaultAccountCompleter); 145 | 146 | ArgumentCompleter setDefaultChainAccountCompleter = 147 | new ArgumentCompleter( 148 | new StringsCompleter("setDefaultChainAccount"), 149 | new StringsCompleter(ConsoleUtils.supportChainList), 150 | NullCompleter.INSTANCE); 151 | completers.add(setDefaultChainAccountCompleter); 152 | } 153 | 154 | public static void addPathsCompleters(List completers, Set paths) { 155 | for (String path : paths) { 156 | addPathCompleters(completers, path); 157 | } 158 | } 159 | 160 | public static void addVarsCompleters( 161 | List completers, Set resourceVars, Set pathVars) { 162 | 163 | for (String var : resourceVars) { 164 | addResourceVarCompleters(completers, var); 165 | } 166 | 167 | for (String var : pathVars) { 168 | addPathVarCompleters(completers, var); 169 | } 170 | } 171 | 172 | public static void updatePathsCompleters(List completers, Set paths) { 173 | for (String path : paths) { 174 | if (!JlineUtils.paths.contains(path)) { 175 | addPathCompleters(completers, path); 176 | } 177 | } 178 | } 179 | 180 | public static void addPathCompleters(List completers, String path) { 181 | JlineUtils.paths.add(path); 182 | 183 | ArgumentCompleter argumentCompleter1 = 184 | new ArgumentCompleter( 185 | new StringsCompleter(), 186 | new StringsCompleter("="), 187 | new StringsCompleter(path), 188 | NullCompleter.INSTANCE); 189 | argumentCompleter1.setStrict(false); 190 | completers.add(argumentCompleter1); 191 | 192 | ArgumentCompleter argumentCompleter2 = 193 | new ArgumentCompleter( 194 | new StringsCompleter(), 195 | new StringsCompleter("="), 196 | new StringsCompleter("WeCross.getResource"), 197 | new StringsCompleter(path), 198 | NullCompleter.INSTANCE); 199 | argumentCompleter2.setStrict(false); 200 | completers.add(argumentCompleter2); 201 | 202 | completers.add( 203 | new ArgumentCompleter( 204 | new StringsCompleter(pathVarSupportedCommands), 205 | new StringsCompleter(path), 206 | NullCompleter.INSTANCE)); 207 | 208 | completers.add( 209 | new ArgumentCompleter( 210 | new StringsCompleter(pathVarNotSupportedCommands), 211 | new StringsCompleter(path), 212 | NullCompleter.INSTANCE)); 213 | 214 | ArgumentCompleter bcosArgumentCompleter = 215 | new ArgumentCompleter( 216 | new StringsCompleter(bcosCommands), 217 | new StringsCompleter(path), 218 | new FilesCompleter(Paths.get(System.getProperty("user.dir"), "conf")), 219 | NullCompleter.INSTANCE); 220 | completers.add(bcosArgumentCompleter); 221 | 222 | ArgumentCompleter fabricArgumentCompleter = 223 | new ArgumentCompleter( 224 | new StringsCompleter(fabricCommands), 225 | new StringsCompleter(path), 226 | new StringsCompleter(orgs), 227 | new DirectoriesCompleter(Paths.get(System.getProperty("user.dir"), "conf")), 228 | new StringsCompleter(), 229 | new StringsCompleter("GO_LANG", "JAVA"), 230 | NullCompleter.INSTANCE); 231 | fabricArgumentCompleter.setStrict(false); 232 | completers.add(fabricArgumentCompleter); 233 | } 234 | 235 | public static void addResourceVarCompleters(List completers, String resourceVar) { 236 | completers.add( 237 | new ArgumentCompleter( 238 | new StringsCompleter(resourceVar + ".call"), NullCompleter.INSTANCE)); 239 | completers.add( 240 | new ArgumentCompleter( 241 | new StringsCompleter(resourceVar + ".sendTransaction"), 242 | NullCompleter.INSTANCE)); 243 | 244 | completers.add( 245 | new ArgumentCompleter( 246 | new StringsCompleter(resourceVar + ".detail"), NullCompleter.INSTANCE)); 247 | } 248 | 249 | public static void addPathVarCompleters(List completers, String pathVar) { 250 | ArgumentCompleter argumentCompleter2 = 251 | new ArgumentCompleter( 252 | new StringsCompleter(), 253 | new StringsCompleter("="), 254 | new StringsCompleter("WeCross.getResource"), 255 | new StringsCompleter(pathVar), 256 | NullCompleter.INSTANCE); 257 | argumentCompleter2.setStrict(false); 258 | completers.add(argumentCompleter2); 259 | 260 | completers.add( 261 | new ArgumentCompleter( 262 | new StringsCompleter(pathVarSupportedCommands), 263 | new StringsCompleter(pathVar), 264 | NullCompleter.INSTANCE)); 265 | } 266 | 267 | public static void addOrgCompleters(List completers, String org) { 268 | if (!JlineUtils.orgs.contains(org)) { 269 | JlineUtils.orgs.add(org); 270 | completers.add( 271 | new ArgumentCompleter( 272 | new StringsCompleter(fabricCommands), 273 | new StringsCompleter(paths), 274 | new StringsCompleter(org), 275 | new DirectoriesCompleter( 276 | Paths.get(System.getProperty("user.dir"), "conf"), true), 277 | new StringsCompleter(contractMethods), 278 | NullCompleter.INSTANCE)); 279 | } 280 | } 281 | 282 | public static void addContractMethodCompleters( 283 | List completers, String contractMethod) { 284 | if (!JlineUtils.contractMethods.contains(contractMethod)) { 285 | JlineUtils.contractMethods.add(contractMethod); 286 | completers.add( 287 | new ArgumentCompleter( 288 | new StringsCompleter(callContractCommands), 289 | new StringsCompleter(paths), 290 | new StringsCompleter(contractMethod), 291 | NullCompleter.INSTANCE)); 292 | } 293 | } 294 | 295 | public static LineReader getLineReader(List completers) throws IOException { 296 | 297 | Terminal terminal = 298 | TerminalBuilder.builder() 299 | .nativeSignals(true) 300 | .signalHandler(Terminal.SignalHandler.SIG_IGN) 301 | .build(); 302 | Attributes termAttribs = terminal.getAttributes(); 303 | 304 | // disable CTRL+D shortcut to exit 305 | // disable CTRL+C shortcut 306 | termAttribs.setControlChar(ControlChar.VEOF, 0); 307 | termAttribs.setControlChar(ControlChar.VINTR, 0); 308 | 309 | terminal.setAttributes(termAttribs); 310 | return LineReaderBuilder.builder() 311 | .terminal(terminal) 312 | .completer(new AggregateCompleter(completers)) 313 | .build() 314 | .option(LineReader.Option.HISTORY_IGNORE_SPACE, false) 315 | .option(LineReader.Option.HISTORY_REDUCE_BLANKS, false); 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/common/PrintUtils.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.common; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.webank.wecross.console.exception.ErrorCode; 5 | import com.webank.wecross.console.exception.WeCrossConsoleException; 6 | import com.webank.wecrosssdk.common.StatusCode; 7 | import com.webank.wecrosssdk.rpc.common.TransactionContext; 8 | import com.webank.wecrosssdk.rpc.methods.response.*; 9 | import java.util.Arrays; 10 | import java.util.List; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | public class PrintUtils { 15 | private static Logger logger = LoggerFactory.getLogger(PrintUtils.class); 16 | 17 | public static void printTransactionResponse(TransactionResponse response, boolean isCall) 18 | throws WeCrossConsoleException { 19 | if (response == null) { 20 | throw new WeCrossConsoleException(ErrorCode.NO_RESPONSE, "Error: no response"); 21 | } else if (response.getErrorCode() != StatusCode.SUCCESS) { 22 | throw new WeCrossConsoleException( 23 | ErrorCode.INTERNAL_ERROR, 24 | "Error: code(" 25 | + response.getErrorCode() 26 | + "), message(" 27 | + response.getMessage() 28 | + ")"); 29 | } else if (response.getReceipt().getErrorCode() != StatusCode.SUCCESS) { 30 | logger.warn("TxError: " + response.getReceipt().toString()); 31 | throw new WeCrossConsoleException( 32 | ErrorCode.INTERNAL_ERROR, 33 | "Error: code(" 34 | + response.getReceipt().getErrorCode() 35 | + "), message(" 36 | + response.getReceipt().getMessage() 37 | + ")"); 38 | } else { 39 | if (!isCall) { 40 | System.out.println("Txhash : " + response.getReceipt().getHash()); 41 | System.out.println("BlockNum: " + response.getReceipt().getBlockNumber()); 42 | System.out.println( 43 | "Result : " + stringArraysToString(response.getReceipt().getResult())); 44 | } else { 45 | System.out.println( 46 | "Result : " + stringArraysToString(response.getReceipt().getResult())); 47 | } 48 | } 49 | } 50 | 51 | public static void printRoutineResponse(XAResponse response) throws WeCrossConsoleException { 52 | if (response == null) { 53 | throw new WeCrossConsoleException(ErrorCode.NO_RESPONSE, "Error: no response"); 54 | } else if (response.getErrorCode() != StatusCode.SUCCESS) { 55 | TransactionContext.txThreadLocal.remove(); 56 | TransactionContext.pathInTransactionThreadLocal.remove(); 57 | FileUtils.cleanFile(FileUtils.CONF, FileUtils.TRANSACTION_LOG_TOML); 58 | throw new WeCrossConsoleException( 59 | ErrorCode.INTERNAL_ERROR, 60 | "Error: code(" 61 | + response.getErrorCode() 62 | + "), message(" 63 | + response.getMessage() 64 | + ")"); 65 | } else if (response.getXARawResponse().getStatus() != StatusCode.SUCCESS) { 66 | TransactionContext.txThreadLocal.remove(); 67 | TransactionContext.pathInTransactionThreadLocal.remove(); 68 | FileUtils.cleanFile(FileUtils.CONF, FileUtils.TRANSACTION_LOG_TOML); 69 | throw new WeCrossConsoleException( 70 | ErrorCode.INTERNAL_ERROR, 71 | Arrays.toString(response.getXARawResponse().getChainErrorMessages().toArray())); 72 | } else { 73 | System.out.println("Result: success!"); 74 | } 75 | } 76 | 77 | public static void printRollbackResponse(XAResponse response) throws WeCrossConsoleException { 78 | if (response == null) { 79 | throw new WeCrossConsoleException(ErrorCode.NO_RESPONSE, "Error: no response"); 80 | } else if (response.getErrorCode() != StatusCode.SUCCESS) { 81 | throw new WeCrossConsoleException( 82 | ErrorCode.INTERNAL_ERROR, 83 | "Error: code(" 84 | + response.getErrorCode() 85 | + "), message(" 86 | + response.getMessage() 87 | + ")"); 88 | } else if (response.getXARawResponse().getStatus() != StatusCode.SUCCESS) { 89 | System.out.println( 90 | Arrays.toString(response.getXARawResponse().getChainErrorMessages().toArray())); 91 | } else { 92 | System.out.println("Result: success!"); 93 | } 94 | } 95 | 96 | public static void printRoutineInfoResponse(XATransactionResponse response, List paths) 97 | throws Exception { 98 | if (response == null) { 99 | throw new WeCrossConsoleException(ErrorCode.NO_RESPONSE, "Error: no response"); 100 | } else if (response.getErrorCode() != StatusCode.SUCCESS) { 101 | throw new WeCrossConsoleException( 102 | ErrorCode.INTERNAL_ERROR, 103 | "Error: code(" 104 | + response.getErrorCode() 105 | + "), message(" 106 | + response.getMessage() 107 | + ")"); 108 | } else if (response.getRawXATransactionResponse().getXaResponse().getStatus() 109 | != StatusCode.SUCCESS) { 110 | throw new WeCrossConsoleException( 111 | ErrorCode.INTERNAL_ERROR, 112 | Arrays.toString( 113 | response.getRawXATransactionResponse() 114 | .getXaResponse() 115 | .getChainErrorMessages() 116 | .toArray())); 117 | } else { 118 | List pathList = 119 | response.getRawXATransactionResponse().getXaTransaction().getPaths(); 120 | boolean checkPathFlag = true; 121 | if (pathList.size() != paths.size()) { 122 | checkPathFlag = false; 123 | } else { 124 | for (String path : paths) { 125 | if (!pathList.contains(path)) { 126 | checkPathFlag = false; 127 | break; 128 | } 129 | } 130 | } 131 | if (!checkPathFlag) { 132 | System.out.println( 133 | "ERROR: path not fit in response, please use command 'listXATransactions' to check correct transaction path."); 134 | } else { 135 | ConsoleUtils.printJson( 136 | response.getRawXATransactionResponse().getXaTransaction().toString()); 137 | } 138 | } 139 | } 140 | 141 | public static void printRoutineIDResponse(XATransactionListResponse response) throws Exception { 142 | if (response == null) { 143 | throw new WeCrossConsoleException(ErrorCode.NO_RESPONSE, "Error: no response"); 144 | } else if (response.getErrorCode() != StatusCode.SUCCESS) { 145 | throw new WeCrossConsoleException( 146 | ErrorCode.INTERNAL_ERROR, 147 | "Error: code(" 148 | + response.getErrorCode() 149 | + "), message(" 150 | + response.getMessage() 151 | + ")"); 152 | } else { 153 | ObjectMapper objectMapper = new ObjectMapper(); 154 | System.out.println( 155 | "Result: " 156 | + objectMapper 157 | .writerWithDefaultPrettyPrinter() 158 | .writeValueAsString( 159 | response.getRawXATransactionListResponse() 160 | .getXaList())); 161 | } 162 | } 163 | 164 | public static void printCommandResponse(CommandResponse response) 165 | throws WeCrossConsoleException { 166 | logger.debug("response: {}", response.getResult()); 167 | if (response == null) { 168 | throw new WeCrossConsoleException(ErrorCode.NO_RESPONSE, "Error: no response"); 169 | } else if (response.getErrorCode() != StatusCode.SUCCESS) { 170 | throw new WeCrossConsoleException( 171 | ErrorCode.INTERNAL_ERROR, 172 | "Error: code(" 173 | + response.getErrorCode() 174 | + "), message(" 175 | + response.getMessage() 176 | + ")"); 177 | } else { 178 | System.out.println("Result: " + response.getResult()); 179 | } 180 | } 181 | 182 | public static void printUAResponse(UAResponse response) throws WeCrossConsoleException { 183 | if (response == null) { 184 | throw new WeCrossConsoleException(ErrorCode.NO_RESPONSE, "Error: no response"); 185 | } else if (response.getErrorCode() != StatusCode.SUCCESS) { 186 | throw new WeCrossConsoleException( 187 | ErrorCode.INTERNAL_ERROR, 188 | "Error: code(" 189 | + response.getErrorCode() 190 | + "), message(" 191 | + response.getMessage() 192 | + ")"); 193 | } else if (response.getUAReceipt().getErrorCode() != StatusCode.SUCCESS) { 194 | logger.warn("UAResponse: " + response.getUAReceipt().toString()); 195 | throw new WeCrossConsoleException( 196 | ErrorCode.INTERNAL_ERROR, 197 | "Error: code(" 198 | + response.getUAReceipt().getErrorCode() 199 | + "), message(" 200 | + response.getUAReceipt().getMessage() 201 | + ")"); 202 | } else { 203 | System.out.println("Result: " + response.getUAReceipt().getMessage()); 204 | if (response.getUAReceipt().getUniversalAccount() != null) { 205 | ConsoleUtils.doubleLine(); 206 | System.out.println(response.getUAReceipt().getUniversalAccount().toFormatString()); 207 | } 208 | } 209 | } 210 | 211 | /** 212 | * specific string arrays toString method, empty string "" should be shown 213 | * 214 | * @param a array to print 215 | * @return string format of a 216 | */ 217 | public static String stringArraysToString(String[] a) { 218 | if (a == null) return "null"; 219 | 220 | int iMax = a.length - 1; 221 | if (iMax == -1) return "[]"; 222 | 223 | StringBuilder b = new StringBuilder(); 224 | b.append('['); 225 | for (int i = 0; ; i++) { 226 | if ("".equals(a[i])) { 227 | b.append("\"\""); 228 | } else { 229 | b.append(a[i]); 230 | } 231 | if (i == iMax) return b.append(']').toString(); 232 | b.append(", "); 233 | } 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/common/TarUtils.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.common; 2 | 3 | import java.io.BufferedOutputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.IOException; 8 | import java.nio.file.Paths; 9 | import java.util.Base64; 10 | import java.util.Collection; 11 | import org.apache.commons.compress.archivers.ArchiveEntry; 12 | import org.apache.commons.compress.archivers.tar.TarArchiveEntry; 13 | import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; 14 | import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; 15 | import org.apache.commons.io.FilenameUtils; 16 | import org.apache.commons.io.IOUtils; 17 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 18 | 19 | public class TarUtils { 20 | 21 | // Huuugggeee hole here!!! the path in tar.gz must start with src/ and then with pathPrefix 22 | public static final String goPrefix = "src/chaincode"; 23 | 24 | /** 25 | * Generate a targz inputstream from source folder. 26 | * 27 | * @param src Source location 28 | * @param pathPrefix prefix to add to the all files found. 29 | * @return return inputstream. 30 | * @throws IOException 31 | */ 32 | private static byte[] generateTarGzInputStreamBytes(File src, String pathPrefix) 33 | throws IOException { 34 | 35 | File sourceDirectory = src; 36 | 37 | ByteArrayOutputStream bos = new ByteArrayOutputStream(500000); 38 | 39 | String sourcePath = sourceDirectory.getAbsolutePath(); 40 | 41 | TarArchiveOutputStream archiveOutputStream = 42 | new TarArchiveOutputStream( 43 | new GzipCompressorOutputStream(new BufferedOutputStream(bos))); 44 | archiveOutputStream.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU); 45 | 46 | try { 47 | Collection childrenFiles = 48 | org.apache.commons.io.FileUtils.listFiles(sourceDirectory, null, true); 49 | 50 | ArchiveEntry archiveEntry; 51 | FileInputStream fileInputStream; 52 | for (File childFile : childrenFiles) { 53 | String childPath = childFile.getAbsolutePath(); 54 | String relativePath = 55 | childPath.substring((sourcePath.length() + 1), childPath.length()); 56 | 57 | if (pathPrefix != null) { 58 | relativePath = Paths.get(pathPrefix, relativePath).toString(); 59 | } 60 | 61 | relativePath = FilenameUtils.separatorsToUnix(relativePath); 62 | 63 | archiveEntry = new TarArchiveEntry(childFile, relativePath); 64 | fileInputStream = new FileInputStream(childFile); 65 | archiveOutputStream.putArchiveEntry((TarArchiveEntry) archiveEntry); 66 | 67 | try { 68 | IOUtils.copy(fileInputStream, archiveOutputStream); 69 | } finally { 70 | IOUtils.closeQuietly(fileInputStream); 71 | archiveOutputStream.closeArchiveEntry(); 72 | } 73 | } 74 | } finally { 75 | IOUtils.closeQuietly(archiveOutputStream); 76 | } 77 | 78 | return bos.toByteArray(); 79 | } 80 | 81 | public static byte[] generateTarGzInputStreamBytes(String path, String pathPrefix) 82 | throws IOException { 83 | System.out.println("path: " + path); 84 | PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 85 | 86 | File file = resolver.getResource(path).getFile(); 87 | return generateTarGzInputStreamBytes( 88 | file, pathPrefix); // Inside tar.gz is: src/chaincode/ 89 | } 90 | 91 | public static byte[] generateTarGzInputStreamBytesFoGoChaincode(String path) 92 | throws IOException { 93 | System.out.println("path: " + path); 94 | PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 95 | 96 | File file = resolver.getResource(path).getFile(); 97 | return generateTarGzInputStreamBytes( 98 | file, goPrefix); // Inside tar.gz is: src/chaincode/ 99 | } 100 | 101 | public static String generateTarGzInputStreamEncodedString(String path) throws IOException { 102 | return Base64.getEncoder().encodeToString(generateTarGzInputStreamBytes(path, "")); 103 | } 104 | 105 | public static String generateTarGzInputStreamEncodedStringFoGoChaincode(String path) 106 | throws IOException { 107 | 108 | return Base64.getEncoder().encodeToString(generateTarGzInputStreamBytes(path, goPrefix)); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/common/TransactionInfo.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.common; 2 | 3 | import java.util.List; 4 | 5 | public class TransactionInfo { 6 | String transactionID; 7 | List paths; 8 | 9 | public TransactionInfo(String transactionID, List paths) { 10 | this.transactionID = transactionID; 11 | this.paths = paths; 12 | } 13 | 14 | public TransactionInfo() {} 15 | 16 | public String getTransactionID() { 17 | return transactionID; 18 | } 19 | 20 | public void setTransactionID(String transactionID) { 21 | this.transactionID = transactionID; 22 | } 23 | 24 | public List getPaths() { 25 | return paths; 26 | } 27 | 28 | public void setPaths(List paths) { 29 | this.paths = paths; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | StringBuilder sb = new StringBuilder(); 35 | sb.append(transactionID).append(" "); 36 | for (String path : paths) { 37 | sb.append(path).append(" "); 38 | } 39 | return sb.toString(); 40 | } 41 | 42 | public String toPathString() { 43 | StringBuilder sb = new StringBuilder(); 44 | for (String path : paths) { 45 | sb.append(path).append(" "); 46 | } 47 | return sb.toString(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/common/Version.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.common; 2 | 3 | public class Version { 4 | 5 | public static final String Version = "v1.4.0"; 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/common/WelcomeInfo.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.common; 2 | 3 | public class WelcomeInfo { 4 | 5 | public static void welcome() { 6 | ConsoleUtils.doubleLine(); 7 | System.out.println("Welcome to WeCross console(" + Version.Version + ")!"); 8 | System.out.println("Type 'help' or 'h' for help. Type 'quit' or 'q' to quit console."); 9 | System.out.println(); 10 | ConsoleUtils.doubleLine(); 11 | } 12 | 13 | public static void help(String[] params) { 14 | if (HelpInfo.promptNoParams(params, "help")) { 15 | return; 16 | } 17 | if (params.length > 2) { 18 | HelpInfo.promptHelp("help"); 19 | return; 20 | } 21 | StringBuilder sb = new StringBuilder(); 22 | sb.append( 23 | "------------------------------------------ Account ------------------------------------------\n"); 24 | sb.append("login Login SDK if you have already registered.\n"); 25 | sb.append("logout Logout SDK.\n"); 26 | sb.append("listAccount List your Universal Account's information.\n"); 27 | sb.append("registerAccount Register a Universal Account.\n"); 28 | sb.append( 29 | "addChainAccount Add a Chain Account to your Universal Account.\n"); 30 | sb.append( 31 | "setDefaultAccount Set the chain account to be the default account to send transaction.\n"); 32 | 33 | sb.append( 34 | "\n------------------------------------ Resource Operation -------------------------------------\n"); 35 | sb.append( 36 | "listResources List all resources including remote resources.\n"); 37 | sb.append( 38 | "listLocalResources List local resources configured by WeCross server.\n"); 39 | sb.append("detail Get resource information.\n"); 40 | 41 | sb.append("call Call constant method of smart contract.\n"); 42 | sb.append("sendTransaction Call non-constant method of smart contract.\n"); 43 | sb.append( 44 | "WeCross.getResource Init resource by path, and assign it to a custom variable.\n"); 45 | sb.append("[resource].[command] Equal to: command [path].\n"); 46 | 47 | sb.append( 48 | "\n---------------------------------------- XA Routine -----------------------------------------\n"); 49 | sb.append("startTransaction Start an xa transaction.\n"); 50 | sb.append( 51 | "invoke Call non-constant method of smart contract, will auto-transfer to command execTransaction during transaction.\n"); 52 | sb.append( 53 | "callTransaction Call constant method of smart contract during transaction.\n"); 54 | sb.append( 55 | "execTransaction Call non-constant method of smart contract during transaction.\n"); 56 | sb.append("commitTransaction Commit an xa transaction.\n"); 57 | sb.append("rollbackTransaction Rollback an xa transaction.\n"); 58 | sb.append("loadTransaction Load a specified transaction context.\n"); 59 | sb.append("getXATransaction Get info of specified XA transaction.\n"); 60 | sb.append("listXATransactions List XA transactions in route.\n"); 61 | 62 | sb.append( 63 | "\n--------------------------------------- HTLC Routine ----------------------------------------\n"); 64 | sb.append("genTimelock Generate two valid timelocks.\n"); 65 | sb.append("genSecretAndHash Generate a secret and its hash.\n"); 66 | sb.append("newHTLCProposal Create a htlc transfer proposal .\n"); 67 | sb.append("checkTransferStatus Check htlc transfer status by hash.\n"); 68 | sb.append("getCurrentTransactionID Get Current xa Transaction ID.\n"); 69 | 70 | sb.append( 71 | "\n----------------------- Extended commands only used for certain chain -----------------------\n"); 72 | sb.append("bcosDeploy Deploy contract in BCOS chain.\n"); 73 | sb.append("bcosRegister Register contract abi in BCOS chain.\n"); 74 | sb.append("fabricInstall Install chaincode in fabric chain.\n"); 75 | sb.append("fabricInstantiate Instantiate chaincode in fabric chain.\n"); 76 | sb.append("fabricUpgrade Upgrade chaincode in fabric chain.\n"); 77 | 78 | sb.append( 79 | "\n------------------------------------------ Others -------------------------------------------\n"); 80 | sb.append("supportedStubs List supported stubs of WeCross router.\n"); 81 | sb.append("quit Quit console.\n"); 82 | 83 | System.out.println(sb.toString()); 84 | ConsoleUtils.singleLine(); 85 | System.out.println(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/custom/BCOSCommand.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.custom; 2 | 3 | import com.webank.wecross.console.common.ConsoleUtils; 4 | import com.webank.wecross.console.common.FileUtils; 5 | import com.webank.wecross.console.common.HelpInfo; 6 | import com.webank.wecross.console.common.PrintUtils; 7 | import com.webank.wecross.console.exception.ErrorCode; 8 | import com.webank.wecross.console.exception.WeCrossConsoleException; 9 | import com.webank.wecrosssdk.rpc.WeCrossRPC; 10 | import com.webank.wecrosssdk.rpc.common.ResourceDetail; 11 | import com.webank.wecrosssdk.rpc.methods.response.CommandResponse; 12 | import com.webank.wecrosssdk.rpc.methods.response.ResourceResponse; 13 | import com.webank.wecrosssdk.utils.RPCUtils; 14 | import java.io.File; 15 | import java.util.*; 16 | import org.slf4j.Logger; 17 | import org.slf4j.LoggerFactory; 18 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 19 | 20 | public class BCOSCommand { 21 | private static final Logger logger = LoggerFactory.getLogger(BCOSCommand.class); 22 | private WeCrossRPC weCrossRPC; 23 | 24 | public BCOSCommand(WeCrossRPC weCrossRPC) { 25 | this.weCrossRPC = weCrossRPC; 26 | } 27 | 28 | /** 29 | * deploy contract 30 | * 31 | * @params BCOSDeploy [path] [filePath] [className] [version] 32 | */ 33 | public void deploy(String[] params) throws Exception { 34 | if (params.length == 1) { 35 | throw new WeCrossConsoleException(ErrorCode.PARAM_MISSING, "bcosDeploy"); 36 | } 37 | if ("-h".equals(params[1]) || "--help".equals(params[1])) { 38 | HelpInfo.BCOSDeployHelp(); 39 | return; 40 | } 41 | if (params.length < 4) { 42 | throw new WeCrossConsoleException(ErrorCode.PARAM_MISSING, "bcosDeploy"); 43 | } 44 | 45 | String path = params[1]; 46 | String chain = path.substring(0, path.lastIndexOf('.') + 1); 47 | RPCUtils.checkPath(path); 48 | String stubType = ""; 49 | ResourceResponse resources = weCrossRPC.listResources(false).send(); 50 | for (ResourceDetail resourceDetail : resources.getResources().getResourceDetails()) { 51 | if (resourceDetail.getPath().startsWith(chain)) { 52 | stubType = resourceDetail.getStubType(); 53 | break; 54 | } 55 | } 56 | if (stubType.equals("")) { 57 | throw new WeCrossConsoleException(ErrorCode.INVALID_PATH, path); 58 | } 59 | PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 60 | List args = new ArrayList<>(); 61 | // BCOSDeployWasm [path] [abi] [bin] 62 | if (stubType.contains("WASM")) { 63 | String name = path.split("\\.")[2]; 64 | String binContent = FileUtils.readFileContentToHexString(params[2]); 65 | String abiContent = FileUtils.readFileContent(params[3]); 66 | args.addAll(Arrays.asList(name, abiContent, binContent)); 67 | for (int i = 4; i < params.length; i++) { 68 | // for constructor 69 | args.add(ConsoleUtils.parseString(params[i])); 70 | } 71 | } else { 72 | // Solidity 73 | String cnsName = path.split("\\.")[2]; 74 | String sourcePath = params[2]; 75 | String contractName = params[3]; 76 | 77 | org.springframework.core.io.Resource resource = 78 | resolver.getResource("file:" + sourcePath); 79 | if (!resource.exists()) { 80 | resource = resolver.getResource("classpath:" + sourcePath); 81 | if (!resource.exists()) { 82 | logger.error("Source file: {} not exists", sourcePath); 83 | throw new Exception("Source file: " + sourcePath + " not exists"); 84 | } 85 | } 86 | 87 | String filename = resource.getFilename(); 88 | String realPath = resource.getFile().getAbsolutePath(); 89 | String dir = 90 | realPath.substring(0, realPath.lastIndexOf(File.separator)) + File.separator; 91 | 92 | String sourceContent = FileUtils.mergeSource(dir, filename, resolver, new HashSet<>()); 93 | 94 | if (stubType.contains("BCOS3")) { 95 | args.addAll(Arrays.asList(cnsName, sourceContent, contractName)); 96 | for (int i = 4; i < params.length; i++) { 97 | // for constructor 98 | args.add(ConsoleUtils.parseString(params[i])); 99 | } 100 | } else { 101 | String version = params[4]; 102 | args.addAll(Arrays.asList(cnsName, sourceContent, contractName, version)); 103 | for (int i = 5; i < params.length; i++) { 104 | // for constructor 105 | args.add(ConsoleUtils.parseString(params[i])); 106 | } 107 | } 108 | } 109 | CommandResponse response = weCrossRPC.customCommand("deploy", path, args.toArray()).send(); 110 | PrintUtils.printCommandResponse(response); 111 | } 112 | 113 | /** 114 | * register abi in cns 115 | * 116 | * @params bcosRegister [path] [filePath] [address] [contractName] [version] 117 | */ 118 | public void register(String[] params) throws Exception { 119 | if (params.length == 1) { 120 | throw new WeCrossConsoleException(ErrorCode.PARAM_MISSING, "bcosRegister"); 121 | } 122 | if ("-h".equals(params[1]) || "--help".equals(params[1])) { 123 | HelpInfo.BCOSRegisterHelp(); 124 | return; 125 | } 126 | 127 | if (params.length < 6) { 128 | throw new WeCrossConsoleException(ErrorCode.PARAM_MISSING, "bcosRegister"); 129 | } 130 | 131 | String path = params[1]; 132 | RPCUtils.checkPath(path); 133 | String cnsName = path.split("\\.")[2]; 134 | String sourcePath = params[2]; 135 | String address = params[3]; 136 | String contractName = params[4]; 137 | String version = params[5]; 138 | 139 | PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 140 | org.springframework.core.io.Resource resource = resolver.getResource("file:" + sourcePath); 141 | if (!resource.exists()) { 142 | resource = resolver.getResource("classpath:" + sourcePath); 143 | if (!resource.exists()) { 144 | logger.error("Source file: {} not exists", sourcePath); 145 | throw new Exception("Source file: " + sourcePath + " not exists"); 146 | } 147 | } 148 | 149 | String filename = resource.getFilename(); 150 | String realPath = resource.getFile().getAbsolutePath(); 151 | String dir = realPath.substring(0, realPath.lastIndexOf(File.separator)) + File.separator; 152 | 153 | String sourceContent = FileUtils.mergeSource(dir, filename, resolver, new HashSet<>()); 154 | 155 | List args = 156 | new ArrayList<>( 157 | Arrays.asList( 158 | cnsName, 159 | sourcePath.endsWith("abi") ? "abi" : "sol", 160 | sourceContent, 161 | address, 162 | contractName, 163 | version)); 164 | 165 | CommandResponse response = 166 | weCrossRPC.customCommand("register", path, args.toArray()).send(); 167 | PrintUtils.printCommandResponse(response); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/custom/FabricCommand.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.custom; 2 | 3 | import com.webank.wecross.console.common.*; 4 | import com.webank.wecross.console.exception.ErrorCode; 5 | import com.webank.wecross.console.exception.WeCrossConsoleException; 6 | import com.webank.wecrosssdk.rpc.WeCrossRPC; 7 | import com.webank.wecrosssdk.rpc.methods.response.CommandResponse; 8 | import com.webank.wecrosssdk.utils.RPCUtils; 9 | import java.io.File; 10 | 11 | public class FabricCommand { 12 | private WeCrossRPC weCrossRPC; 13 | 14 | public FabricCommand(WeCrossRPC weCrossRPC) { 15 | this.weCrossRPC = weCrossRPC; 16 | } 17 | 18 | /** 19 | * install contract 20 | * 21 | * @params fabricInstall [path] [orgName] [sourcePath] [version] [language] 22 | */ 23 | public void install(String[] params) throws Exception { 24 | // The command is 25 | // fabricInstall payment.fabric.sacc Org1 contracts/chaincode/sacc 1.0 26 | // GO_LANG 27 | // fabricInstall payment.fabric.sacc Org2 contracts/chaincode/sacc 1.0 28 | // GO_LANG 29 | if (params.length == 1) { 30 | throw new WeCrossConsoleException(ErrorCode.PARAM_MISSING, "fabricInstall"); 31 | } 32 | if ("-h".equals(params[1]) || "--help".equals(params[1])) { 33 | HelpInfo.fabricInstallHelp(); 34 | return; 35 | } 36 | if (params.length != 6) { 37 | throw new WeCrossConsoleException(ErrorCode.PARAM_MISSING, "fabricInstall"); 38 | } 39 | 40 | String path = params[1]; 41 | RPCUtils.checkPath(path); 42 | String name = path.split("\\.")[2]; 43 | String orgName = params[2]; 44 | String sourcePath = uniformPath(params[3]); 45 | String version = params[4]; 46 | String language = params[5]; 47 | 48 | String codes; 49 | if (language.equals("GO_LANG")) { 50 | codes = TarUtils.generateTarGzInputStreamEncodedStringFoGoChaincode(sourcePath); 51 | } else { 52 | codes = TarUtils.generateTarGzInputStreamEncodedString(sourcePath); 53 | } 54 | 55 | Object[] args = new Object[] {name, version, orgName, language, codes}; 56 | 57 | CommandResponse response = weCrossRPC.customCommand("install", path, args).send(); 58 | PrintUtils.printCommandResponse(response); 59 | } 60 | 61 | /** 62 | * instantiate chaincode 63 | * 64 | * @params fabricInstantiate [path] [orgNames] [sourcePath] [version] [language] [policyFile] 65 | * [initArgs] 66 | */ 67 | public void instantiate(String[] params) throws Exception { 68 | // The command is: 69 | // fabricInstantiate payment.fabric.sacc ["Org1","Org2"] 70 | // contracts/chaincode/sacc 1.0 GO_LANG policy.yaml ["a","10"] 71 | 72 | if (params.length == 1) { 73 | throw new WeCrossConsoleException(ErrorCode.PARAM_MISSING, "fabricInstantiate"); 74 | } 75 | if ("-h".equals(params[1]) || "--help".equals(params[1])) { 76 | HelpInfo.fabricInstantiateHelp(); 77 | return; 78 | } 79 | if (params.length != 8) { 80 | throw new WeCrossConsoleException(ErrorCode.PARAM_MISSING, "fabricInstantiate"); 81 | } 82 | 83 | String path = params[1]; 84 | RPCUtils.checkPath(path); 85 | String name = path.split("\\.")[2]; 86 | String orgNames = params[2]; 87 | String sourcePath = uniformPath(params[3]); 88 | String version = params[4]; 89 | String language = params[5]; 90 | String policyFile = params[6]; 91 | String initArgs = params[7]; 92 | 93 | String policy; 94 | if (policyFile.equals("default")) { 95 | policy = ""; 96 | } else { 97 | policy = FileUtils.readFileToBytesString(sourcePath + File.separator + policyFile); 98 | } 99 | 100 | Object[] args = new Object[] {name, version, orgNames, language, policy, initArgs}; 101 | 102 | CommandResponse response = weCrossRPC.customCommand("instantiate", path, args).send(); 103 | PrintUtils.printCommandResponse(response); 104 | } 105 | 106 | /** 107 | * upgrade chaincode 108 | * 109 | * @params fabricUpgrade [path] [orgNames] [sourcePath] [version] [language] [policyFile] 110 | * [initArgs] 111 | */ 112 | public void upgrade(String[] params) throws Exception { 113 | // The command is: 114 | // upgrade payment.fabric.sacc ["Org1","Org2"] 115 | // contracts/chaincode/sacc 2.0 GO_LANG policy.yaml ["a","10"] 116 | 117 | if (params.length == 1) { 118 | throw new WeCrossConsoleException(ErrorCode.PARAM_MISSING, "fabricUpgrade"); 119 | } 120 | if ("-h".equals(params[1]) || "--help".equals(params[1])) { 121 | HelpInfo.fabricUpgradeHelp(); 122 | return; 123 | } 124 | if (params.length != 8) { 125 | throw new WeCrossConsoleException(ErrorCode.PARAM_MISSING, "fabricUpgrade"); 126 | } 127 | 128 | String path = params[1]; 129 | RPCUtils.checkPath(path); 130 | String name = path.split("\\.")[2]; 131 | String orgNames = params[2]; 132 | String sourcePath = uniformPath(params[3]); 133 | String version = params[4]; 134 | String language = params[5]; 135 | String policyFile = params[6]; 136 | String initArgs = params[7]; 137 | 138 | String policy; 139 | if (policyFile.equals("default")) { 140 | policy = ""; 141 | } else { 142 | policy = FileUtils.readFileToBytesString(sourcePath + File.separator + policyFile); 143 | } 144 | 145 | Object[] args = new Object[] {name, version, orgNames, language, policy, initArgs}; 146 | 147 | CommandResponse response = weCrossRPC.customCommand("upgrade", path, args).send(); 148 | PrintUtils.printCommandResponse(response); 149 | } 150 | 151 | private String uniformPath(String path) { 152 | if (path.startsWith("/") || path.startsWith("\\") || path.startsWith(File.pathSeparator)) { 153 | return "file:" + path; 154 | } else { 155 | return "classpath:" + path; 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/exception/ErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.exception; 2 | 3 | public class ErrorCode { 4 | 5 | // common 6 | public static final int INTERNAL_ERROR = 1; 7 | 8 | // init wecross service 9 | public static final int INIT_WECROSS_SERVICE_ERROR = 1001; 10 | public static final int HAVE_NOT_LOGGED_IN = 1002; 11 | 12 | // status in utils 13 | public static final int ILLEGAL_PARAM = 2001; 14 | public static final int METHOD_MISSING = 2002; 15 | public static final int PARAM_MISSING = 2003; 16 | public static final int INVALID_PATH = 2004; 17 | public static final int NO_RESPONSE = 2005; 18 | 19 | // status in routine 20 | public static final int INVALID_TXID = 3001; 21 | public static final int TX_LOG_NOT_EXIST = 3002; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/exception/WeCrossConsoleException.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.exception; 2 | 3 | public class WeCrossConsoleException extends java.lang.Exception { 4 | 5 | private static final long serialVersionUID = 3754251447587995515L; 6 | 7 | private Integer errorCode; 8 | 9 | public WeCrossConsoleException(Integer code, String message) { 10 | super(message); 11 | errorCode = code; 12 | } 13 | 14 | public Integer getErrorCode() { 15 | return errorCode; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/mock/MockResource.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.mock; 2 | 3 | import com.webank.wecross.console.common.ConsoleUtils; 4 | import com.webank.wecrosssdk.exception.WeCrossSDKException; 5 | import com.webank.wecrosssdk.resource.Resource; 6 | import com.webank.wecrosssdk.resource.ResourceFactory; 7 | import com.webank.wecrosssdk.rpc.WeCrossRPC; 8 | import java.io.Serializable; 9 | import java.util.Arrays; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | public class MockResource implements Serializable { 14 | 15 | private Logger logger = LoggerFactory.getLogger(MockResource.class); 16 | 17 | private Resource resource; 18 | 19 | public MockResource(WeCrossRPC weCrossRPC, String path) { 20 | try { 21 | resource = ResourceFactory.build(weCrossRPC, path); 22 | } catch (WeCrossSDKException e) { 23 | System.out.println(e.getMessage()); 24 | } 25 | } 26 | 27 | public void detail() { 28 | try { 29 | ConsoleUtils.printJson(resource.detail().toString()); 30 | } catch (WeCrossSDKException e) { 31 | System.out.println(e.getMessage()); 32 | } 33 | } 34 | 35 | public void call(String method, String... args) { 36 | try { 37 | System.out.println("Result: " + Arrays.toString(resource.call(method, args))); 38 | } catch (WeCrossSDKException e) { 39 | logger.info("call error: {}", e.getMessage()); 40 | System.out.println(e.getMessage()); 41 | } 42 | } 43 | 44 | public void sendTransaction(String method, String... args) { 45 | try { 46 | System.out.println( 47 | "Result: " + Arrays.toString(resource.sendTransaction(method, args))); 48 | } catch (WeCrossSDKException e) { 49 | logger.info("sendTransaction error: {}", e.getMessage()); 50 | System.out.println(e.getMessage()); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/mock/MockWeCross.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.mock; 2 | 3 | import com.webank.wecross.console.common.ConsoleUtils; 4 | import com.webank.wecrosssdk.rpc.WeCrossRPC; 5 | import java.io.Serializable; 6 | 7 | public class MockWeCross implements Serializable { 8 | private static WeCrossRPC weCrossRPC; 9 | 10 | public MockWeCross(WeCrossRPC weCrossRPC) { 11 | MockWeCross.weCrossRPC = weCrossRPC; 12 | } 13 | 14 | public static MockResource getResource(String path) { 15 | if (!ConsoleUtils.isValidPath(path)) { 16 | System.out.println("Please provide a valid path"); 17 | return null; 18 | } 19 | return new MockResource(weCrossRPC, path); 20 | } 21 | 22 | public WeCrossRPC getWeCrossRPC() { 23 | return weCrossRPC; 24 | } 25 | 26 | public void setWeCrossRPC(WeCrossRPC weCrossRPC) { 27 | MockWeCross.weCrossRPC = weCrossRPC; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/routine/HTLCFace.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.routine; 2 | 3 | import com.webank.wecrosssdk.rpc.WeCrossRPC; 4 | import java.util.Map; 5 | 6 | public interface HTLCFace { 7 | void setWeCrossRPC(WeCrossRPC weCrossRPC); 8 | 9 | void genTimelock(String[] params); 10 | 11 | void genSecretAndHash(String[] params) throws Exception; 12 | 13 | void checkTransferStatus(String[] params, Map pathMaps) throws Exception; 14 | 15 | void newProposal(String[] params, Map pathMaps) throws Exception; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/routine/HTLCImpl.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.routine; 2 | 3 | import com.webank.wecross.console.common.ConsoleUtils; 4 | import com.webank.wecross.console.common.Hash; 5 | import com.webank.wecross.console.common.HelpInfo; 6 | import com.webank.wecrosssdk.common.StatusCode; 7 | import com.webank.wecrosssdk.resource.Resource; 8 | import com.webank.wecrosssdk.resource.ResourceFactory; 9 | import com.webank.wecrosssdk.rpc.WeCrossRPC; 10 | import com.webank.wecrosssdk.rpc.common.Receipt; 11 | import com.webank.wecrosssdk.rpc.methods.response.TransactionResponse; 12 | import java.math.BigInteger; 13 | import java.security.NoSuchAlgorithmException; 14 | import java.util.Map; 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | 18 | public class HTLCImpl implements HTLCFace { 19 | private WeCrossRPC weCrossRPC; 20 | private final Logger logger = LoggerFactory.getLogger(HTLCImpl.class); 21 | private static final String TRUE_FLAG = "true"; 22 | private static final String NULL_FLAG = "null"; 23 | private static final String SPLIT_REGEX = "##"; 24 | private static final String SUCCESS_FLAG = "success"; 25 | 26 | @Override 27 | public void genTimelock(String[] params) { 28 | if (params.length != 2) { 29 | HelpInfo.promptHelp("genTimelock"); 30 | return; 31 | } 32 | if ("-h".equals(params[1]) || "--help".equals(params[1])) { 33 | HelpInfo.genTimeLockHelp(); 34 | return; 35 | } 36 | 37 | int interval = Integer.parseInt(params[1]); 38 | if (interval < 300) { 39 | System.out.println("condition: interval > 300"); 40 | } else { 41 | BigInteger now = BigInteger.valueOf(System.currentTimeMillis() / 1000); 42 | int doubleInterval = interval * 2; 43 | BigInteger t0 = now.add(BigInteger.valueOf(doubleInterval)); 44 | BigInteger t1 = now.add(BigInteger.valueOf(interval)); 45 | System.out.println("timelock0: " + t0); 46 | System.out.println("timelock1: " + t1); 47 | } 48 | } 49 | 50 | @Override 51 | public void genSecretAndHash(String[] params) throws Exception { 52 | if (params.length != 1) { 53 | HelpInfo.genSecretAndHashHelp(); 54 | return; 55 | } 56 | 57 | Hash hash = new Hash(); 58 | String secret = hash.getRandom(32); 59 | System.out.println("hash : " + hash.sha256(secret)); 60 | System.out.println("secret: " + secret); 61 | } 62 | 63 | @Override 64 | public void checkTransferStatus(String[] params, Map pathMaps) 65 | throws Exception { 66 | if (params.length == 1 || params.length > 3) { 67 | HelpInfo.promptHelp("checkTransferStatus"); 68 | return; 69 | } 70 | if ("-h".equals(params[1]) || "--help".equals(params[1])) { 71 | HelpInfo.checkTransferStatusHelp(); 72 | return; 73 | } 74 | if (params.length == 2) { 75 | HelpInfo.promptHelp("checkTransferStatus"); 76 | } else { 77 | String path = ConsoleUtils.parsePath(params, pathMaps); 78 | if (path == null) { 79 | return; 80 | } 81 | 82 | String hash = params[2]; 83 | 84 | Resource resource = ResourceFactory.build(weCrossRPC, path); 85 | String proposalInfo = resource.call("getProposalInfo", hash)[0].trim(); 86 | if (NULL_FLAG.equals(proposalInfo)) { 87 | System.out.println("status: proposal not found!"); 88 | return; 89 | } 90 | String[] proposalItems = proposalInfo.split(SPLIT_REGEX); 91 | BigInteger timelock = new BigInteger(proposalItems[2]); 92 | 93 | boolean selfUnlocked = TRUE_FLAG.equals(proposalItems[4]); 94 | boolean selfRolledback = TRUE_FLAG.equals(proposalItems[5]); 95 | boolean counterpartyUnlocked = TRUE_FLAG.equals(proposalItems[8]); 96 | 97 | if (selfUnlocked && counterpartyUnlocked) { 98 | System.out.println("status: succeeded!"); 99 | return; 100 | } 101 | 102 | if (selfRolledback) { 103 | System.out.println("status: rolled back!"); 104 | return; 105 | } 106 | 107 | BigInteger now = BigInteger.valueOf(System.currentTimeMillis() / 1000); 108 | if (timelock.compareTo(now) <= 0) { 109 | System.out.println("status: failed!"); 110 | return; 111 | } 112 | System.out.println("status: ongoing!"); 113 | } 114 | } 115 | 116 | @Override 117 | public void newProposal(String[] params, Map pathMaps) throws Exception { 118 | if (params.length == 1) { 119 | HelpInfo.promptHelp("newHTLCProposal"); 120 | return; 121 | } 122 | if ("-h".equals(params[1]) || "--help".equals(params[1])) { 123 | HelpInfo.newProposalHelp(); 124 | return; 125 | } 126 | 127 | if (!checkProposal(params)) { 128 | return; 129 | } 130 | 131 | String path = ConsoleUtils.parsePath(params, pathMaps); 132 | if (path == null) { 133 | return; 134 | } 135 | String[] args = new String[10]; 136 | args[0] = ConsoleUtils.parseString(params[2]); 137 | for (int i = 1; i < 10; i++) { 138 | args[i] = ConsoleUtils.parseString(params[i + 3]); 139 | } 140 | 141 | TransactionResponse response = weCrossRPC.sendTransaction(path, "newProposal", args).send(); 142 | Receipt receipt = response.getReceipt(); 143 | if (response.getErrorCode() != StatusCode.SUCCESS) { 144 | ConsoleUtils.printJson(response.toString()); 145 | return; 146 | } else if (response.getReceipt().getErrorCode() != StatusCode.SUCCESS) { 147 | logger.warn("TxError: " + response.getReceipt().toString()); 148 | ConsoleUtils.printJson(receipt.toString()); 149 | return; 150 | } else { 151 | System.out.println("Txhash: " + receipt.getHash()); 152 | System.out.println("BlockNum: " + receipt.getBlockNumber()); 153 | String result = receipt.getResult()[0].trim(); 154 | if (SUCCESS_FLAG.equalsIgnoreCase(result)) { 155 | String txHash = response.getReceipt().getHash(); 156 | long blockNum = response.getReceipt().getBlockNumber(); 157 | setNewContractTxInfo(path, ConsoleUtils.parseString(params[2]), txHash, blockNum); 158 | if (TRUE_FLAG.equalsIgnoreCase(params[4])) { 159 | setSecret( 160 | path, 161 | ConsoleUtils.parseString(params[2]), 162 | ConsoleUtils.parseString(params[3])); 163 | } 164 | System.out.println("Result: create a htlc proposal successfully"); 165 | } else { 166 | System.out.println("Result: " + result); 167 | } 168 | } 169 | } 170 | 171 | private boolean checkProposal(String[] params) throws NoSuchAlgorithmException { 172 | if (params.length != 13) { 173 | System.out.println("invalid number of parameters, 14 params needed"); 174 | return false; 175 | } 176 | 177 | Hash hash = new Hash(); 178 | if (TRUE_FLAG.equalsIgnoreCase(params[4])) { 179 | if (!params[2].equals(hash.sha256(params[3]))) { 180 | System.out.println("hash not matched"); 181 | return false; 182 | } 183 | } 184 | 185 | if (params[5].equals(params[6]) || params[9].equals(params[10])) { 186 | System.out.println("the sender and receiver must be different"); 187 | } 188 | 189 | BigInteger amount0 = new BigInteger(params[7]); 190 | BigInteger amount1 = new BigInteger(params[11]); 191 | 192 | if (amount0.compareTo(BigInteger.valueOf(0)) > 0 193 | && amount1.compareTo(BigInteger.valueOf(0)) > 0) { 194 | return true; 195 | } else { 196 | System.out.println("transfer amount must be greater than 0"); 197 | return false; 198 | } 199 | } 200 | 201 | private void setNewContractTxInfo(String path, String hash, String txHash, long blockNum) 202 | throws Exception { 203 | TransactionResponse response = 204 | weCrossRPC 205 | .sendTransaction( 206 | path, 207 | "setNewProposalTxInfo", 208 | hash, 209 | txHash, 210 | String.valueOf(blockNum)) 211 | .send(); 212 | Receipt receipt = response.getReceipt(); 213 | if (response.getErrorCode() != StatusCode.SUCCESS 214 | || receipt.getErrorCode() != StatusCode.SUCCESS) { 215 | if (receipt != null) { 216 | System.out.println("failed to setNewProposalTxInfo: " + receipt.getMessage()); 217 | } else { 218 | System.out.println("failed to setNewProposalTxInfo: " + response.getMessage()); 219 | } 220 | } else { 221 | logger.info( 222 | "newProposal succeeded, path: {}, txHash: {}, blockNum: {}", 223 | path, 224 | txHash, 225 | blockNum); 226 | } 227 | } 228 | 229 | private void setSecret(String path, String hash, String secret) throws Exception { 230 | TransactionResponse response = 231 | weCrossRPC.sendTransaction(path, "setSecret", hash, secret).send(); 232 | Receipt receipt = response.getReceipt(); 233 | if (response.getErrorCode() != StatusCode.SUCCESS 234 | || receipt.getErrorCode() != StatusCode.SUCCESS) { 235 | if (receipt != null) { 236 | System.out.println("failed to setSecret: " + receipt.getMessage()); 237 | } else { 238 | System.out.println("failed to setSecret: " + response.getMessage()); 239 | } 240 | } else { 241 | logger.info("setSecret succeeded, path: {}, hashs: {}, secret: {}", path, hash, secret); 242 | } 243 | } 244 | 245 | public WeCrossRPC getWeCrossRPC() { 246 | return weCrossRPC; 247 | } 248 | 249 | @Override 250 | public void setWeCrossRPC(WeCrossRPC weCrossRPC) { 251 | this.weCrossRPC = weCrossRPC; 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/routine/XAFace.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.routine; 2 | 3 | import com.webank.wecrosssdk.rpc.WeCrossRPC; 4 | import java.util.Map; 5 | 6 | public interface XAFace { 7 | void setWeCrossRPC(WeCrossRPC weCrossRPC); 8 | 9 | void callTransaction(String[] params, Map pathMaps) throws Exception; 10 | 11 | void execTransaction(String[] params, Map pathMaps) throws Exception; 12 | 13 | void startTransaction(String[] params) throws Exception; 14 | 15 | void commitTransaction(String[] params) throws Exception; 16 | 17 | void rollbackTransaction(String[] params) throws Exception; 18 | 19 | void autoCommitXATransaction(String[] params, Map pathMaps) throws Exception; 20 | 21 | void getXATransaction(String[] params) throws Exception; 22 | 23 | void getCurrentTransactionID(String[] params) throws Exception; 24 | 25 | void loadTransaction(String[] params) throws Exception; 26 | 27 | boolean isTransactionInfoExist(String txID, String[] paths) throws Exception; 28 | 29 | void listXATransactions(String[] params) throws Exception; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/webank/wecross/console/rpc/RPCFace.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console.rpc; 2 | 3 | import com.webank.wecross.console.exception.WeCrossConsoleException; 4 | import com.webank.wecrosssdk.rpc.WeCrossRPC; 5 | import java.util.Map; 6 | import java.util.Set; 7 | 8 | public interface RPCFace { 9 | 10 | void setWeCrossRPC(WeCrossRPC weCrossRPC); 11 | 12 | void supportedStubs(String[] params) throws Exception; 13 | 14 | void listAccount(String[] params) throws Exception; 15 | 16 | void listResources(String[] params) throws Exception; 17 | 18 | void getResourceInfo(String[] params, Map pathMaps) throws Exception; 19 | 20 | void call(String[] params, Map pathMaps) throws Exception; 21 | 22 | void sendTransaction(String[] params, Map pathMaps) throws Exception; 23 | 24 | void invoke(String[] params, Map pathMaps) throws Exception; 25 | 26 | void login(String[] params) throws Exception; 27 | 28 | void internalLogin() throws Exception; 29 | 30 | void registerAccount(String[] params) throws Exception; 31 | 32 | void addChainAccount(String[] params) throws Exception; 33 | 34 | void setDefaultAccount(String[] params) throws Exception; 35 | 36 | void setDefaultChainAccount(String[] params) throws Exception; 37 | 38 | void logout(String[] params) throws Exception; 39 | 40 | Set getPaths() throws WeCrossConsoleException; 41 | 42 | void getBlock(String[] params) throws Exception; 43 | } 44 | -------------------------------------------------------------------------------- /src/main/resources/application-sample.toml: -------------------------------------------------------------------------------- 1 | [connection] 2 | server = '127.0.0.1:8250' 3 | sslKey = 'classpath:ssl.key' 4 | sslCert = 'classpath:ssl.crt' 5 | caCert = 'classpath:ca.crt' 6 | sslSwitch = 2 # disable ssl:2, SSL without client auth:1 , SSL with client and server auth: 0 7 | 8 | #[login] 9 | #username = 'username' 10 | #password = 'password' 11 | 12 | -------------------------------------------------------------------------------- /src/main/resources/application.toml: -------------------------------------------------------------------------------- 1 | [connection] 2 | server = '127.0.0.1:8250' 3 | sslKey = 'classpath:ssl.key' 4 | sslCert = 'classpath:ssl.crt' 5 | caCert = 'classpath:ca.crt' 6 | sslSwitch = 2 # disable ssl:2, SSL without client auth:1 , SSL with client and server auth: 0 7 | -------------------------------------------------------------------------------- /src/main/resources/contracts/chaincode/asset/assetSample.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | 7 | "github.com/hyperledger/fabric/core/chaincode/shim" 8 | "github.com/hyperledger/fabric/protos/peer" 9 | ) 10 | 11 | const ( 12 | SuccessFlag = "Success" 13 | FailFlag = "Fail" 14 | AccountKey = "Account-%s" 15 | ) 16 | 17 | type Asset struct { 18 | } 19 | 20 | func (a *Asset) Init(stub shim.ChaincodeStubInterface) peer.Response { 21 | setBalance(stub, "Alice", 1000) 22 | setBalance(stub, "Oscar", 100) 23 | return shim.Success(nil) 24 | } 25 | 26 | func (a *Asset) Invoke(stub shim.ChaincodeStubInterface) (res peer.Response) { 27 | fn, args := stub.GetFunctionAndParameters() 28 | switch fn { 29 | case "transfer": 30 | res = a.transfer(stub, args) 31 | case "transfer_revert": 32 | res = a.transfer_revert(stub, args) 33 | case "balanceOf": 34 | res = a.balanceOf(stub, args) 35 | case "balanceOf_revert": 36 | res = a.balanceOf_revert(stub, args) 37 | default: 38 | return shim.Error("invalid function name") 39 | } 40 | // Return the result as success payload 41 | return res 42 | } 43 | 44 | // sender, receiver, amount 45 | func (a *Asset) transfer(stub shim.ChaincodeStubInterface, args []string) peer.Response { 46 | if len(args) != 3 { 47 | return shim.Error("Invalid args length, should be: [sender, receiver, amount]") 48 | } 49 | amount := stringToUint64(args[2]) 50 | senderBalance := getBalance(stub, args[0]) 51 | if senderBalance < amount { 52 | return shim.Error(FailFlag) 53 | } 54 | 55 | receiverBalance := getBalance(stub, args[1]) 56 | if (receiverBalance + amount) < receiverBalance { 57 | return shim.Error(FailFlag) 58 | } 59 | 60 | setBalance(stub, args[0], senderBalance-amount) 61 | setBalance(stub, args[1], receiverBalance+amount) 62 | return shim.Success([]byte(SuccessFlag)) 63 | } 64 | 65 | func (a *Asset) transfer_revert(stub shim.ChaincodeStubInterface, args []string) peer.Response { 66 | newArgs := []string{args[1], args[0], args[2]} 67 | return a.transfer(stub, newArgs) 68 | } 69 | 70 | func (a *Asset) balanceOf(stub shim.ChaincodeStubInterface, args []string) peer.Response { 71 | if len(args) != 1 { 72 | return shim.Error("Invalid args length, should be: [account]") 73 | } 74 | return shim.Success(uint64ToBytes(getBalance(stub, args[0]))) 75 | } 76 | 77 | func (a *Asset) balanceOf_revert(stub shim.ChaincodeStubInterface, args []string) peer.Response { 78 | if len(args) != 1 { 79 | return shim.Error("Invalid args length, should be: [account]") 80 | } 81 | return shim.Success(uint64ToBytes(getBalance(stub, args[0]))) 82 | } 83 | 84 | func getBalance(stub shim.ChaincodeStubInterface, account string) uint64 { 85 | res, err := stub.GetState(getAccountKey(account)) 86 | checkError(err) 87 | if res == nil { 88 | return 0 89 | } else { 90 | return bytesToUint64(res) 91 | } 92 | } 93 | 94 | func setBalance(stub shim.ChaincodeStubInterface, account string, amount uint64) { 95 | err := stub.PutState(getAccountKey(account), uint64ToBytes(amount)) 96 | checkError(err) 97 | } 98 | 99 | func getAccountKey(account string) string { 100 | return fmt.Sprintf(AccountKey, account) 101 | } 102 | 103 | func bytesToUint64(bts []byte) uint64 { 104 | u, err := strconv.ParseUint(string(bts), 10, 64) 105 | checkError(err) 106 | return u 107 | } 108 | 109 | func uint64ToBytes(u uint64) []byte { 110 | return []byte(uint64ToString(u)) 111 | } 112 | 113 | func uint64ToString(u uint64) string { 114 | return strconv.FormatUint(u, 10) 115 | } 116 | 117 | func stringToUint64(str string) uint64 { 118 | i, e := strconv.Atoi(str) 119 | if e != nil { 120 | return 0 121 | } 122 | return uint64(i) 123 | } 124 | 125 | func checkError(err error) { 126 | if err != nil { 127 | panic(err) 128 | } 129 | } 130 | 131 | func main() { 132 | if err := shim.Start(new(Asset)); err != nil { 133 | fmt.Printf("Error starting Asset chaincode: %s", err) 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/main/resources/contracts/chaincode/evidence/evidenceSample.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/hyperledger/fabric/core/chaincode/shim" 7 | "github.com/hyperledger/fabric/protos/peer" 8 | ) 9 | 10 | type Evidence struct { 11 | } 12 | 13 | func (t *Evidence) Init(stub shim.ChaincodeStubInterface) peer.Response { 14 | return shim.Success(nil) 15 | } 16 | 17 | 18 | func (t *Evidence) Invoke(stub shim.ChaincodeStubInterface) (res peer.Response) { 19 | fn, args := stub.GetFunctionAndParameters() 20 | switch fn { 21 | case "newEvidence": 22 | res = t.newEvidence(stub, args) 23 | case "newEvidence_revert": 24 | res = t.newEvidence_revert(stub, args) 25 | case "queryEvidence": 26 | res = t.queryEvidence(stub, args) 27 | case "queryEvidence_revert": 28 | res = t.queryEvidence_revert(stub, args) 29 | default: 30 | return shim.Error("invalid function name") 31 | } 32 | // Return the result as success payload 33 | return res 34 | } 35 | 36 | // id, evidenceInfo 37 | func (t *Evidence) newEvidence(stub shim.ChaincodeStubInterface, args []string) peer.Response { 38 | if len(args) != 2 { 39 | return shim.Error("Invalid args length, should be: [id, evidenceInfo]") 40 | } 41 | 42 | err := stub.PutState(args[0], []byte(args[1])) 43 | if err != nil { 44 | return shim.Error(fmt.Errorf("Failed to new evidence: %s", args[0]).Error()) 45 | } 46 | return shim.Success([]byte("Success")) 47 | } 48 | 49 | // id, evidenceInfo 50 | func (t *Evidence) newEvidence_revert(stub shim.ChaincodeStubInterface, args []string) peer.Response { 51 | if len(args) != 2 { 52 | return shim.Error("Invalid args length, should be: [id, evidenceInfo]") 53 | } 54 | 55 | err := stub.PutState(args[0], []byte("")) 56 | if err != nil { 57 | return shim.Error(fmt.Errorf("Failed to revert evidence: %s", args[0]).Error()) 58 | } 59 | return shim.Success([]byte("Success")) 60 | } 61 | 62 | // id 63 | func (t *Evidence) queryEvidence(stub shim.ChaincodeStubInterface, args []string) peer.Response { 64 | if len(args) != 1 { 65 | return shim.Error(fmt.Errorf("Invalid args length. should be [id]").Error()) 66 | } 67 | 68 | value, err := stub.GetState(args[0]) 69 | if err != nil { 70 | return shim.Error(fmt.Errorf("Failed to query evidence: %s with error: %s", args[0], err).Error()) 71 | } 72 | 73 | return shim.Success([]byte(value)) 74 | } 75 | 76 | func (t *Evidence) queryEvidence_revert(stub shim.ChaincodeStubInterface, args []string) peer.Response { 77 | return shim.Success([]byte("Success")) 78 | } 79 | 80 | func main() { 81 | if err := shim.Start(new(Evidence)); err != nil { 82 | fmt.Printf("Error starting Evidence chaincode: %s", err) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/resources/contracts/chaincode/evidence/policy.yaml: -------------------------------------------------------------------------------- 1 | identities: # list roles to be used in the policy 2 | fabric_user1: {"role": {"name": "member", "mspId": "Org1MSP"}} 3 | fabric_admin_org1: {"role": {"name": "admin", "mspId": "Org1MSP"}} 4 | fabric_admin_org2: {"role": {"name": "admin", "mspId": "Org2MSP"}} 5 | 6 | policy: # the policy .. could have been flat but show grouping. 7 | 1-of: # signed by one of these groups can -of means 'OR' 8 | - 1-of: 9 | - signed-by: "fabric_user1" # a reference to one of the identities defined above. 10 | - signed-by: "fabric_admin_org1" 11 | - 1-of: 12 | - signed-by: "fabric_admin_org2" 13 | 14 | -------------------------------------------------------------------------------- /src/main/resources/contracts/chaincode/helloworld/helloworld.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/hyperledger/fabric/core/chaincode/shim" 7 | "github.com/hyperledger/fabric/protos/peer" 8 | ) 9 | 10 | const NAME = "name" 11 | 12 | type HelloWorld struct { 13 | } 14 | 15 | func (hw *HelloWorld) Init(stub shim.ChaincodeStubInterface) peer.Response { 16 | // init the variable name with "Hello, World!" 17 | err := stub.PutState(NAME, []byte("Hello, World!")) 18 | if err != nil { 19 | return shim.Error("fail in initializing smart contract HelloWorld") 20 | } 21 | return shim.Success(nil) 22 | } 23 | 24 | // Invoke is called per transaction on the chaincode. Each transaction is 25 | // either a 'get' or a 'set'. 26 | 27 | func (hw *HelloWorld) Invoke(stub shim.ChaincodeStubInterface) peer.Response { 28 | // Extract the function and args from the transaction proposal 29 | fn, args := stub.GetFunctionAndParameters() 30 | 31 | var result string 32 | var err error 33 | if fn == "set" { 34 | result, err = set(stub, args) 35 | } else if fn == "get" { // assume 'get' even if fn is nil 36 | result, err = get(stub) 37 | } else { 38 | err = fmt.Errorf("invalid call") 39 | } 40 | 41 | if err != nil { 42 | return shim.Error(err.Error()) 43 | } 44 | 45 | // Return the result as success payload 46 | return shim.Success([]byte(result)) 47 | } 48 | 49 | // Set updates the variable name with a new value. If succeed, the updated value is back. 50 | func set(stub shim.ChaincodeStubInterface, args []string) (string, error) { 51 | if len(args) != 1 { 52 | return "", fmt.Errorf("no value is input") 53 | } 54 | 55 | err := stub.PutState(NAME, []byte(args[0])) 56 | if err != nil { 57 | return "", fmt.Errorf("failed in set: %s", err) 58 | } 59 | return args[0], nil 60 | } 61 | 62 | // Get returns the value of the variable name 63 | func get(stub shim.ChaincodeStubInterface) (string, error) { 64 | value, err := stub.GetState(NAME) 65 | if err != nil { 66 | return "", fmt.Errorf("failed in get: %s", err) 67 | } 68 | if value == nil { 69 | return "", fmt.Errorf("variable name does not exist") 70 | } 71 | return string(value), nil 72 | } 73 | 74 | // main function starts up the chaincode in the container during instantiate 75 | func main() { 76 | if err := shim.Start(new(HelloWorld)); err != nil { 77 | fmt.Printf("Error starting HelloWrold chaincode: %s", err) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/resources/contracts/chaincode/htlc/htlc_sample.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/hyperledger/fabric/core/chaincode/shim" 7 | "github.com/hyperledger/fabric/protos/peer" 8 | ) 9 | 10 | const ( 11 | LedgerChainCodeNameKey = "LedgerChainCodeName" 12 | LedgerChainCodeChannelKey = "LedgerChainCodeChannel" 13 | SugarAccountKeyPrefix = "S-%s" 14 | SuccessFlag = "success" 15 | ) 16 | 17 | type HtlcChaincode struct { 18 | MyHTLC HTLC 19 | } 20 | 21 | func (a *HtlcChaincode) Init(stub shim.ChaincodeStubInterface) (res peer.Response) { 22 | defer func() { 23 | if r := recover(); r != nil { 24 | res = shim.Error(fmt.Sprintf("%v", r)) 25 | } 26 | }() 27 | 28 | var freeIndexStack [Size]int 29 | var proposalList [Size]string 30 | for i := 0; i < Size; i++ { 31 | proposalList[i] = NullFlag 32 | freeIndexStack[i] = Size - i - 1 33 | } 34 | var proposals = Proposals{ 35 | FreeIndexStack: freeIndexStack, 36 | ProposalList: proposalList, 37 | Depth: Size, 38 | } 39 | 40 | p, err := json.Marshal(&proposals) 41 | checkError(err) 42 | 43 | err = stub.PutState(ProposalsKey, p) 44 | checkError(err) 45 | 46 | fn, args := stub.GetFunctionAndParameters() 47 | 48 | switch fn { 49 | case "init": 50 | res = a.init(stub, args) 51 | default: 52 | res = shim.Success(nil) 53 | } 54 | 55 | return 56 | } 57 | 58 | func (a *HtlcChaincode) Invoke(stub shim.ChaincodeStubInterface) (res peer.Response) { 59 | defer func() { 60 | if r := recover(); r != nil { 61 | res = shim.Error(fmt.Sprintf("%v", r)) 62 | } 63 | }() 64 | 65 | fcn, args := stub.GetFunctionAndParameters() 66 | 67 | switch fcn { 68 | case "init": 69 | res = a.init(stub, args) 70 | case "lock": 71 | res = a.lock(stub, args) 72 | case "unlock": 73 | res = a.unlock(stub, args) 74 | case "rollback": 75 | res = a.rollback(stub, args) 76 | case "newProposal": 77 | res = a.newProposal(stub, args) 78 | case "setNewProposalTxInfo": 79 | res = a.setNewProposalTxInfo(stub, args) 80 | case "getNewProposalTxInfo": 81 | res = a.getNewProposalTxInfo(stub, args) 82 | case "getNegotiatedData": 83 | res = a.getNegotiatedData(stub, args) 84 | case "getProposalInfo": 85 | res = a.getProposalInfo(stub, args) 86 | case "setSecret": 87 | res = a.setSecret(stub, args) 88 | case "getProposalIDs": 89 | res = a.getProposalIDs(stub) 90 | case "deleteProposalID": 91 | res = a.deleteProposalID(stub, args) 92 | case "setCounterpartyLockState": 93 | res = a.setCounterpartyLockState(stub, args) 94 | case "setCounterpartyUnlockState": 95 | res = a.setCounterpartyUnlockState(stub, args) 96 | case "setCounterpartyRollbackState": 97 | res = a.setCounterpartyRollbackState(stub, args) 98 | case "balanceOf": 99 | res = a.balanceOf(stub, args) 100 | case "queryAddress": 101 | res = a.queryAddress(stub) 102 | default: 103 | res = shim.Error("invalid function name") 104 | } 105 | 106 | return 107 | } 108 | 109 | func (a *HtlcChaincode) init(stub shim.ChaincodeStubInterface, args []string) peer.Response { 110 | if len(args) < 2 { 111 | return shim.Error("invalid arguments") 112 | } 113 | 114 | name, channel := args[0], args[1] 115 | 116 | err := stub.PutState(LedgerChainCodeNameKey, []byte(name)) 117 | if err != nil { 118 | return shim.Error(err.Error()) 119 | } 120 | 121 | err = stub.PutState(LedgerChainCodeChannelKey, []byte(channel)) 122 | if err != nil { 123 | return shim.Error(err.Error()) 124 | } 125 | 126 | return shim.Success([]byte(SuccessFlag)) 127 | } 128 | 129 | func (a *HtlcChaincode) newProposal(stub shim.ChaincodeStubInterface, args []string) peer.Response { 130 | if len(args) != 10 { 131 | return shim.Error("invalid arguments") 132 | } 133 | 134 | hash, role, sender0, receiver0, amount0, timelock0, sender1, receiver1, amount1, timelock1 := 135 | args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9] 136 | a.MyHTLC.newProposal(stub, hash, role, sender0, receiver0, amount0, timelock0, sender1, receiver1, amount1, timelock1) 137 | return shim.Success([]byte(SuccessFlag)) 138 | } 139 | 140 | func (a *HtlcChaincode) setNewProposalTxInfo(stub shim.ChaincodeStubInterface, args []string) peer.Response { 141 | if len(args) != 3 { 142 | return shim.Error("invalid arguments") 143 | } 144 | 145 | hash, txHash, blockNum := args[0], args[1], args[2] 146 | a.MyHTLC.setNewProposalTxInfo(stub, hash, txHash, blockNum) 147 | return shim.Success([]byte(SuccessFlag)) 148 | } 149 | 150 | func (a *HtlcChaincode) getNewProposalTxInfo(stub shim.ChaincodeStubInterface, args []string) peer.Response { 151 | if len(args) != 1 { 152 | return shim.Error("invalid arguments") 153 | } 154 | 155 | hash := args[0] 156 | return shim.Success(a.MyHTLC.getNewProposalTxInfo(stub, hash)) 157 | } 158 | 159 | func (a *HtlcChaincode) getNegotiatedData(stub shim.ChaincodeStubInterface, args []string) peer.Response { 160 | if len(args) != 1 { 161 | return shim.Error("invalid arguments") 162 | } 163 | 164 | hash := args[0] 165 | return shim.Success(a.MyHTLC.getNegotiatedData(stub, hash)) 166 | } 167 | 168 | func (a *HtlcChaincode) getProposalInfo(stub shim.ChaincodeStubInterface, args []string) peer.Response { 169 | if len(args) != 1 { 170 | return shim.Error("invalid arguments") 171 | } 172 | 173 | hash := args[0] 174 | return shim.Success(a.MyHTLC.getProposalInfo(stub, hash)) 175 | } 176 | 177 | func (a *HtlcChaincode) setSecret(stub shim.ChaincodeStubInterface, args []string) peer.Response { 178 | if len(args) != 2 { 179 | return shim.Error("invalid arguments") 180 | } 181 | 182 | hash, secret := args[0], args[1] 183 | a.MyHTLC.setSecret(stub, hash, secret) 184 | return shim.Success([]byte(SuccessFlag)) 185 | } 186 | 187 | func (a *HtlcChaincode) lock(stub shim.ChaincodeStubInterface, args []string) peer.Response { 188 | if len(args) != 1 { 189 | return shim.Error("invalid arguments") 190 | } 191 | 192 | hash := args[0] 193 | result := a.MyHTLC.lock(stub, hash) 194 | if result == "done" { 195 | return shim.Success([]byte("success")) 196 | } else if result != "continue" { 197 | return shim.Success([]byte(result)) 198 | } 199 | 200 | var pd ProposalData 201 | a.MyHTLC.getSelfProposalData(stub, hash, &pd) 202 | cname, err := stub.GetState(LedgerChainCodeNameKey) 203 | if err != nil { 204 | return shim.Error(err.Error()) 205 | } 206 | channel, err := stub.GetState(LedgerChainCodeChannelKey) 207 | if err != nil { 208 | return shim.Error(err.Error()) 209 | } 210 | trans := [][]byte{[]byte("escrowToSugar"), []byte(pd.Sender), []byte(hash), uint64ToBytes(pd.Amount)} 211 | response := stub.InvokeChaincode(string(cname), trans, string(channel)) 212 | if response.Status != shim.OK { 213 | return shim.Success([]byte(response.Message)) 214 | } 215 | 216 | err = stub.PutState(getSugarAccountKey(hash), response.Payload) 217 | if err != nil { 218 | return shim.Error(err.Error()) 219 | } 220 | 221 | pd.Locked = true 222 | a.MyHTLC.setSelfProposalData(stub, hash, &pd) 223 | return shim.Success([]byte(SuccessFlag)) 224 | } 225 | 226 | func (a *HtlcChaincode) unlock(stub shim.ChaincodeStubInterface, args []string) peer.Response { 227 | if len(args) < 2 { 228 | return shim.Error("invalid arguments") 229 | } 230 | 231 | hash, secret := args[0], args[1] 232 | result := a.MyHTLC.unlock(stub, hash, secret) 233 | if result == "done" { 234 | return shim.Success([]byte("success")) 235 | } else if result != "continue" { 236 | return shim.Success([]byte(result)) 237 | } 238 | 239 | var pd ProposalData 240 | a.MyHTLC.getSelfProposalData(stub, hash, &pd) 241 | sa, err := stub.GetState(getSugarAccountKey(hash)) 242 | if err != nil { 243 | return shim.Error(err.Error()) 244 | } 245 | cname, err := stub.GetState(LedgerChainCodeNameKey) 246 | if err != nil { 247 | return shim.Error(err.Error()) 248 | } 249 | channel, err := stub.GetState(LedgerChainCodeChannelKey) 250 | if err != nil { 251 | return shim.Error(err.Error()) 252 | } 253 | trans := [][]byte{[]byte("withdrawFromSugarAccount"), sa, []byte(pd.Receiver), []byte(secret)} 254 | response := stub.InvokeChaincode(string(cname), trans, string(channel)) 255 | if response.Status != shim.OK { 256 | return shim.Success([]byte(response.Message)) 257 | } 258 | 259 | pd.Unlocked = true 260 | pd.Secret = secret 261 | a.MyHTLC.setSelfProposalData(stub, hash, &pd) 262 | return shim.Success([]byte(SuccessFlag)) 263 | } 264 | 265 | func (a *HtlcChaincode) rollback(stub shim.ChaincodeStubInterface, args []string) peer.Response { 266 | if len(args) != 1 { 267 | return shim.Error("invalid arguments") 268 | } 269 | 270 | hash := args[0] 271 | result := a.MyHTLC.rollback(stub, hash) 272 | if result == "done" { 273 | return shim.Success([]byte("success")) 274 | } else if result != "continue" { 275 | return shim.Success([]byte(result)) 276 | } 277 | 278 | var pd ProposalData 279 | a.MyHTLC.getSelfProposalData(stub, hash, &pd) 280 | sa, err := stub.GetState(getSugarAccountKey(hash)) 281 | if err != nil { 282 | return shim.Error(err.Error()) 283 | } 284 | cname, err := stub.GetState(LedgerChainCodeNameKey) 285 | if err != nil { 286 | return shim.Error(err.Error()) 287 | } 288 | channel, err := stub.GetState(LedgerChainCodeChannelKey) 289 | if err != nil { 290 | return shim.Error(err.Error()) 291 | } 292 | trans := [][]byte{[]byte("withdrawFromSugarAccount"), sa, []byte(pd.Sender)} 293 | response := stub.InvokeChaincode(string(cname), trans, string(channel)) 294 | if response.Status != shim.OK { 295 | return shim.Success([]byte(response.Message)) 296 | } 297 | 298 | pd.Rolledback = true 299 | a.MyHTLC.setSelfProposalData(stub, hash, &pd) 300 | return shim.Success([]byte(SuccessFlag)) 301 | } 302 | 303 | func (a *HtlcChaincode) getProposalIDs(stub shim.ChaincodeStubInterface) peer.Response { 304 | return shim.Success(a.MyHTLC.getProposalIDs(stub)) 305 | } 306 | 307 | func (a *HtlcChaincode) deleteProposalID(stub shim.ChaincodeStubInterface, args []string) peer.Response { 308 | if len(args) != 1 { 309 | return shim.Error("invalid arguments") 310 | } 311 | 312 | hash := args[0] 313 | a.MyHTLC.deleteProposalID(stub, hash) 314 | return shim.Success([]byte(SuccessFlag)) 315 | } 316 | 317 | func (a *HtlcChaincode) setCounterpartyLockState(stub shim.ChaincodeStubInterface, args []string) peer.Response { 318 | if len(args) != 1 { 319 | return shim.Error("invalid arguments") 320 | } 321 | 322 | hash := args[0] 323 | a.MyHTLC.setCounterpartyLockState(stub, hash) 324 | return shim.Success([]byte(SuccessFlag)) 325 | } 326 | 327 | func (a *HtlcChaincode) setCounterpartyUnlockState(stub shim.ChaincodeStubInterface, args []string) peer.Response { 328 | if len(args) != 1 { 329 | return shim.Error("invalid arguments") 330 | } 331 | 332 | hash := args[0] 333 | a.MyHTLC.setCounterpartyUnlockState(stub, hash) 334 | return shim.Success([]byte(SuccessFlag)) 335 | } 336 | 337 | func (a *HtlcChaincode) setCounterpartyRollbackState(stub shim.ChaincodeStubInterface, args []string) peer.Response { 338 | if len(args) != 1 { 339 | return shim.Error("invalid arguments") 340 | } 341 | 342 | hash := args[0] 343 | a.MyHTLC.setCounterpartyRollbackState(stub, hash) 344 | return shim.Success([]byte(SuccessFlag)) 345 | } 346 | 347 | func (a *HtlcChaincode) balanceOf(stub shim.ChaincodeStubInterface, args []string) peer.Response { 348 | if len(args) != 1 { 349 | return shim.Error("invalid arguments") 350 | } 351 | 352 | cname, err := stub.GetState(LedgerChainCodeNameKey) 353 | if err != nil { 354 | return shim.Error(err.Error()) 355 | } 356 | channel, err := stub.GetState(LedgerChainCodeChannelKey) 357 | if err != nil { 358 | return shim.Error(err.Error()) 359 | } 360 | trans := [][]byte{[]byte("balanceOf"), []byte(args[0])} 361 | response := stub.InvokeChaincode(string(cname), trans, string(channel)) 362 | if response.Status != 200 { 363 | return shim.Success([]byte(response.Message)) 364 | } 365 | return shim.Success(response.Payload) 366 | } 367 | 368 | func (a *HtlcChaincode) queryAddress(stub shim.ChaincodeStubInterface) peer.Response { 369 | return shim.Success([]byte(getTxOrigin(stub))) 370 | } 371 | 372 | func getSugarAccountKey(hash string) string { 373 | return fmt.Sprintf(SugarAccountKeyPrefix, hash) 374 | } 375 | 376 | func main() { 377 | err := shim.Start(new(HtlcChaincode)) 378 | if err != nil { 379 | fmt.Printf("Error: %s", err) 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /src/main/resources/contracts/chaincode/interchain/interchainSample.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/hyperledger/fabric/core/chaincode/shim" 7 | "github.com/hyperledger/fabric/protos/peer" 8 | ) 9 | 10 | const ( 11 | ChannelKey = "channel" 12 | HubNameKey = "hub_name" 13 | DataKey = "data" 14 | ) 15 | 16 | type Interchain struct { 17 | } 18 | 19 | func (i *Interchain) Init(stub shim.ChaincodeStubInterface) (res peer.Response) { 20 | defer func() { 21 | if r := recover(); r != nil { 22 | res = shim.Error(fmt.Sprintf("%v", r)) 23 | } 24 | }() 25 | 26 | data := []string{"Talk is cheap, show me the code."} 27 | dataBytes, err := json.Marshal(data) 28 | checkError(err) 29 | 30 | err = stub.PutState(DataKey, dataBytes) 31 | checkError(err) 32 | 33 | return shim.Success(nil) 34 | } 35 | 36 | func (i *Interchain) Invoke(stub shim.ChaincodeStubInterface) (res peer.Response) { 37 | defer func() { 38 | if r := recover(); r != nil { 39 | res = shim.Error(fmt.Sprintf("%v", r)) 40 | } 41 | }() 42 | 43 | fcn, args := stub.GetFunctionAndParameters() 44 | 45 | switch fcn { 46 | case "init": 47 | res = i.init(stub, args) 48 | case "interchain": 49 | res = i.interchain(stub, args) 50 | case "callback": 51 | res = i.callback(stub, args) 52 | case "get": 53 | res = i.get(stub) 54 | case "set": 55 | res = i.set(stub, args) 56 | default: 57 | res = shim.Error("invalid function name") 58 | } 59 | 60 | return 61 | } 62 | 63 | /* 64 | * @args channel || hub 65 | */ 66 | func (i *Interchain) init(stub shim.ChaincodeStubInterface, args []string) peer.Response { 67 | if len(args) != 2 { 68 | return shim.Error("incorrect number of arguments, expecting 2") 69 | } 70 | 71 | err := stub.PutState(ChannelKey, []byte(args[0])) 72 | checkError(err) 73 | 74 | err = stub.PutState(HubNameKey, []byte(args[1])) 75 | checkError(err) 76 | 77 | return shim.Success(nil) 78 | } 79 | 80 | /* 81 | * invoke other chain 82 | * @args path || method || args || callbackPath || callbackMethod 83 | */ 84 | func (i *Interchain) interchain(stub shim.ChaincodeStubInterface, args []string) peer.Response { 85 | if len(args) != 5 { 86 | return shim.Error("incorrect number of arguments, expecting 5") 87 | } 88 | 89 | channel, err := stub.GetState(ChannelKey) 90 | checkError(err) 91 | 92 | hub, err := stub.GetState(HubNameKey) 93 | checkError(err) 94 | 95 | var trans [][]byte 96 | trans = append(trans, []byte("interchainInvoke")) 97 | trans = append(trans, []byte(args[0])) 98 | trans = append(trans, []byte(args[1])) 99 | 100 | input := []string{args[2]} 101 | inputData, err := json.Marshal(input) 102 | checkError(err) 103 | trans = append(trans, inputData) 104 | 105 | trans = append(trans, []byte(args[3])) 106 | trans = append(trans, []byte(args[4])) 107 | 108 | return stub.InvokeChaincode(string(hub), trans, string(channel)) 109 | } 110 | 111 | /* 112 | * @args state || result 113 | * result is json form of string array 114 | */ 115 | func (i *Interchain) callback(stub shim.ChaincodeStubInterface, args []string) peer.Response { 116 | if len(args) != 2 { 117 | return shim.Error("incorrect number of arguments, expecting 2") 118 | } 119 | 120 | if "true" == args[0] { 121 | err := stub.PutState(DataKey, []byte(args[1])) 122 | checkError(err) 123 | } 124 | return shim.Success([]byte(args[1])) 125 | } 126 | 127 | func (i *Interchain) get(stub shim.ChaincodeStubInterface) peer.Response { 128 | data, err := stub.GetState(DataKey) 129 | checkError(err) 130 | return shim.Success(data) 131 | } 132 | 133 | func (i *Interchain) set(stub shim.ChaincodeStubInterface, args []string) peer.Response { 134 | if len(args) != 1 { 135 | return shim.Error("incorrect number of arguments, expecting 1") 136 | } 137 | 138 | err := stub.PutState(DataKey, []byte(args[0])) 139 | checkError(err) 140 | 141 | return shim.Success([]byte(args[0])) 142 | } 143 | 144 | func checkError(err error) { 145 | if err != nil { 146 | panic(err) 147 | } 148 | } 149 | 150 | func main() { 151 | err := shim.Start(new(Interchain)) 152 | if err != nil { 153 | fmt.Printf("Error: %s", err) 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/main/resources/contracts/chaincode/sacc/policy.yaml: -------------------------------------------------------------------------------- 1 | identities: # list roles to be used in the policy 2 | fabric_user1: {"role": {"name": "member", "mspId": "Org1MSP"}} 3 | fabric_admin_org1: {"role": {"name": "admin", "mspId": "Org1MSP"}} 4 | fabric_admin_org2: {"role": {"name": "admin", "mspId": "Org2MSP"}} 5 | 6 | policy: # the policy .. could have been flat but show grouping. 7 | 1-of: # signed by one of these groups can -of means 'OR' 8 | - 1-of: 9 | - signed-by: "fabric_user1" # a reference to one of the identities defined above. 10 | - signed-by: "fabric_admin_org1" 11 | - 1-of: 12 | - signed-by: "fabric_admin_org2" 13 | 14 | -------------------------------------------------------------------------------- /src/main/resources/contracts/chaincode/sacc/sacc.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright IBM Corp All Rights Reserved 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package main 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/hyperledger/fabric/core/chaincode/shim" 13 | "github.com/hyperledger/fabric/protos/peer" 14 | ) 15 | 16 | // SimpleAsset implements a simple chaincode to manage an asset 17 | type SimpleAsset struct { 18 | } 19 | 20 | // Init is called during chaincode instantiation to initialize any 21 | // data. Note that chaincode upgrade also calls this function to reset 22 | // or to migrate data. 23 | func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response { 24 | // Get the args from the transaction proposal 25 | _, args := stub.GetFunctionAndParameters() // Input: "init, args[0], args[1] ..." 26 | if len(args) != 2 { 27 | return shim.Error("Incorrect arguments. Expecting a key and a value0") 28 | } 29 | 30 | // Set up any variables or assets here by calling stub.PutState() 31 | 32 | // We store the key and the value on the ledger 33 | err := stub.PutState(args[0], []byte(args[1])) 34 | if err != nil { 35 | return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0])) 36 | } 37 | return shim.Success(nil) 38 | } 39 | 40 | // Invoke is called per transaction on the chaincode. Each transaction is 41 | // either a 'get' or a 'set' on the asset created by Init function. The Set 42 | // method may create a new asset by specifying a new key-value pair. 43 | func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response { 44 | // Extract the function and args from the transaction proposal 45 | fn, args := stub.GetFunctionAndParameters() 46 | 47 | var result string 48 | var err error 49 | if fn == "set" { 50 | result, err = set(stub, args) 51 | } else { // assume 'get' even if fn is nil 52 | result, err = get(stub, args) 53 | } 54 | if err != nil { 55 | return shim.Error(err.Error()) 56 | } 57 | 58 | // Return the result as success payload 59 | return shim.Success([]byte(result)) 60 | } 61 | 62 | // Set stores the asset (both key and value) on the ledger. If the key exists, 63 | // it will override the value with the new one 64 | func set(stub shim.ChaincodeStubInterface, args []string) (string, error) { 65 | if len(args) != 2 { 66 | return "", fmt.Errorf("Incorrect arguments. Expecting a key and a value") 67 | } 68 | 69 | err := stub.PutState(args[0], []byte(args[1])) 70 | if err != nil { 71 | return "", fmt.Errorf("Failed to set asset: %s", args[0]) 72 | } 73 | return args[1], nil 74 | } 75 | 76 | // Get returns the value of the specified asset key 77 | func get(stub shim.ChaincodeStubInterface, args []string) (string, error) { 78 | if len(args) != 1 { 79 | return "", fmt.Errorf("Incorrect arguments. Expecting a key") 80 | } 81 | 82 | value, err := stub.GetState(args[0]) 83 | if err != nil { 84 | return "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err) 85 | } 86 | if value == nil { 87 | return "", fmt.Errorf("Asset not found: %s", args[0]) 88 | } 89 | return string(value), nil 90 | } 91 | 92 | // main function starts up the chaincode in the container during instantiate 93 | func main() { 94 | if err := shim.Start(new(SimpleAsset)); err != nil { 95 | fmt.Printf("Error starting SimpleAsset chaincode: %s", err) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/resources/contracts/liquid/hello_world/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | -------------------------------------------------------------------------------- /src/main/resources/contracts/liquid/hello_world/.liquid/abi_gen/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "abi-gen" 3 | version = "1.0.0-rc2" 4 | authors = ["vita-dounai "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [[bin]] 9 | name = "abi-gen" 10 | path = "main.rs" 11 | 12 | [dependencies.contract] 13 | path = "../../" 14 | package = "hello_world" 15 | default-features = false 16 | features = ["liquid-abi-gen"] 17 | 18 | [dependencies.liquid_lang] 19 | git = "https://github.com/WeBankBlockchain/liquid" 20 | branch = "dev" 21 | package = "liquid_lang" 22 | default-features = false 23 | features = ["contract-abi-gen"] 24 | 25 | [dependencies] 26 | serde = "1.0" 27 | serde_json = "1.0" -------------------------------------------------------------------------------- /src/main/resources/contracts/liquid/hello_world/.liquid/abi_gen/main.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, env}; 2 | 3 | fn main() -> Result<(), std::io::Error> { 4 | let mut abi = HashMap::new(); 5 | 6 | let contract_abi = ::generate_abi(); 7 | 8 | let mut local_abi = 9 | Vec::with_capacity(contract_abi.event_abis.len() + contract_abi.fn_abis.len() + 1); 10 | local_abi.extend( 11 | contract_abi 12 | .event_abis 13 | .iter() 14 | .map(|event_abi| liquid_lang::AbiKind::Event(event_abi.clone())), 15 | ); 16 | local_abi.push(liquid_lang::AbiKind::Constructor( 17 | contract_abi.constructor_abi, 18 | )); 19 | local_abi.extend( 20 | contract_abi 21 | .fn_abis 22 | .iter() 23 | .map(|fn_abi| liquid_lang::AbiKind::ExternalFn(fn_abi.clone())), 24 | ); 25 | abi.insert(String::from("$local"), local_abi); 26 | 27 | for (iface_name, fn_abis) in contract_abi.iface_abis { 28 | let fn_abis = fn_abis 29 | .iter() 30 | .map(|fn_abi| liquid_lang::AbiKind::ExternalFn(fn_abi.clone())) 31 | .collect::>(); 32 | abi.insert(iface_name, fn_abis); 33 | } 34 | 35 | let target_dir = env::var("CARGO_TARGET_DIR").unwrap_or("target".into()); 36 | std::fs::create_dir(&target_dir).ok(); 37 | std::fs::write("hello_world.abi", serde_json::to_string(&abi).unwrap())?; 38 | Ok(()) 39 | } 40 | -------------------------------------------------------------------------------- /src/main/resources/contracts/liquid/hello_world/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello_world" 3 | version = "0.1.0" 4 | authors = ["[your_name] "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | scale = { package = "parity-scale-codec", version = "1.3.1", default-features = false, features = ["derive", "full"] } 11 | 12 | liquid_lang = { version = "1.0.0-rc2", git = "https://github.com/WeBankBlockchain/liquid", branch = "dev", package = "liquid_lang", default-features = false, features = ["contract"] } 13 | liquid_primitives = { version = "1.0.0-rc2", git = "https://github.com/WeBankBlockchain/liquid", branch = "dev", package = "liquid_primitives", default-features = false } 14 | liquid_prelude = { version = "1.0.0-rc2", git = "https://github.com/WeBankBlockchain/liquid", branch = "dev", package = "liquid_prelude", default-features = false } 15 | liquid_macro = { version = "1.0.0-rc2", git = "https://github.com/WeBankBlockchain/liquid", branch = "dev", package = "liquid_macro", default-features = false } 16 | liquid_abi_gen = { version = "1.0.0-rc2", git = "https://github.com/WeBankBlockchain/liquid", branch = "dev", package = "liquid_abi_gen", default-features = false, optional = true } 17 | 18 | [dev-dependencies] 19 | predicates = "1.0.5" 20 | 21 | [lib] 22 | name = "hello_world" 23 | crate-type = [ 24 | # Used for normal contract Wasm blobs. 25 | "cdylib", 26 | # Used for ABI generation. 27 | "rlib", 28 | ] 29 | 30 | [features] 31 | default = ["std"] 32 | std = [ 33 | "liquid_lang/std", 34 | "scale/std", 35 | "liquid_primitives/std", 36 | "liquid_prelude/std", 37 | "liquid_macro/std", 38 | ] 39 | liquid-abi-gen = [ 40 | "std", 41 | "liquid_abi_gen", 42 | "liquid_lang/contract-abi-gen", 43 | ] 44 | gm = [ 45 | "liquid_lang/gm", 46 | "liquid_primitives/gm", 47 | ] 48 | 49 | [profile.release] 50 | panic = "abort" 51 | lto = true 52 | opt-level = "z" 53 | overflow-checks = true 54 | 55 | [workspace] 56 | members = [ 57 | ".liquid/abi_gen", 58 | ] 59 | exclude = [ 60 | ".liquid", 61 | ] 62 | -------------------------------------------------------------------------------- /src/main/resources/contracts/liquid/hello_world/hello_world.abi: -------------------------------------------------------------------------------- 1 | [{"inputs":[],"type":"constructor"},{"constant":true,"inputs":[],"name":"get","outputs":[{"internalType":"string","type":"string"}],"type":"function"},{"conflictFields":[{"kind":0,"path":[],"read_only":false,"slot":0}],"constant":false,"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"set","outputs":[],"type":"function"}] -------------------------------------------------------------------------------- /src/main/resources/contracts/liquid/hello_world/hello_world.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeBankBlockchain/WeCross-Console/d8b8f82c1cd49356d689f2c16288b8c8ebff434d/src/main/resources/contracts/liquid/hello_world/hello_world.wasm -------------------------------------------------------------------------------- /src/main/resources/contracts/liquid/hello_world/hello_world_gm.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeBankBlockchain/WeCross-Console/d8b8f82c1cd49356d689f2c16288b8c8ebff434d/src/main/resources/contracts/liquid/hello_world/hello_world_gm.wasm -------------------------------------------------------------------------------- /src/main/resources/contracts/liquid/hello_world/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | use liquid::storage; 4 | use liquid_lang as liquid; 5 | 6 | #[liquid::contract] 7 | mod hello_world { 8 | use super::*; 9 | 10 | #[liquid(storage)] 11 | struct HelloWorld { 12 | name: storage::Value, 13 | } 14 | 15 | #[liquid(methods)] 16 | impl HelloWorld { 17 | pub fn new(&mut self) { 18 | self.name.initialize(String::from("Alice")); 19 | } 20 | 21 | pub fn get(&self) -> String { 22 | self.name.clone() 23 | } 24 | 25 | pub fn set(&mut self, name: String) { 26 | self.name.set(name) 27 | } 28 | } 29 | 30 | #[cfg(test)] 31 | mod tests { 32 | use super::*; 33 | 34 | #[test] 35 | fn get_works() { 36 | let contract = HelloWorld::new(); 37 | assert_eq!(contract.get(), "Alice"); 38 | } 39 | 40 | #[test] 41 | fn set_works() { 42 | let mut contract = HelloWorld::new(); 43 | 44 | let new_name = String::from("Bob"); 45 | contract.set(new_name.clone()); 46 | assert_eq!(contract.get(), "Bob"); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/resources/contracts/solidity/AssetSample.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.22 <0.6.0; 2 | 3 | contract Asset { 4 | mapping(string => uint256) ledger; 5 | 6 | string constant SUCCESS_FLAG = "Success"; 7 | string constant FAIL_FLAG = "Fail"; 8 | 9 | constructor() public { 10 | ledger["Alice"] = 1000; 11 | ledger["Oscar"] = 100; 12 | } 13 | 14 | function transfer(string memory _sender, string memory _receiver, uint256 _amount) public 15 | returns (string memory) 16 | { 17 | uint256 senderBalance = ledger[_sender]; 18 | if(senderBalance < _amount) { 19 | revert(FAIL_FLAG); 20 | } 21 | 22 | uint256 receiverBalance = ledger[_receiver]; 23 | if((receiverBalance + _amount) < receiverBalance){ 24 | revert(FAIL_FLAG); 25 | } 26 | 27 | ledger[_sender] = senderBalance - _amount; 28 | ledger[_receiver] = receiverBalance + _amount; 29 | return SUCCESS_FLAG; 30 | } 31 | 32 | function transfer_revert(string memory _sender, string memory _receiver, uint256 _amount) public 33 | returns (string memory) 34 | { 35 | return transfer(_receiver, _sender, _amount); 36 | } 37 | 38 | function balanceOf(string memory _account) public view 39 | returns (uint256) 40 | { 41 | return ledger[_account]; 42 | } 43 | 44 | function balanceOf_revert(string memory _account) public view 45 | returns (uint256) 46 | { 47 | return ledger[_account]; 48 | } 49 | } -------------------------------------------------------------------------------- /src/main/resources/contracts/solidity/EvidenceSample.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0 <0.6.0; 2 | pragma experimental ABIEncoderV2; 3 | 4 | contract Evidence { 5 | 6 | mapping(string => string) infos; 7 | 8 | function() external { 9 | 10 | } 11 | 12 | function newEvidence(string memory id, string memory evidenceInfo) public returns(bool) { 13 | infos[id] = evidenceInfo; 14 | return true; 15 | } 16 | 17 | function newEvidence_revert(string memory id, string memory evidenceInfo) public returns(bool) { 18 | delete infos[id]; 19 | return true; 20 | } 21 | 22 | function queryEvidence(string memory id) public view returns(string memory) { 23 | return infos[id]; 24 | } 25 | 26 | function queryEvidence_revert(string memory id) public view returns(string memory) { 27 | return infos[id]; 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/resources/contracts/solidity/HelloWeCross.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.24 <0.6.0; 2 | pragma experimental ABIEncoderV2; 3 | 4 | contract HelloWeCross { 5 | string[] ss; 6 | 7 | function set(string[] memory _ss) public returns (string[] memory) { 8 | ss = _ss; 9 | return ss; 10 | } 11 | 12 | function getAndClear() public returns(string[] memory) { 13 | string[] memory _ss = ss; 14 | ss.length = 0; 15 | return _ss; 16 | } 17 | 18 | function get() public view returns(string[] memory) { 19 | return ss; 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/resources/contracts/solidity/HelloWorld.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.0 <0.6.0; 2 | 3 | contract HelloWorld { 4 | string name; 5 | 6 | constructor() public { 7 | name = "Hello, World!"; 8 | } 9 | 10 | function get() public view returns (string memory) { 11 | return name; 12 | } 13 | 14 | function set(string memory n) public { 15 | name = n; 16 | } 17 | } -------------------------------------------------------------------------------- /src/main/resources/contracts/solidity/InterchainGetBlockSample.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.22 <0.6.0; 2 | pragma experimental ABIEncoderV2; 3 | 4 | import "./WeCrossHub.sol"; 5 | 6 | 7 | contract InterchainGetBlockSample { 8 | WeCrossHub hub; 9 | 10 | string[] blockStr = [""]; 11 | 12 | function init(address _hub) public 13 | { 14 | hub = WeCrossHub(_hub); 15 | } 16 | 17 | function interchainGetBlock(string memory _path, string memory _method, string memory _args, string memory _callbackPath, string memory _callbackMethod) public 18 | returns(string memory) 19 | { 20 | string[] memory args = new string[](1); 21 | args[0] = _args; 22 | 23 | return hub.interchainGetBlock(_path, _method, args, _callbackPath, _callbackMethod); 24 | } 25 | 26 | function callback(bool state, string[] memory _result) public 27 | returns(string[] memory) 28 | { 29 | if(state) { 30 | blockStr = _result; 31 | } 32 | 33 | return _result; 34 | } 35 | 36 | function get() public view 37 | returns(string[] memory) 38 | { 39 | return blockStr; 40 | } 41 | 42 | function set(string[] memory _data) public 43 | returns(string[] memory) 44 | { 45 | blockStr = _data; 46 | return blockStr; 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /src/main/resources/contracts/solidity/InterchainSample.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.22 <0.6.0; 2 | pragma experimental ABIEncoderV2; 3 | 4 | import "./WeCrossHub.sol"; 5 | 6 | 7 | contract InterchainSample { 8 | WeCrossHub hub; 9 | 10 | string[] data = ["Talk is cheap, show me the code."]; 11 | 12 | function init(address _hub) public 13 | { 14 | hub = WeCrossHub(_hub); 15 | } 16 | 17 | function interchain(string memory _path, string memory _method, string memory _args, string memory _callbackPath, string memory _callbackMethod) public 18 | returns(string memory) 19 | { 20 | string[] memory args = new string[](1); 21 | args[0] = _args; 22 | 23 | return hub.interchainInvoke(_path, _method, args, _callbackPath, _callbackMethod); 24 | } 25 | 26 | function callback(bool state, string[] memory _result) public 27 | returns(string[] memory) 28 | { 29 | if(state) { 30 | data = _result; 31 | } 32 | 33 | return _result; 34 | } 35 | 36 | function get() public view 37 | returns(string[] memory) 38 | { 39 | return data; 40 | } 41 | 42 | function set(string[] memory _data) public 43 | returns(string[] memory) 44 | { 45 | data = _data; 46 | return data; 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /src/main/resources/contracts/solidity/LedgerSampleHTLC.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.22 <0.6.0; 2 | 3 | import "./LedgerSample.sol"; 4 | import "./HTLC.sol"; 5 | 6 | contract LedgerSampleHTLC is HTLC, LedgerSampleHolder { 7 | 8 | // asset contract address 9 | address assetContract; 10 | 11 | /* 12 | @param: assetContract 13 | */ 14 | function init(string memory _assetContract) public 15 | returns (string memory result) 16 | { 17 | assetContract = stringToAddress(_assetContract); 18 | result = successFlag; 19 | } 20 | 21 | /* 22 | @param: hash 23 | */ 24 | function lock(string memory _hash) public 25 | returns (string memory result) 26 | { 27 | result = super.lock(_hash); 28 | if(sameString(result, "done")) { 29 | result = successFlag; 30 | return result; 31 | } else if (!sameString(result, "continue")) { 32 | return result; 33 | } 34 | 35 | address sender = getSender(_hash); 36 | uint amount = getAmount(_hash); 37 | if (LedgerSample(assetContract).allowance(sender, address(this)) < uint(amount)) { 38 | result = "insufficient authorized assets"; 39 | return result; 40 | } 41 | 42 | // This htlc contract becomes the temporary owner of the assets 43 | LedgerSample(assetContract).sendFrom(sender, address(this), uint(amount),""); 44 | 45 | setLockState(_hash); 46 | result = successFlag; 47 | } 48 | 49 | /* 50 | @param: hash | secret 51 | */ 52 | function unlock(string memory _hash, string memory _secret) public 53 | returns (string memory result) 54 | { 55 | result = super.unlock(_hash, _secret); 56 | if(sameString(result, "done")) { 57 | result = successFlag; 58 | return result; 59 | } else if (!sameString(result, "continue")) { 60 | return result; 61 | } 62 | 63 | // transfer from htlc contract to receiver 64 | address receiver = getReceiver(_hash); 65 | uint amount = getAmount(_hash); 66 | LedgerSample(assetContract).send(receiver, uint(amount),""); 67 | 68 | setUnlockState(_hash); 69 | setSecret(_hash, _secret); 70 | result = successFlag; 71 | } 72 | 73 | /* 74 | @param: hash 75 | */ 76 | function rollback(string memory _hash) public 77 | returns (string memory result) 78 | { 79 | result = super.rollback(_hash); 80 | if(sameString(result, "done")) { 81 | result = successFlag; 82 | return result; 83 | } else if (!sameString(result, "continue")) { 84 | return result; 85 | } 86 | 87 | // transfer from htlc contract to sender 88 | address sender = getSender(_hash); 89 | uint amount = getAmount(_hash); 90 | LedgerSample(assetContract).send(sender, uint(amount),""); 91 | 92 | setRollbackState(_hash); 93 | result = successFlag; 94 | } 95 | 96 | /* 97 | @param: address 98 | */ 99 | function balanceOf(string memory account) public view 100 | returns(uint256) 101 | { 102 | return LedgerSample(assetContract).balance(stringToAddress(account)); 103 | } 104 | 105 | function queryAddress() public view 106 | returns(address) 107 | { 108 | return tx.origin; 109 | } 110 | } -------------------------------------------------------------------------------- /src/main/resources/contracts/solidity/Sacc.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.0 <0.6.0; 2 | 3 | contract SimpleAsset { 4 | mapping(string => string) ledger; 5 | constructor(string memory key,string memory value) public{ 6 | ledger[key] = value; 7 | } 8 | 9 | function set(string memory key,string memory value) public returns (string memory){ 10 | ledger[key] = value; 11 | return value; 12 | } 13 | 14 | function get(string memory key) public view returns(string memory){ 15 | return ledger[key]; 16 | } 17 | } -------------------------------------------------------------------------------- /src/main/resources/contracts/solidity/WeCrossHub.sol: -------------------------------------------------------------------------------- 1 | /* 2 | * v1.0.0 3 | * hub contract for WeCross 4 | * main entrance of interchain call 5 | */ 6 | 7 | pragma solidity >=0.4.22 <0.6.0; 8 | pragma experimental ABIEncoderV2; 9 | 10 | contract WeCrossHub { 11 | 12 | // string constant EVENT_TYPE = "INTERCHAIN"; 13 | 14 | string constant NULL_FLAG = "null"; 15 | 16 | string constant VERSION = "v1.0.0"; 17 | 18 | string constant CALL_TYPE_QUERY = "0"; 19 | 20 | string constant CALL_TYPE_INVOKE = "1"; 21 | 22 | string constant CALL_TYPE_GET_BLOCK = "2"; 23 | 24 | uint256 increment = 0; 25 | 26 | uint256 currentIndex = 0; 27 | 28 | mapping(uint256 => string) requests; 29 | 30 | mapping(string => string[]) callbackResults; 31 | 32 | function getVersion() public pure 33 | returns(string memory) 34 | { 35 | return VERSION; 36 | } 37 | 38 | // get current uid 39 | function getIncrement() public view 40 | returns(uint256) 41 | { 42 | return increment; 43 | } 44 | 45 | // invoke other chain 46 | function interchainInvoke(string memory _path, string memory _method, string[] memory _args, string memory _callbackPath, string memory _callbackMethod) public 47 | returns(string memory uid) 48 | { 49 | return handleRequest(CALL_TYPE_INVOKE, _path, _method, _args, _callbackPath, _callbackMethod); 50 | } 51 | 52 | // query other chain, not support right now 53 | function interchainQuery(string memory _path, string memory _method, string[] memory _args, string memory _callbackPath, string memory _callbackMethod) public 54 | returns(string memory uid) 55 | { 56 | return handleRequest(CALL_TYPE_QUERY, _path, _method, _args, _callbackPath, _callbackMethod); 57 | } 58 | 59 | function interchainGetBlock(string memory _path, string memory _method, string[] memory _args, string memory _callbackPath, string memory _callbackMethod) public 60 | returns(string memory uid) 61 | { 62 | return handleRequest(CALL_TYPE_GET_BLOCK, _path, _method, _args, _callbackPath, _callbackMethod); 63 | } 64 | 65 | function handleRequest(string memory _callType, string memory _path, string memory _method, string[] memory _args, string memory _callbackPath, string memory _callbackMethod) private 66 | returns(string memory uid) 67 | { 68 | uid = uint256ToString(++increment); 69 | 70 | string[] memory reuqest = new string[](8); 71 | reuqest[0] = uid; 72 | reuqest[1] = _callType; 73 | reuqest[2] = _path; 74 | reuqest[3] = _method; 75 | reuqest[4] = serializeStringArray(_args); 76 | reuqest[5] = _callbackPath; 77 | reuqest[6] = _callbackMethod; 78 | reuqest[7] = addressToString(tx.origin); 79 | 80 | requests[increment] = serializeStringArray(reuqest); 81 | } 82 | 83 | function getInterchainRequests(uint256 _num) public view 84 | returns(string memory) 85 | { 86 | if(currentIndex == increment) { 87 | return NULL_FLAG; 88 | } 89 | 90 | uint256 num = _num < (increment - currentIndex) ? _num : (increment - currentIndex); 91 | 92 | string[] memory tempRequests = new string[](num); 93 | for(uint256 i = 0; i < num; i++){ 94 | tempRequests[i] = requests[currentIndex+i+1]; 95 | } 96 | 97 | return serializeStringArray(tempRequests); 98 | } 99 | 100 | function updateCurrentRequestIndex(uint256 _index) public 101 | { 102 | if(currentIndex < _index) { 103 | currentIndex = _index; 104 | } 105 | } 106 | 107 | function registerCallbackResult(string memory _uid, string memory _tid, string memory _seq, string memory _errorCode, string memory _errorMsg, string memory _result) public 108 | { 109 | string[5] memory result = [_tid, _seq, _errorCode, _errorMsg, _result]; 110 | callbackResults[_uid] = result; 111 | } 112 | 113 | function selectCallbackResult(string memory _uid) public view 114 | returns(string[] memory) 115 | { 116 | return callbackResults[_uid]; 117 | } 118 | 119 | function serializeStringArray(string[] memory _arr) internal pure 120 | returns(string memory jsonStr) 121 | { 122 | uint len = _arr.length; 123 | if(len == 0) { 124 | return "[]"; 125 | } 126 | 127 | jsonStr = '['; 128 | for (uint i = 0; i < len - 1; i++) { 129 | jsonStr = string(abi.encodePacked(jsonStr, '"')); 130 | jsonStr = string(abi.encodePacked(jsonStr, jsonEscape(_arr[i]))); 131 | jsonStr = string(abi.encodePacked(jsonStr, '",')); 132 | } 133 | 134 | jsonStr = string(abi.encodePacked(jsonStr, '"')); 135 | jsonStr = string(abi.encodePacked(jsonStr, jsonEscape(_arr[len - 1]))); 136 | jsonStr = string(abi.encodePacked(jsonStr, '"')); 137 | jsonStr = string(abi.encodePacked(jsonStr, ']')); 138 | } 139 | 140 | function jsonEscape(string memory _str) internal pure 141 | returns(string memory) 142 | { 143 | bytes memory bts = bytes(_str); 144 | uint256 len = bts.length; 145 | bytes memory temp = new bytes(len * 2); 146 | uint256 i = 0; 147 | uint256 j = 0; 148 | for(; j 0) { 172 | result = bytes32(uint(result) / (2 ** 8)); 173 | result |= bytes32(((_value % 10) + 48) * 2 ** (8 * 31)); 174 | _value /= 10; 175 | } 176 | return bytes32ToString(result); 177 | } 178 | 179 | function bytes32ToString(bytes32 _bts32) internal pure 180 | returns (string memory) 181 | { 182 | 183 | bytes memory result = new bytes(_bts32.length); 184 | 185 | uint len = _bts32.length; 186 | for(uint i = 0; i < len; i++) { 187 | result[i] = _bts32[i]; 188 | } 189 | 190 | return string(result); 191 | } 192 | 193 | function addressToString(address _addr) internal pure 194 | returns (string memory) 195 | { 196 | bytes memory result = new bytes(40); 197 | for (uint i = 0; i < 20; i++) { 198 | byte temp = byte(uint8(uint(_addr) / (2 ** (8 * (19 - i))))); 199 | byte b1 = byte(uint8(temp) / 16); 200 | byte b2 = byte(uint8(temp) - 16 * uint8(b1)); 201 | result[2 * i] = convert(b1); 202 | result[2 * i + 1] = convert(b2); 203 | } 204 | return string(abi.encodePacked("0x", string(result))); 205 | } 206 | 207 | function convert(byte _b) internal pure 208 | returns (byte) 209 | { 210 | if (uint8(_b) < 10) { 211 | return byte(uint8(_b) + 0x30); 212 | } else { 213 | return byte(uint8(_b) + 0x57); 214 | } 215 | } 216 | } -------------------------------------------------------------------------------- /src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | logs/ 5 | ./ 6 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /src/test/java/com/webank/wecross/console/ConsoleUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console; 2 | 3 | import com.webank.wecross.console.common.ConsoleUtils; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | public class ConsoleUtilsTest { 8 | 9 | @Test 10 | public void testTokenizeCommand() throws Exception { 11 | String[] commands = 12 | ConsoleUtils.tokenizeCommand( 13 | " callByCNS [ ( ) ] HelloWorld.sol set \"{Hello}\" { \"a\":123, \"b\": 567 } \" hello! \" "); 14 | 15 | Assert.assertEquals(commands.length, 7); 16 | Assert.assertArrayEquals( 17 | new String[] { 18 | "callByCNS", 19 | "[ ( ) ]", 20 | "HelloWorld.sol", 21 | "set", 22 | "\"{Hello}\"", 23 | "{ \"a\":123, \"b\": 567 }", 24 | "\" hello! \"", 25 | }, 26 | commands); 27 | } 28 | 29 | @Test 30 | public void isValidPathTest() { 31 | boolean isTrue; 32 | boolean isFalse; 33 | isTrue = ConsoleUtils.isValidPath("a.b.c"); 34 | Assert.assertTrue(isTrue); 35 | 36 | isFalse = ConsoleUtils.isValidPath(".a.b.c"); 37 | Assert.assertFalse(isFalse); 38 | 39 | isFalse = ConsoleUtils.isValidPath("a.b.c."); 40 | Assert.assertFalse(isFalse); 41 | 42 | isFalse = ConsoleUtils.isValidPath("a.b..c"); 43 | Assert.assertFalse(isFalse); 44 | 45 | isFalse = ConsoleUtils.isValidPath("a.b"); 46 | Assert.assertFalse(isFalse); 47 | 48 | isFalse = ConsoleUtils.isValidPath("a.b.c.d"); 49 | Assert.assertFalse(isFalse); 50 | } 51 | 52 | @Test 53 | public void parseRequestTest() throws Exception { 54 | String input = "r.status"; 55 | String output = "r.status()"; 56 | Assert.assertEquals(output, ConsoleUtils.parseCommand(ConsoleUtils.tokenizeCommand(input))); 57 | 58 | input = "r.detail"; 59 | output = "r.detail()"; 60 | Assert.assertEquals(output, ConsoleUtils.parseCommand(ConsoleUtils.tokenizeCommand(input))); 61 | 62 | input = "r.call Int getInt"; 63 | output = "r.call \"Int\",\"getInt\""; 64 | Assert.assertEquals(output, ConsoleUtils.parseCommand(ConsoleUtils.tokenizeCommand(input))); 65 | 66 | input = "r.sendTransaction String getString \"hello world\""; 67 | output = "r.sendTransaction \"String\",\"getString\",\"hello world\""; 68 | Assert.assertEquals(output, ConsoleUtils.parseCommand(ConsoleUtils.tokenizeCommand(input))); 69 | 70 | input = "r = WeCross.getResource a.b.c"; 71 | output = "r = WeCross.getResource \"a.b.c\""; 72 | Assert.assertEquals(output, ConsoleUtils.parseCommand(ConsoleUtils.tokenizeCommand(input))); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/test/java/com/webank/wecross/console/FileUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console; 2 | 3 | import com.moandjiezana.toml.Toml; 4 | import com.moandjiezana.toml.TomlWriter; 5 | import com.webank.wecross.console.common.FileUtils; 6 | import com.webank.wecross.console.common.TransactionInfo; 7 | import com.webank.wecross.console.exception.WeCrossConsoleException; 8 | import java.io.File; 9 | import java.io.FileWriter; 10 | import java.io.FilenameFilter; 11 | import java.io.IOException; 12 | import java.util.*; 13 | import org.junit.Assert; 14 | import org.junit.Test; 15 | 16 | public class FileUtilsTest { 17 | @Test 18 | public void readFileContentTest() throws Exception { 19 | String fileName = "test"; 20 | try (FileWriter writer = new FileWriter(fileName)) { 21 | writer.write("Hello World"); 22 | } catch (IOException e) { 23 | System.out.println(e); 24 | } 25 | 26 | String readFileContent = FileUtils.readFileContent(fileName); 27 | Assert.assertEquals("Hello World", readFileContent); 28 | Assert.assertThrows(IOException.class, () -> FileUtils.readFileContent("..")); 29 | FileUtils.cleanFile(System.getProperty("user.dir"), fileName); 30 | } 31 | 32 | @Test 33 | public void getTomlTest() throws Exception { 34 | String fileName = "test.toml"; 35 | TransactionInfo transactionInfo = new TransactionInfo("123", Arrays.asList("123", "456")); 36 | TomlWriter writer = new TomlWriter(); 37 | try { 38 | writer.write(transactionInfo, new File(fileName)); 39 | } catch (IOException e) { 40 | System.out.println(e); 41 | } 42 | 43 | Toml toml = FileUtils.getToml(fileName); 44 | String txID = FileUtils.getTransactionID(toml); 45 | List paths = FileUtils.getTransactionPath(toml); 46 | 47 | Assert.assertEquals("123", txID); 48 | Assert.assertEquals("123", paths.get(0)); 49 | Assert.assertEquals("456", paths.get(1)); 50 | Assert.assertThrows( 51 | WeCrossConsoleException.class, 52 | () -> FileUtils.getToml("classpath:" + fileName + "1")); 53 | Assert.assertThrows(RuntimeException.class, () -> FileUtils.getToml(fileName + "1")); 54 | 55 | FileUtils.cleanFile(System.getProperty("user.dir"), fileName); 56 | } 57 | 58 | @Test 59 | public void getTransactionInfoMapTest() throws Exception { 60 | String fileName1 = "test-123.toml"; 61 | String fileName2 = "test-234.toml"; 62 | TransactionInfo transactionInfo1 = new TransactionInfo("123", Arrays.asList("123", "456")); 63 | TransactionInfo transactionInfo2 = new TransactionInfo("234", Arrays.asList("234", "345")); 64 | TomlWriter writer = new TomlWriter(); 65 | try { 66 | writer.write(transactionInfo1, new File(fileName1)); 67 | writer.write(transactionInfo2, new File(fileName2)); 68 | } catch (IOException e) { 69 | System.out.println(e); 70 | } 71 | File dir = new File(System.getProperty("user.dir")); 72 | FilenameFilter filter = 73 | new FilenameFilter() { 74 | @Override 75 | public boolean accept(File dir, String name) { 76 | return name.startsWith("test-"); 77 | } 78 | }; 79 | String[] children = dir.list(filter); 80 | Assert.assertNotNull(children); 81 | Assert.assertEquals(2, children.length); 82 | Arrays.sort(children); 83 | List txIDs = new ArrayList<>(); 84 | List> path = new ArrayList<>(); 85 | for (String child : children) { 86 | Toml toml = FileUtils.getToml(child); 87 | String txID = FileUtils.getTransactionID(toml); 88 | List paths = FileUtils.getTransactionPath(toml); 89 | txIDs.add(txID); 90 | path.add(paths); 91 | } 92 | 93 | Assert.assertEquals("123", txIDs.get(0)); 94 | Assert.assertEquals("123", path.get(0).get(0)); 95 | Assert.assertEquals("456", path.get(0).get(1)); 96 | 97 | Assert.assertEquals("234", txIDs.get(1)); 98 | Assert.assertEquals("234", path.get(1).get(0)); 99 | Assert.assertEquals("345", path.get(1).get(1)); 100 | 101 | FileUtils.cleanFile(System.getProperty("user.dir"), fileName1); 102 | FileUtils.cleanFile(System.getProperty("user.dir"), fileName2); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/test/java/com/webank/wecross/console/TarUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.webank.wecross.console; 2 | 3 | import com.webank.wecross.console.common.TarUtils; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | public class TarUtilsTest { 8 | @Test 9 | public void encodeTest() throws Exception { 10 | String name = "sacc"; 11 | String str = 12 | TarUtils.generateTarGzInputStreamEncodedString( 13 | "classpath:contracts/chaincode/" + name); 14 | System.out.println(str); 15 | Assert.assertTrue(str.length() != 0); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/resources/ContractTypeTest.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.24 <0.6.0; 2 | pragma experimental ABIEncoderV2; 3 | 4 | contract ContractTypeTest 5 | { 6 | uint256 u; 7 | bool b; 8 | address addr; 9 | bytes32 bs32; 10 | string s; 11 | bytes bs; 12 | 13 | function setValue(uint256 _u, bool _b, address _addr, bytes32 _bs32, string memory _s, bytes memory _bs) public { 14 | u = _u; 15 | b = _b; 16 | addr = _addr; 17 | bs32 = _bs32; 18 | s = _s; 19 | bs = _bs; 20 | } 21 | 22 | function getValue() view public returns(uint256 _u, bool _b, address _addr, bytes32 _bs32, string memory _s, bytes memory _bs) { 23 | _u = u; 24 | _b = b; 25 | _addr = addr; 26 | _bs32 = bs32; 27 | _s = s; 28 | _bs = bs; 29 | } 30 | 31 | uint256[] u_dynamic; 32 | bool[] b_dynamic; 33 | address[] addr_dynamic; 34 | bytes32[] bs32_dynamic; 35 | string[] s_dynamic; 36 | bytes[] bs_dynamic; 37 | 38 | function setDynamicValue(uint256[] memory _u, bool[] memory _b, address[] memory _addr, bytes32[] memory _bs32, string[] memory _s, bytes[] memory _bs) public { 39 | u_dynamic = _u; 40 | b_dynamic= _b; 41 | addr_dynamic = _addr; 42 | bs32_dynamic = _bs32; 43 | s_dynamic = _s; 44 | bs_dynamic = _bs; 45 | } 46 | 47 | function getDynamicValue() view public returns(uint256[] memory _u, bool[] memory _b, address[] memory _addr, bytes32[] memory _bs32, string[] memory _s, bytes[] memory _bs) { 48 | _u = u_dynamic; 49 | _b = b_dynamic; 50 | _addr = addr_dynamic; 51 | _bs32 = bs32_dynamic; 52 | _s = s_dynamic; 53 | _bs = bs_dynamic; 54 | } 55 | 56 | uint256[3] u_fixed; 57 | bool[3] b_fixed; 58 | address[3] addr_fixed; 59 | bytes32[3] bs32_fixed; 60 | string[3] s_fixed; 61 | bytes[3] bs_fixed; 62 | 63 | function setFixedValue(uint256[3] memory _u, bool[3] memory _b, address[3] memory _addr, bytes32[3] memory _bs32, string[3] memory _s, bytes[3] memory _bs) public { 64 | u_fixed = _u; 65 | b_fixed = _b; 66 | addr_fixed = _addr; 67 | bs32_fixed = _bs32; 68 | s_fixed = _s; 69 | bs_fixed = _bs; 70 | } 71 | 72 | function getFixedValue() view public returns(uint256[3] memory _u, bool[3] memory _b, address[3] memory _addr, bytes32[3] memory _bs32, string[3] memory _s, bytes[3] memory _bs) { 73 | _u = u_fixed; 74 | _b = b_fixed; 75 | _addr = addr_fixed; 76 | _bs32 = bs32_fixed; 77 | _s = s_fixed; 78 | _bs = bs_fixed; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/test/resources/TupleTest.sol: -------------------------------------------------------------------------------- 1 | pragma solidity>=0.5.0 <0.6.11; 2 | pragma experimental ABIEncoderV2; 3 | contract TupleTest { 4 | struct Item { 5 | int a; 6 | int b; 7 | int c; 8 | } 9 | 10 | struct Info { 11 | string name; 12 | int count; 13 | Item[] items; 14 | } 15 | 16 | int a; 17 | Item b; 18 | string c; 19 | 20 | constructor(int _a, Item memory _b, string memory _c) public { 21 | a = _a; 22 | b = _b; 23 | c = _c; 24 | } 25 | 26 | function set1(int _a, Item memory _b, string memory _c) public { 27 | a = _a; 28 | b = _b; 29 | c = _c; 30 | } 31 | 32 | function get1() view public returns(int, Item memory, string memory) { 33 | return (a, b, c); 34 | } 35 | 36 | function getAndSet1(int _a, Item memory _b, string memory _c) public returns(int, Item memory, string memory) { 37 | a = _a; 38 | b = _b; 39 | c = _c; 40 | return (a, b, c); 41 | } 42 | 43 | function getAndSet2(int a,Info[] memory b,string memory c) public returns (int, Info[] memory, string memory) { 44 | return (a, b, c); 45 | } 46 | 47 | // function set2(int _d,Info[] memory _e,string memory _f) public { 48 | // d = _d; 49 | // e = _e; 50 | // f = _f; 51 | // } 52 | 53 | // function getAndSet2(int _d,Info[] memory _e,string memory _f) public returns (int, Info[] memory, string memory) { 54 | // d = _d; 55 | // e = _e; 56 | // f = _f; 57 | 58 | // return (d, e, f); 59 | // } 60 | 61 | function getSampleTupleValue() public view returns(int a,Info[][] memory b,string memory c){ 62 | a=100; 63 | Info[][] memory infos4 = new Info[][](2); 64 | for(int i=0;i<10;++i){ 65 | infos4[0] = new Info[](1); 66 | infos4[1] = new Info[](1); 67 | } 68 | 69 | infos4[0][0].name="Hello world! + 1 "; 70 | infos4[0][0].count=100; 71 | infos4[0][0].items= new Item[](1); 72 | infos4[0][0].items[0].a=1; 73 | infos4[0][0].items[0].b=2; 74 | infos4[0][0].items[0].c=3; 75 | 76 | infos4[1][0].name="Hello world! + 2 "; 77 | infos4[1][0].count=101; 78 | infos4[1][0].items= new Item[](1); 79 | infos4[1][0].items[0].a=4; 80 | infos4[1][0].items[0].b=5; 81 | infos4[1][0].items[0].c=6; 82 | 83 | c = "Hello world! + 3 "; 84 | b = infos4; 85 | } 86 | } --------------------------------------------------------------------------------