From 8c61c81e3fb291f5226f746c53fce4ddc1911d15 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Fri, 3 Jul 2020 17:17:34 +0800 Subject: [PATCH 001/150] updated to version 1.3.1-SNAPSHOT; --- core | 2 +- explorer | 2 +- framework | 2 +- libs/bft-smart | 2 +- test | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core b/core index 8eb96bd9..a0eadf0f 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 8eb96bd9f656fdd4432066d7f5e9a1ec444a6d6a +Subproject commit a0eadf0f73e8bcafc6a356741d60f07f892dcaec diff --git a/explorer b/explorer index da3b9c92..95c6dd67 160000 --- a/explorer +++ b/explorer @@ -1 +1 @@ -Subproject commit da3b9c925d7bc263474baf2c72ff0cee5c8308e1 +Subproject commit 95c6dd67e11745ce010ff3555e0a724a6ff86e5a diff --git a/framework b/framework index 7260fab6..7656ac3b 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 7260fab6ee0336e2a197ddef7bebf2daf9363844 +Subproject commit 7656ac3b4e434e07e338d9772767158922c1b8c7 diff --git a/libs/bft-smart b/libs/bft-smart index 1a3c32c4..8e6dd2fe 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 1a3c32c4090e3cf7551998366a4d26a0160451ec +Subproject commit 8e6dd2fe6fe3c94e7c6534263f0cc622c4132fd8 diff --git a/test b/test index bd78673d..77b9b639 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit bd78673d397932becaf670c240488dc5a0bee2fa +Subproject commit 77b9b639562020a1eb51f49e9d0a3f54644c440e From 1ac739b83c9748111afc0af3316822e676565e65 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Tue, 15 Sep 2020 11:41:04 +0800 Subject: [PATCH 002/150] created 1.4.0-SNAPSHOT version; --- core | 2 +- deploy/deploy-gateway/pom.xml | 2 +- deploy/deploy-kvdb/pom.xml | 2 +- deploy/deploy-peer/pom.xml | 2 +- deploy/pom.xml | 4 ++-- framework | 2 +- test | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core b/core index ec842b88..fcd02532 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit ec842b88f4ea19ffa8f9a00f31317e5e4dc5218b +Subproject commit fcd02532f3d4d31d1bdc68a9010d58f6fa5725fe diff --git a/deploy/deploy-gateway/pom.xml b/deploy/deploy-gateway/pom.xml index 237523f3..a28fbe3b 100644 --- a/deploy/deploy-gateway/pom.xml +++ b/deploy/deploy-gateway/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain deploy-root - 1.3.0.RELEASE + 1.4.0-SNAPSHOT deploy-gateway diff --git a/deploy/deploy-kvdb/pom.xml b/deploy/deploy-kvdb/pom.xml index 14e45781..bdf82e22 100644 --- a/deploy/deploy-kvdb/pom.xml +++ b/deploy/deploy-kvdb/pom.xml @@ -5,7 +5,7 @@ deploy-root com.jd.blockchain - 1.3.0.RELEASE + 1.4.0-SNAPSHOT 4.0.0 diff --git a/deploy/deploy-peer/pom.xml b/deploy/deploy-peer/pom.xml index 4c6640ec..b9edadbe 100644 --- a/deploy/deploy-peer/pom.xml +++ b/deploy/deploy-peer/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain deploy-root - 1.3.0.RELEASE + 1.4.0-SNAPSHOT deploy-peer diff --git a/deploy/pom.xml b/deploy/pom.xml index 7be22fa3..de93b710 100644 --- a/deploy/pom.xml +++ b/deploy/pom.xml @@ -9,11 +9,11 @@ ../project/parent deploy-root - 1.3.0.RELEASE + 1.4.0-SNAPSHOT pom - 1.3.0.RELEASE + 1.4.0-SNAPSHOT 1.0.1.RELEASE diff --git a/framework b/framework index b5e7aec4..0183fb97 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit b5e7aec41425d85f6374c8bf2a604c69b6adad83 +Subproject commit 0183fb97869ae6213451d6b65d06c7b760eb45d8 diff --git a/test b/test index f5057486..58f53885 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit f5057486324d0daf2f8ef9f223a04537d03edede +Subproject commit 58f5388523d033e9d2720670137878628c8bc336 From fc4aad04baabd7a91fcda30dd0d48941164bbbd6 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Tue, 15 Sep 2020 17:51:11 +0800 Subject: [PATCH 003/150] completed the integration of core, framework and test module with version 1.4.0-SNAPSHOT; --- core | 2 +- framework | 2 +- test | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index fcd02532..74fe2d11 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit fcd02532f3d4d31d1bdc68a9010d58f6fa5725fe +Subproject commit 74fe2d114ebdaeb163bca256ca555aa83bc27f3d diff --git a/framework b/framework index 0183fb97..afbd2eaa 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 0183fb97869ae6213451d6b65d06c7b760eb45d8 +Subproject commit afbd2eaa6d3c9019f36d9a6d86126864713b6fe6 diff --git a/test b/test index 58f53885..c85c469b 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 58f5388523d033e9d2720670137878628c8bc336 +Subproject commit c85c469bdb4dcfdae72544a91067eeb91c330479 From 3e65904926bef1a54a47c51ad69d13734e8380a5 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Tue, 15 Sep 2020 18:20:06 +0800 Subject: [PATCH 004/150] upgraded submodule; --- explorer | 2 +- kvdb | 2 +- libs/bft-smart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/explorer b/explorer index 95c6dd67..f79293ab 160000 --- a/explorer +++ b/explorer @@ -1 +1 @@ -Subproject commit 95c6dd67e11745ce010ff3555e0a724a6ff86e5a +Subproject commit f79293ab00e5ac74382d442ec5027604ee8260ea diff --git a/kvdb b/kvdb index 6e541d84..410de249 160000 --- a/kvdb +++ b/kvdb @@ -1 +1 @@ -Subproject commit 6e541d84081362c86430a89806c7dfcbb5fd8a71 +Subproject commit 410de24918b6c7214bafe316f5cc734d87c5b433 diff --git a/libs/bft-smart b/libs/bft-smart index 8e6dd2fe..26482cf4 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 8e6dd2fe6fe3c94e7c6534263f0cc622c4132fd8 +Subproject commit 26482cf43365583e5d303544ddf05d44a2ad4a41 From bbe57253e5c3aa7346c5b93ec00895d6af7fa097 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Sun, 20 Sep 2020 23:01:01 +0800 Subject: [PATCH 005/150] implemented the sequence transaction seeking in ledger database; --- core | 2 +- framework | 2 +- test | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index 74fe2d11..e012c739 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 74fe2d114ebdaeb163bca256ca555aa83bc27f3d +Subproject commit e012c739a8b03d1f1a5714aec10e14fa3219d00b diff --git a/framework b/framework index afbd2eaa..85286017 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit afbd2eaa6d3c9019f36d9a6d86126864713b6fe6 +Subproject commit 852860179ce8f96a839e4ef79698d37c95dec710 diff --git a/test b/test index c85c469b..e26670ec 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit c85c469bdb4dcfdae72544a91067eeb91c330479 +Subproject commit e26670ec0bec5103b6732f396894078711416509 From 59be3aa40384ec1c3334b18dadad024f69bdfc2f Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Mon, 21 Sep 2020 12:29:30 +0800 Subject: [PATCH 006/150] refactored TransactionSet to record the TransactionRequest and TransactionResult independently; --- core | 2 +- framework | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index e012c739..c7f866ea 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit e012c739a8b03d1f1a5714aec10e14fa3219d00b +Subproject commit c7f866ea614f8e25d23889842aca63b47cd32f8f diff --git a/framework b/framework index 85286017..9aabedd7 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 852860179ce8f96a839e4ef79698d37c95dec710 +Subproject commit 9aabedd728c8a163bb5343b9da791e9b67455833 From 7a74845e1ae47d80e2e3ddf7ba7eb6147ac48ef0 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Mon, 21 Sep 2020 17:09:57 +0800 Subject: [PATCH 007/150] upgraded framework to support serialization for DataContract proxy; --- framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework b/framework index 9aabedd7..32c3a050 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 9aabedd728c8a163bb5343b9da791e9b67455833 +Subproject commit 32c3a050c220bf9e40879c2fb2af6659ed9cb9a6 From ab6b8dadb53d5509d548119d4ff053ea14283ac7 Mon Sep 17 00:00:00 2001 From: imuge Date: Fri, 9 Oct 2020 14:59:53 +0800 Subject: [PATCH 008/150] remove kvdb from jdchain --- core | 2 +- deploy/deploy-kvdb/pom.xml | 99 ------------------- .../src/main/resources/assembly.xml | 54 ---------- .../src/main/resources/config/cluster.conf | 11 --- .../src/main/resources/config/kvdb.conf | 15 --- .../main/resources/script/kvdb-benchmark.sh | 12 --- .../src/main/resources/script/kvdb-cli.sh | 12 --- .../src/main/resources/script/start.sh | 23 ----- .../src/main/resources/script/stop.sh | 27 ----- .../src/main/resources/system/dblist | 2 - deploy/pom.xml | 1 - kvdb | 1 - pom.xml | 1 - 13 files changed, 1 insertion(+), 259 deletions(-) delete mode 100644 deploy/deploy-kvdb/pom.xml delete mode 100644 deploy/deploy-kvdb/src/main/resources/assembly.xml delete mode 100644 deploy/deploy-kvdb/src/main/resources/config/cluster.conf delete mode 100644 deploy/deploy-kvdb/src/main/resources/config/kvdb.conf delete mode 100644 deploy/deploy-kvdb/src/main/resources/script/kvdb-benchmark.sh delete mode 100644 deploy/deploy-kvdb/src/main/resources/script/kvdb-cli.sh delete mode 100644 deploy/deploy-kvdb/src/main/resources/script/start.sh delete mode 100644 deploy/deploy-kvdb/src/main/resources/script/stop.sh delete mode 100644 deploy/deploy-kvdb/src/main/resources/system/dblist delete mode 160000 kvdb diff --git a/core b/core index c7f866ea..8a269ab6 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit c7f866ea614f8e25d23889842aca63b47cd32f8f +Subproject commit 8a269ab652f3e08d658cc922aa7744ab14d1cb30 diff --git a/deploy/deploy-kvdb/pom.xml b/deploy/deploy-kvdb/pom.xml deleted file mode 100644 index bdf82e22..00000000 --- a/deploy/deploy-kvdb/pom.xml +++ /dev/null @@ -1,99 +0,0 @@ - - - - deploy-root - com.jd.blockchain - 1.4.0-SNAPSHOT - - 4.0.0 - - deploy-kvdb - 1.0.1.RELEASE - - - - - com.jd.blockchain - kvdb-protocol - ${kvdb.version} - - - - com.jd.blockchain - kvdb-engine - ${kvdb.version} - - - - com.jd.blockchain - kvdb-server - ${kvdb.version} - - - - com.jd.blockchain - kvdb-cli - ${kvdb.version} - - - - com.jd.blockchain - kvdb-benchmark - ${kvdb.version} - - - - com.jd.blockchain - kvdb-client - ${kvdb.version} - - - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - make-assembly - package - - single - - - kvdb - - src/main/resources/assembly.xml - - - - - - - - - net.nicoulaj.maven.plugins - checksum-maven-plugin - 1.8 - - - - artifacts - - - - - - SHA-256 - - ${project.basedir}/target/deployment-kvdb-${project.version}.zip - true - ${project.basedir}/target/SHA-256.xml - - - - - diff --git a/deploy/deploy-kvdb/src/main/resources/assembly.xml b/deploy/deploy-kvdb/src/main/resources/assembly.xml deleted file mode 100644 index 34a09ee3..00000000 --- a/deploy/deploy-kvdb/src/main/resources/assembly.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - ${project.version} - - zip - - false - - - src/main/resources/script - bin - unix - - - src/main/resources/config - config - unix - - - src/main/resources/system - system - unix - - - - - false - true - libs - - - - - - true - - com.jd.blockchain:kvdb-engine - com.jd.blockchain:kvdb-benchmark - com.jd.blockchain:kvdb-client - com.jd.blockchain:kvdb-protocol - com.jd.blockchain:kvdb-cli - com.jd.blockchain:kvdb-server - - - libs - false - - - - - \ No newline at end of file diff --git a/deploy/deploy-kvdb/src/main/resources/config/cluster.conf b/deploy/deploy-kvdb/src/main/resources/config/cluster.conf deleted file mode 100644 index 9801c753..00000000 --- a/deploy/deploy-kvdb/src/main/resources/config/cluster.conf +++ /dev/null @@ -1,11 +0,0 @@ -# 数据库集群的分片数,每一个分片都赋予唯一的编号,分片编号最小为 0,所有分片的编号必须连续递增 -#cluster.test1.partitions=2 -# 数据库集群 ‘’ 的第 1 个分片的数据库实例地址(URL格式); -#cluster.test1.0=kvdb://localhost:7078/test1 -# 数据库集群 ‘’ 的第 2 个分片的数据库实例地址(URL格式); -#cluster.test1.1=kvdb://localhost:7079/test1 - -# 指定多个不同的集群 -#cluster.test2.partitions=2 -#cluster.test2.0=kvdb://localhost:7078/test2 -#cluster.test2.1=kvdb://localhost:7079/test2 \ No newline at end of file diff --git a/deploy/deploy-kvdb/src/main/resources/config/kvdb.conf b/deploy/deploy-kvdb/src/main/resources/config/kvdb.conf deleted file mode 100644 index 1b47c61a..00000000 --- a/deploy/deploy-kvdb/src/main/resources/config/kvdb.conf +++ /dev/null @@ -1,15 +0,0 @@ -# 数据库服务的本机监听地址; -server.host=0.0.0.0 - -# 数据库服务的本机监听端口; -server.port=7078 - -# 管理控制台的端口; -# 注:管理控制台总是绑定到环回地址 127.0.0.1,只允许本机访问; -manager.port=7060 - -# 数据库实例默认的根目录 -dbs.rootdir=../dbs - -# 数据库实例默认的本地分区数 -dbs.partitions=4 \ No newline at end of file diff --git a/deploy/deploy-kvdb/src/main/resources/script/kvdb-benchmark.sh b/deploy/deploy-kvdb/src/main/resources/script/kvdb-benchmark.sh deleted file mode 100644 index b2180397..00000000 --- a/deploy/deploy-kvdb/src/main/resources/script/kvdb-benchmark.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -HOME=$(cd `dirname $0`;cd ../; pwd) -KVDB=$(ls $HOME/libs | grep kvdb-benchmark) -JVM_SET="-Xmx2g -Xms2g" -LOG_SET="-Dlogging.path="$HOME/logs" -Dlogging.level=error" -PROC_INFO=$HOME/libs/$KVDB -if [ ! -n "$KVDB" ]; then - echo "Can not find kvdb-benchmark !!!" -else - java -jar $LOG_SET $JVM_SET $PROC_INFO $* -fi \ No newline at end of file diff --git a/deploy/deploy-kvdb/src/main/resources/script/kvdb-cli.sh b/deploy/deploy-kvdb/src/main/resources/script/kvdb-cli.sh deleted file mode 100644 index fd6474a8..00000000 --- a/deploy/deploy-kvdb/src/main/resources/script/kvdb-cli.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -HOME=$(cd `dirname $0`;cd ../; pwd) -KVDB=$(ls $HOME/libs | grep kvdb-cli) -JVM_SET="-Xmx2g -Xms2g" -LOG_SET="-Dlogging.path="$HOME/logs" -Dlogging.level.root=error" -PROC_INFO=$HOME/libs/$KVDB -if [ ! -n "$KVDB" ]; then - echo "Can not find kvdb-cli !!!" -else - java -jar $LOG_SET $JVM_SET $PROC_INFO $* -fi \ No newline at end of file diff --git a/deploy/deploy-kvdb/src/main/resources/script/start.sh b/deploy/deploy-kvdb/src/main/resources/script/start.sh deleted file mode 100644 index 18fdc9c6..00000000 --- a/deploy/deploy-kvdb/src/main/resources/script/start.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -HOME=$(cd `dirname $0`;cd ../; pwd) -KVDB=$(ls $HOME/libs | grep kvdb-server) -JVM_SET="-Xmx2g -Xms2g" -PROC_INFO=$HOME/libs/$KVDB" -home "$HOME -LOG_SET="-Dlogging.path="$HOME/logs" -Dlogging.level=error" -#echo $PROC_INFO -#get PID -PID=`ps -ef | grep "$PROC_INFO" | grep -v grep | awk '{print $2}'` -#echo $PID -if [[ ! -z $PID ]] -then - echo "process already exists,please check... If necessary, you should kill the process first." - exit -fi -if [ ! -n "$KVDB" ]; then - echo "Can not find kvdb-server !!!" -else - nohup java -jar $LOG_SET $JVM_SET $PROC_INFO $* >/dev/null 2>&1 & - - echo $! > $HOME/system/pid -fi \ No newline at end of file diff --git a/deploy/deploy-kvdb/src/main/resources/script/stop.sh b/deploy/deploy-kvdb/src/main/resources/script/stop.sh deleted file mode 100644 index 5b654ff7..00000000 --- a/deploy/deploy-kvdb/src/main/resources/script/stop.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -#启动Home路径 -HOME=$(cd `dirname $0`;cd ../; pwd) - -#进程启动后PID.log所在路径 -PID_LOG=$HOME/system/pid - -#从启动文件中读取PID -if [ -f "$PID_LOG" ]; then - # File exist - echo "Read PID From File:[$PID_LOG] ..." - PID=`sed -n '$p' $PID_LOG` -#启动文件不存在则直接通过PS进行过滤 -else - PID=`ps -ef | grep $HOME/libs/kvdb-server | grep -v grep | awk '{print $2}'` -fi - -#通过Kill命令将进程杀死 -if [ -z "$PID" ]; then - echo "Unable to find kvdb PID. stop aborted." -else - echo "Start to kill PID = $PID ..." - kill -9 $PID - echo "kvdb has been stopped ..." - echo "" > $PID_LOG -fi \ No newline at end of file diff --git a/deploy/deploy-kvdb/src/main/resources/system/dblist b/deploy/deploy-kvdb/src/main/resources/system/dblist deleted file mode 100644 index 0d45040c..00000000 --- a/deploy/deploy-kvdb/src/main/resources/system/dblist +++ /dev/null @@ -1,2 +0,0 @@ -#通过配置enable为true可以在kvdb-server启动时创建或加载指定数据库 -#db.test1.enable=true \ No newline at end of file diff --git a/deploy/pom.xml b/deploy/pom.xml index de93b710..fbb4ce19 100644 --- a/deploy/pom.xml +++ b/deploy/pom.xml @@ -21,7 +21,6 @@ ../core deploy-gateway deploy-peer - deploy-kvdb diff --git a/kvdb b/kvdb deleted file mode 160000 index 410de249..00000000 --- a/kvdb +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 410de24918b6c7214bafe316f5cc734d87c5b433 diff --git a/pom.xml b/pom.xml index cd954299..eff9ec18 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,6 @@ project framework core - kvdb deploy test samples From 9eda61a3d82fe2d96a66db28615f60597a16bbb6 Mon Sep 17 00:00:00 2001 From: imuge Date: Fri, 9 Oct 2020 15:50:58 +0800 Subject: [PATCH 009/150] register DataContracts in peer booter --- core | 2 +- samples/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index 8a269ab6..8a2bbf69 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 8a269ab652f3e08d658cc922aa7744ab14d1cb30 +Subproject commit 8a2bbf692aaa8a3136c19f8a00bbf70a8e59c25a diff --git a/samples/pom.xml b/samples/pom.xml index ab981eb5..b73ce4e6 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -11,7 +11,7 @@ com.jd.blockchain jdchain-samples - 1.2.0.RELEASE + 1.2.1.RELEASE pom From a2cc54b9db9f8050185c2042903a024b118abb34 Mon Sep 17 00:00:00 2001 From: imuge Date: Mon, 12 Oct 2020 19:09:44 +0800 Subject: [PATCH 010/150] add kvdb as git submodule --- .gitmodules | 5 +++-- libs/kvdb | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) create mode 160000 libs/kvdb diff --git a/.gitmodules b/.gitmodules index 6c974aa8..9b0e9384 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,6 +16,7 @@ [submodule "test"] path = test url = git@github.com:blockchain-jd-com/jdchain-test.git -[submodule "kvdb"] - path = kvdb +[submodule "libs/kvdb"] + path = libs/kvdb url = git@github.com:blockchain-jd-com/jdchain-kvdb.git + diff --git a/libs/kvdb b/libs/kvdb new file mode 160000 index 00000000..7bc93fcd --- /dev/null +++ b/libs/kvdb @@ -0,0 +1 @@ +Subproject commit 7bc93fcd911db8ca0754601b9ecb9ff44e7c7c1e From e862faad0a1c45e7e111a5469929db9778656ad1 Mon Sep 17 00:00:00 2001 From: imuge Date: Wed, 14 Oct 2020 08:36:38 +0800 Subject: [PATCH 011/150] update kvdb --- core | 2 +- deploy/pom.xml | 1 - libs/kvdb | 2 +- test | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/core b/core index 8a2bbf69..99278662 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 8a2bbf692aaa8a3136c19f8a00bbf70a8e59c25a +Subproject commit 9927866232d1b0110bf21a5ace2b85764d7e540d diff --git a/deploy/pom.xml b/deploy/pom.xml index fbb4ce19..98b06e0a 100644 --- a/deploy/pom.xml +++ b/deploy/pom.xml @@ -14,7 +14,6 @@ 1.4.0-SNAPSHOT - 1.0.1.RELEASE diff --git a/libs/kvdb b/libs/kvdb index 7bc93fcd..2a81f9db 160000 --- a/libs/kvdb +++ b/libs/kvdb @@ -1 +1 @@ -Subproject commit 7bc93fcd911db8ca0754601b9ecb9ff44e7c7c1e +Subproject commit 2a81f9dbacecb99145337b2ea6f0f91ac86a2a6f diff --git a/test b/test index e26670ec..e90499f7 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit e26670ec0bec5103b6732f396894078711416509 +Subproject commit e90499f74c5eef7770bad8225929995e47d4bd95 From 44fa83bf9d64e7a951d58aaee95a7f6646cefec5 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Wed, 14 Oct 2020 15:40:03 +0800 Subject: [PATCH 012/150] passed the compilation; --- core | 2 +- framework | 2 +- libs/bft-smart | 2 +- libs/kvdb | 2 +- test | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core b/core index 99278662..a9bf2d0e 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 9927866232d1b0110bf21a5ace2b85764d7e540d +Subproject commit a9bf2d0effdbf5485c27f5917a57a15550026123 diff --git a/framework b/framework index 32c3a050..c4ac2cfd 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 32c3a050c220bf9e40879c2fb2af6659ed9cb9a6 +Subproject commit c4ac2cfdc674bf94e0ee7efc3bd93f1f5119a128 diff --git a/libs/bft-smart b/libs/bft-smart index 26482cf4..8e90c430 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 26482cf43365583e5d303544ddf05d44a2ad4a41 +Subproject commit 8e90c4309ebc06819e91627c127b06a386c7c29e diff --git a/libs/kvdb b/libs/kvdb index 2a81f9db..f3d3df5f 160000 --- a/libs/kvdb +++ b/libs/kvdb @@ -1 +1 @@ -Subproject commit 2a81f9dbacecb99145337b2ea6f0f91ac86a2a6f +Subproject commit f3d3df5fc4ca32be00cbfb92034bcd26d335aa5d diff --git a/test b/test index e90499f7..11986101 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit e90499f74c5eef7770bad8225929995e47d4bd95 +Subproject commit 11986101a14392c9b1a95200783109204fcc0e0c From 599cf9e6f56843f912d2c19108868c8f5ca7c001 Mon Sep 17 00:00:00 2001 From: zhangshuang Date: Thu, 15 Oct 2020 14:27:50 +0800 Subject: [PATCH 013/150] add autonode test example --- .../samples/SDKDemo_ActiveParticipant.java | 25 +++--- .../samples/SDKDemo_DeactiveParticipant.java | 77 +++++++++++++++++++ .../samples/SDK_RegistParticipant_Demo.java | 7 +- 3 files changed, 96 insertions(+), 13 deletions(-) create mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_DeactiveParticipant.java diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ActiveParticipant.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ActiveParticipant.java index c8a19209..47aba604 100644 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ActiveParticipant.java +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ActiveParticipant.java @@ -1,8 +1,7 @@ package com.jd.blockchain.sdk.samples; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.utils.http.ResponseConverter; -import com.jd.blockchain.utils.web.client.WebResponseConverter; +import com.jd.blockchain.utils.http.converters.JsonResponseConverter; +import com.jd.blockchain.utils.web.model.WebResponse; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; @@ -22,8 +21,7 @@ public class SDKDemo_ActiveParticipant { // 接受激活参与方操作的共识节点Http服务地址, 根据具体环境配置进行修改 private static String httpIp = "127.0.0.1"; - private static String httpPort = "7085"; - + private static String httpPort = "7080"; public static void main(String[] args) { @@ -36,15 +34,15 @@ public class SDKDemo_ActiveParticipant { List para=new ArrayList(); // 账本值根据具体情况进行修改 - BasicNameValuePair base58LedgerHash = new BasicNameValuePair("ledgerHash", "j5n3SmYT3rS5aDgwQbDUxBYUMEP9GvVfMiQK3Tcr3vxz3M"); + BasicNameValuePair base58LedgerHash = new BasicNameValuePair("ledgerHash", "j5tuvAR3Q6ATsMNYTwt7SxVeCqd73itQbpmePxzSg6Zsxc"); // 激活的新参与方的共识网络地址 BasicNameValuePair host = new BasicNameValuePair("consensusHost", "127.0.0.1"); - BasicNameValuePair port = new BasicNameValuePair("consensusPort", "20000"); + BasicNameValuePair port = new BasicNameValuePair("consensusPort", "16000"); // 指定已经启动的其他共识节点的HTTP管理端口 BasicNameValuePair manageHost = new BasicNameValuePair("remoteManageHost", "127.0.0.1"); - BasicNameValuePair managePort = new BasicNameValuePair("remoteManagePort", "12000"); + BasicNameValuePair managePort = new BasicNameValuePair("remoteManagePort", "7083"); para.add(base58LedgerHash); para.add(host); @@ -57,9 +55,14 @@ public class SDKDemo_ActiveParticipant { HttpClient httpClient = HttpClients.createDefault(); HttpResponse response = httpClient.execute(httpPost); - ResponseConverter responseConverter = new WebResponseConverter(TransactionResponse.class); - Object converterResponse = responseConverter.getResponse(null, response.getEntity().getContent(), null); - System.out.println("response result = " + ((TransactionResponse)converterResponse).getExecutionState()); + JsonResponseConverter jsonConverter = new JsonResponseConverter(WebResponse.class); + + WebResponse webResponse = (WebResponse) jsonConverter.getResponse(null, response.getEntity().getContent(), null); + System.out.println("response result = " + webResponse.isSuccess()); + if (!webResponse.isSuccess()) { + System.out.println("error msg = " + webResponse.getError().getErrorMessage()); + } + } catch (Exception e) { e.printStackTrace(); diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_DeactiveParticipant.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_DeactiveParticipant.java new file mode 100644 index 00000000..700c25e9 --- /dev/null +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_DeactiveParticipant.java @@ -0,0 +1,77 @@ +package com.jd.blockchain.sdk.samples; + +import com.jd.blockchain.crypto.AddressEncoding; +import com.jd.blockchain.crypto.KeyGenUtils; +import com.jd.blockchain.crypto.PubKey; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.http.converters.JsonResponseConverter; +import com.jd.blockchain.utils.web.model.WebResponse; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author: zhangshuang + * @Date: 2020/5/27 5:18 PM + * Version 1.0 + */ +public class SDKDemo_DeactiveParticipant { + + // 接受去激活参与方操作的共识节点Http服务地址, 根据具体环境配置进行修改 + private static String httpIp = "127.0.0.1"; + private static String httpPort = "7080"; + + public static void main(String[] args) { + + String url = "http://" + httpIp + ":" + httpPort + "/management/delegate/deactiveparticipant"; + + // 即将进行去激活的共识节点公钥信息 + String PUB = "3snPdw7i7Pf2u9KTNUhxrYxgEymH24zP3NNNauRVwX5yDD6rzu2uBY"; + PubKey deactivePubKey = KeyGenUtils.decodePubKey(PUB); + Bytes address = AddressEncoding.generateAddress(deactivePubKey); + + System.out.println("url = " + url); + + HttpPost httpPost = new HttpPost(url); + + List para=new ArrayList(); + + // 账本值根据具体情况进行修改 + BasicNameValuePair base58LedgerHash = new BasicNameValuePair("ledgerHash", "j5tuvAR3Q6ATsMNYTwt7SxVeCqd73itQbpmePxzSg6Zsxc"); + + BasicNameValuePair deactiveAddress = new BasicNameValuePair("participantAddress", address.toBase58()); + // 指定已经启动的其他共识节点的HTTP管理端口 + BasicNameValuePair manageHost = new BasicNameValuePair("remoteManageHost", "127.0.0.1"); + BasicNameValuePair managePort = new BasicNameValuePair("remoteManagePort", "7083"); + + para.add(base58LedgerHash); + para.add(deactiveAddress); + para.add(manageHost); + para.add(managePort); + + try { + httpPost.setEntity(new UrlEncodedFormEntity(para,"UTF-8")); + HttpClient httpClient = HttpClients.createDefault(); + + HttpResponse response = httpClient.execute(httpPost); + JsonResponseConverter jsonConverter = new JsonResponseConverter(WebResponse.class); + + WebResponse webResponse = (WebResponse) jsonConverter.getResponse(null, response.getEntity().getContent(), null); + System.out.println("response result = " + webResponse.isSuccess()); + if (!webResponse.isSuccess()) { + System.out.println("error msg = " + webResponse.getError().getErrorMessage()); + } + + + } catch (Exception e) { + e.printStackTrace(); + System.out.println("Active participant post request error!"); + } + } +} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_RegistParticipant_Demo.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_RegistParticipant_Demo.java index ea81ac09..25e9d6a0 100644 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_RegistParticipant_Demo.java +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_RegistParticipant_Demo.java @@ -4,7 +4,10 @@ import com.jd.blockchain.crypto.AddressEncoding; import com.jd.blockchain.crypto.KeyGenUtils; import com.jd.blockchain.crypto.PrivKey; import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.*; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.PreparedTransaction; +import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.TransactionTemplate; public class SDK_RegistParticipant_Demo extends SDK_Base_Demo { @@ -27,7 +30,7 @@ public class SDK_RegistParticipant_Demo extends SDK_Base_Demo { BlockchainKeypair user = new BlockchainKeypair(pubKey, privKey); // 定义交易模板 - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + TransactionTemplate txTpl = blockchainService.newTransaction(blockchainService.getLedgerHashs()[0]); // 注册参与方 txTpl.participants().register("Peer4", user.getIdentity()); From f725a47ddb95645df95506e1c9af9513156ad35e Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Fri, 16 Oct 2020 16:52:09 +0800 Subject: [PATCH 014/150] updated submodules; --- core | 2 +- framework | 2 +- libs/bft-smart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index a9bf2d0e..61c8e0e3 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit a9bf2d0effdbf5485c27f5917a57a15550026123 +Subproject commit 61c8e0e36705b9fd153012039733a76de8b11705 diff --git a/framework b/framework index c4ac2cfd..7641d701 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit c4ac2cfdc674bf94e0ee7efc3bd93f1f5119a128 +Subproject commit 7641d701b646a48854fe39ed8c764bb16d4e10f9 diff --git a/libs/bft-smart b/libs/bft-smart index 8e90c430..24e77b3e 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 8e90c4309ebc06819e91627c127b06a386c7c29e +Subproject commit 24e77b3ef9d32e0d1d9b62f3b888d5e0f107d8c7 From a114c41b39bdeb7f9a805c327f2dafe6a9874bc8 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Mon, 19 Oct 2020 11:04:59 +0800 Subject: [PATCH 015/150] modify headers --- core | 2 +- explorer | 2 +- framework | 2 +- libs/bft-smart | 2 +- test | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core b/core index 61c8e0e3..48d99a20 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 61c8e0e36705b9fd153012039733a76de8b11705 +Subproject commit 48d99a20522bb80926f83c6c7b8815f6a67144d5 diff --git a/explorer b/explorer index f79293ab..599f5290 160000 --- a/explorer +++ b/explorer @@ -1 +1 @@ -Subproject commit f79293ab00e5ac74382d442ec5027604ee8260ea +Subproject commit 599f52909f2cd141eabca5432a515fe0ac19e8eb diff --git a/framework b/framework index 7641d701..6afcd0d1 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 7641d701b646a48854fe39ed8c764bb16d4e10f9 +Subproject commit 6afcd0d1f2387c37cc722c35b3eba57f86611b62 diff --git a/libs/bft-smart b/libs/bft-smart index 24e77b3e..aa8fa56a 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 24e77b3ef9d32e0d1d9b62f3b888d5e0f107d8c7 +Subproject commit aa8fa56a6ddd82087d282af45e76867188b7d5a8 diff --git a/test b/test index 11986101..179e3a35 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 11986101a14392c9b1a95200783109204fcc0e0c +Subproject commit 179e3a35b1184a111147f5e9e930fa5ebc638f1d From 2d4ed105607e74de81177b9035dfa258e67c517c Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Mon, 19 Oct 2020 17:26:02 +0800 Subject: [PATCH 016/150] update headers --- core | 2 +- explorer | 2 +- libs/bft-smart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index 48d99a20..c7d6e89b 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 48d99a20522bb80926f83c6c7b8815f6a67144d5 +Subproject commit c7d6e89be7c62d28fa2fc41722fac94a982e7ba9 diff --git a/explorer b/explorer index 599f5290..2f8f4843 160000 --- a/explorer +++ b/explorer @@ -1 +1 @@ -Subproject commit 599f52909f2cd141eabca5432a515fe0ac19e8eb +Subproject commit 2f8f48435e65d4f6598b1ede9c6a7021b10d2a53 diff --git a/libs/bft-smart b/libs/bft-smart index aa8fa56a..6447741b 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit aa8fa56a6ddd82087d282af45e76867188b7d5a8 +Subproject commit 6447741b215b9a01d732e129f8995ebd7b0a2df0 From 7a459a1a9651757702b0ff7898b5b34788930e9a Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Tue, 20 Oct 2020 18:48:22 +0800 Subject: [PATCH 017/150] update headers --- core | 2 +- libs/bft-smart | 2 +- test | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index c7d6e89b..4321739d 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit c7d6e89be7c62d28fa2fc41722fac94a982e7ba9 +Subproject commit 4321739d580b734443be2f211f1b44e0d559f0d5 diff --git a/libs/bft-smart b/libs/bft-smart index 6447741b..9ccf9c71 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 6447741b215b9a01d732e129f8995ebd7b0a2df0 +Subproject commit 9ccf9c71735d92efe468e6d0e94e3479a2002354 diff --git a/test b/test index 179e3a35..7e35dd59 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 179e3a35b1184a111147f5e9e930fa5ebc638f1d +Subproject commit 7e35dd59f754fe681f57c63fc3cadf897e9d09d9 From 8c0224e8f25b39f6ee1a4d3ad60b048792c219dc Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Tue, 20 Oct 2020 19:00:38 +0800 Subject: [PATCH 018/150] modify default config --- .../src/main/resources/config/gateway.conf | 14 +++----------- .../src/main/resources/config/init/bftsmart.config | 2 ++ 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/deploy/deploy-gateway/src/main/resources/config/gateway.conf b/deploy/deploy-gateway/src/main/resources/config/gateway.conf index e19b82b9..06e8cece 100644 --- a/deploy/deploy-gateway/src/main/resources/config/gateway.conf +++ b/deploy/deploy-gateway/src/main/resources/config/gateway.conf @@ -5,20 +5,12 @@ http.port=8080 #网关的HTTP服务上下文路径,可选; #http.context-path= -#对端Peer节点的数量 -peer.size=2 #共识节点的服务地址(与该网关节点连接的Peer节点的IP地址); -peer.0.host=127.0.0.1 +peer.host=127.0.0.1 #共识节点的服务端口(与该网关节点连接的Peer节点的端口,即在Peer节点的peer-startup.sh中定义的端口); -peer.0.port=7080 +peer.port=7080 #共识节点的服务是否启用安全证书; -peer.0.secure=false -#共识节点的服务地址(与该网关节点连接的Peer节点的IP地址); -peer.1.host=127.0.0.1 -#共识节点的服务端口(与该网关节点连接的Peer节点的端口,即在Peer节点的peer-startup.sh中定义的端口); -peer.1.port=7081 -#共识节点的服务是否启用安全证书; -peer.1.secure=false +peer.secure=false #共识节点的服务提供解析器 #BftSmart共识Provider:com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider diff --git a/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config b/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config index b5bfa5a3..bd4035ab 100644 --- a/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config +++ b/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config @@ -74,6 +74,8 @@ system.servers.f = 1 #Timeout to asking for a client request system.totalordermulticast.timeout = 60000 +#Allowable time tolerance range(millisecond) +system.totalordermulticast.timeTolerance = 3000000 #Maximum batch size (in number of messages) system.totalordermulticast.maxbatchsize = 2000 From 9fef1785f2f49377956b4c2619ffea16841a278e Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Wed, 21 Oct 2020 16:07:36 +0800 Subject: [PATCH 019/150] update headers --- core | 2 +- libs/bft-smart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index 4321739d..d014bcbe 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 4321739d580b734443be2f211f1b44e0d559f0d5 +Subproject commit d014bcbe14da5c4b61b145044f2281bf6bb9ae2f diff --git a/libs/bft-smart b/libs/bft-smart index 9ccf9c71..790b41da 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 9ccf9c71735d92efe468e6d0e94e3479a2002354 +Subproject commit 790b41da98060b6afeda49e0b26a5224be2f9177 From 99ce148d0ad6d98caec393bfd1c9d187aa05ee62 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Wed, 21 Oct 2020 17:30:16 +0800 Subject: [PATCH 020/150] update header --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index 790b41da..018bd4c6 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 790b41da98060b6afeda49e0b26a5224be2f9177 +Subproject commit 018bd4c67aa0566ae28af47a2ec037a2c4716dd1 From e8e423c706ea8faad1d53db2fab067791621371c Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Wed, 21 Oct 2020 17:42:35 +0800 Subject: [PATCH 021/150] update headers --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index 018bd4c6..061a37cc 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 018bd4c67aa0566ae28af47a2ec037a2c4716dd1 +Subproject commit 061a37ccd99f2959f8b02eb6586ef503d8f1d0a3 From 61b756630c7e8d31edbeddc056b26f03c496a058 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Wed, 21 Oct 2020 18:20:13 +0800 Subject: [PATCH 022/150] update headers --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index 061a37cc..a5689655 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 061a37ccd99f2959f8b02eb6586ef503d8f1d0a3 +Subproject commit a568965555581aed2bc1e3874a41b8bb062d46bd From 91ed30595816a86deaf3b8c9513eb75b48044187 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Wed, 21 Oct 2020 22:27:02 +0800 Subject: [PATCH 023/150] update header --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index a5689655..449e3254 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit a568965555581aed2bc1e3874a41b8bb062d46bd +Subproject commit 449e3254d23acbb5dd19b7d08a731ddb2c808f80 From b4c6d8a51fc4ddbcc7c43535e38b6110382325d5 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Wed, 21 Oct 2020 22:51:40 +0800 Subject: [PATCH 024/150] update header --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index 449e3254..5b877865 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 449e3254d23acbb5dd19b7d08a731ddb2c808f80 +Subproject commit 5b877865b59799e20e35aea2b2454f2f1ed4ff87 From f4b3b90c0f303a449dd1435a8be4c78de7c9bae3 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Thu, 22 Oct 2020 09:22:54 +0800 Subject: [PATCH 025/150] update headers --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index 5b877865..bca2bfba 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 5b877865b59799e20e35aea2b2454f2f1ed4ff87 +Subproject commit bca2bfbaec457b7b4967754e68182efb88a4af55 From 617c86d2586608d27d1e2c6b858fd394537c700e Mon Sep 17 00:00:00 2001 From: zhangshuang Date: Thu, 22 Oct 2020 11:16:22 +0800 Subject: [PATCH 026/150] solve sdk compile problem according to new ledger transaction stuction --- samples/pom.xml | 12 +++++++++++- samples/sdk-samples/pom.xml | 12 ++++++++++++ .../sdk/samples/SDKDemo_ConfigureSecurity.java | 3 --- .../sdk/samples/SDKDemo_InsertData.java | 2 +- .../jd/blockchain/sdk/samples/SDKDemo_Query.java | 5 ++--- .../sdk/samples/SDKDemo_RegistParticipant.java | 3 --- .../sdk/samples/SDKDemo_RegisterAccount.java | 3 --- .../sdk/samples/SDKDemo_RegisterUser.java | 3 --- .../sdk/samples/SDKDemo_Tx_Persistance.java | 5 +---- .../sdk/samples/SDK_InsertData_Demo.java | 4 ++-- .../jd/blockchain/sdk/test/SDK_Contract_Test.java | 2 +- .../test/SDK_GateWay_BatchInsertData_Test_.java | 6 ------ .../sdk/test/SDK_GateWay_DataAccount_Test_.java | 6 ------ .../sdk/test/SDK_GateWay_InsertData_Test_.java | 6 ------ .../SDK_GateWay_Participant_Regist_Test_.java | 3 --- .../sdk/test/SDK_GateWay_Query_Test_.java | 15 ++++----------- .../sdk/test/SDK_GateWay_User_Test_.java | 6 ------ 17 files changed, 34 insertions(+), 62 deletions(-) diff --git a/samples/pom.xml b/samples/pom.xml index b73ce4e6..397ebb30 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -15,7 +15,7 @@ pom - 1.3.0.RELEASE + 1.3.1-SNAPSHOT @@ -42,6 +42,16 @@ crypto-framework ${framework.version} + + com.jd.blockchain + crypto-classic + ${framework.version} + + + com.jd.blockchain + crypto-sm + ${framework.version} + diff --git a/samples/sdk-samples/pom.xml b/samples/sdk-samples/pom.xml index 73cc5064..10e0ab45 100644 --- a/samples/sdk-samples/pom.xml +++ b/samples/sdk-samples/pom.xml @@ -18,6 +18,18 @@ com.jd.blockchain ledger-model + + com.jd.blockchain + crypto-classic + + + com.jd.blockchain + crypto-framework + + + com.jd.blockchain + crypto-sm + com.jd.blockchain contract-samples diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ConfigureSecurity.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ConfigureSecurity.java index d7d2170b..fc1fad1d 100644 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ConfigureSecurity.java +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ConfigureSecurity.java @@ -38,10 +38,7 @@ public class SDKDemo_ConfigureSecurity { // 注册相关class DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); PrivKey privKey = SDKDemo_Params.privkey1; diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_InsertData.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_InsertData.java index 59d94201..7a684a0b 100644 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_InsertData.java +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_InsertData.java @@ -64,7 +64,7 @@ public class SDKDemo_InsertData { // TX 准备就绪; PreparedTransaction prepTx = txTemp.prepare(); - String txHash = ByteArray.toBase64(prepTx.getHash().toBytes()); + String txHash = ByteArray.toBase64(prepTx.getTransactionHash().toBytes()); // 使用私钥进行签名; AsymmetricKeypair keyPair = getSponsorKey(); diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java index 6d81393d..6f4e9e19 100644 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java @@ -7,7 +7,6 @@ import com.jd.blockchain.ledger.BlockchainKeypair; import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerTransaction; -import com.jd.blockchain.ledger.Transaction; import com.jd.blockchain.sdk.BlockchainService; import com.jd.blockchain.sdk.client.GatewayServiceFactory; import com.jd.blockchain.utils.net.NetworkAddress; @@ -61,8 +60,8 @@ public class SDKDemo_Query { LedgerTransaction[] txList = service.getTransactions(LEDGER_HASH, ledgerNumber, 0, 100); // 根据交易的 hash 获得交易;注:客户端生成 PrepareTransaction 时得到交易hash; - HashDigest txHash = txList[0].getTransactionContent().getHash(); - Transaction tx = service.getTransactionByContentHash(LEDGER_HASH, txHash); + HashDigest txHash = txList[0].getRequest().getTransactionHash(); + LedgerTransaction tx = service.getTransactionByContentHash(LEDGER_HASH, txHash); // 获取数据; String commerceAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf=="; diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegistParticipant.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegistParticipant.java index 813cce1f..2494c058 100644 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegistParticipant.java +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegistParticipant.java @@ -44,10 +44,7 @@ public class SDKDemo_RegistParticipant { service = serviceFactory.getBlockchainService(); DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); DataContractRegistry.register(ParticipantRegisterOperation.class); DataContractRegistry.register(ParticipantStateUpdateOperation.class); diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterAccount.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterAccount.java index 07b84984..3d184070 100644 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterAccount.java +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterAccount.java @@ -20,10 +20,7 @@ public class SDKDemo_RegisterAccount { } DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); BlockchainKeypair CLIENT_CERT = new BlockchainKeypair(SDKDemo_Params.pubKey0, SDKDemo_Params.privkey0); diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterUser.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterUser.java index 778e5851..ebbe250a 100644 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterUser.java +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterUser.java @@ -38,10 +38,7 @@ public class SDKDemo_RegisterUser { // 注册相关class DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); PrivKey privKey = SDKDemo_Params.privkey1; diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Tx_Persistance.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Tx_Persistance.java index 5c2d452f..24417893 100644 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Tx_Persistance.java +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Tx_Persistance.java @@ -40,10 +40,7 @@ public class SDKDemo_Tx_Persistance { // 注册相关class DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); PrivKey privKey1 = SDKDemo_Params.privkey0; @@ -87,7 +84,7 @@ public class SDKDemo_Tx_Persistance { TransactionContent txContent = BinaryProtocol.decode(txContentBytes, TransactionContent.class); // 对交易内容签名; - DigitalSignature signature1 = SignatureUtils.sign(txContent, keyPair1); + DigitalSignature signature1 = SignatureUtils.sign(keyPair1.getAlgorithm(),txContent, keyPair1); // 根据交易内容重新准备交易; PreparedTransaction decodedPrepTx = blockchainService.prepareTransaction(txContent); diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java index d90b5233..928af76a 100644 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java @@ -48,7 +48,7 @@ public class SDK_InsertData_Demo extends SDK_Base_Demo { LedgerTransaction[] txList = blockchainService.getTransactions(ledgerHash, ledgerNumber, 0, 100); // 遍历交易列表 for (LedgerTransaction ledgerTransaction : txList) { - TransactionContent txContent = ledgerTransaction.getTransactionContent(); + TransactionContent txContent = ledgerTransaction.getRequest().getTransactionContent(); Operation[] operations = txContent.getOperations(); if (operations != null && operations.length > 0) { for (Operation operation : operations) { @@ -101,7 +101,7 @@ public class SDK_InsertData_Demo extends SDK_Base_Demo { } //根据交易的 hash 获得交易;注:客户端生成 PrepareTransaction 时得到交易hash; - HashDigest txHash = txList[0].getTransactionContent().getHash(); + HashDigest txHash = txList[0].getTransactionHash(); // Transaction tx = blockchainService.getTransactionByContentHash(ledgerHash, txHash); // String[] objKeys = new String[] { "x001", "x002" }; // KVDataEntry[] kvData = blockchainService.getDataEntries(ledgerHash, commerceAccount, objKeys); diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java index 244d8071..52e2be93 100644 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java +++ b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java @@ -286,7 +286,7 @@ public class SDK_Contract_Test { // TX 准备就绪; PreparedTransaction prepTx = txTemp.prepare(); - String txHash = ByteArray.toBase64(prepTx.getHash().toBytes()); + String txHash = ByteArray.toBase64(prepTx.getTransactionHash().toBytes()); // 使用私钥进行签名; AsymmetricKeypair keyPair = getSponsorKey(); diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_BatchInsertData_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_BatchInsertData_Test_.java index 747c835e..d459ac94 100644 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_BatchInsertData_Test_.java +++ b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_BatchInsertData_Test_.java @@ -21,11 +21,8 @@ import com.jd.blockchain.crypto.HashFunction; import com.jd.blockchain.crypto.SignatureFunction; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.EndpointRequest; -import com.jd.blockchain.ledger.NodeRequest; import com.jd.blockchain.ledger.PreparedTransaction; import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionContentBody; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionState; @@ -68,10 +65,7 @@ public class SDK_GateWay_BatchInsertData_Test_ { service = serviceFactory.getBlockchainService(); DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); } diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_DataAccount_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_DataAccount_Test_.java index 7d343505..114c6de6 100644 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_DataAccount_Test_.java +++ b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_DataAccount_Test_.java @@ -19,11 +19,8 @@ import com.jd.blockchain.crypto.HashFunction; import com.jd.blockchain.crypto.SignatureFunction; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.EndpointRequest; -import com.jd.blockchain.ledger.NodeRequest; import com.jd.blockchain.ledger.PreparedTransaction; import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionContentBody; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionState; @@ -62,10 +59,7 @@ public class SDK_GateWay_DataAccount_Test_ { service = serviceFactory.getBlockchainService(); DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); } diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_InsertData_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_InsertData_Test_.java index ed6567e9..5d420d5f 100644 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_InsertData_Test_.java +++ b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_InsertData_Test_.java @@ -21,11 +21,8 @@ import com.jd.blockchain.crypto.HashFunction; import com.jd.blockchain.crypto.SignatureFunction; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.EndpointRequest; -import com.jd.blockchain.ledger.NodeRequest; import com.jd.blockchain.ledger.PreparedTransaction; import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionContentBody; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionState; @@ -65,10 +62,7 @@ public class SDK_GateWay_InsertData_Test_ { service = serviceFactory.getBlockchainService(); DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); } diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Participant_Regist_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Participant_Regist_Test_.java index 634357f5..0b9e6a93 100644 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Participant_Regist_Test_.java +++ b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Participant_Regist_Test_.java @@ -59,10 +59,7 @@ public class SDK_GateWay_Participant_Regist_Test_ { service = serviceFactory.getBlockchainService(); DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); DataContractRegistry.register(ParticipantRegisterOperation.class); DataContractRegistry.register(ParticipantStateUpdateOperation.class); diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java index 3d291811..2879c503 100644 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java +++ b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java @@ -23,16 +23,12 @@ import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; import com.jd.blockchain.ledger.DigitalSignature; -import com.jd.blockchain.ledger.EndpointRequest; import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerInfo; import com.jd.blockchain.ledger.LedgerTransaction; -import com.jd.blockchain.ledger.NodeRequest; import com.jd.blockchain.ledger.ParticipantNode; -import com.jd.blockchain.ledger.Transaction; import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionContentBody; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionState; @@ -72,10 +68,7 @@ public class SDK_GateWay_Query_Test_ { service = serviceFactory.getBlockchainService(); DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); } @@ -119,16 +112,16 @@ public class SDK_GateWay_Query_Test_ { LedgerTransaction[] txList = service.getTransactions(ledgerHash, ledgerNumber, 0, 100); for (LedgerTransaction ledgerTransaction : txList) { - System.out.println("ledgerTransaction.Hash=" + ledgerTransaction.getHash()); + System.out.println("ledgerTransaction.Hash=" + ledgerTransaction.getTransactionHash()); } txList = service.getTransactions(ledgerHash, hashDigest, 0, 100); for (LedgerTransaction ledgerTransaction : txList) { - System.out.println("ledgerTransaction.Hash=" + ledgerTransaction.getHash()); + System.out.println("ledgerTransaction.Hash=" + ledgerTransaction.getTransactionHash()); } - Transaction tx = service.getTransactionByContentHash(ledgerHash, hashDigest); - DigitalSignature[] signatures = tx.getEndpointSignatures(); + LedgerTransaction tx = service.getTransactionByContentHash(ledgerHash, hashDigest); + DigitalSignature[] signatures = tx.getRequest().getEndpointSignatures(); for (DigitalSignature signature : signatures) { System.out.println(signature.getDigest().getAlgorithm()); } diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_User_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_User_Test_.java index d69b0f97..5310624e 100644 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_User_Test_.java +++ b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_User_Test_.java @@ -23,11 +23,8 @@ import com.jd.blockchain.crypto.PubKey; import com.jd.blockchain.crypto.SignatureFunction; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.EndpointRequest; -import com.jd.blockchain.ledger.NodeRequest; import com.jd.blockchain.ledger.PreparedTransaction; import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionContentBody; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionState; @@ -89,10 +86,7 @@ public class SDK_GateWay_User_Test_ { service = serviceFactory.getBlockchainService(); DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); } From a2863c9a0efb745153bc7308b67451f8790a3b4a Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Thu, 22 Oct 2020 13:09:08 +0800 Subject: [PATCH 027/150] update headers --- libs/bft-smart | 2 +- test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/bft-smart b/libs/bft-smart index bca2bfba..090453d8 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit bca2bfbaec457b7b4967754e68182efb88a4af55 +Subproject commit 090453d86b38142577588ce94f8205025d974a70 diff --git a/test b/test index 7e35dd59..cd9da6fc 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 7e35dd59f754fe681f57c63fc3cadf897e9d09d9 +Subproject commit cd9da6fc29bd3d18a76c1ba47f7f152fce1d4ca0 From 66562acf41ac34c3339165ea3e835f572af336ee Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Thu, 22 Oct 2020 15:38:01 +0800 Subject: [PATCH 028/150] update headers --- libs/bft-smart | 2 +- test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/bft-smart b/libs/bft-smart index 090453d8..22ceb39c 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 090453d86b38142577588ce94f8205025d974a70 +Subproject commit 22ceb39c5ea63c21836dbe4a6b0da08feb147ae7 diff --git a/test b/test index cd9da6fc..d723a4b8 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit cd9da6fc29bd3d18a76c1ba47f7f152fce1d4ca0 +Subproject commit d723a4b84e3357fdc8b5593fe2592e317bd70188 From c49b4e2ec212e2717a826c66fe60e5929eabb1b9 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Fri, 23 Oct 2020 10:46:02 +0800 Subject: [PATCH 029/150] updated framework; --- framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework b/framework index 7641d701..946231da 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 7641d701b646a48854fe39ed8c764bb16d4e10f9 +Subproject commit 946231da1a2c5186526d467180faf10943e63fa2 From 4d4ec6fdd6d34e3c9f3b8667c6ca08fedc69464a Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Fri, 23 Oct 2020 14:49:12 +0800 Subject: [PATCH 030/150] update headers --- core | 2 +- libs/bft-smart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index d014bcbe..c770f544 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit d014bcbe14da5c4b61b145044f2281bf6bb9ae2f +Subproject commit c770f544e9892b4cc2e937a336abf59a40fc198a diff --git a/libs/bft-smart b/libs/bft-smart index 22ceb39c..f2660860 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 22ceb39c5ea63c21836dbe4a6b0da08feb147ae7 +Subproject commit f2660860f71850b4e70ae529fbdb8320623bcaff From 168f68b7df9c6080dc8e3270e0809ee8d9ff77c8 Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Fri, 23 Oct 2020 20:35:14 +0800 Subject: [PATCH 031/150] add the docker-demo submodule; --- deploy/docker-demo/pom.xml | 85 ++++++++++++++++++ deploy/docker-demo/readme.md | 41 +++++++++ deploy/docker-demo/src/main/docker/Dockerfile | 35 ++++++++ .../src/main/docker/script/shutdown.sh | 4 + .../src/main/docker/script/start.sh | 28 ++++++ .../docker-demo/src/main/docker/zip/conf.zip | Bin 0 -> 313206 bytes .../main/resources/docker-compose-all.yaml | 36 ++++++++ .../src/main/resources/start-net.sh | 5 ++ deploy/docker-demo/src/main/resources/zip.sh | 9 ++ deploy/pom.xml | 1 + 10 files changed, 244 insertions(+) create mode 100644 deploy/docker-demo/pom.xml create mode 100644 deploy/docker-demo/readme.md create mode 100644 deploy/docker-demo/src/main/docker/Dockerfile create mode 100644 deploy/docker-demo/src/main/docker/script/shutdown.sh create mode 100644 deploy/docker-demo/src/main/docker/script/start.sh create mode 100644 deploy/docker-demo/src/main/docker/zip/conf.zip create mode 100644 deploy/docker-demo/src/main/resources/docker-compose-all.yaml create mode 100644 deploy/docker-demo/src/main/resources/start-net.sh create mode 100755 deploy/docker-demo/src/main/resources/zip.sh diff --git a/deploy/docker-demo/pom.xml b/deploy/docker-demo/pom.xml new file mode 100644 index 00000000..d7e7f123 --- /dev/null +++ b/deploy/docker-demo/pom.xml @@ -0,0 +1,85 @@ + + + + jdchain-root + com.jd.blockchain + 1.2.1.RELEASE + ../../pom.xml + + 1.3.0 + 4.0.0 + + docker-demo + + + jdchain-demo + + + maven-resources-plugin + 3.0.2 + + + copy-resources + validate + + copy-resources + + + + UTF-8 + ${project.basedir}/src/main/docker/zip + false + + + ${project.basedir}/../deploy-peer/target/ + false + + jdchain-peer-${project.version}.RELEASE.zip + + + + + ${project.basedir}/../deploy-gateway/target/ + false + + jdchain-gateway-${project.version}.RELEASE.zip + + + + + + + + + + + com.spotify + docker-maven-plugin + 1.2.2 + + + + + build-image + + package + + build + + + + + + + jdchain-demo + ${project.version} + + ${project.basedir}/src/main/docker + + + + + + \ No newline at end of file diff --git a/deploy/docker-demo/readme.md b/deploy/docker-demo/readme.md new file mode 100644 index 00000000..eb4034f1 --- /dev/null +++ b/deploy/docker-demo/readme.md @@ -0,0 +1,41 @@ +# jdchain-demo镜像使用说明 +本镜像主要为快速构建JDChain测试环境使用,内嵌固定的公私钥,不可用于生产正式环境。 +JDChain在docker中的安装路径:/export/jdchain,网关对外端口为:8080。可通过docker-compose-all文件来修改端口。 +demo环境中加载了部分测试数据,区块高度:22,交易总数:23,用户总数:6,数据账户总数:3,合约总数:2。 + +## 如何生成镜像 +1. 需要预先在deploy-peer和deploy-gateway中生成zip安装包; +2. 本项目中执行:mvn clean package;会在docker环境中生成jdchain-peer镜像; +3. 生成镜像文件。执行resource中:zip.sh,可生成镜像的tar.gz压缩包; + +## 镜像快速使用 +1.在已经安装docker工具的环境中,装入jdchain-demo镜像: +```` +docker load -i jdchain-demo_1.3.0.tar.gz +```` +2.启动脚本 +每次执行启动脚本时,会删除原有的容器,然后重新构建全新的容器。 +所以每次执行之后,会清除原先链上新增的区块。 +```` +sh start-net.sh +```` +3.卸载容器 +如果不再使用容器,在start-net.sh脚本所在路径下执行: +```` +docker-compose -f docker-compose-all.yaml down +```` + +## SDK连接网关参数 +```` +ip=localhost +port=8080 +#默认公钥的内容(Base58编码数据); +keys.default.pubkey=3snPdw7i7PisoLpqqtETdqzQeKVjQReP2Eid9wYK67q9z6trvByGZs +#默认私钥的内容(加密的Base58编码数据);在 pk-path 和 pk 之间必须设置其一; +keys.default.privkey=177gk2PbxhHeEdfAAqGfShJQyeV4XvGsJ9CvJFUbToBqwW1YJd5obicySE1St6SvPPaRrUP +#默认私钥的解码密码; +keys.default.privkey-password=8EjkXVSTxMFjCvNNsTo8RBMDEVQmk7gYkW4SCDuvdsBG +```` + + + diff --git a/deploy/docker-demo/src/main/docker/Dockerfile b/deploy/docker-demo/src/main/docker/Dockerfile new file mode 100644 index 00000000..616e1b74 --- /dev/null +++ b/deploy/docker-demo/src/main/docker/Dockerfile @@ -0,0 +1,35 @@ +FROM centos:8.2.2004 + +# install tools +RUN yum install wget -y \ + && wget -O /etc/yum.repos.d/epel-7.repo http://mirrors.aliyun.com/repo/epel-7.repo \ + && yum install java net-tools nc crontabs expect unzip -y \ + && yum install langpacks-zh_CN.noarch -y \ + && echo "LANG=zh_CN.utf8" >> /etc/locale.conf \ + && source /etc/locale.conf \ + && yum clean all + +WORKDIR /export/jdchain +COPY zip/* /export/jdchain/ + +# env +ENV RELEASE_DIR=/export/jdchain +ENV RELEASE_VERSION=1.3.0 +#ENV DATA_DIR=/shared +ENV NAME=conf +ENV SERVER_NAME_PEER=deploy-peer +ENV SERVER_NAME_GW=deploy-gateway + +COPY script/* /export/jdchain/ +RUN chmod +x /export/jdchain/*.sh + +# ports +EXPOSE 8080 +#EXPOSE 16000 +#EXPOSE 16010 +#EXPOSE 16020 +#EXPOSE 16030 + +#ENTRYPOINT ["/bin/sh","-c","/export/jdchain/start.sh"] +ENTRYPOINT sh /export/jdchain/start.sh + diff --git a/deploy/docker-demo/src/main/docker/script/shutdown.sh b/deploy/docker-demo/src/main/docker/script/shutdown.sh new file mode 100644 index 00000000..8cf6d207 --- /dev/null +++ b/deploy/docker-demo/src/main/docker/script/shutdown.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +ps -ef|grep 'jdchain'|grep -v grep|cut -c 9-15|xargs kill -9 + diff --git a/deploy/docker-demo/src/main/docker/script/start.sh b/deploy/docker-demo/src/main/docker/script/start.sh new file mode 100644 index 00000000..a6cc134c --- /dev/null +++ b/deploy/docker-demo/src/main/docker/script/start.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +cd $RELEASE_DIR + +# invoke it once again; +#gw_pid_file="./gw/bin/PID.log" +#if [ ! -f gw_pid_file ] ; then +# echo "get the PID.log, only to start the peer and gateway." + unzip -o conf.zip + + for i in `seq 0 3` + do + unzip -n -d ./peer$i jdchain-peer-$RELEASE_VERSION.RELEASE.zip + chmod +x ./peer$i/bin/* + done + + unzip -n -d ./gw jdchain-gateway-$RELEASE_VERSION.RELEASE.zip + chmod +x ./gw/bin/* +#fi + +sh ./peer0/bin/peer-startup.sh +sh ./peer1/bin/peer-startup.sh +sh ./peer2/bin/peer-startup.sh +sh ./peer3/bin/peer-startup.sh +sleep 30 +sh ./gw/bin/startup.sh + +tail -f /dev/null diff --git a/deploy/docker-demo/src/main/docker/zip/conf.zip b/deploy/docker-demo/src/main/docker/zip/conf.zip new file mode 100644 index 0000000000000000000000000000000000000000..8f4c3d971597e1c19518154ba2873970578248ed GIT binary patch literal 313206 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../core deploy-gateway deploy-peer + docker-demo From 8b9320d9db984f2dd37bff25a8a71230ea1e1e7b Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Mon, 26 Oct 2020 11:14:40 +0800 Subject: [PATCH 032/150] modify shell of startup and shutdown --- core | 2 +- .../gateway/boot/GatewayBooter.java | 36 ------ .../src/main/resources/scripts/shutdown.sh | 91 +++++++++----- .../src/main/resources/scripts/startup.sh | 112 ++++++++++++++--- .../jd/blockchain/boot/peer/PeerBooter.java | 24 ---- .../main/resources/scripts/peer-shutdown.sh | 91 +++++++++----- .../main/resources/scripts/peer-startup.sh | 116 +++++++++++++++--- explorer | 2 +- libs/bft-smart | 2 +- 9 files changed, 327 insertions(+), 149 deletions(-) diff --git a/core b/core index c770f544..d55343ab 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit c770f544e9892b4cc2e937a336abf59a40fc198a +Subproject commit d55343ab297329f9476d7fa1494ebb4c9c5fd878 diff --git a/deploy/deploy-gateway/src/main/java/com/jd/blockchain/gateway/boot/GatewayBooter.java b/deploy/deploy-gateway/src/main/java/com/jd/blockchain/gateway/boot/GatewayBooter.java index 4c9d5537..82413a65 100644 --- a/deploy/deploy-gateway/src/main/java/com/jd/blockchain/gateway/boot/GatewayBooter.java +++ b/deploy/deploy-gateway/src/main/java/com/jd/blockchain/gateway/boot/GatewayBooter.java @@ -15,45 +15,9 @@ public class GatewayBooter { public static void main(String[] args) { try { - writePID(); GatewayServerBooter.main(args); } catch (Exception e) { System.err.println("Error!!! --[" + e.getClass().getName() + "] " + e.getMessage()); } } - - private static final void writePID() throws Exception { - URL url = GatewayBooter.class.getProtectionDomain().getCodeSource().getLocation(); - String currPath = java.net.URLDecoder.decode(url.getPath(), "UTF-8"); - if (currPath.contains("!/")) { - currPath = currPath.substring(5, currPath.indexOf("!/")); - } - if (currPath.endsWith(".jar")) { - currPath = currPath.substring(0, currPath.lastIndexOf("/") + 1); - } - System.out.printf("currentPath = %s \r\n", currPath); - File file = new File(currPath); - String homeDir = file.getParent(); - String pidFilePath = homeDir + File.separator + "bin" + File.separator + "PID.log"; - File pidFile = new File(pidFilePath); - if (!pidFile.exists()) { - File dir = pidFile.getParentFile(); - if (!dir.exists()) { - dir.mkdirs(); - } - pidFile.createNewFile(); - } - String name = ManagementFactory.getRuntimeMXBean().getName(); - String pid = name.split("@")[0]; - List bootInfos = new ArrayList<>(); - bootInfos.add("JDChain gateway starts to boot ......\r\n"); - bootInfos.add(String.format("GW_BOOT_TIME = [%s] \r\n", new Date().toString())); - bootInfos.add(String.format("GW_BOOT_PID = [%s] \r\n", pid)); - try (FileOutputStream outputStream = new FileOutputStream(pidFile)) { - for (String bootInfo : bootInfos) { - outputStream.write(bootInfo.getBytes(StandardCharsets.UTF_8)); - } - outputStream.flush(); - } - } } diff --git a/deploy/deploy-gateway/src/main/resources/scripts/shutdown.sh b/deploy/deploy-gateway/src/main/resources/scripts/shutdown.sh index 0491e963..068c5ed0 100644 --- a/deploy/deploy-gateway/src/main/resources/scripts/shutdown.sh +++ b/deploy/deploy-gateway/src/main/resources/scripts/shutdown.sh @@ -1,32 +1,65 @@ #!/bin/bash -#启动Home路径 -BOOT_HOME=$(cd `dirname $0`;cd ../; pwd) - -#进程启动后PID.log所在路径 -PID_LOG=$BOOT_HOME/bin/PID.log - -#从启动文件中读取PID -if [ -f "$PID_LOG" ]; then - # File exist - echo "Read PID From File:[$PID_LOG] ..." - PID_LINE=`sed -n '$p' $PID_LOG` - echo "Last Gateway Boot Info = $PID_LINE ..." - if [[ $PID_LINE == *GW_BOOT_PID* ]]; then - LOG_PID=$(echo $PID_LINE | cut -d "=" -f 2 | cut -d "[" -f 2 | cut -d "]" -f 1) - echo "Last Gateway Boot PID = $LOG_PID ..." - PID=`ps -ef | grep deploy-gateway- | grep $LOG_PID | grep -v grep | awk '{print $2}'` +#定义程序启动的Jar包前缀 +APP_JAR_PREFIX=deploy-gateway- + +#获取当前的根目录 +APP_HOME=$(cd `dirname $0`;cd ../; pwd) + +#System路径 +APP_LIB_PATH=$APP_HOME/lib + +#获取Peer节点的启动Jar包 +APP_JAR=$(ls $APP_LIB_PATH | grep $APP_JAR_PREFIX) + +#APP_JAR的具体路径 +APP_JAR_PATH=$APP_LIB_PATH/$APP_JAR + +################################### +#(函数)判断程序是否已启动 +# +#说明: +#使用awk,分割出pid ($1部分),及Java程序名称($2部分) +################################### +#初始化psid变量(全局) +psid=0 + +checkpid() { + psid=`ps -ef | grep $APP_JAR_PATH | grep -v grep | awk '{print $2}'` +} + +################################### +#(函数)停止程序 +# +#说明: +#1. 首先调用checkpid函数,刷新$psid全局变量 +#2. 如果程序已经启动($psid不等于0),则开始执行停止,否则,提示程序未运行 +#3. 使用kill -9 pid命令进行强制杀死进程 +#4. 执行kill命令行紧接其后,马上查看上一句命令的返回值: $? +#5. 如果步骤4的结果$?等于0,则打印[OK],否则打印[Failed] +#注意:echo -n 表示打印字符后,不换行 +#注意: 在shell编程中,"$?" 表示上一句命令或者一个函数的返回值 +################################### +stop() { + checkpid + + if [[ $psid -ne 0 ]]; then + echo "Stopping Gateway ......(pid=$psid) " + JAVA_CMD="kill -9 $psid" + sleep 1 + $JAVA_CMD + if [[ $? -eq 0 ]]; then + echo "[OK]" + else + echo "[Failed]" fi -#启动文件不存在则直接通过PS进行过滤 -else - PID=`ps -ef | grep $BOOT_HOME/lib/deploy-gateway- | grep -v grep | awk '{print $2}'` -fi - -#通过Kill命令将进程杀死 -if [ -z "$PID" ]; then - echo "Unable to find gateway PID. stop aborted." -else - echo "Start to kill PID = $PID ..." - kill -9 $PID - echo "Gateway has been stopped ..." -fi \ No newline at end of file + else + echo "================================" + echo "WARN: Gateway is not running" + echo "================================" + fi +} + + +#真正停止的处理流程 +stop \ No newline at end of file diff --git a/deploy/deploy-gateway/src/main/resources/scripts/startup.sh b/deploy/deploy-gateway/src/main/resources/scripts/startup.sh index 01c86077..76189f54 100644 --- a/deploy/deploy-gateway/src/main/resources/scripts/startup.sh +++ b/deploy/deploy-gateway/src/main/resources/scripts/startup.sh @@ -1,19 +1,103 @@ #!/bin/bash -HOME=$(cd `dirname $0`;cd ../; pwd) -GATEWAY=$(ls $HOME/lib | grep deploy-gateway-) -PROC_INFO=$HOME/lib/$GATEWAY" -c "$HOME/config/gateway.conf -#echo $PROC_INFO -#get PID -PID=`ps -ef | grep "$PROC_INFO" | grep -v grep | awk '{print $2}'` -#echo $PID -if [[ ! -z $PID ]] -then - echo "process already exists,please check... If necessary, you should kill the process first." - exit +#设置Java命令 +JAVA_BIN=java + +#定义程序启动的Jar包前缀 +APP_JAR_PREFIX=deploy-gateway- + +#检查Java环境变量 +if [ ! -n "$JAVA_HOME" ]; then + echo "UnFound environment variable[JAVA_HOME], will use command[java]..." +else + JAVA_BIN=$JAVA_HOME/bin/java fi -if [ ! -n "$GATEWAY" ]; then - echo "GateWay Is Null !!!" + +#获取当前的根目录 +APP_HOME=$(cd `dirname $0`;cd ../; pwd) + +#Lib目录 +APP_LIB_PATH=$APP_HOME/lib + +#节点输出日志路径 +LOG_OUT=$APP_HOME/bin/gw.out + +#获取Peer节点的启动Jar包 +APP_JAR=$(ls $APP_LIB_PATH | grep $APP_JAR_PREFIX) + +#Config配置路径 +CONFIG_PATH=$APP_HOME/config + +#gateway.conf完整路径 +GATEWAY_CONFIG=$CONFIG_PATH/gateway.conf + +#定义程序启动的参数 +JAVA_OPTS="-jar -server -Xms1024m -Xmx1024m" + +#APP具体相关命令 +APP_CMD=$APP_LIB_PATH/$APP_JAR" -c "$GATEWAY_CONFIG + +#APP_JAR的具体路径 +APP_JAR_PATH=$APP_LIB_PATH/$APP_JAR + +#JAVA_CMD具体命令 +JAVA_CMD="$JAVA_BIN $JAVA_OPTS $APP_CMD" + +################################### +#(函数)判断程序是否已启动 +# +#说明: +#使用awk,分割出pid ($1部分),及Java程序名称($2部分) +################################### +#初始化psid变量(全局) +psid=0 + +checkpid() { + javaps=`ps -ef | grep $APP_JAR_PATH | grep -v grep | awk '{print $2}'` + + if [[ -n "$javaps" ]]; then + psid=$javaps + else + psid=0 + fi +} + +################################### +#(函数)打印系统环境参数 +################################### +info() { + echo "System Information:" + echo "****************************" + echo `uname -a` + echo + echo `$JAVA_BIN -version` + echo + echo "APP_HOME=$APP_HOME" + echo "APP_JAR=$APP_JAR" + echo "CONFIG_PATH=$CONFIG_PATH" + echo "APP_JAR_PATH=$APP_JAR_PATH" + echo + echo "JAVA_CMD=$JAVA_CMD" + echo "****************************" +} + +#真正启动的处理流程 +checkpid + +if [[ $psid -ne 0 ]]; then + echo "================================" + echo "warn: Gateway already started! (pid=$psid)" + echo "================================" else - nohup java -jar -server -Djdchain.log=$HOME $PROC_INFO $* >$HOME/bin/gw.out 2>&1 & + echo "Starting Gateway ......" + nohup $JAVA_BIN $JAVA_OPTS $APP_CMD $* >$LOG_OUT 2>&1 & + JAVA_CMD="$JAVA_BIN $JAVA_OPTS $APP_CMD $*" + sleep 1 + checkpid + if [[ $psid -ne 0 ]]; then + echo "(pid=$psid) [OK]" + info + else + echo "[Failed]" + fi fi \ No newline at end of file diff --git a/deploy/deploy-peer/src/main/java/com/jd/blockchain/boot/peer/PeerBooter.java b/deploy/deploy-peer/src/main/java/com/jd/blockchain/boot/peer/PeerBooter.java index d465a4ba..df9196e5 100644 --- a/deploy/deploy-peer/src/main/java/com/jd/blockchain/boot/peer/PeerBooter.java +++ b/deploy/deploy-peer/src/main/java/com/jd/blockchain/boot/peer/PeerBooter.java @@ -33,12 +33,8 @@ public class PeerBooter { public static void main(String[] args) { try { - HomeContext homeContext = HomeBooter.createHomeContext(args); - startPeer(homeContext); - - writePID(homeContext.getHomeDir()); } catch (Exception e) { System.err.println("Error!!! --[" + e.getClass().getName() + "] " + e.getMessage()); } @@ -56,24 +52,4 @@ public class PeerBooter { SYSTEM_MAIN_CLASS, home.getSystemClassLoader(), home.getStartingArgs() }; modularFactoryMethod.invoke(null, systemStartingArgs); } - - private static final void writePID(String homeDir) throws IOException { - String pidFilePath = homeDir + File.separator + "bin" + File.separator + "PID.log"; - File pidFile = new File(pidFilePath); - if (!pidFile.exists()) { - pidFile.createNewFile(); - } - String name = ManagementFactory.getRuntimeMXBean().getName(); - String pid = name.split("@")[0]; - List bootInfos = new ArrayList<>(); - bootInfos.add("JDChain peer node starts to boot ......\r\n"); - bootInfos.add(String.format("PEER_BOOT_TIME = [%s] \r\n", new Date().toString())); - bootInfos.add(String.format("PEER_BOOT_PID = [%s] \r\n", pid)); - try (FileOutputStream outputStream = new FileOutputStream(pidFile)) { - for (String bootInfo : bootInfos) { - outputStream.write(bootInfo.getBytes(StandardCharsets.UTF_8)); - } - outputStream.flush(); - } - } } diff --git a/deploy/deploy-peer/src/main/resources/scripts/peer-shutdown.sh b/deploy/deploy-peer/src/main/resources/scripts/peer-shutdown.sh index 4df77fb5..cd4c21dc 100644 --- a/deploy/deploy-peer/src/main/resources/scripts/peer-shutdown.sh +++ b/deploy/deploy-peer/src/main/resources/scripts/peer-shutdown.sh @@ -1,32 +1,65 @@ #!/bin/bash -#启动Home路径 -BOOT_HOME=$(cd `dirname $0`;cd ../; pwd) - -#进程启动后PID.log所在路径 -PID_LOG=$BOOT_HOME/bin/PID.log - -#从启动文件中读取PID -if [ -f "$PID_LOG" ]; then - # File exist - echo "Read PID From File:[$PID_LOG] ..." - PID_LINE=`sed -n '$p' $PID_LOG` - echo "Last Peer Boot Info = $PID_LINE ..." - if [[ $PID_LINE == *PEER_BOOT_PID* ]]; then - LOG_PID=$(echo $PID_LINE | cut -d "=" -f 2 | cut -d "[" -f 2 | cut -d "]" -f 1) - echo "Last Peer Boot PID = $LOG_PID ..." - PID=`ps -ef | grep deploy-peer- | grep $LOG_PID | grep -v grep | awk '{print $2}'` +#定义程序启动的Jar包前缀 +APP_JAR_PREFIX=deploy-peer- + +#获取当前的根目录 +APP_HOME=$(cd `dirname $0`;cd ../; pwd) + +#System路径 +APP_SYSTEM_PATH=$APP_HOME/system + +#获取Peer节点的启动Jar包 +APP_JAR=$(ls $APP_SYSTEM_PATH | grep $APP_JAR_PREFIX) + +#APP_JAR的具体路径 +APP_JAR_PATH=$APP_SYSTEM_PATH/$APP_JAR + +################################### +#(函数)判断程序是否已启动 +# +#说明: +#使用awk,分割出pid ($1部分),及Java程序名称($2部分) +################################### +#初始化psid变量(全局) +psid=0 + +checkpid() { + psid=`ps -ef | grep $APP_JAR_PATH | grep -v grep | awk '{print $2}'` +} + +################################### +#(函数)停止程序 +# +#说明: +#1. 首先调用checkpid函数,刷新$psid全局变量 +#2. 如果程序已经启动($psid不等于0),则开始执行停止,否则,提示程序未运行 +#3. 使用kill -9 pid命令进行强制杀死进程 +#4. 执行kill命令行紧接其后,马上查看上一句命令的返回值: $? +#5. 如果步骤4的结果$?等于0,则打印[OK],否则打印[Failed] +#注意:echo -n 表示打印字符后,不换行 +#注意: 在shell编程中,"$?" 表示上一句命令或者一个函数的返回值 +################################### +stop() { + checkpid + + if [[ $psid -ne 0 ]]; then + echo "Stopping Peer ......(pid=$psid) " + JAVA_CMD="kill -9 $psid" + sleep 1 + $JAVA_CMD + if [[ $? -eq 0 ]]; then + echo "[OK]" + else + echo "[Failed]" fi -#启动文件不存在则直接通过PS进行过滤 -else - PID=`ps -ef | grep $BOOT_HOME/system/deploy-peer- | grep -v grep | awk '{print $2}'` -fi - -#通过Kill命令将进程杀死 -if [ -z "$PID" ]; then - echo "Unable to find peer PID. stop aborted." -else - echo "Start to kill PID = $PID ..." - kill -9 $PID - echo "Peer has been stopped ..." -fi \ No newline at end of file + else + echo "================================" + echo "WARN: Peer is not running" + echo "================================" + fi +} + + +#真正停止的处理流程 +stop \ No newline at end of file diff --git a/deploy/deploy-peer/src/main/resources/scripts/peer-startup.sh b/deploy/deploy-peer/src/main/resources/scripts/peer-startup.sh index 3367c3fc..19dfa675 100644 --- a/deploy/deploy-peer/src/main/resources/scripts/peer-startup.sh +++ b/deploy/deploy-peer/src/main/resources/scripts/peer-startup.sh @@ -1,19 +1,107 @@ #!/bin/bash -HOME=$(cd `dirname $0`;cd ../; pwd) -PEER=$(ls $HOME/system | grep deploy-peer-) -PROC_INFO=$HOME/system/$PEER" -home="$HOME" -c "$HOME/config/ledger-binding.conf" -p 7080" -#echo $PROC_INFO -#get PID -PID=`ps -ef | grep "$PROC_INFO" | grep -v grep | awk '{print $2}'` -#echo $PID -if [[ ! -z $PID ]] -then - echo "process already exists,please check... If necessary, you should kill the process first." - exit +#设置Java命令 +JAVA_BIN=java + +#定义程序启动的Jar包前缀 +APP_JAR_PREFIX=deploy-peer- + +#Peer节点Web端口 +#请运维根据实际环境进行调整 +WEB_PORT=7080 + +#检查Java环境变量 +if [ ! -n "$JAVA_HOME" ]; then + echo "UnFound environment variable[JAVA_HOME], will use command[java]..." +else + JAVA_BIN=$JAVA_HOME/bin/java fi -if [ ! -n "$PEER" ]; then - echo "Peer Is Null !!!" + +#获取当前的根目录 +APP_HOME=$(cd `dirname $0`;cd ../; pwd) + +#System目录 +APP_SYSTEM_PATH=$APP_HOME/system + +#节点输出日志路径 +LOG_OUT=$APP_HOME/bin/peer.out + +#获取Peer节点的启动Jar包 +APP_JAR=$(ls $APP_SYSTEM_PATH | grep $APP_JAR_PREFIX) + +#Config配置路径 +CONFIG_PATH=$APP_HOME/config + +#ledger-binding.conf完整路径 +LEDGER_BINDING_CONFIG=$CONFIG_PATH/ledger-binding.conf + +#定义程序启动的参数 +JAVA_OPTS="-jar -server -Xms2048m -Xmx2048m" + +#APP具体相关命令 +APP_CMD=$APP_SYSTEM_PATH/$APP_JAR" -home="$APP_HOME" -c "$LEDGER_BINDING_CONFIG" -p "$WEB_PORT + +#APP_JAR的具体路径 +APP_JAR_PATH=$APP_SYSTEM_PATH/$APP_JAR + +#JAVA_CMD具体命令 +JAVA_CMD="$JAVA_BIN $JAVA_OPTS $APP_CMD" + +################################### +#(函数)判断程序是否已启动 +# +#说明: +#使用awk,分割出pid ($1部分),及Java程序名称($2部分) +################################### +#初始化psid变量(全局) +psid=0 + +checkpid() { + javaps=`ps -ef | grep $APP_JAR_PATH | grep -v grep | awk '{print $2}'` + + if [[ -n "$javaps" ]]; then + psid=$javaps + else + psid=0 + fi +} + +################################### +#(函数)打印系统环境参数 +################################### +info() { + echo "System Information:" + echo "****************************" + echo `uname -a` + echo + echo `$JAVA_BIN -version` + echo + echo "APP_HOME=$APP_HOME" + echo "APP_JAR=$APP_JAR" + echo "CONFIG_PATH=$CONFIG_PATH" + echo "APP_JAR_PATH=$APP_JAR_PATH" + echo + echo "JAVA_CMD=$JAVA_CMD" + echo "****************************" +} + +#真正启动的处理流程 +checkpid + +if [[ $psid -ne 0 ]]; then + echo "================================" + echo "warn: Peer already started! (pid=$psid)" + echo "================================" else - nohup java -jar -server -Xmx1g -Xms1g -Djdchain.log=$HOME $PROC_INFO $* >$HOME/bin/peer.out 2>&1 & + echo "Starting Peer ......" + nohup $JAVA_BIN $JAVA_OPTS $APP_CMD $* >$LOG_OUT 2>&1 & + JAVA_CMD="$JAVA_BIN $JAVA_OPTS $APP_CMD $*" + sleep 1 + checkpid + if [[ $psid -ne 0 ]]; then + echo "(pid=$psid) [OK]" + info + else + echo "[Failed]" + fi fi \ No newline at end of file diff --git a/explorer b/explorer index 2f8f4843..3ffc3324 160000 --- a/explorer +++ b/explorer @@ -1 +1 @@ -Subproject commit 2f8f48435e65d4f6598b1ede9c6a7021b10d2a53 +Subproject commit 3ffc3324c9fe20307cc36c07c361daa1f5d3f11e diff --git a/libs/bft-smart b/libs/bft-smart index f2660860..722663f9 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit f2660860f71850b4e70ae529fbdb8320623bcaff +Subproject commit 722663f988affc77cc5aec502da455afb3f7eec5 From 8bfbb966ee9bbb40a66022d3622afe981c205dbc Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Mon, 26 Oct 2020 11:23:04 +0800 Subject: [PATCH 033/150] update headers --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index d55343ab..a95adc7d 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit d55343ab297329f9476d7fa1494ebb4c9c5fd878 +Subproject commit a95adc7d00e8e0655815f023ffb0c307393665bb From 8139da44dceaa8399b606d0925e92bfe80d710a7 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Mon, 26 Oct 2020 17:56:56 +0800 Subject: [PATCH 034/150] update headers --- core | 2 +- libs/bft-smart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index a95adc7d..aeb7d921 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit a95adc7d00e8e0655815f023ffb0c307393665bb +Subproject commit aeb7d92157cafa2db86b8df487af68054b2442a9 diff --git a/libs/bft-smart b/libs/bft-smart index 722663f9..3229cb2c 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 722663f988affc77cc5aec502da455afb3f7eec5 +Subproject commit 3229cb2c909080c3001dbb669d8a73c182fa1701 From 6fc5adf06aedc124e29063e12bb95cdb40e10094 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Tue, 27 Oct 2020 11:37:11 +0800 Subject: [PATCH 035/150] update headers --- core | 2 +- libs/bft-smart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index aeb7d921..d386a9a1 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit aeb7d92157cafa2db86b8df487af68054b2442a9 +Subproject commit d386a9a13ad14769ac4ea903b8ba260a5a4651e2 diff --git a/libs/bft-smart b/libs/bft-smart index 3229cb2c..2b11d098 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 3229cb2c909080c3001dbb669d8a73c182fa1701 +Subproject commit 2b11d098e33d44e5d60c2b5c2af6b7d34fb25a82 From 05a3159f5f79daa59130651019bb19ec861bfbcb Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Tue, 27 Oct 2020 13:51:31 +0800 Subject: [PATCH 036/150] add docker-sdk; --- deploy/docker-sdk/pom.xml | 70 +++++++ .../com/jd/blockchain/ContractParams.java | 107 ++++++++++ .../main/java/com/jd/blockchain/SDKDemo.java | 68 +++++++ .../com/jd/blockchain/SDKDemo_Constant.java | 46 +++++ .../java/com/jd/blockchain/SDK_Base_Demo.java | 191 ++++++++++++++++++ .../jd/chain/contract/TransferContract.java | 32 +++ .../contract-compile-1.3.0.RELEASE.car | Bin 0 -> 5129 bytes 7 files changed, 514 insertions(+) create mode 100644 deploy/docker-sdk/pom.xml create mode 100644 deploy/docker-sdk/src/main/java/com/jd/blockchain/ContractParams.java create mode 100644 deploy/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo.java create mode 100644 deploy/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo_Constant.java create mode 100644 deploy/docker-sdk/src/main/java/com/jd/blockchain/SDK_Base_Demo.java create mode 100644 deploy/docker-sdk/src/main/java/com/jd/chain/contract/TransferContract.java create mode 100644 deploy/docker-sdk/src/main/resources/contract-compile-1.3.0.RELEASE.car diff --git a/deploy/docker-sdk/pom.xml b/deploy/docker-sdk/pom.xml new file mode 100644 index 00000000..1c7e0787 --- /dev/null +++ b/deploy/docker-sdk/pom.xml @@ -0,0 +1,70 @@ + + + + deploy-root + com.jd.blockchain + 1.4.0-SNAPSHOT + + 4.0.0 + + docker-sdk + + + 1.3.0.RELEASE + + + + + com.jd.blockchain + crypto-classic + ${ledger.version} + + + com.jd.blockchain + crypto-sm + ${ledger.version} + + + com.jd.blockchain + ledger-model + ${ledger.version} + + + com.jd.blockchain + sdk-client + ${ledger.version} + + + + + + + maven-assembly-plugin + + false + + jar-with-dependencies + + + + + com.jd.blockchain.SDKDemo + + + + + + make-assembly + package + + single + + + + + + + + \ No newline at end of file diff --git a/deploy/docker-sdk/src/main/java/com/jd/blockchain/ContractParams.java b/deploy/docker-sdk/src/main/java/com/jd/blockchain/ContractParams.java new file mode 100644 index 00000000..b1464b4e --- /dev/null +++ b/deploy/docker-sdk/src/main/java/com/jd/blockchain/ContractParams.java @@ -0,0 +1,107 @@ +package com.jd.blockchain; + +import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.BlockchainKeypair; + +public class ContractParams { + String contractZipName; + BlockchainKeypair signAdminKey; + BlockchainIdentity contractIdentity; + boolean isDeploy; + boolean isExecute; + boolean hasVersion; //contract's version; + long version; + BlockchainIdentity dataAccount; + String key; + String value; + + public String getContractZipName() { + return contractZipName; + } + + public ContractParams setContractZipName(String contractZipName) { + this.contractZipName = contractZipName; + return this; + } + + public BlockchainKeypair getSignAdminKey() { + return signAdminKey; + } + + public ContractParams setSignAdminKey(BlockchainKeypair signAdminKey) { + this.signAdminKey = signAdminKey; + return this; + } + + public BlockchainIdentity getContractIdentity() { + return contractIdentity; + } + + public ContractParams setContractIdentity(BlockchainIdentity contractIdentity) { + this.contractIdentity = contractIdentity; + return this; + } + + public boolean isDeploy() { + return isDeploy; + } + + public ContractParams setDeploy(boolean deploy) { + isDeploy = deploy; + return this; + } + + public boolean isExecute() { + return isExecute; + } + + public ContractParams setExecute(boolean execute) { + isExecute = execute; + return this; + } + + public boolean isHasVersion() { + return hasVersion; + } + + public ContractParams setHasVersion(boolean hasVersion) { + this.hasVersion = hasVersion; + return this; + } + + public long getVersion() { + return version; + } + + public ContractParams setVersion(long version) { + this.version = version; + return this; + } + + public BlockchainIdentity getDataAccount() { + return dataAccount; + } + + public ContractParams setDataAccount(BlockchainIdentity dataAccount) { + this.dataAccount = dataAccount; + return this; + } + + public String getKey() { + return key; + } + + public ContractParams setKey(String key) { + this.key = key; + return this; + } + + public String getValue() { + return value; + } + + public ContractParams setValue(String value) { + this.value = value; + return this; + } +} diff --git a/deploy/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo.java b/deploy/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo.java new file mode 100644 index 00000000..5e02ccf1 --- /dev/null +++ b/deploy/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo.java @@ -0,0 +1,68 @@ +package com.jd.blockchain; + +import com.jd.blockchain.ledger.*; +import org.apache.commons.codec.binary.Base64; + +import java.util.Random; +import java.util.UUID; + +public class SDKDemo extends SDK_Base_Demo{ + public static void main(String[] args) { + SDKDemo sdkDemo = new SDKDemo(); + //注册用户; + sdkDemo.registerUsers(); + //构建数据账户; + sdkDemo.genDataAccount(); + //发布和执行合约; + sdkDemo.deployContract(); + } + + //注册用户; + public void registerUsers(){ + this.registerUser(); + } + + //构建数据账户; + public void genDataAccount(){ + byte[] arr = new byte[1024]; + new Random().nextBytes(arr); + String value = Base64.encodeBase64String(arr); + this.insertData(null,null,"key1",value,-1); + } + + public BlockchainKeypair insertData(BlockchainKeypair dataAccount, BlockchainKeypair signAdminKey, + String key, String value, long version) { + // 在本地定义注册账号的 TX; + TransactionTemplate txTemp = blockchainService.newTransaction(ledgerHash); + //采用KeyGenerator来生成BlockchainKeypair; + if(dataAccount == null){ + dataAccount = BlockchainKeyGenerator.getInstance().generate(); + txTemp.dataAccounts().register(dataAccount.getIdentity()); + } + + System.out.println("current dataAccount=" + dataAccount.getAddress()); + txTemp.dataAccount(dataAccount.getAddress()).setText(key, value, version); + txTemp.dataAccount(dataAccount.getAddress()).setTimestamp(UUID.randomUUID().toString(),System.currentTimeMillis(),-1); + + // TX 准备就绪 + commit(txTemp,signAdminKey); + + //get the version + TypedKVEntry[] kvData = blockchainService.getDataEntries(ledgerHash, + dataAccount.getAddress().toBase58(), key); + System.out.println(String.format("key1 info:key=%s,value=%s,version=%d", + kvData[0].getKey(),kvData[0].getValue().toString(),kvData[0].getVersion())); + + return dataAccount; + } + + public void deployContract(){ + ContractParams contractParams = new ContractParams(); + contractParams.setContractZipName("contract-compile-1.3.0.RELEASE.car").setDeploy(true).setExecute(false); + BlockchainIdentity contractAddress = + this.contractHandle(contractParams); + contractParams.setContractIdentity(contractAddress); + this.contractHandle(contractParams); + this.contractHandle(contractParams.setExecute(true)); + } +} diff --git a/deploy/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo_Constant.java b/deploy/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo_Constant.java new file mode 100644 index 00000000..ec7ec7c2 --- /dev/null +++ b/deploy/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo_Constant.java @@ -0,0 +1,46 @@ +package com.jd.blockchain; + +import com.jd.blockchain.crypto.KeyGenUtils; +import com.jd.blockchain.crypto.PrivKey; +import com.jd.blockchain.crypto.PubKey; +import com.jd.blockchain.ledger.BlockchainKeypair; +import org.apache.commons.io.FileUtils; +import org.springframework.core.io.ClassPathResource; + +import java.io.File; +import java.io.InputStream; + +public class SDKDemo_Constant { + + public static String GW_IPADDR = "localhost"; + public static int GW_PORT = 8080; + public static String GW_PUB_KEY = "3snPdw7i7PisoLpqqtETdqzQeKVjQReP2Eid9wYK67q9z6trvByGZs"; + public static String GW_PRIV_KEY = "177gk2PbxhHeEdfAAqGfShJQyeV4XvGsJ9CvJFUbToBqwW1YJd5obicySE1St6SvPPaRrUP"; + public static String GW_PASSWORD = "8EjkXVSTxMFjCvNNsTo8RBMDEVQmk7gYkW4SCDuvdsBG"; + + public static PrivKey gwPrivkey0 = KeyGenUtils.decodePrivKey(GW_PRIV_KEY, GW_PASSWORD); + public static PubKey gwPubKey0 = KeyGenUtils.decodePubKey(GW_PUB_KEY); + public static BlockchainKeypair adminKey = new BlockchainKeypair(gwPubKey0, gwPrivkey0); + + public static final byte[] readChainCodes(String contractZip) { + // 构建合约的字节数组; + try { + ClassPathResource contractPath = new ClassPathResource(contractZip); +// File contractFile = new File(contractPath.getURI()); + + InputStream in = contractPath.getInputStream(); + // 将文件写入至config目录下 + File directory = new File("."); + String configPath = directory.getAbsolutePath() + File.separator + "contract.jar"; + File targetFile = new File(configPath); + // 先将原来文件删除再Copy + if (targetFile.exists()) { + FileUtils.forceDelete(targetFile); + } + FileUtils.copyInputStreamToFile(in, targetFile); + return FileUtils.readFileToByteArray(targetFile); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } +} diff --git a/deploy/docker-sdk/src/main/java/com/jd/blockchain/SDK_Base_Demo.java b/deploy/docker-sdk/src/main/java/com/jd/blockchain/SDK_Base_Demo.java new file mode 100644 index 00000000..51cc1741 --- /dev/null +++ b/deploy/docker-sdk/src/main/java/com/jd/blockchain/SDK_Base_Demo.java @@ -0,0 +1,191 @@ +package com.jd.blockchain; + +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.*; +import com.jd.blockchain.sdk.BlockchainService; +import com.jd.blockchain.sdk.client.GatewayServiceFactory; +import com.jd.blockchain.transaction.GenericValueHolder; +import com.jd.blockchain.utils.Bytes; +import com.jd.chain.contract.TransferContract; + +import static com.jd.blockchain.SDKDemo_Constant.readChainCodes; +import static com.jd.blockchain.transaction.ContractReturnValue.decode; + +public abstract class SDK_Base_Demo { + protected BlockchainKeypair adminKey; + + protected HashDigest ledgerHash; + + protected BlockchainService blockchainService; + + public SDK_Base_Demo() { + init(); + } + + public void init() { + // 生成连接网关的账号 + adminKey = SDKDemo_Constant.adminKey; + + // 连接网关 + GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(SDKDemo_Constant.GW_IPADDR, + SDKDemo_Constant.GW_PORT, false, adminKey); + + // 获取网关对应的Service处理类 + blockchainService = serviceFactory.getBlockchainService(); + + HashDigest[] ledgerHashs = blockchainService.getLedgerHashs(); + // 获取当前账本Hash + ledgerHash = ledgerHashs[0]; + } + + public TransactionResponse commit(TransactionTemplate txTpl){ + return this.commitA(txTpl,null); + } + + /** + * 默认使用A方式commit; + * @param txTpl + * @param signAdminKey + * @return + */ + public TransactionResponse commit(TransactionTemplate txTpl, BlockchainKeypair signAdminKey){ + return commitA(txTpl, signAdminKey); + } + + /** + * 采用A方式提交; + * @param txTpl + * @param signAdminKey + * @return + */ + public TransactionResponse commitA(TransactionTemplate txTpl, BlockchainKeypair signAdminKey) { + PreparedTransaction ptx = txTpl.prepare(); + + if(signAdminKey != null){ + System.out.println("signAdminKey's pubKey = "+signAdminKey.getIdentity().getPubKey()); + ptx.sign(signAdminKey); + }else { + System.out.println("adminKey's pubKey = "+adminKey.getIdentity().getPubKey()); + ptx.sign(adminKey); + } + TransactionResponse transactionResponse = ptx.commit(); + + if (transactionResponse.isSuccess()) { + System.out.println(String.format("height=%d, ###OK#, contentHash=%s, executionState=%s", + transactionResponse.getBlockHeight(), + transactionResponse.getContentHash(), transactionResponse.getExecutionState().toString())); + } else { + System.out.println(String.format("height=%d, ###exception#, contentHash=%s, executionState=%s", + transactionResponse.getBlockHeight(), + transactionResponse.getContentHash(), transactionResponse.getExecutionState().toString())); + } + return transactionResponse; + } + + /** + * 生成一个区块链用户,并注册到区块链; + */ + public BlockchainKeypair registerUser() { + return this.registerUser(null,null,null); + } + + public BlockchainKeypair registerUser(String cryptoType, BlockchainKeypair signAdminKey, BlockchainKeypair userKeypair) { + // 在本地定义注册账号的 TX; + TransactionTemplate txTemp = blockchainService.newTransaction(ledgerHash); + if(userKeypair == null){ + if("SM2".equals(cryptoType)){ + userKeypair = BlockchainKeyGenerator.getInstance().generate(cryptoType); + }else { + userKeypair = BlockchainKeyGenerator.getInstance().generate(); + } + } + System.out.println("user'address="+userKeypair.getAddress()); + txTemp.users().register(userKeypair.getIdentity()); + // TX 准备就绪; + commit(txTemp,signAdminKey); + return userKeypair; + } + + public BlockchainKeypair registerUser(BlockchainKeypair signAdminKey, BlockchainKeypair userKeypair) { + return registerUser(null,signAdminKey,userKeypair); + } + + /** + * 生成一个区块链用户,并注册到区块链; + */ + public BlockchainKeypair registerUserByNewSigner(BlockchainKeypair signer) { + return this.registerUser(signer,null); + } + + public BlockchainIdentity createDataAccount() { + // 首先注册一个数据账户 + BlockchainKeypair newDataAccount = BlockchainKeyGenerator.getInstance().generate(); + + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + txTpl.dataAccounts().register(newDataAccount.getIdentity()); + commit(txTpl); + return newDataAccount.getIdentity(); + } + + public String create1(Bytes contractAddress, String address, String account, String content) { + System.out.println(String.format("params,String address=%s, String account=%s, String content=%s, Bytes contractAddress=%s", + address,account,content,contractAddress.toBase58())); + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + // 使用合约创建 + TransferContract guanghu = txTpl.contract(contractAddress, TransferContract.class); + GenericValueHolder result = decode(guanghu.putval(address, account, content, System.currentTimeMillis())); + commit(txTpl); + return result.get(); + } + + public BlockchainIdentity contractHandle(ContractParams contractParams) { + if(contractParams.getContractZipName() == null){ + contractParams.setContractZipName("contract-JDChain-Contract.jar"); + } + // 发布jar包 + // 定义交易模板 + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + Bytes contractAddress = null; + if(contractParams.getContractIdentity() != null){ + contractAddress = contractParams.getContractIdentity().getAddress(); + } + + if(contractParams.isDeploy){ + // 将jar包转换为二进制数据 + byte[] contractCode = readChainCodes(contractParams.getContractZipName()); + + // 生成一个合约账号 + if(contractParams.getContractIdentity() == null){ + contractParams.setContractIdentity(BlockchainKeyGenerator.getInstance().generate().getIdentity()); + } + contractAddress = contractParams.getContractIdentity().getAddress(); + System.out.println("contract's address=" + contractAddress); + + // 生成发布合约操作 + if(contractParams.isHasVersion()){ +// txTpl.contracts().deploy(contractParams.contractIdentity, contractCode, contractParams.version); + } else { + txTpl.contracts().deploy(contractParams.contractIdentity, contractCode); + } + + + // 生成预发布交易; + commit(txTpl,contractParams.getSignAdminKey()); + } + + if(contractParams.isExecute){ + // 注册一个数据账户 + if(contractParams.dataAccount == null){ + contractParams.dataAccount = createDataAccount(); + contractParams.key = "jd_zhangsan"; + contractParams.value = "{\"dest\":\"KA006\",\"id\":\"cc-fin08-01\",\"items\":\"FIN001|3030\",\"source\":\"FIN001\"}"; + } + // 获取数据账户地址x + String dataAddress = contractParams.dataAccount.getAddress().toBase58(); + // 打印数据账户地址 + System.out.printf("DataAccountAddress = %s \r\n", dataAddress); + System.out.println("return value = "+create1(contractAddress, dataAddress, contractParams.key, contractParams.value)); + } + return contractParams.contractIdentity; + } +} diff --git a/deploy/docker-sdk/src/main/java/com/jd/chain/contract/TransferContract.java b/deploy/docker-sdk/src/main/java/com/jd/chain/contract/TransferContract.java new file mode 100644 index 00000000..a3a41529 --- /dev/null +++ b/deploy/docker-sdk/src/main/java/com/jd/chain/contract/TransferContract.java @@ -0,0 +1,32 @@ +package com.jd.chain.contract; + +import com.jd.blockchain.contract.Contract; +import com.jd.blockchain.contract.ContractEvent; + +@Contract +public interface TransferContract { + + @ContractEvent(name = "create") + String create(String address, String account, long money); + + @ContractEvent(name = "transfer") + String transfer(String address, String from, String to, long money); + + @ContractEvent(name = "read") + long read(String address, String account); + + @ContractEvent(name = "readAll") + String readAll(String address, String account); + + @ContractEvent(name = "putval1") + String putval(String address, String account, String content, Long time); + + @ContractEvent(name = "putvalBif") + String putvalBifurcation(String address, String account, String content, String isHalf); + + @ContractEvent(name = "getTxSigners") + String getTxSigners(String input); + + @ContractEvent(name = "test") + String test(String input); +} diff --git a/deploy/docker-sdk/src/main/resources/contract-compile-1.3.0.RELEASE.car b/deploy/docker-sdk/src/main/resources/contract-compile-1.3.0.RELEASE.car new file mode 100644 index 0000000000000000000000000000000000000000..cd7c3c825ef6c2d305a0a7e3c1ea974825205a86 GIT binary patch literal 5129 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 Date: Tue, 27 Oct 2020 13:51:53 +0800 Subject: [PATCH 037/150] add docker-sdk; --- deploy/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/deploy/pom.xml b/deploy/pom.xml index 2b416ee0..c500f2d3 100644 --- a/deploy/pom.xml +++ b/deploy/pom.xml @@ -20,6 +20,7 @@ ../core deploy-gateway deploy-peer + docker-sdk docker-demo From 2f0a4bbb23ab300ecbe89d8d2b799e1973ff1d3c Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Tue, 27 Oct 2020 17:01:17 +0800 Subject: [PATCH 038/150] add docker-sdk; --- deploy/docker-demo/pom.xml | 9 +++++++++ .../src/main/docker/script/start.sh | 2 ++ .../docker-demo/src/main/docker/zip/conf.zip | Bin 313206 -> 90971 bytes deploy/docker-sdk/pom.xml | 1 + 4 files changed, 12 insertions(+) diff --git a/deploy/docker-demo/pom.xml b/deploy/docker-demo/pom.xml index d7e7f123..398d3973 100644 --- a/deploy/docker-demo/pom.xml +++ b/deploy/docker-demo/pom.xml @@ -47,6 +47,15 @@ jdchain-gateway-${project.version}.RELEASE.zip + + + + ${project.basedir}/../docker-sdk/target/ + false + + docker-sdk-${project.version}.RELEASE.jar + + diff --git a/deploy/docker-demo/src/main/docker/script/start.sh b/deploy/docker-demo/src/main/docker/script/start.sh index a6cc134c..5a3b5bd9 100644 --- a/deploy/docker-demo/src/main/docker/script/start.sh +++ b/deploy/docker-demo/src/main/docker/script/start.sh @@ -24,5 +24,7 @@ sh ./peer2/bin/peer-startup.sh sh ./peer3/bin/peer-startup.sh sleep 30 sh ./gw/bin/startup.sh +sleep 10 +java -jar docker-sdk-1.3.0.RELEASE.jar > sdk.log tail -f /dev/null diff --git a/deploy/docker-demo/src/main/docker/zip/conf.zip b/deploy/docker-demo/src/main/docker/zip/conf.zip index 8f4c3d971597e1c19518154ba2873970578248ed..7be2f764f5359050ad7c34aa30bcfea457b915dc 100644 GIT binary patch delta 4318 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 F{U3NAhim`< delta 224877 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 LB|Ai8K#u+gW(BD< diff --git a/deploy/docker-sdk/pom.xml b/deploy/docker-sdk/pom.xml index 1c7e0787..85cacb21 100644 --- a/deploy/docker-sdk/pom.xml +++ b/deploy/docker-sdk/pom.xml @@ -8,6 +8,7 @@ 1.4.0-SNAPSHOT 4.0.0 + 1.3.0.RELEASE docker-sdk From ba443b45c29c817930c9cdadba77c8beb927eb0d Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Tue, 27 Oct 2020 17:16:03 +0800 Subject: [PATCH 039/150] update headers --- libs/bft-smart | 2 +- test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/bft-smart b/libs/bft-smart index 2b11d098..7c35da16 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 2b11d098e33d44e5d60c2b5c2af6b7d34fb25a82 +Subproject commit 7c35da16829788821affef26f499a35806acb8d3 diff --git a/test b/test index d723a4b8..687ee2fd 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit d723a4b84e3357fdc8b5593fe2592e317bd70188 +Subproject commit 687ee2fd6415ff304839514276c59b32765be256 From 00ca066e0d65ac547e38b6ea87e8dc6561e01ffd Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Tue, 27 Oct 2020 17:47:48 +0800 Subject: [PATCH 040/150] update headers --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index 7c35da16..443e433e 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 7c35da16829788821affef26f499a35806acb8d3 +Subproject commit 443e433eff0f504796e5898a281d631a6779486f From a61f3453e7ca85d9f06988efc81f595228ffae0b Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Tue, 27 Oct 2020 18:01:01 +0800 Subject: [PATCH 041/150] add the dos2unix for win; --- deploy/docker-demo/pom.xml | 16 +++++++++++++++- deploy/docker-demo/src/main/docker/Dockerfile | 2 ++ .../java/com/jd/blockchain/SDK_Base_Demo.java | 7 +------ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/deploy/docker-demo/pom.xml b/deploy/docker-demo/pom.xml index 398d3973..59c4e340 100644 --- a/deploy/docker-demo/pom.xml +++ b/deploy/docker-demo/pom.xml @@ -10,12 +10,26 @@ 1.3.0 4.0.0 - docker-demo jdchain-demo + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + UTF-8 + false + true + false + false + + + maven-resources-plugin 3.0.2 diff --git a/deploy/docker-demo/src/main/docker/Dockerfile b/deploy/docker-demo/src/main/docker/Dockerfile index 616e1b74..c6d8edde 100644 --- a/deploy/docker-demo/src/main/docker/Dockerfile +++ b/deploy/docker-demo/src/main/docker/Dockerfile @@ -5,6 +5,7 @@ RUN yum install wget -y \ && wget -O /etc/yum.repos.d/epel-7.repo http://mirrors.aliyun.com/repo/epel-7.repo \ && yum install java net-tools nc crontabs expect unzip -y \ && yum install langpacks-zh_CN.noarch -y \ + && yum install dos2unix -y \ && echo "LANG=zh_CN.utf8" >> /etc/locale.conf \ && source /etc/locale.conf \ && yum clean all @@ -21,6 +22,7 @@ ENV SERVER_NAME_PEER=deploy-peer ENV SERVER_NAME_GW=deploy-gateway COPY script/* /export/jdchain/ +RUN dos2unix /export/jdchain/*.sh RUN chmod +x /export/jdchain/*.sh # ports diff --git a/deploy/docker-sdk/src/main/java/com/jd/blockchain/SDK_Base_Demo.java b/deploy/docker-sdk/src/main/java/com/jd/blockchain/SDK_Base_Demo.java index 51cc1741..9f2e4754 100644 --- a/deploy/docker-sdk/src/main/java/com/jd/blockchain/SDK_Base_Demo.java +++ b/deploy/docker-sdk/src/main/java/com/jd/blockchain/SDK_Base_Demo.java @@ -162,12 +162,7 @@ public abstract class SDK_Base_Demo { System.out.println("contract's address=" + contractAddress); // 生成发布合约操作 - if(contractParams.isHasVersion()){ -// txTpl.contracts().deploy(contractParams.contractIdentity, contractCode, contractParams.version); - } else { - txTpl.contracts().deploy(contractParams.contractIdentity, contractCode); - } - + txTpl.contracts().deploy(contractParams.contractIdentity, contractCode); // 生成预发布交易; commit(txTpl,contractParams.getSignAdminKey()); From aa2628f62ab390154181f7a45a0b2fa068a5f4ed Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Tue, 27 Oct 2020 18:48:39 +0800 Subject: [PATCH 042/150] check the zip and sdk.jar; --- deploy/docker-demo/src/main/docker/script/start.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/deploy/docker-demo/src/main/docker/script/start.sh b/deploy/docker-demo/src/main/docker/script/start.sh index 5a3b5bd9..c55380b6 100644 --- a/deploy/docker-demo/src/main/docker/script/start.sh +++ b/deploy/docker-demo/src/main/docker/script/start.sh @@ -2,10 +2,15 @@ cd $RELEASE_DIR -# invoke it once again; -#gw_pid_file="./gw/bin/PID.log" -#if [ ! -f gw_pid_file ] ; then -# echo "get the PID.log, only to start the peer and gateway." +# check the files; +peer_file="./jdchain-peer-$RELEASE_VERSION.RELEASE.zip" +gw_file="./jdchain-gateway-$RELEASE_VERSION.RELEASE.zip" +sdk_file="./docker-sdk-$RELEASE_VERSION.RELEASE.jar" +if [[ ! -f $peer_file ]] || [[ ! -f $gw_file ]] || [[ ! -f $sdk_file ]] ; then +echo "not find $peer_file or $gw_file or $sdk_file in the $RELEASE_DIR, please check the image of jdchain-demo:$RELEASE_VERSION." +exit 1 +fi + unzip -o conf.zip for i in `seq 0 3` @@ -16,7 +21,6 @@ cd $RELEASE_DIR unzip -n -d ./gw jdchain-gateway-$RELEASE_VERSION.RELEASE.zip chmod +x ./gw/bin/* -#fi sh ./peer0/bin/peer-startup.sh sh ./peer1/bin/peer-startup.sh From fbdccbcf82bd14f9bbfbc32820c3d76da943c7a5 Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Wed, 28 Oct 2020 10:23:46 +0800 Subject: [PATCH 043/150] modify the md for: how to generate the image; --- deploy/docker-demo/readme.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/deploy/docker-demo/readme.md b/deploy/docker-demo/readme.md index eb4034f1..d227843d 100644 --- a/deploy/docker-demo/readme.md +++ b/deploy/docker-demo/readme.md @@ -1,11 +1,13 @@ # jdchain-demo镜像使用说明 本镜像主要为快速构建JDChain测试环境使用,内嵌固定的公私钥,不可用于生产正式环境。 JDChain在docker中的安装路径:/export/jdchain,网关对外端口为:8080。可通过docker-compose-all文件来修改端口。 -demo环境中加载了部分测试数据,区块高度:22,交易总数:23,用户总数:6,数据账户总数:3,合约总数:2。 +demo环境构建完成后执行sdk加载部分测试数据,区块高度:22,交易总数:23,用户总数:6,数据账户总数:3,合约总数:2。 ## 如何生成镜像 -1. 需要预先在deploy-peer和deploy-gateway中生成zip安装包; -2. 本项目中执行:mvn clean package;会在docker环境中生成jdchain-peer镜像; +1. 需要预先在deploy-peer和deploy-gateway中生成zip安装包,copy的源路径是target; +2. 需要预先在docker-sdk中执行:mvn clean package,生成sdk可执行jar; +2. 本项目中执行:mvn clean package;会从dpploy-peer/dploy-gw/docker-sdk的target中提取zip包和可执行jar, +在docker环境中生成jdchain-peer镜像; 3. 生成镜像文件。执行resource中:zip.sh,可生成镜像的tar.gz压缩包; ## 镜像快速使用 From 85c875c36e8a6c9e3bc5d482d5ae03c04d6686ed Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Wed, 28 Oct 2020 10:25:06 +0800 Subject: [PATCH 044/150] add docker-sdk; --- deploy/docker-demo/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/docker-demo/readme.md b/deploy/docker-demo/readme.md index d227843d..626a6ad2 100644 --- a/deploy/docker-demo/readme.md +++ b/deploy/docker-demo/readme.md @@ -1,7 +1,7 @@ # jdchain-demo镜像使用说明 本镜像主要为快速构建JDChain测试环境使用,内嵌固定的公私钥,不可用于生产正式环境。 JDChain在docker中的安装路径:/export/jdchain,网关对外端口为:8080。可通过docker-compose-all文件来修改端口。 -demo环境构建完成后执行sdk加载部分测试数据,区块高度:22,交易总数:23,用户总数:6,数据账户总数:3,合约总数:2。 +demo环境构建完成后执行sdk加载部分测试数据,区块高度:7,交易总数:8,用户总数:5,数据账户总数:2,合约总数:1。 ## 如何生成镜像 1. 需要预先在deploy-peer和deploy-gateway中生成zip安装包,copy的源路径是target; From 75a78c628137e4d15008ca7246013f6bf0fe5ace Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Wed, 28 Oct 2020 10:26:01 +0800 Subject: [PATCH 045/150] add docker-sdk; --- deploy/docker-demo/readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deploy/docker-demo/readme.md b/deploy/docker-demo/readme.md index 626a6ad2..44b5a646 100644 --- a/deploy/docker-demo/readme.md +++ b/deploy/docker-demo/readme.md @@ -1,7 +1,7 @@ # jdchain-demo镜像使用说明 -本镜像主要为快速构建JDChain测试环境使用,内嵌固定的公私钥,不可用于生产正式环境。 -JDChain在docker中的安装路径:/export/jdchain,网关对外端口为:8080。可通过docker-compose-all文件来修改端口。 -demo环境构建完成后执行sdk加载部分测试数据,区块高度:7,交易总数:8,用户总数:5,数据账户总数:2,合约总数:1。 +本镜像主要为快速构建JDChain测试环境使用,内嵌固定的公私钥,不可用于生产正式环境。 +JDChain在docker中的安装路径:/export/jdchain,网关对外端口为:8080。可通过docker-compose-all文件来修改端口。 +demo环境构建完成后执行sdk加载部分测试数据,区块高度:7,交易总数:8,用户总数:5,数据账户总数:2,合约总数:1。 ## 如何生成镜像 1. 需要预先在deploy-peer和deploy-gateway中生成zip安装包,copy的源路径是target; From 549b4f3f574df0f0c719f34833c6caa005b2a3e3 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Wed, 28 Oct 2020 10:36:35 +0800 Subject: [PATCH 046/150] update headers --- core | 2 +- libs/bft-smart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index d386a9a1..ae37116d 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit d386a9a13ad14769ac4ea903b8ba260a5a4651e2 +Subproject commit ae37116d73a5447820352368371a1771d58a4ef8 diff --git a/libs/bft-smart b/libs/bft-smart index 443e433e..31a935b2 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 443e433eff0f504796e5898a281d631a6779486f +Subproject commit 31a935b2bfbe631d4971a19e55656d49337b86ba From 4ea012d4f5ea016b8badc9f27c90ffe9f2b8f063 Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Wed, 28 Oct 2020 11:23:54 +0800 Subject: [PATCH 047/150] update the log4j2.xml; --- .../docker-demo/src/main/docker/zip/conf.zip | Bin 90971 -> 91179 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/deploy/docker-demo/src/main/docker/zip/conf.zip b/deploy/docker-demo/src/main/docker/zip/conf.zip index 7be2f764f5359050ad7c34aa30bcfea457b915dc..dc8dffb12ecef03f0a8dfecc4da7f9fb539a07a9 100644 GIT binary patch delta 8494 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 D*PO+3 From eb24a899b68fdce61352c3467d168d909d3f7ab8 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Wed, 28 Oct 2020 14:12:35 +0800 Subject: [PATCH 048/150] update headers --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index 31a935b2..db13ce3d 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 31a935b2bfbe631d4971a19e55656d49337b86ba +Subproject commit db13ce3d97faacfdee948592c8785e5d51a59967 From 996cd357747aa7ae3c4ee64f89376f05edc5a210 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Wed, 28 Oct 2020 16:03:15 +0800 Subject: [PATCH 049/150] update headers --- core | 2 +- libs/bft-smart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index ae37116d..de60f40a 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit ae37116d73a5447820352368371a1771d58a4ef8 +Subproject commit de60f40a2ee7992b092738f040e42532a4ea8a84 diff --git a/libs/bft-smart b/libs/bft-smart index db13ce3d..d35aa41d 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit db13ce3d97faacfdee948592c8785e5d51a59967 +Subproject commit d35aa41d6b5e56f342ffb74d0fc04892d76df5a6 From b699524b2babd105dbb80755159124da166ddab0 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Thu, 29 Oct 2020 18:37:17 +0800 Subject: [PATCH 050/150] upgraded framework and core; --- core | 2 +- framework | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index 61c8e0e3..b0dbba8a 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 61c8e0e36705b9fd153012039733a76de8b11705 +Subproject commit b0dbba8a9e707d71a34e921725b7bc71cb2d4184 diff --git a/framework b/framework index 7641d701..8420f0d7 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 7641d701b646a48854fe39ed8c764bb16d4e10f9 +Subproject commit 8420f0d74af47269560de064898e913cf9742091 From 1cc05ed9f4ccc8959dc428c702ff649205c75909 Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Fri, 30 Oct 2020 17:07:04 +0800 Subject: [PATCH 051/150] add the docker's module to optimize the constructure of docker-demo; --- deploy/{ => docker}/docker-demo/pom.xml | 46 ++++++++++++++---- .../docker-demo/src/main/docker/Dockerfile | 0 .../src/main/docker/script/shutdown.sh | 0 .../src/main/docker/script/start.sh | 0 .../docker-demo/src/main/docker/zip/conf.zip | Bin .../main/resources/docker-compose-all.yaml | 0 .../src/main/resources/start-net.sh | 0 .../docker-demo/src/main/resources/zip.sh | 0 deploy/{ => docker}/docker-sdk/pom.xml | 17 +++---- .../com/jd/blockchain/ContractParams.java | 0 .../main/java/com/jd/blockchain/SDKDemo.java | 0 .../com/jd/blockchain/SDKDemo_Constant.java | 0 .../java/com/jd/blockchain/SDK_Base_Demo.java | 0 .../jd/chain/contract/TransferContract.java | 0 .../contract-compile-1.3.0.RELEASE.car | Bin deploy/docker/pom.xml | 25 ++++++++++ deploy/{docker-demo => docker}/readme.md | 11 +++-- 17 files changed, 73 insertions(+), 26 deletions(-) rename deploy/{ => docker}/docker-demo/pom.xml (73%) rename deploy/{ => docker}/docker-demo/src/main/docker/Dockerfile (100%) rename deploy/{ => docker}/docker-demo/src/main/docker/script/shutdown.sh (100%) rename deploy/{ => docker}/docker-demo/src/main/docker/script/start.sh (100%) rename deploy/{ => docker}/docker-demo/src/main/docker/zip/conf.zip (100%) rename deploy/{ => docker}/docker-demo/src/main/resources/docker-compose-all.yaml (100%) rename deploy/{ => docker}/docker-demo/src/main/resources/start-net.sh (100%) rename deploy/{ => docker}/docker-demo/src/main/resources/zip.sh (100%) mode change 100755 => 100644 rename deploy/{ => docker}/docker-sdk/pom.xml (83%) rename deploy/{ => docker}/docker-sdk/src/main/java/com/jd/blockchain/ContractParams.java (100%) rename deploy/{ => docker}/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo.java (100%) rename deploy/{ => docker}/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo_Constant.java (100%) rename deploy/{ => docker}/docker-sdk/src/main/java/com/jd/blockchain/SDK_Base_Demo.java (100%) rename deploy/{ => docker}/docker-sdk/src/main/java/com/jd/chain/contract/TransferContract.java (100%) rename deploy/{ => docker}/docker-sdk/src/main/resources/contract-compile-1.3.0.RELEASE.car (100%) create mode 100644 deploy/docker/pom.xml rename deploy/{docker-demo => docker}/readme.md (63%) diff --git a/deploy/docker-demo/pom.xml b/deploy/docker/docker-demo/pom.xml similarity index 73% rename from deploy/docker-demo/pom.xml rename to deploy/docker/docker-demo/pom.xml index 59c4e340..a6b6ef36 100644 --- a/deploy/docker-demo/pom.xml +++ b/deploy/docker/docker-demo/pom.xml @@ -3,15 +3,21 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - jdchain-root + docker com.jd.blockchain - 1.2.1.RELEASE - ../../pom.xml + 1.3.0.RELEASE - 1.3.0 4.0.0 docker-demo + + + com.jd.blockchain + docker-sdk + ${project.version} + + + jdchain-demo @@ -30,6 +36,26 @@ + + + + + + + + + + + + + + + + + + + + maven-resources-plugin 3.0.2 @@ -47,18 +73,18 @@ false - ${project.basedir}/../deploy-peer/target/ + ${project.basedir}/../../deploy-peer/target/ false - jdchain-peer-${project.version}.RELEASE.zip + jdchain-peer-${project.version}.zip - ${project.basedir}/../deploy-gateway/target/ + ${project.basedir}/../../deploy-gateway/target/ false - jdchain-gateway-${project.version}.RELEASE.zip + jdchain-gateway-${project.version}.zip @@ -67,7 +93,7 @@ ${project.basedir}/../docker-sdk/target/ false - docker-sdk-${project.version}.RELEASE.jar + docker-sdk-${project.version}.jar @@ -97,7 +123,7 @@ jdchain-demo - ${project.version} + ${docker.tag} ${project.basedir}/src/main/docker diff --git a/deploy/docker-demo/src/main/docker/Dockerfile b/deploy/docker/docker-demo/src/main/docker/Dockerfile similarity index 100% rename from deploy/docker-demo/src/main/docker/Dockerfile rename to deploy/docker/docker-demo/src/main/docker/Dockerfile diff --git a/deploy/docker-demo/src/main/docker/script/shutdown.sh b/deploy/docker/docker-demo/src/main/docker/script/shutdown.sh similarity index 100% rename from deploy/docker-demo/src/main/docker/script/shutdown.sh rename to deploy/docker/docker-demo/src/main/docker/script/shutdown.sh diff --git a/deploy/docker-demo/src/main/docker/script/start.sh b/deploy/docker/docker-demo/src/main/docker/script/start.sh similarity index 100% rename from deploy/docker-demo/src/main/docker/script/start.sh rename to deploy/docker/docker-demo/src/main/docker/script/start.sh diff --git a/deploy/docker-demo/src/main/docker/zip/conf.zip b/deploy/docker/docker-demo/src/main/docker/zip/conf.zip similarity index 100% rename from deploy/docker-demo/src/main/docker/zip/conf.zip rename to deploy/docker/docker-demo/src/main/docker/zip/conf.zip diff --git a/deploy/docker-demo/src/main/resources/docker-compose-all.yaml b/deploy/docker/docker-demo/src/main/resources/docker-compose-all.yaml similarity index 100% rename from deploy/docker-demo/src/main/resources/docker-compose-all.yaml rename to deploy/docker/docker-demo/src/main/resources/docker-compose-all.yaml diff --git a/deploy/docker-demo/src/main/resources/start-net.sh b/deploy/docker/docker-demo/src/main/resources/start-net.sh similarity index 100% rename from deploy/docker-demo/src/main/resources/start-net.sh rename to deploy/docker/docker-demo/src/main/resources/start-net.sh diff --git a/deploy/docker-demo/src/main/resources/zip.sh b/deploy/docker/docker-demo/src/main/resources/zip.sh old mode 100755 new mode 100644 similarity index 100% rename from deploy/docker-demo/src/main/resources/zip.sh rename to deploy/docker/docker-demo/src/main/resources/zip.sh diff --git a/deploy/docker-sdk/pom.xml b/deploy/docker/docker-sdk/pom.xml similarity index 83% rename from deploy/docker-sdk/pom.xml rename to deploy/docker/docker-sdk/pom.xml index 85cacb21..acd99c8c 100644 --- a/deploy/docker-sdk/pom.xml +++ b/deploy/docker/docker-sdk/pom.xml @@ -3,39 +3,34 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - deploy-root + docker com.jd.blockchain - 1.4.0-SNAPSHOT + 1.3.0.RELEASE 4.0.0 - 1.3.0.RELEASE docker-sdk - - 1.3.0.RELEASE - - com.jd.blockchain crypto-classic - ${ledger.version} + ${project.version} com.jd.blockchain crypto-sm - ${ledger.version} + ${project.version} com.jd.blockchain ledger-model - ${ledger.version} + ${project.version} com.jd.blockchain sdk-client - ${ledger.version} + ${project.version} diff --git a/deploy/docker-sdk/src/main/java/com/jd/blockchain/ContractParams.java b/deploy/docker/docker-sdk/src/main/java/com/jd/blockchain/ContractParams.java similarity index 100% rename from deploy/docker-sdk/src/main/java/com/jd/blockchain/ContractParams.java rename to deploy/docker/docker-sdk/src/main/java/com/jd/blockchain/ContractParams.java diff --git a/deploy/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo.java b/deploy/docker/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo.java similarity index 100% rename from deploy/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo.java rename to deploy/docker/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo.java diff --git a/deploy/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo_Constant.java b/deploy/docker/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo_Constant.java similarity index 100% rename from deploy/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo_Constant.java rename to deploy/docker/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo_Constant.java diff --git a/deploy/docker-sdk/src/main/java/com/jd/blockchain/SDK_Base_Demo.java b/deploy/docker/docker-sdk/src/main/java/com/jd/blockchain/SDK_Base_Demo.java similarity index 100% rename from deploy/docker-sdk/src/main/java/com/jd/blockchain/SDK_Base_Demo.java rename to deploy/docker/docker-sdk/src/main/java/com/jd/blockchain/SDK_Base_Demo.java diff --git a/deploy/docker-sdk/src/main/java/com/jd/chain/contract/TransferContract.java b/deploy/docker/docker-sdk/src/main/java/com/jd/chain/contract/TransferContract.java similarity index 100% rename from deploy/docker-sdk/src/main/java/com/jd/chain/contract/TransferContract.java rename to deploy/docker/docker-sdk/src/main/java/com/jd/chain/contract/TransferContract.java diff --git a/deploy/docker-sdk/src/main/resources/contract-compile-1.3.0.RELEASE.car b/deploy/docker/docker-sdk/src/main/resources/contract-compile-1.3.0.RELEASE.car similarity index 100% rename from deploy/docker-sdk/src/main/resources/contract-compile-1.3.0.RELEASE.car rename to deploy/docker/docker-sdk/src/main/resources/contract-compile-1.3.0.RELEASE.car diff --git a/deploy/docker/pom.xml b/deploy/docker/pom.xml new file mode 100644 index 00000000..81a492ab --- /dev/null +++ b/deploy/docker/pom.xml @@ -0,0 +1,25 @@ + + + + deploy-root + com.jd.blockchain + 1.4.0-SNAPSHOT + + 4.0.0 + 1.3.0.RELEASE + pom + + docker + + + 1.3.0 + + + + docker-sdk + docker-demo + + + \ No newline at end of file diff --git a/deploy/docker-demo/readme.md b/deploy/docker/readme.md similarity index 63% rename from deploy/docker-demo/readme.md rename to deploy/docker/readme.md index 44b5a646..a83be9d4 100644 --- a/deploy/docker-demo/readme.md +++ b/deploy/docker/readme.md @@ -4,11 +4,12 @@ JDChain在docker中的安装路径:/export/jdchain,网关对外端口为:8 demo环境构建完成后执行sdk加载部分测试数据,区块高度:7,交易总数:8,用户总数:5,数据账户总数:2,合约总数:1。 ## 如何生成镜像 -1. 需要预先在deploy-peer和deploy-gateway中生成zip安装包,copy的源路径是target; -2. 需要预先在docker-sdk中执行:mvn clean package,生成sdk可执行jar; -2. 本项目中执行:mvn clean package;会从dpploy-peer/dploy-gw/docker-sdk的target中提取zip包和可执行jar, -在docker环境中生成jdchain-peer镜像; -3. 生成镜像文件。执行resource中:zip.sh,可生成镜像的tar.gz压缩包; +1. 如果构建的docker镜像为当前开发版本,将docker模块中的跟主版本对齐,然后在deploy模块执行:mvn clean package即可。 +如果镜像版本与所在开发版本不一致(举例说明:构建1.3.0的镜像版本,但当前开发版本是1.4.0),需要预先在deploy-peer和deploy-gateway的 +target文件夹下放置相应版本zip安装包(jdchain-peer-xxx.zip,jdchain-gateway-xxx.zip),然后在docker模块执行:mvn clean package。 +2. 在maven构建过程中,两个zip安装包和docker-sdk-xxx.jar,会放至docker-demo模块src/main/docker/zip文件夹下。 +3. maven构建完成后,控制台执行:docker images,可看到构建的jdchain-peer镜像。 +4. 生成镜像文件。执行docker-demo模块中src/main/resources/zip.sh,可生成镜像的tar.gz压缩包; ## 镜像快速使用 1.在已经安装docker工具的环境中,装入jdchain-demo镜像: From 5a895f61620c0666ac274b40764f57897c015ed2 Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Fri, 30 Oct 2020 17:22:33 +0800 Subject: [PATCH 052/150] add docker-sdk; --- deploy/pom.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/deploy/pom.xml b/deploy/pom.xml index c500f2d3..28926d36 100644 --- a/deploy/pom.xml +++ b/deploy/pom.xml @@ -20,8 +20,7 @@ ../core deploy-gateway deploy-peer - docker-sdk - docker-demo - + docker + From 928655aefb75ebd7a7363649f65026a607b93f3e Mon Sep 17 00:00:00 2001 From: zhangshuang Date: Thu, 5 Nov 2020 17:37:14 +0800 Subject: [PATCH 053/150] modify consensus config file ,write state transfer log to disk --- .../deploy-peer/src/main/resources/config/init/bftsmart.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config b/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config index bd4035ab..99bbc27e 100644 --- a/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config +++ b/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config @@ -128,7 +128,7 @@ system.totalordermulticast.timeout_highMark = 200 system.totalordermulticast.log = true system.totalordermulticast.log_parallel = false -system.totalordermulticast.log_to_disk = false +system.totalordermulticast.log_to_disk = true system.totalordermulticast.sync_log = false #Period at which BFT-SMaRt requests the state to the application (for the state transfer state protocol) From 6a127c472571a63f684860f6f9fc6a97a7ccf4d2 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Mon, 9 Nov 2020 10:08:00 +0800 Subject: [PATCH 054/150] update peer-startup.sh and headers --- core | 2 +- .../src/main/resources/scripts/peer-startup.sh | 12 +++++++++++- libs/bft-smart | 2 +- test | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/core b/core index de60f40a..78b21340 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit de60f40a2ee7992b092738f040e42532a4ea8a84 +Subproject commit 78b213405ddbf5ea2bea734476470de27110e01b diff --git a/deploy/deploy-peer/src/main/resources/scripts/peer-startup.sh b/deploy/deploy-peer/src/main/resources/scripts/peer-startup.sh index 19dfa675..9cb6597f 100644 --- a/deploy/deploy-peer/src/main/resources/scripts/peer-startup.sh +++ b/deploy/deploy-peer/src/main/resources/scripts/peer-startup.sh @@ -7,8 +7,15 @@ JAVA_BIN=java APP_JAR_PREFIX=deploy-peer- #Peer节点Web端口 -#请运维根据实际环境进行调整 +#请运维根据实际环境进行调整或通过-p参数传入 WEB_PORT=7080 +#端口配置参数 +IS_CONFIG=false +for i in "$@"; do + if [ $i = "-p" ];then + IS_CONFIG=true + fi +done #检查Java环境变量 if [ ! -n "$JAVA_HOME" ]; then @@ -40,6 +47,9 @@ JAVA_OPTS="-jar -server -Xms2048m -Xmx2048m" #APP具体相关命令 APP_CMD=$APP_SYSTEM_PATH/$APP_JAR" -home="$APP_HOME" -c "$LEDGER_BINDING_CONFIG" -p "$WEB_PORT +if [ $IS_CONFIG = true ];then + APP_CMD=$APP_SYSTEM_PATH/$APP_JAR" -home="$APP_HOME" -c "$LEDGER_BINDING_CONFIG +fi #APP_JAR的具体路径 APP_JAR_PATH=$APP_SYSTEM_PATH/$APP_JAR diff --git a/libs/bft-smart b/libs/bft-smart index d35aa41d..7663a03a 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit d35aa41d6b5e56f342ffb74d0fc04892d76df5a6 +Subproject commit 7663a03ac746e4d7990733f76f46db58bec9d34c diff --git a/test b/test index 687ee2fd..79c32511 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 687ee2fd6415ff304839514276c59b32765be256 +Subproject commit 79c32511abda32ce819f9deccc6f46235d281ae1 From 341073398a284a2b0b08c705284268522a58b2c4 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Mon, 9 Nov 2020 10:30:51 +0800 Subject: [PATCH 055/150] update headers --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 78b21340..b257e102 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 78b213405ddbf5ea2bea734476470de27110e01b +Subproject commit b257e1029e49dff60dcf5ab7cf9a57adbb257745 From 814eed366c73967738e3d44453b1620a5bc08339 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Tue, 10 Nov 2020 10:05:05 +0800 Subject: [PATCH 056/150] update headers --- core | 2 +- libs/bft-smart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index b257e102..49814841 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit b257e1029e49dff60dcf5ab7cf9a57adbb257745 +Subproject commit 49814841e2d5c59407e3bf11d96c3a94e53661fc diff --git a/libs/bft-smart b/libs/bft-smart index 7663a03a..2a10ee3e 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 7663a03ac746e4d7990733f76f46db58bec9d34c +Subproject commit 2a10ee3e41f132746de032ae4b73c983e499e630 From 2d20081969379ee0ea2781ae45bbec9dc44b7354 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Tue, 10 Nov 2020 15:21:05 +0800 Subject: [PATCH 057/150] update headers --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index 2a10ee3e..a1471c43 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 2a10ee3e41f132746de032ae4b73c983e499e630 +Subproject commit a1471c4389bac254357007837dfff71a2b2c40e8 From 653bb259fb37848948eceec220c96d610aa2025c Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Thu, 12 Nov 2020 02:24:45 +0800 Subject: [PATCH 058/150] completed extracting crypto data types as interface; --- core | 2 +- framework | 2 +- test | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index b0dbba8a..aceff5b6 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit b0dbba8a9e707d71a34e921725b7bc71cb2d4184 +Subproject commit aceff5b672bb4da013748cabead81d48e6226b2a diff --git a/framework b/framework index 8420f0d7..8adaeccc 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 8420f0d74af47269560de064898e913cf9742091 +Subproject commit 8adaecccc57b2f34761719d5c057f7269c24d217 diff --git a/test b/test index 11986101..46a416c6 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 11986101a14392c9b1a95200783109204fcc0e0c +Subproject commit 46a416c610aaef1fa69e6d0b8e59a6c8f1057224 From beaed311ff1f1557a04008171fc6122f91ee68ab Mon Sep 17 00:00:00 2001 From: zhangshuang Date: Thu, 12 Nov 2020 09:22:27 +0800 Subject: [PATCH 059/150] cancel sender thread config --- .../deploy-peer/src/main/resources/config/init/bftsmart.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config b/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config index 99bbc27e..cdc1b1a5 100644 --- a/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config +++ b/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config @@ -55,7 +55,7 @@ system.server.3.network.secure=false #system.authentication.hmacAlgorithm = HmacSHA1 #Specify if the communication system should use a thread to send data (true or false) -system.communication.useSenderThread = true +system.communication.useSenderThread = false #Force all processes to use the same public/private keys pair and secret key. This is useful when deploying experiments #and benchmarks, but must not be used in production systems. From 969e53fb774c69ea97856862314da0f9a8095454 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Thu, 12 Nov 2020 14:01:36 +0800 Subject: [PATCH 060/150] Renamed the types in ledger database for more appropriate expression; --- core | 2 +- framework | 2 +- test | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index aceff5b6..859fa7c1 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit aceff5b672bb4da013748cabead81d48e6226b2a +Subproject commit 859fa7c13f64dfba754f9eb97f319320e040c151 diff --git a/framework b/framework index 8adaeccc..a12e9af6 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 8adaecccc57b2f34761719d5c057f7269c24d217 +Subproject commit a12e9af631f2f806d0d75eac97544ab644fae04e diff --git a/test b/test index 46a416c6..716cf058 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 46a416c610aaef1fa69e6d0b8e59a6c8f1057224 +Subproject commit 716cf058bfd335bc60844be40f3f36e7d5ec82d8 From 20618d1631186cb53abadc8fe6d1e3b0ed1079ed Mon Sep 17 00:00:00 2001 From: zhangshuang Date: Thu, 12 Nov 2020 16:10:24 +0800 Subject: [PATCH 061/150] update header --- core | 2 +- libs/bft-smart | 2 +- test | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index 49814841..22a63e4f 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 49814841e2d5c59407e3bf11d96c3a94e53661fc +Subproject commit 22a63e4fe85398a090f7e4abf99cd212549be70f diff --git a/libs/bft-smart b/libs/bft-smart index a1471c43..caeda287 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit a1471c4389bac254357007837dfff71a2b2c40e8 +Subproject commit caeda28790884979c2353d632b60de3c265a27be diff --git a/test b/test index 79c32511..0dc92a2f 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 79c32511abda32ce819f9deccc6f46235d281ae1 +Subproject commit 0dc92a2f6bffe9896839e573baa0c5d4c7fbbd5c From 194ddb4e75074d192e1433ccd37797f61047e713 Mon Sep 17 00:00:00 2001 From: zhangshuang Date: Thu, 12 Nov 2020 16:38:32 +0800 Subject: [PATCH 062/150] add auto node shell --- core | 2 +- deploy/deploy-peer/pom.xml | 18 ++++++++ .../main/resources/scripts/active-parti.sh | 10 +++++ .../main/resources/scripts/deactive-parti.sh | 10 +++++ .../src/main/resources/scripts/reg-parti.sh | 10 +++++ .../SDK_Update_ConsensusSettings_Demo.java | 42 +++++++++++++++++++ 6 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 deploy/deploy-peer/src/main/resources/scripts/active-parti.sh create mode 100644 deploy/deploy-peer/src/main/resources/scripts/deactive-parti.sh create mode 100644 deploy/deploy-peer/src/main/resources/scripts/reg-parti.sh create mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Update_ConsensusSettings_Demo.java diff --git a/core b/core index 22a63e4f..b5a9bd91 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 22a63e4fe85398a090f7e4abf99cd212549be70f +Subproject commit b5a9bd9155034260d8babebb6d8701c3627c226b diff --git a/deploy/deploy-peer/pom.xml b/deploy/deploy-peer/pom.xml index b9edadbe..a31a5614 100644 --- a/deploy/deploy-peer/pom.xml +++ b/deploy/deploy-peer/pom.xml @@ -58,6 +58,24 @@ ${core.version} + + com.jd.blockchain + tools-regparti-booter + ${core.version} + + + + com.jd.blockchain + tools-activeparti-booter + ${core.version} + + + + com.jd.blockchain + tools-deactiveparti-booter + ${core.version} + + diff --git a/deploy/deploy-peer/src/main/resources/scripts/active-parti.sh b/deploy/deploy-peer/src/main/resources/scripts/active-parti.sh new file mode 100644 index 00000000..df895210 --- /dev/null +++ b/deploy/deploy-peer/src/main/resources/scripts/active-parti.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +OME=$(cd `dirname $0`;cd ../; pwd) +boot_file=$(ls ../libs | grep tools-activeparti-booter-) +if [ ! -n "$boot_file" ]; then + echo "tools-activeparti-booter is null" +else + echo "active participant" + java -jar $HOME/libs/$boot_file $* +fi \ No newline at end of file diff --git a/deploy/deploy-peer/src/main/resources/scripts/deactive-parti.sh b/deploy/deploy-peer/src/main/resources/scripts/deactive-parti.sh new file mode 100644 index 00000000..0dc00080 --- /dev/null +++ b/deploy/deploy-peer/src/main/resources/scripts/deactive-parti.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +OME=$(cd `dirname $0`;cd ../; pwd) +boot_file=$(ls ../libs | grep tools-deactiveparti-booter-) +if [ ! -n "$boot_file" ]; then + echo "tools-deactiveparti-booter is null" +else + echo "deactive participant" + java -jar $HOME/libs/$boot_file $* +fi \ No newline at end of file diff --git a/deploy/deploy-peer/src/main/resources/scripts/reg-parti.sh b/deploy/deploy-peer/src/main/resources/scripts/reg-parti.sh new file mode 100644 index 00000000..cd31b360 --- /dev/null +++ b/deploy/deploy-peer/src/main/resources/scripts/reg-parti.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +HOME=$(cd `dirname $0`;cd ../; pwd) + boot_file=$(ls ../libs | grep tools-regparti-booter-) + if [ ! -n "$boot_file" ]; then + echo "tools-regparti-booter is null" + else + echo "register new participant" + java -jar $HOME/libs/$boot_file $* + fi \ No newline at end of file diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Update_ConsensusSettings_Demo.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Update_ConsensusSettings_Demo.java new file mode 100644 index 00000000..de875c32 --- /dev/null +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Update_ConsensusSettings_Demo.java @@ -0,0 +1,42 @@ +package com.jd.blockchain.sdk.samples; + +import com.jd.blockchain.ledger.PreparedTransaction; +import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.TransactionTemplate; +import com.jd.blockchain.utils.Property; + +import java.util.ArrayList; +import java.util.List; + +public class SDK_Update_ConsensusSettings_Demo extends SDK_Base_Demo { + + public static void main(String[] args) { + new SDK_Update_ConsensusSettings_Demo().updateSettings(); + } + + public void updateSettings() { + + List properties = new ArrayList(); + + // 修改bftsmart.conf配置文件中的选项; + properties.add(new Property("system.communication.useSenderThread", "false")); + + Property[] propertiesArray = properties.toArray(new Property[properties.size()]); + + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + + txTpl.settings().update(propertiesArray); + + // TX 准备就绪; + PreparedTransaction prepTx = txTpl.prepare(); + + // 使用私钥进行签名; + prepTx.sign(adminKey); + + // 提交交易; + TransactionResponse transactionResponse = prepTx.commit(); + + System.out.println(transactionResponse.isSuccess()); + + } +} From 4d02bc655710ffb45b02c1cc9c6a75e9c4252b37 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Thu, 12 Nov 2020 17:07:38 +0800 Subject: [PATCH 063/150] update headers --- core | 2 +- framework | 2 +- test | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index b5a9bd91..c2074f06 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit b5a9bd9155034260d8babebb6d8701c3627c226b +Subproject commit c2074f0661b4d3bb7bbc674870ff81a1ce150351 diff --git a/framework b/framework index 6afcd0d1..f92776f7 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 6afcd0d1f2387c37cc722c35b3eba57f86611b62 +Subproject commit f92776f7b789f3288073aa134df38df55eb81ae5 diff --git a/test b/test index 0dc92a2f..0b91bba8 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 0dc92a2f6bffe9896839e573baa0c5d4c7fbbd5c +Subproject commit 0b91bba862d52844e18ca420098afcefb8a68ca5 From fdd608c852a445cf2541dfb958da203fd4b4ebae Mon Sep 17 00:00:00 2001 From: zhangshuang Date: Thu, 12 Nov 2020 17:48:18 +0800 Subject: [PATCH 064/150] fix merge develop code , compile error! --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index c2074f06..0e30483c 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit c2074f0661b4d3bb7bbc674870ff81a1ce150351 +Subproject commit 0e30483c0b030262ab64378315426a978367b7a1 From 64a1c1e2eb5d00bc4cb0770c3b49470bfffed612 Mon Sep 17 00:00:00 2001 From: zhangshuang Date: Thu, 12 Nov 2020 18:27:30 +0800 Subject: [PATCH 065/150] fix sdk compile error --- .../test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java | 5 ++++- .../sdk/test/SDK_GateWay_BatchInsertData_Test_.java | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java index 52e2be93..0425f5ce 100644 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java +++ b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java @@ -6,6 +6,8 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import com.jd.blockchain.crypto.base.DefaultCryptoEncoding; +import com.jd.blockchain.crypto.base.HashDigestBytes; import org.junit.Before; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -297,7 +299,8 @@ public class SDK_Contract_Test { } private static HashDigest getLedgerHash() { - return new HashDigest(Base58Utils.decode(ledgerAddress)); + byte[] addressBytes = Base58Utils.decode(ledgerAddress); + return new HashDigestBytes(DefaultCryptoEncoding.decodeAlgorithm(addressBytes), addressBytes); } /** diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_BatchInsertData_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_BatchInsertData_Test_.java index d459ac94..eb04157b 100644 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_BatchInsertData_Test_.java +++ b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_BatchInsertData_Test_.java @@ -10,6 +10,8 @@ package test.com.jd.blockchain.sdk.test; import static org.junit.Assert.assertEquals; +import com.jd.blockchain.crypto.base.DefaultCryptoEncoding; +import com.jd.blockchain.crypto.base.HashDigestBytes; import org.junit.Before; import org.junit.Test; @@ -113,7 +115,7 @@ public class SDK_GateWay_BatchInsertData_Test_ { private HashDigest getLedgerHash() { byte[] hashBytes = Base58Utils.decode(ledgerHash); - return new HashDigest(hashBytes); + return new HashDigestBytes(DefaultCryptoEncoding.decodeAlgorithm(hashBytes), hashBytes); } From 02e4074ec124f09471c506f77788204509f11760 Mon Sep 17 00:00:00 2001 From: imuge Date: Fri, 13 Nov 2020 15:14:28 +0800 Subject: [PATCH 066/150] Update repo.sh Fix remote config error in the first time. --- build/repo.sh | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/build/repo.sh b/build/repo.sh index 56aac1d5..545289a8 100755 --- a/build/repo.sh +++ b/build/repo.sh @@ -1,4 +1,3 @@ - #调用当前脚本目录下 env.sh 脚本,设置环境变量,处理当前传入参数; if [ ! $ENV_SHELL ] then @@ -85,24 +84,6 @@ git config remote.origin.pushurl $REMOTE_ORIGIN_URL echo "远程仓库的地址更新为:"$REMOTE_ORIGIN_URL echo "" -#同步更新子模块的远程仓库 origin 的地址; -echo "---------------- 更新子模块的远程仓库地址 ----------------" -# 子模块名称列表; - -SUBMODULES=$(git submodule | awk '{print $2}') -for m in $SUBMODULES; -do - SUBMODULE_URL=$(git config --get submodule.$m.url) - echo "模块[$m].URL="$SUBMODULE_URL - - cd $BASE_DIR/$m - - git config remote.origin.url $SUBMODULE_URL - git config remote.origin.pushurl $SUBMODULE_URL - - cd $BASE_DIR -done - #检查是否要跳过子模块更新环节; if [ $SKIP_SUBMODULES_UPDATE == 1 ] then From 50068fdde03db1188d3b405011998f774138c299 Mon Sep 17 00:00:00 2001 From: imuge Date: Fri, 13 Nov 2020 15:47:50 +0800 Subject: [PATCH 067/150] Update repo.sh --- build/repo.sh | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/build/repo.sh b/build/repo.sh index 545289a8..d3a12ab3 100755 --- a/build/repo.sh +++ b/build/repo.sh @@ -84,6 +84,28 @@ git config remote.origin.pushurl $REMOTE_ORIGIN_URL echo "远程仓库的地址更新为:"$REMOTE_ORIGIN_URL echo "" +#同步更新子模块的远程仓库 origin 的地址; +echo "---------------- 更新子模块的远程仓库地址 ----------------" +# 子模块名称列表; + +SUBMODULES=$(git submodule | awk '{print $2}') +for m in $SUBMODULES; +do + SUBMODULE_URL=$(git config --get submodule.$m.url) + echo "模块[$m].URL="$SUBMODULE_URL + + cd $BASE_DIR/$m + + git config remote.origin.url $SUBMODULE_URL + git config remote.origin.pushurl $SUBMODULE_URL + + cd $BASE_DIR +done + +#首次执行同步更新子模块的远程仓库 origin 的地址会将主项目地址更改,以下操作确保主项目远程仓库地址正确 +git config remote.origin.url $REMOTE_ORIGIN_URL +git config remote.origin.pushurl $REMOTE_ORIGIN_URL + #检查是否要跳过子模块更新环节; if [ $SKIP_SUBMODULES_UPDATE == 1 ] then From 6bb25dd62681279c77f1b05c937edd8311885972 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Sat, 14 Nov 2020 16:00:47 +0800 Subject: [PATCH 068/150] init release 1.4.0; --- core | 2 +- framework | 2 +- libs/bft-smart | 2 +- test | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core b/core index 859fa7c1..ce1d81dd 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 859fa7c13f64dfba754f9eb97f319320e040c151 +Subproject commit ce1d81ddeb51ddc2f96c5d7e1a89b7383ace9352 diff --git a/framework b/framework index a12e9af6..4b6516c4 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit a12e9af631f2f806d0d75eac97544ab644fae04e +Subproject commit 4b6516c469753d124b0d9bde1c1d46e6f661e221 diff --git a/libs/bft-smart b/libs/bft-smart index 24e77b3e..8a3c8963 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 24e77b3ef9d32e0d1d9b62f3b888d5e0f107d8c7 +Subproject commit 8a3c8963b270e1126ed1fdc8573fafe92ed1e3f3 diff --git a/test b/test index 716cf058..334d9f1c 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 716cf058bfd335bc60844be40f3f36e7d5ec82d8 +Subproject commit 334d9f1c584a2dd2adb959c3f9bf00d7e5a51202 From 785bfdc4acc742aa1e28bf2080ad3cfeea02e186 Mon Sep 17 00:00:00 2001 From: zhangshuang Date: Sun, 15 Nov 2020 09:14:54 +0800 Subject: [PATCH 069/150] modify version to 1.4.0 release, and add miss code --- core | 2 +- deploy/deploy-gateway/pom.xml | 2 +- deploy/deploy-peer/pom.xml | 20 ++++++++++++++++++- .../main/resources/scripts/active-parti.sh | 10 ++++++++++ .../main/resources/scripts/deactive-parti.sh | 10 ++++++++++ .../src/main/resources/scripts/reg-parti.sh | 10 ++++++++++ deploy/pom.xml | 4 ++-- explorer | 2 +- framework | 2 +- libs/bft-smart | 2 +- test | 2 +- 11 files changed, 57 insertions(+), 9 deletions(-) create mode 100644 deploy/deploy-peer/src/main/resources/scripts/active-parti.sh create mode 100644 deploy/deploy-peer/src/main/resources/scripts/deactive-parti.sh create mode 100644 deploy/deploy-peer/src/main/resources/scripts/reg-parti.sh diff --git a/core b/core index ce1d81dd..8592001e 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit ce1d81ddeb51ddc2f96c5d7e1a89b7383ace9352 +Subproject commit 8592001ea0af771c88357767031b59377b3d2a40 diff --git a/deploy/deploy-gateway/pom.xml b/deploy/deploy-gateway/pom.xml index a28fbe3b..aaa989eb 100644 --- a/deploy/deploy-gateway/pom.xml +++ b/deploy/deploy-gateway/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain deploy-root - 1.4.0-SNAPSHOT + 1.4.0.RELEASE deploy-gateway diff --git a/deploy/deploy-peer/pom.xml b/deploy/deploy-peer/pom.xml index b9edadbe..b3520323 100644 --- a/deploy/deploy-peer/pom.xml +++ b/deploy/deploy-peer/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain deploy-root - 1.4.0-SNAPSHOT + 1.4.0.RELEASE deploy-peer @@ -58,6 +58,24 @@ ${core.version} + + com.jd.blockchain + tools-regparti-booter + ${core.version} + + + + com.jd.blockchain + tools-activeparti-booter + ${core.version} + + + + com.jd.blockchain + tools-deactiveparti-booter + ${core.version} + + diff --git a/deploy/deploy-peer/src/main/resources/scripts/active-parti.sh b/deploy/deploy-peer/src/main/resources/scripts/active-parti.sh new file mode 100644 index 00000000..df895210 --- /dev/null +++ b/deploy/deploy-peer/src/main/resources/scripts/active-parti.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +OME=$(cd `dirname $0`;cd ../; pwd) +boot_file=$(ls ../libs | grep tools-activeparti-booter-) +if [ ! -n "$boot_file" ]; then + echo "tools-activeparti-booter is null" +else + echo "active participant" + java -jar $HOME/libs/$boot_file $* +fi \ No newline at end of file diff --git a/deploy/deploy-peer/src/main/resources/scripts/deactive-parti.sh b/deploy/deploy-peer/src/main/resources/scripts/deactive-parti.sh new file mode 100644 index 00000000..0dc00080 --- /dev/null +++ b/deploy/deploy-peer/src/main/resources/scripts/deactive-parti.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +OME=$(cd `dirname $0`;cd ../; pwd) +boot_file=$(ls ../libs | grep tools-deactiveparti-booter-) +if [ ! -n "$boot_file" ]; then + echo "tools-deactiveparti-booter is null" +else + echo "deactive participant" + java -jar $HOME/libs/$boot_file $* +fi \ No newline at end of file diff --git a/deploy/deploy-peer/src/main/resources/scripts/reg-parti.sh b/deploy/deploy-peer/src/main/resources/scripts/reg-parti.sh new file mode 100644 index 00000000..cd31b360 --- /dev/null +++ b/deploy/deploy-peer/src/main/resources/scripts/reg-parti.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +HOME=$(cd `dirname $0`;cd ../; pwd) + boot_file=$(ls ../libs | grep tools-regparti-booter-) + if [ ! -n "$boot_file" ]; then + echo "tools-regparti-booter is null" + else + echo "register new participant" + java -jar $HOME/libs/$boot_file $* + fi \ No newline at end of file diff --git a/deploy/pom.xml b/deploy/pom.xml index 98b06e0a..20df00f4 100644 --- a/deploy/pom.xml +++ b/deploy/pom.xml @@ -9,11 +9,11 @@ ../project/parent deploy-root - 1.4.0-SNAPSHOT + 1.4.0.RELEASE pom - 1.4.0-SNAPSHOT + 1.4.0.RELEASE diff --git a/explorer b/explorer index f79293ab..3ffc3324 160000 --- a/explorer +++ b/explorer @@ -1 +1 @@ -Subproject commit f79293ab00e5ac74382d442ec5027604ee8260ea +Subproject commit 3ffc3324c9fe20307cc36c07c361daa1f5d3f11e diff --git a/framework b/framework index 4b6516c4..647bcffa 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 4b6516c469753d124b0d9bde1c1d46e6f661e221 +Subproject commit 647bcffa1a4b0a6cf4df0db8e55247ca84890224 diff --git a/libs/bft-smart b/libs/bft-smart index 8a3c8963..a038dcf6 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 8a3c8963b270e1126ed1fdc8573fafe92ed1e3f3 +Subproject commit a038dcf677d0fc5ed2f72794606c332538fe85fa diff --git a/test b/test index 334d9f1c..f0bcf9a1 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 334d9f1c584a2dd2adb959c3f9bf00d7e5a51202 +Subproject commit f0bcf9a13568af8d1b6c036463246de9719734bd From 0adb2b536885aab295d4f3d9602b06458f96372a Mon Sep 17 00:00:00 2001 From: zhangshuang Date: Sun, 15 Nov 2020 10:50:02 +0800 Subject: [PATCH 070/150] fix shell error --- deploy/deploy-peer/src/main/resources/scripts/active-parti.sh | 2 +- deploy/deploy-peer/src/main/resources/scripts/deactive-parti.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/deploy-peer/src/main/resources/scripts/active-parti.sh b/deploy/deploy-peer/src/main/resources/scripts/active-parti.sh index df895210..648f6963 100644 --- a/deploy/deploy-peer/src/main/resources/scripts/active-parti.sh +++ b/deploy/deploy-peer/src/main/resources/scripts/active-parti.sh @@ -1,6 +1,6 @@ #!/bin/bash -OME=$(cd `dirname $0`;cd ../; pwd) +HOME=$(cd `dirname $0`;cd ../; pwd) boot_file=$(ls ../libs | grep tools-activeparti-booter-) if [ ! -n "$boot_file" ]; then echo "tools-activeparti-booter is null" diff --git a/deploy/deploy-peer/src/main/resources/scripts/deactive-parti.sh b/deploy/deploy-peer/src/main/resources/scripts/deactive-parti.sh index 0dc00080..67ad5314 100644 --- a/deploy/deploy-peer/src/main/resources/scripts/deactive-parti.sh +++ b/deploy/deploy-peer/src/main/resources/scripts/deactive-parti.sh @@ -1,6 +1,6 @@ #!/bin/bash -OME=$(cd `dirname $0`;cd ../; pwd) +HOME=$(cd `dirname $0`;cd ../; pwd) boot_file=$(ls ../libs | grep tools-deactiveparti-booter-) if [ ! -n "$boot_file" ]; then echo "tools-deactiveparti-booter is null" From 54ed76b758ce9bbba197c79f8376f510cfc747d5 Mon Sep 17 00:00:00 2001 From: zhangshuang Date: Sun, 15 Nov 2020 11:25:07 +0800 Subject: [PATCH 071/150] fix deactive node command line error --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 8592001e..fdcedaa1 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 8592001ea0af771c88357767031b59377b3d2a40 +Subproject commit fdcedaa10d27f219f0bb0df90d740e40b8fa74b2 From 8ece97f7d51f7694d9a367603bf1c30a3ce097db Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Sun, 15 Nov 2020 11:30:48 +0800 Subject: [PATCH 072/150] upgraded version to 1.4.0.RELEASE; --- core | 2 +- deploy/pom.xml | 2 +- framework | 2 +- libs/bft-smart | 2 +- pom.xml | 2 +- test | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core b/core index ce1d81dd..e4aa0356 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit ce1d81ddeb51ddc2f96c5d7e1a89b7383ace9352 +Subproject commit e4aa0356ea6e0a17785036f816d20cc636771379 diff --git a/deploy/pom.xml b/deploy/pom.xml index 98b06e0a..98958e86 100644 --- a/deploy/pom.xml +++ b/deploy/pom.xml @@ -13,7 +13,7 @@ pom - 1.4.0-SNAPSHOT + 1.4.0.RELEASE diff --git a/framework b/framework index 4b6516c4..b88f5269 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 4b6516c469753d124b0d9bde1c1d46e6f661e221 +Subproject commit b88f526928a05bba68903230d3634c02595e1161 diff --git a/libs/bft-smart b/libs/bft-smart index 8a3c8963..862320c1 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 8a3c8963b270e1126ed1fdc8573fafe92ed1e3f3 +Subproject commit 862320c19f048e49f2097d7f83a55f7317793dbc diff --git a/pom.xml b/pom.xml index eff9ec18..7c51bb32 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain jdchain-root - 1.2.1.RELEASE + 1.4.0.RELEASE pom jdchain root project diff --git a/test b/test index 334d9f1c..977587c1 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 334d9f1c584a2dd2adb959c3f9bf00d7e5a51202 +Subproject commit 977587c1cc6f7176ca6c2d04eedba470e5034203 From 67f284d83f884726fb0324b3d6b5b0ac6d35bff7 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Sun, 15 Nov 2020 11:41:18 +0800 Subject: [PATCH 073/150] upgraded the version of core; --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index e4aa0356..edaad6b9 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit e4aa0356ea6e0a17785036f816d20cc636771379 +Subproject commit edaad6b97ba509f2c5a9bb23d353d7f6158bbc5a From f8e8dc63a8d78f120f1a84a530f1789a35c6a711 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Sun, 15 Nov 2020 12:04:40 +0800 Subject: [PATCH 074/150] upgraded versions of submodules; --- core | 2 +- explorer | 2 +- libs/kvdb | 2 +- test | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core b/core index edaad6b9..b1b0a0b0 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit edaad6b97ba509f2c5a9bb23d353d7f6158bbc5a +Subproject commit b1b0a0b0a3a690a5f8a73d30da0e6ffd1a5b40eb diff --git a/explorer b/explorer index 3ffc3324..5c2524a4 160000 --- a/explorer +++ b/explorer @@ -1 +1 @@ -Subproject commit 3ffc3324c9fe20307cc36c07c361daa1f5d3f11e +Subproject commit 5c2524a4a4f2c2a85976dd95c6f4c39262ccdbd7 diff --git a/libs/kvdb b/libs/kvdb index f3d3df5f..331e3842 160000 --- a/libs/kvdb +++ b/libs/kvdb @@ -1 +1 @@ -Subproject commit f3d3df5fc4ca32be00cbfb92034bcd26d335aa5d +Subproject commit 331e3842ec0ecc6f0cf04a6873d2b4dbe4daffc2 diff --git a/test b/test index 977587c1..b00251a0 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 977587c1cc6f7176ca6c2d04eedba470e5034203 +Subproject commit b00251a0d19e9708b914ce29f8b748b862d4218e From fef9a17e3f07ffbe8819d92bfc8dc60092e67bc6 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Sun, 15 Nov 2020 12:16:29 +0800 Subject: [PATCH 075/150] upgraded version of kvdb; --- libs/kvdb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/kvdb b/libs/kvdb index 331e3842..d9ec7f37 160000 --- a/libs/kvdb +++ b/libs/kvdb @@ -1 +1 @@ -Subproject commit 331e3842ec0ecc6f0cf04a6873d2b4dbe4daffc2 +Subproject commit d9ec7f3748724053a2c1eb7a3e2128cc715a2a33 From 0a179ef849deef5dd4a1642c4d63eae970fd5ba7 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Sun, 15 Nov 2020 15:49:46 +0800 Subject: [PATCH 076/150] optimized the default values of bftsmart.config; --- .../src/main/resources/config/init/bftsmart.config | 6 ++++++ libs/bft-smart | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config b/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config index b5bfa5a3..12342e86 100644 --- a/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config +++ b/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config @@ -57,6 +57,12 @@ system.server.3.network.secure=false #Specify if the communication system should use a thread to send data (true or false) system.communication.useSenderThread = true +#The time interval for retrying to send message after connection failure. In milliseconds; +system.communication.send.retryInterval=2000 + +#The number of retries to send message after connection failure. +system.communication.send.retryCount=100 + #Force all processes to use the same public/private keys pair and secret key. This is useful when deploying experiments #and benchmarks, but must not be used in production systems. system.communication.defaultkeys = true diff --git a/libs/bft-smart b/libs/bft-smart index 862320c1..b9db7d7c 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 862320c19f048e49f2097d7f83a55f7317793dbc +Subproject commit b9db7d7cf8469ba8c94e896846f136f381d9f7d8 From 388d9723af8b0308a730587b49529cd3ef84729c Mon Sep 17 00:00:00 2001 From: zhangshuang Date: Sun, 15 Nov 2020 15:57:04 +0800 Subject: [PATCH 077/150] modify sdk version, compile, import package error --- .../src/main/resources/docs/code_example.MD | 8 ++-- .../src/main/resources/docs/安装部署.MD | 2 +- samples/contract-samples/pom.xml | 2 +- samples/pom.xml | 19 ++++++++- samples/sdk-samples/pom.xml | 27 +++++++++++- .../samples/SDKDemo_ConfigureSecurity.java | 3 -- .../sdk/samples/SDKDemo_InsertData.java | 2 +- .../blockchain/sdk/samples/SDKDemo_Query.java | 5 +-- .../samples/SDKDemo_RegistParticipant.java | 3 -- .../sdk/samples/SDKDemo_RegisterAccount.java | 3 -- .../sdk/samples/SDKDemo_RegisterUser.java | 3 -- .../sdk/samples/SDKDemo_Tx_Persistance.java | 5 +-- .../SDK_ConsensusSettings_Update_Demo.java | 42 +++++++++++++++++++ .../sdk/samples/SDK_InsertData_Demo.java | 4 +- .../sdk/test/SDK_Contract_Test.java | 6 ++- .../SDK_GateWay_BatchInsertData_Test_.java | 11 ++--- .../test/SDK_GateWay_DataAccount_Test_.java | 6 --- .../test/SDK_GateWay_InsertData_Test_.java | 6 --- .../SDK_GateWay_Participant_Regist_Test_.java | 3 -- .../sdk/test/SDK_GateWay_Query_Test_.java | 15 ++----- .../sdk/test/SDK_GateWay_User_Test_.java | 6 --- 21 files changed, 108 insertions(+), 73 deletions(-) create mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_ConsensusSettings_Update_Demo.java diff --git a/deploy/deploy-gateway/src/main/resources/docs/code_example.MD b/deploy/deploy-gateway/src/main/resources/docs/code_example.MD index cdb599ff..2f429d3f 100644 --- a/deploy/deploy-gateway/src/main/resources/docs/code_example.MD +++ b/deploy/deploy-gateway/src/main/resources/docs/code_example.MD @@ -3,23 +3,23 @@ com.jd.blockchain sdk-client - 1.3.0.RELEASE + 1.4.0.RELEASE com.jd.blockchain contract-starter - 1.3.0.RELEASE + 1.4.0.RELEASE com.jd.blockchain crypto-classic - 1.3.0.RELEASE + 1.4.0.RELEASE com.jd.blockchain crypto-sm - 1.3.0.RELEASE + 1.4.0.RELEASE ``` # 2. 数据快速上链 diff --git a/deploy/deploy-peer/src/main/resources/docs/安装部署.MD b/deploy/deploy-peer/src/main/resources/docs/安装部署.MD index 3157a953..c2eb5e3f 100644 --- a/deploy/deploy-peer/src/main/resources/docs/安装部署.MD +++ b/deploy/deploy-peer/src/main/resources/docs/安装部署.MD @@ -1,6 +1,6 @@ # JDChain安装部署指南 -本部署指南基于JDChain1.3.0.RELEASE版本来构建。 +本部署指南基于JDChain1.4.0.RELEASE版本来构建。 ## 1. 部署环境 ### 1.1 系统部署结构 ![部署结构](imgs/structure.png) diff --git a/samples/contract-samples/pom.xml b/samples/contract-samples/pom.xml index 955f2fc4..c032e9dd 100644 --- a/samples/contract-samples/pom.xml +++ b/samples/contract-samples/pom.xml @@ -6,7 +6,7 @@ com.jd.blockchain jdchain-samples - 1.2.1.RELEASE + 1.4.0.RELEASE contract-samples diff --git a/samples/pom.xml b/samples/pom.xml index b73ce4e6..fe6c9688 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -11,11 +11,11 @@ com.jd.blockchain jdchain-samples - 1.2.1.RELEASE + 1.4.0.RELEASE pom - 1.3.0.RELEASE + 1.4.0.RELEASE @@ -42,6 +42,21 @@ crypto-framework ${framework.version} + + com.jd.blockchain + crypto-classic + ${framework.version} + + + com.jd.blockchain + crypto-sm + ${framework.version} + + + com.jd.blockchain + crypto-base + ${framework.version} + diff --git a/samples/sdk-samples/pom.xml b/samples/sdk-samples/pom.xml index 73cc5064..68645bd2 100644 --- a/samples/sdk-samples/pom.xml +++ b/samples/sdk-samples/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain jdchain-samples - 1.2.1.RELEASE + 1.4.0.RELEASE sdk-samples @@ -23,6 +23,31 @@ contract-samples ${project.version} + + com.jd.blockchain + crypto-base + 1.4.0.RELEASE + + + com.jd.blockchain + crypto-framework + ${framework.version} + + + com.jd.blockchain + crypto-classic + ${framework.version} + + + com.jd.blockchain + crypto-sm + ${framework.version} + + + com.jd.blockchain + crypto-utils-classic + ${framework.version} + diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ConfigureSecurity.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ConfigureSecurity.java index d7d2170b..fc1fad1d 100644 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ConfigureSecurity.java +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ConfigureSecurity.java @@ -38,10 +38,7 @@ public class SDKDemo_ConfigureSecurity { // 注册相关class DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); PrivKey privKey = SDKDemo_Params.privkey1; diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_InsertData.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_InsertData.java index 59d94201..7a684a0b 100644 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_InsertData.java +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_InsertData.java @@ -64,7 +64,7 @@ public class SDKDemo_InsertData { // TX 准备就绪; PreparedTransaction prepTx = txTemp.prepare(); - String txHash = ByteArray.toBase64(prepTx.getHash().toBytes()); + String txHash = ByteArray.toBase64(prepTx.getTransactionHash().toBytes()); // 使用私钥进行签名; AsymmetricKeypair keyPair = getSponsorKey(); diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java index 6d81393d..6f4e9e19 100644 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java @@ -7,7 +7,6 @@ import com.jd.blockchain.ledger.BlockchainKeypair; import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerTransaction; -import com.jd.blockchain.ledger.Transaction; import com.jd.blockchain.sdk.BlockchainService; import com.jd.blockchain.sdk.client.GatewayServiceFactory; import com.jd.blockchain.utils.net.NetworkAddress; @@ -61,8 +60,8 @@ public class SDKDemo_Query { LedgerTransaction[] txList = service.getTransactions(LEDGER_HASH, ledgerNumber, 0, 100); // 根据交易的 hash 获得交易;注:客户端生成 PrepareTransaction 时得到交易hash; - HashDigest txHash = txList[0].getTransactionContent().getHash(); - Transaction tx = service.getTransactionByContentHash(LEDGER_HASH, txHash); + HashDigest txHash = txList[0].getRequest().getTransactionHash(); + LedgerTransaction tx = service.getTransactionByContentHash(LEDGER_HASH, txHash); // 获取数据; String commerceAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf=="; diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegistParticipant.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegistParticipant.java index 813cce1f..2494c058 100644 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegistParticipant.java +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegistParticipant.java @@ -44,10 +44,7 @@ public class SDKDemo_RegistParticipant { service = serviceFactory.getBlockchainService(); DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); DataContractRegistry.register(ParticipantRegisterOperation.class); DataContractRegistry.register(ParticipantStateUpdateOperation.class); diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterAccount.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterAccount.java index 07b84984..3d184070 100644 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterAccount.java +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterAccount.java @@ -20,10 +20,7 @@ public class SDKDemo_RegisterAccount { } DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); BlockchainKeypair CLIENT_CERT = new BlockchainKeypair(SDKDemo_Params.pubKey0, SDKDemo_Params.privkey0); diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterUser.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterUser.java index 778e5851..ebbe250a 100644 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterUser.java +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterUser.java @@ -38,10 +38,7 @@ public class SDKDemo_RegisterUser { // 注册相关class DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); PrivKey privKey = SDKDemo_Params.privkey1; diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Tx_Persistance.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Tx_Persistance.java index 5c2d452f..ef0762c4 100644 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Tx_Persistance.java +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Tx_Persistance.java @@ -40,10 +40,7 @@ public class SDKDemo_Tx_Persistance { // 注册相关class DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); PrivKey privKey1 = SDKDemo_Params.privkey0; @@ -87,7 +84,7 @@ public class SDKDemo_Tx_Persistance { TransactionContent txContent = BinaryProtocol.decode(txContentBytes, TransactionContent.class); // 对交易内容签名; - DigitalSignature signature1 = SignatureUtils.sign(txContent, keyPair1); + DigitalSignature signature1 = SignatureUtils.sign(keyPair1.getAlgorithm(), txContent, keyPair1); // 根据交易内容重新准备交易; PreparedTransaction decodedPrepTx = blockchainService.prepareTransaction(txContent); diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_ConsensusSettings_Update_Demo.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_ConsensusSettings_Update_Demo.java new file mode 100644 index 00000000..9c0ab330 --- /dev/null +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_ConsensusSettings_Update_Demo.java @@ -0,0 +1,42 @@ +package com.jd.blockchain.sdk.samples; + +import com.jd.blockchain.ledger.PreparedTransaction; +import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.TransactionTemplate; +import com.jd.blockchain.utils.Property; + +import java.util.ArrayList; +import java.util.List; + +public class SDK_ConsensusSettings_Update_Demo extends SDK_Base_Demo { + + public static void main(String[] args) { + new SDK_ConsensusSettings_Update_Demo().updateSettings(); + } + + public void updateSettings() { + + List properties = new ArrayList(); + + // 修改bftsmart.conf配置文件中的选项; + properties.add(new Property("system.communication.useSenderThread", "false")); + + Property[] propertiesArray = properties.toArray(new Property[properties.size()]); + + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + + txTpl.settings().update(propertiesArray); + + // TX 准备就绪; + PreparedTransaction prepTx = txTpl.prepare(); + + // 使用私钥进行签名; + prepTx.sign(adminKey); + + // 提交交易; + TransactionResponse transactionResponse = prepTx.commit(); + + System.out.println(transactionResponse.isSuccess()); + + } +} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java index d90b5233..512cb5cd 100644 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java +++ b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java @@ -48,7 +48,7 @@ public class SDK_InsertData_Demo extends SDK_Base_Demo { LedgerTransaction[] txList = blockchainService.getTransactions(ledgerHash, ledgerNumber, 0, 100); // 遍历交易列表 for (LedgerTransaction ledgerTransaction : txList) { - TransactionContent txContent = ledgerTransaction.getTransactionContent(); + TransactionContent txContent = ledgerTransaction.getRequest().getTransactionContent(); Operation[] operations = txContent.getOperations(); if (operations != null && operations.length > 0) { for (Operation operation : operations) { @@ -101,7 +101,7 @@ public class SDK_InsertData_Demo extends SDK_Base_Demo { } //根据交易的 hash 获得交易;注:客户端生成 PrepareTransaction 时得到交易hash; - HashDigest txHash = txList[0].getTransactionContent().getHash(); + HashDigest txHash = txList[0].getRequest().getTransactionHash(); // Transaction tx = blockchainService.getTransactionByContentHash(ledgerHash, txHash); // String[] objKeys = new String[] { "x001", "x002" }; // KVDataEntry[] kvData = blockchainService.getDataEntries(ledgerHash, commerceAccount, objKeys); diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java index 244d8071..ed0eee08 100644 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java +++ b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java @@ -6,6 +6,8 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import com.jd.blockchain.crypto.base.DefaultCryptoEncoding; +import com.jd.blockchain.crypto.base.HashDigestBytes; import org.junit.Before; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -286,7 +288,7 @@ public class SDK_Contract_Test { // TX 准备就绪; PreparedTransaction prepTx = txTemp.prepare(); - String txHash = ByteArray.toBase64(prepTx.getHash().toBytes()); + String txHash = ByteArray.toBase64(prepTx.getTransactionHash().toBytes()); // 使用私钥进行签名; AsymmetricKeypair keyPair = getSponsorKey(); @@ -297,7 +299,7 @@ public class SDK_Contract_Test { } private static HashDigest getLedgerHash() { - return new HashDigest(Base58Utils.decode(ledgerAddress)); + return new HashDigestBytes(DefaultCryptoEncoding.decodeAlgorithm(Base58Utils.decode(ledgerAddress)), Base58Utils.decode(ledgerAddress)); } /** diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_BatchInsertData_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_BatchInsertData_Test_.java index 747c835e..7e2d78e3 100644 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_BatchInsertData_Test_.java +++ b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_BatchInsertData_Test_.java @@ -10,6 +10,8 @@ package test.com.jd.blockchain.sdk.test; import static org.junit.Assert.assertEquals; +import com.jd.blockchain.crypto.base.DefaultCryptoEncoding; +import com.jd.blockchain.crypto.base.HashDigestBytes; import org.junit.Before; import org.junit.Test; @@ -21,11 +23,8 @@ import com.jd.blockchain.crypto.HashFunction; import com.jd.blockchain.crypto.SignatureFunction; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.EndpointRequest; -import com.jd.blockchain.ledger.NodeRequest; import com.jd.blockchain.ledger.PreparedTransaction; import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionContentBody; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionState; @@ -68,10 +67,7 @@ public class SDK_GateWay_BatchInsertData_Test_ { service = serviceFactory.getBlockchainService(); DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); } @@ -118,8 +114,7 @@ public class SDK_GateWay_BatchInsertData_Test_ { } private HashDigest getLedgerHash() { - byte[] hashBytes = Base58Utils.decode(ledgerHash); - return new HashDigest(hashBytes); + return new HashDigestBytes(DefaultCryptoEncoding.decodeAlgorithm(Base58Utils.decode(ledgerHash)), Base58Utils.decode(ledgerHash)); } diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_DataAccount_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_DataAccount_Test_.java index 7d343505..114c6de6 100644 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_DataAccount_Test_.java +++ b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_DataAccount_Test_.java @@ -19,11 +19,8 @@ import com.jd.blockchain.crypto.HashFunction; import com.jd.blockchain.crypto.SignatureFunction; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.EndpointRequest; -import com.jd.blockchain.ledger.NodeRequest; import com.jd.blockchain.ledger.PreparedTransaction; import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionContentBody; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionState; @@ -62,10 +59,7 @@ public class SDK_GateWay_DataAccount_Test_ { service = serviceFactory.getBlockchainService(); DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); } diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_InsertData_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_InsertData_Test_.java index ed6567e9..5d420d5f 100644 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_InsertData_Test_.java +++ b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_InsertData_Test_.java @@ -21,11 +21,8 @@ import com.jd.blockchain.crypto.HashFunction; import com.jd.blockchain.crypto.SignatureFunction; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.EndpointRequest; -import com.jd.blockchain.ledger.NodeRequest; import com.jd.blockchain.ledger.PreparedTransaction; import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionContentBody; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionState; @@ -65,10 +62,7 @@ public class SDK_GateWay_InsertData_Test_ { service = serviceFactory.getBlockchainService(); DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); } diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Participant_Regist_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Participant_Regist_Test_.java index 634357f5..0b9e6a93 100644 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Participant_Regist_Test_.java +++ b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Participant_Regist_Test_.java @@ -59,10 +59,7 @@ public class SDK_GateWay_Participant_Regist_Test_ { service = serviceFactory.getBlockchainService(); DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); DataContractRegistry.register(ParticipantRegisterOperation.class); DataContractRegistry.register(ParticipantStateUpdateOperation.class); diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java index 3d291811..2879c503 100644 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java +++ b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java @@ -23,16 +23,12 @@ import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; import com.jd.blockchain.ledger.DigitalSignature; -import com.jd.blockchain.ledger.EndpointRequest; import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerInfo; import com.jd.blockchain.ledger.LedgerTransaction; -import com.jd.blockchain.ledger.NodeRequest; import com.jd.blockchain.ledger.ParticipantNode; -import com.jd.blockchain.ledger.Transaction; import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionContentBody; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionState; @@ -72,10 +68,7 @@ public class SDK_GateWay_Query_Test_ { service = serviceFactory.getBlockchainService(); DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); } @@ -119,16 +112,16 @@ public class SDK_GateWay_Query_Test_ { LedgerTransaction[] txList = service.getTransactions(ledgerHash, ledgerNumber, 0, 100); for (LedgerTransaction ledgerTransaction : txList) { - System.out.println("ledgerTransaction.Hash=" + ledgerTransaction.getHash()); + System.out.println("ledgerTransaction.Hash=" + ledgerTransaction.getTransactionHash()); } txList = service.getTransactions(ledgerHash, hashDigest, 0, 100); for (LedgerTransaction ledgerTransaction : txList) { - System.out.println("ledgerTransaction.Hash=" + ledgerTransaction.getHash()); + System.out.println("ledgerTransaction.Hash=" + ledgerTransaction.getTransactionHash()); } - Transaction tx = service.getTransactionByContentHash(ledgerHash, hashDigest); - DigitalSignature[] signatures = tx.getEndpointSignatures(); + LedgerTransaction tx = service.getTransactionByContentHash(ledgerHash, hashDigest); + DigitalSignature[] signatures = tx.getRequest().getEndpointSignatures(); for (DigitalSignature signature : signatures) { System.out.println(signature.getDigest().getAlgorithm()); } diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_User_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_User_Test_.java index d69b0f97..5310624e 100644 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_User_Test_.java +++ b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_User_Test_.java @@ -23,11 +23,8 @@ import com.jd.blockchain.crypto.PubKey; import com.jd.blockchain.crypto.SignatureFunction; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.EndpointRequest; -import com.jd.blockchain.ledger.NodeRequest; import com.jd.blockchain.ledger.PreparedTransaction; import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionContentBody; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionState; @@ -89,10 +86,7 @@ public class SDK_GateWay_User_Test_ { service = serviceFactory.getBlockchainService(); DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionContentBody.class); DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(NodeRequest.class); - DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); } From 3c8616037b072d58ea997ca58ab857797a584a9d Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Sun, 15 Nov 2020 16:52:53 +0800 Subject: [PATCH 078/150] upgraded version of core module and bft-smart module; --- core | 2 +- libs/bft-smart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index b1b0a0b0..84d526ae 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit b1b0a0b0a3a690a5f8a73d30da0e6ffd1a5b40eb +Subproject commit 84d526ae141f6b103778a923c2d73a9c277724f3 diff --git a/libs/bft-smart b/libs/bft-smart index b9db7d7c..a4422ee2 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit b9db7d7cf8469ba8c94e896846f136f381d9f7d8 +Subproject commit a4422ee2a60e2e79b25cd7caf6161f6e88c42833 From 5eeb79a97d7a9739ea9b5d4253d9b209d3ec0a27 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Sun, 15 Nov 2020 17:30:54 +0800 Subject: [PATCH 079/150] upgraded bft-mart module; --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index a4422ee2..1c5019d5 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit a4422ee2a60e2e79b25cd7caf6161f6e88c42833 +Subproject commit 1c5019d56e538d1744f53d35593ed1d6a3a75dce From 913f293546db212e4d03465c40eebf902ae4a331 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Mon, 16 Nov 2020 14:10:40 +0800 Subject: [PATCH 080/150] added some default properties about communication to the bftsmart.config; --- .../src/main/resources/config/init/bftsmart.config | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config b/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config index 12342e86..6ab5665a 100644 --- a/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config +++ b/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config @@ -55,13 +55,7 @@ system.server.3.network.secure=false #system.authentication.hmacAlgorithm = HmacSHA1 #Specify if the communication system should use a thread to send data (true or false) -system.communication.useSenderThread = true - -#The time interval for retrying to send message after connection failure. In milliseconds; -system.communication.send.retryInterval=2000 - -#The number of retries to send message after connection failure. -system.communication.send.retryCount=100 +#system.communication.useSenderThread = true //unused property; #Force all processes to use the same public/private keys pair and secret key. This is useful when deploying experiments #and benchmarks, but must not be used in production systems. @@ -98,6 +92,12 @@ system.communication.inQueueSize = 500000 # Quantity of messages that can be stored in the send queue of each replica system.communication.outQueueSize = 500000 +#The time interval for retrying to send message after connection failure. In milliseconds; +system.communication.send.retryInterval=2000 + +#The number of retries to send message after connection failure. +system.communication.send.retryCount=100 + #Set to 1 if SMaRt should use signatures, set to 0 if otherwise system.communication.useSignatures = 0 From ca5690070eb16017ebb66729d08eeca5493276dd Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Mon, 16 Nov 2020 14:12:41 +0800 Subject: [PATCH 081/150] upgraded modules; --- core | 2 +- framework | 2 +- libs/bft-smart | 2 +- test | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core b/core index 84d526ae..6fc4ad72 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 84d526ae141f6b103778a923c2d73a9c277724f3 +Subproject commit 6fc4ad72b13f863a32ef86a35f788da7b869f46b diff --git a/framework b/framework index b88f5269..62319f25 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit b88f526928a05bba68903230d3634c02595e1161 +Subproject commit 62319f25e24a2cc2c086fa9c3c81512acc749ca8 diff --git a/libs/bft-smart b/libs/bft-smart index 1c5019d5..6f6276fa 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 1c5019d56e538d1744f53d35593ed1d6a3a75dce +Subproject commit 6f6276fa47777339f0b312f143898507aed5429a diff --git a/test b/test index b00251a0..2df48ba8 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit b00251a0d19e9708b914ce29f8b748b862d4218e +Subproject commit 2df48ba8b7c2eb4e1e8eb5daff333b1b56510afb From b2cff4fcedad77dff60392bbab4ce863eded1292 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Mon, 16 Nov 2020 16:41:19 +0800 Subject: [PATCH 082/150] upgraded submodules; --- core | 2 +- explorer | 2 +- framework | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index 6fc4ad72..f5d33e36 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 6fc4ad72b13f863a32ef86a35f788da7b869f46b +Subproject commit f5d33e36acfe6efee467ae199d1f2597becca91d diff --git a/explorer b/explorer index 5c2524a4..95d7f119 160000 --- a/explorer +++ b/explorer @@ -1 +1 @@ -Subproject commit 5c2524a4a4f2c2a85976dd95c6f4c39262ccdbd7 +Subproject commit 95d7f11931fb500e7f2a180eabe559a153be46cc diff --git a/framework b/framework index 62319f25..8708616d 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 62319f25e24a2cc2c086fa9c3c81512acc749ca8 +Subproject commit 8708616dd5a02780affaa6afc3e4419ae714f7ed From 812bd03452e5b63b2718bb6aae611aed4132f4d1 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Tue, 17 Nov 2020 12:06:43 +0800 Subject: [PATCH 083/150] upgraded submodules; --- core | 2 +- framework | 2 +- libs/bft-smart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index f5d33e36..51c4ff9f 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit f5d33e36acfe6efee467ae199d1f2597becca91d +Subproject commit 51c4ff9fc217bb132a71db18e389a7a43224bf50 diff --git a/framework b/framework index 8708616d..5bb60e73 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 8708616dd5a02780affaa6afc3e4419ae714f7ed +Subproject commit 5bb60e73e1bae167a16a5231f5c8b1a1eff3bc2d diff --git a/libs/bft-smart b/libs/bft-smart index 6f6276fa..249e26ab 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 6f6276fa47777339f0b312f143898507aed5429a +Subproject commit 249e26ab0b3eeacd0f223fd850683422c0803557 From 4064868c4f315057c11cb55da19fb342105b66c3 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Tue, 17 Nov 2020 17:55:53 +0800 Subject: [PATCH 084/150] upgraded modules; --- core | 2 +- framework | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index 51c4ff9f..7ea16d53 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 51c4ff9fc217bb132a71db18e389a7a43224bf50 +Subproject commit 7ea16d536083c29565315e0ba7bfde1ce468a264 diff --git a/framework b/framework index 5bb60e73..393c12dd 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 5bb60e73e1bae167a16a5231f5c8b1a1eff3bc2d +Subproject commit 393c12dd02becec3a0b1ff54f800c2494f9007aa From 2e7fd78bd33286b51530e4ef57b505eb4a38e8fe Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Tue, 17 Nov 2020 17:56:43 +0800 Subject: [PATCH 085/150] upgraded submodules; --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index 249e26ab..5d8dad64 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 249e26ab0b3eeacd0f223fd850683422c0803557 +Subproject commit 5d8dad64ed154493163432efe2ce91073687a6a4 From 796f9aa80983fe9ee622535839ff2f7f33f31e2d Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Tue, 17 Nov 2020 21:44:36 +0800 Subject: [PATCH 086/150] upgraded submodules; --- core | 2 +- framework | 2 +- test | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index 7ea16d53..001a0bdc 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 7ea16d536083c29565315e0ba7bfde1ce468a264 +Subproject commit 001a0bdc831d06c10a85c0fdf5cf89526d71d0af diff --git a/framework b/framework index 393c12dd..be3df38c 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 393c12dd02becec3a0b1ff54f800c2494f9007aa +Subproject commit be3df38c6aa0530477ec6691c788021877421728 diff --git a/test b/test index 2df48ba8..853e67cf 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 2df48ba8b7c2eb4e1e8eb5daff333b1b56510afb +Subproject commit 853e67cfa53704916bf3de1a7826b66d2bd010d5 From 69effd094b19c374ec97ee5bf8d07c8d784e35a7 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Tue, 17 Nov 2020 23:44:05 +0800 Subject: [PATCH 087/150] fixed compilation error related to the deploy-docker; --- deploy/docker/docker-demo/pom.xml | 9 +++++---- deploy/docker/docker-sdk/pom.xml | 2 +- deploy/docker/pom.xml | 6 +----- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/deploy/docker/docker-demo/pom.xml b/deploy/docker/docker-demo/pom.xml index a6b6ef36..c222c23e 100644 --- a/deploy/docker/docker-demo/pom.xml +++ b/deploy/docker/docker-demo/pom.xml @@ -5,7 +5,7 @@ docker com.jd.blockchain - 1.3.0.RELEASE + 1.4.0.RELEASE 4.0.0 docker-demo @@ -24,7 +24,6 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.1 1.8 1.8 @@ -123,9 +122,11 @@ jdchain-demo - ${docker.tag} + + ${project.version} + - ${project.basedir}/src/main/docker + ${project.basedir}/src/main/target diff --git a/deploy/docker/docker-sdk/pom.xml b/deploy/docker/docker-sdk/pom.xml index acd99c8c..276d48c4 100644 --- a/deploy/docker/docker-sdk/pom.xml +++ b/deploy/docker/docker-sdk/pom.xml @@ -5,7 +5,7 @@ docker com.jd.blockchain - 1.3.0.RELEASE + 1.4.0.RELEASE 4.0.0 diff --git a/deploy/docker/pom.xml b/deploy/docker/pom.xml index 81a492ab..6c6e1dab 100644 --- a/deploy/docker/pom.xml +++ b/deploy/docker/pom.xml @@ -5,17 +5,13 @@ deploy-root com.jd.blockchain - 1.4.0-SNAPSHOT + 1.4.0.RELEASE 4.0.0 - 1.3.0.RELEASE pom docker - - 1.3.0 - docker-sdk From 16647efebf48fe4d3178b7886179da4edc73e7e8 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Wed, 18 Nov 2020 11:07:52 +0800 Subject: [PATCH 088/150] ignored the output files of docker demo; --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 740e5266..57d733d7 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,6 @@ contract-libs/coreLib/sdk-base-0.6.0-SNAPSHOT.jar contract-libs/coreLib/utils-common-1.6.1-SNAPSHOT.jar source/tools/tools-initializer/bftsmart.config test/test-integration/runtime/ +deploy/docker/docker-demo/docker/zip/docker-sdk-1.4.0.RELEASE.jar +deploy/docker/docker-demo/docker/zip/jdchain-gateway-1.4.0.RELEASE.zip +deploy/docker/docker-demo/docker/zip/jdchain-peer-1.4.0.RELEASE.zip From 08f3b75258b3abcf7ded38865821537462e3672c Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Wed, 18 Nov 2020 17:29:45 +0800 Subject: [PATCH 089/150] upgraded ignore config; --- .gitignore | 3 +++ deploy/docker/docker-demo/pom.xml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 57d733d7..19f6de8f 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,6 @@ test/test-integration/runtime/ deploy/docker/docker-demo/docker/zip/docker-sdk-1.4.0.RELEASE.jar deploy/docker/docker-demo/docker/zip/jdchain-gateway-1.4.0.RELEASE.zip deploy/docker/docker-demo/docker/zip/jdchain-peer-1.4.0.RELEASE.zip +deploy/docker/docker-demo/src/main/docker/zip/docker-sdk-1.4.0.RELEASE.jar +deploy/docker/docker-demo/src/main/docker/zip/jdchain-gateway-1.4.0.RELEASE.zip +deploy/docker/docker-demo/src/main/docker/zip/jdchain-peer-1.4.0.RELEASE.zip diff --git a/deploy/docker/docker-demo/pom.xml b/deploy/docker/docker-demo/pom.xml index c222c23e..5d77582b 100644 --- a/deploy/docker/docker-demo/pom.xml +++ b/deploy/docker/docker-demo/pom.xml @@ -126,7 +126,7 @@ ${project.version} - ${project.basedir}/src/main/target + ${project.basedir}/target From 630fd8446afd0524ba23832991dec0771c9612b7 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Thu, 19 Nov 2020 14:09:20 +0800 Subject: [PATCH 090/150] upgraded submodule; --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index 5d8dad64..d48340d6 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 5d8dad64ed154493163432efe2ce91073687a6a4 +Subproject commit d48340d6d46813eb2120e034da5c1d39eaae3431 From 4ddb5bba6f171368fad6a196c9f10d63fa0f3985 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Thu, 19 Nov 2020 14:11:33 +0800 Subject: [PATCH 091/150] upgraded explorer; --- explorer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/explorer b/explorer index 95d7f119..1e621f6a 160000 --- a/explorer +++ b/explorer @@ -1 +1 @@ -Subproject commit 95d7f11931fb500e7f2a180eabe559a153be46cc +Subproject commit 1e621f6ad11239fd5bfb2400e15c72b03a73a0fe From 623d9023ddf6ab5e9bcf03b17dc66803b17e6769 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Thu, 19 Nov 2020 15:15:28 +0800 Subject: [PATCH 092/150] upgraded bft-smart module; --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index d48340d6..866c8282 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit d48340d6d46813eb2120e034da5c1d39eaae3431 +Subproject commit 866c8282298546913bc5ea4f0f7404e18a373418 From 662e8053c2d23a1d9bea26114337a8d0408f096e Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Tue, 24 Nov 2020 02:22:42 +0800 Subject: [PATCH 093/150] upgraded summodules; --- core | 2 +- framework | 2 +- test | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index 001a0bdc..b65ad55b 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 001a0bdc831d06c10a85c0fdf5cf89526d71d0af +Subproject commit b65ad55b7ec8ab9084bfe13d0a3cfdc0c30251f4 diff --git a/framework b/framework index be3df38c..4dc1afb6 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit be3df38c6aa0530477ec6691c788021877421728 +Subproject commit 4dc1afb64a109805e26fc349e5d21a1eb8019005 diff --git a/test b/test index 853e67cf..9639de66 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 853e67cfa53704916bf3de1a7826b66d2bd010d5 +Subproject commit 9639de66ca24052dfa2f6ed2c2ab71ad4f894f77 From 24c5d1c0e7615b901beb12022e086bf4407ffa6f Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Tue, 24 Nov 2020 02:24:40 +0800 Subject: [PATCH 094/150] upgraded the framework and core modules, for that simplified the implementation of MerkleAccount with AccountSnapshot; --- core | 2 +- framework | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index b65ad55b..d13a9f95 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit b65ad55b7ec8ab9084bfe13d0a3cfdc0c30251f4 +Subproject commit d13a9f95ca1ec3446b2488704d1bd80d057ec29a diff --git a/framework b/framework index 4dc1afb6..1a823fa7 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 4dc1afb64a109805e26fc349e5d21a1eb8019005 +Subproject commit 1a823fa70a1ca2bd08036dd58e8f5e7b7ab3bd55 From b8c599ff48e7964c518edc9a4cf9f94d2aeb8dd6 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Tue, 24 Nov 2020 10:38:04 +0800 Subject: [PATCH 095/150] upgraded submodules; --- core | 2 +- framework | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index d13a9f95..078fc835 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit d13a9f95ca1ec3446b2488704d1bd80d057ec29a +Subproject commit 078fc8359dc51e1dcf6ef16c400c418580b5e165 diff --git a/framework b/framework index 1a823fa7..51735f00 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 1a823fa70a1ca2bd08036dd58e8f5e7b7ab3bd55 +Subproject commit 51735f00b3ceffedace5ba9f03036cacf597e845 From 592a8a2b13b1bdbddeeb3170824af7dbc441a69b Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Tue, 24 Nov 2020 10:46:13 +0800 Subject: [PATCH 096/150] upgraded core module; --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 078fc835..e0172f7d 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 078fc8359dc51e1dcf6ef16c400c418580b5e165 +Subproject commit e0172f7d43410fbd08c05836a9c2988940838122 From a4032b79e27e258ba95d30a82e676a39f98ccf24 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Tue, 24 Nov 2020 18:40:52 +0800 Subject: [PATCH 097/150] upgraded submodules; --- core | 2 +- test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index e0172f7d..eb1164e4 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit e0172f7d43410fbd08c05836a9c2988940838122 +Subproject commit eb1164e4f88404372bd9d5e07f33c998fab38eae diff --git a/test b/test index 9639de66..5e6d1114 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 9639de66ca24052dfa2f6ed2c2ab71ad4f894f77 +Subproject commit 5e6d11142539c6a882d2e41d1f99bcee7fed7364 From 45757d24caba4adbcc99eee2a2718f7697eeff20 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Thu, 26 Nov 2020 11:03:03 +0800 Subject: [PATCH 098/150] upgraded submodules; --- core | 2 +- framework | 2 +- test | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index eb1164e4..ee8e2f7b 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit eb1164e4f88404372bd9d5e07f33c998fab38eae +Subproject commit ee8e2f7b73615961b91da62ad5945ee9a7b26223 diff --git a/framework b/framework index 51735f00..5a0d722b 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 51735f00b3ceffedace5ba9f03036cacf597e845 +Subproject commit 5a0d722b24e28f02d8834b45b69361563c83b23e diff --git a/test b/test index 5e6d1114..8a281236 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 5e6d11142539c6a882d2e41d1f99bcee7fed7364 +Subproject commit 8a281236f44a937373b387f44f5d1bee9674e502 From 1811c57a05b5f951604dcd9ed3b386e3d14f255c Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Thu, 26 Nov 2020 23:10:27 +0800 Subject: [PATCH 099/150] upgraded submodules; --- core | 2 +- framework | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index ee8e2f7b..7d2e76f6 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit ee8e2f7b73615961b91da62ad5945ee9a7b26223 +Subproject commit 7d2e76f6e8d27e2d24c00d2defcc343caa5344d6 diff --git a/framework b/framework index 5a0d722b..e291c072 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 5a0d722b24e28f02d8834b45b69361563c83b23e +Subproject commit e291c072d5ce55406a3f5d52223e32ddbbb9c7c8 From 1da3fe5017233b59ff00515d406cf6ca86816603 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Thu, 26 Nov 2020 23:20:33 +0800 Subject: [PATCH 100/150] upgraded bft-smart module; --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index 866c8282..46f9b7f6 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 866c8282298546913bc5ea4f0f7404e18a373418 +Subproject commit 46f9b7f6c873d26c5d72082a45c84a8d22538499 From d62967084776da17a2c4c8a6fb64287f24b2215c Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Fri, 27 Nov 2020 19:00:22 +0800 Subject: [PATCH 101/150] upgraded submodules; --- core | 2 +- framework | 2 +- libs/bft-smart | 2 +- test | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core b/core index 7d2e76f6..023faeba 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 7d2e76f6e8d27e2d24c00d2defcc343caa5344d6 +Subproject commit 023faeba67a154d108a8a3398b2a6bd090ad7607 diff --git a/framework b/framework index e291c072..be7ad8bf 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit e291c072d5ce55406a3f5d52223e32ddbbb9c7c8 +Subproject commit be7ad8bf3a69193e8b99b47c23526192e869b67e diff --git a/libs/bft-smart b/libs/bft-smart index 46f9b7f6..0f618055 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 46f9b7f6c873d26c5d72082a45c84a8d22538499 +Subproject commit 0f618055da1deeceb468f68bdec621e883ff9bbf diff --git a/test b/test index 8a281236..341df0a1 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 8a281236f44a937373b387f44f5d1bee9674e502 +Subproject commit 341df0a128d75fbc5276ef359f9977f8a8a268fa From 975ad0df351fe78f271944cfd6f07705c0e5f319 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Sun, 29 Nov 2020 17:07:12 +0800 Subject: [PATCH 102/150] upgraded core module; --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 023faeba..0109238a 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 023faeba67a154d108a8a3398b2a6bd090ad7607 +Subproject commit 0109238abb814b3ff843c6cf1d72870484d75359 From 030326abe9b60e1a5b2cafc92ead3b6801974231 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Tue, 1 Dec 2020 09:55:22 +0800 Subject: [PATCH 103/150] upgraded submodules; --- core | 2 +- explorer | 2 +- libs/bft-smart | 2 +- test | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core b/core index 0109238a..69f2c8ee 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 0109238abb814b3ff843c6cf1d72870484d75359 +Subproject commit 69f2c8eec6e94b6ffc25a0e23887dcc94cbbc562 diff --git a/explorer b/explorer index 1e621f6a..93ebc3d6 160000 --- a/explorer +++ b/explorer @@ -1 +1 @@ -Subproject commit 1e621f6ad11239fd5bfb2400e15c72b03a73a0fe +Subproject commit 93ebc3d69699a6a6a228c8a5cf69027089ef086b diff --git a/libs/bft-smart b/libs/bft-smart index 0f618055..dca1d64b 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 0f618055da1deeceb468f68bdec621e883ff9bbf +Subproject commit dca1d64b1da1614e3cb8f81c16d6680a807c84c2 diff --git a/test b/test index 341df0a1..46ad3564 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 341df0a128d75fbc5276ef359f9977f8a8a268fa +Subproject commit 46ad3564af1625fcbe11bd3f830d114a4cbfca0c From 90e9504c3ddf8d0149afba4804f06f527f303433 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Tue, 1 Dec 2020 11:44:54 +0800 Subject: [PATCH 104/150] ugraded submodules; --- core | 2 +- framework | 2 +- test | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index 69f2c8ee..aa186210 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 69f2c8eec6e94b6ffc25a0e23887dcc94cbbc562 +Subproject commit aa186210bd8341c1d702357d6f57ffa7ac1445e0 diff --git a/framework b/framework index be7ad8bf..3007fedd 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit be7ad8bf3a69193e8b99b47c23526192e869b67e +Subproject commit 3007feddffcc38483805c627908eeda50a81f972 diff --git a/test b/test index 46ad3564..ea8302d6 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 46ad3564af1625fcbe11bd3f830d114a4cbfca0c +Subproject commit ea8302d6ef0ba326d0179e6dbaeb1dd85955494a From f79f1bd3b1a15ca8e12e03912477f5202380d812 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Wed, 2 Dec 2020 09:39:15 +0800 Subject: [PATCH 105/150] upgraded submodules to fix bugs; --- framework | 2 +- libs/bft-smart | 2 +- test | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/framework b/framework index 3007fedd..cb225648 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 3007feddffcc38483805c627908eeda50a81f972 +Subproject commit cb22564841f28f356bd311e3b35a221e547973d8 diff --git a/libs/bft-smart b/libs/bft-smart index dca1d64b..2bbcbfbf 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit dca1d64b1da1614e3cb8f81c16d6680a807c84c2 +Subproject commit 2bbcbfbf94474a251f45ebcc7dcc91391817fe3d diff --git a/test b/test index ea8302d6..e88a682a 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit ea8302d6ef0ba326d0179e6dbaeb1dd85955494a +Subproject commit e88a682afde658eead74d23d86d656941bf20a6b From ad67fb3ef17523d3f54ec8610ee85143e97acd56 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Wed, 2 Dec 2020 11:37:43 +0800 Subject: [PATCH 106/150] upgraded submodules; --- core | 2 +- libs/bft-smart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index aa186210..a362e64b 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit aa186210bd8341c1d702357d6f57ffa7ac1445e0 +Subproject commit a362e64baebc34799ba2039991d30c62c55841eb diff --git a/libs/bft-smart b/libs/bft-smart index 2bbcbfbf..fae2b916 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 2bbcbfbf94474a251f45ebcc7dcc91391817fe3d +Subproject commit fae2b916315ebfc29d2f846b2647536ac7ea83c8 From 44a12febd160864e5c53af90e6d3f9fef8c8143d Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Wed, 2 Dec 2020 11:59:36 +0800 Subject: [PATCH 107/150] upgraded submodules to fix bugs of consensus test cases; --- test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test b/test index e88a682a..1230988e 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit e88a682afde658eead74d23d86d656941bf20a6b +Subproject commit 1230988e3e5bd8247c1bc505556a146f18794a98 From e1331cd131cb4003660a5ae0a33969327487f280 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Wed, 2 Dec 2020 23:41:05 +0800 Subject: [PATCH 108/150] refactored submodules that removing the default methods declared in LedgerTransaction data contract; --- core | 2 +- framework | 2 +- .../sdk/test/SDK_GateWay_Query_Test_.java | 13 +++++-------- test | 2 +- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/core b/core index a362e64b..8ad37f07 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit a362e64baebc34799ba2039991d30c62c55841eb +Subproject commit 8ad37f0727ac0c4bd2786a5b9b2ba19d61ebc468 diff --git a/framework b/framework index cb225648..977dddaf 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit cb22564841f28f356bd311e3b35a221e547973d8 +Subproject commit 977dddaf0dbc8966c007e9676bb1f79ab24d45a2 diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java index 2879c503..fe0b7d5f 100644 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java +++ b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java @@ -16,14 +16,11 @@ import com.jd.blockchain.crypto.AsymmetricKeypair; import com.jd.blockchain.crypto.Crypto; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.HashFunction; -import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.crypto.SignatureDigest; import com.jd.blockchain.crypto.SignatureFunction; import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; import com.jd.blockchain.ledger.DigitalSignature; -import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerInfo; import com.jd.blockchain.ledger.LedgerTransaction; @@ -32,10 +29,10 @@ import com.jd.blockchain.ledger.TransactionContent; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionState; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.sdk.BlockchainService; import com.jd.blockchain.sdk.client.GatewayServiceFactory; import com.jd.blockchain.transaction.TxResponseMessage; -import com.jd.blockchain.utils.serialize.json.JSONSerializeUtils; /** * 插入数据测试 @@ -112,12 +109,12 @@ public class SDK_GateWay_Query_Test_ { LedgerTransaction[] txList = service.getTransactions(ledgerHash, ledgerNumber, 0, 100); for (LedgerTransaction ledgerTransaction : txList) { - System.out.println("ledgerTransaction.Hash=" + ledgerTransaction.getTransactionHash()); + System.out.println("ledgerTransaction.Hash=" + ledgerTransaction.getRequest().getTransactionHash()); } txList = service.getTransactions(ledgerHash, hashDigest, 0, 100); for (LedgerTransaction ledgerTransaction : txList) { - System.out.println("ledgerTransaction.Hash=" + ledgerTransaction.getTransactionHash()); + System.out.println("ledgerTransaction.Hash=" + ledgerTransaction.getRequest().getTransactionHash()); } LedgerTransaction tx = service.getTransactionByContentHash(ledgerHash, hashDigest); @@ -125,8 +122,8 @@ public class SDK_GateWay_Query_Test_ { for (DigitalSignature signature : signatures) { System.out.println(signature.getDigest().getAlgorithm()); } - System.out.println("transaction.blockHeight=" + tx.getBlockHeight()); - System.out.println("transaction.executionState=" + tx.getExecutionState()); + System.out.println("transaction.blockHeight=" + tx.getResult().getBlockHeight()); + System.out.println("transaction.executionState=" + tx.getResult().getExecutionState()); ParticipantNode[] participants = service.getConsensusParticipants(ledgerHash); for (ParticipantNode participant : participants) { diff --git a/test b/test index 1230988e..6bc09d89 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 1230988e3e5bd8247c1bc505556a146f18794a98 +Subproject commit 6bc09d89d690d61a731c5e2aaca44de226c1fe96 From 2255ab620d76c8e36c68620f1952ca5339b9c018 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Thu, 3 Dec 2020 16:24:01 +0800 Subject: [PATCH 109/150] upgraded submodules; --- core | 2 +- explorer | 2 +- libs/bft-smart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index 8ad37f07..9383e4d3 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 8ad37f0727ac0c4bd2786a5b9b2ba19d61ebc468 +Subproject commit 9383e4d3435d32113ce69172368408a77d73fd7d diff --git a/explorer b/explorer index 93ebc3d6..8f92cf38 160000 --- a/explorer +++ b/explorer @@ -1 +1 @@ -Subproject commit 93ebc3d69699a6a6a228c8a5cf69027089ef086b +Subproject commit 8f92cf38203aebd3ace501d798aaecb83bdd6e52 diff --git a/libs/bft-smart b/libs/bft-smart index fae2b916..fb5234f3 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit fae2b916315ebfc29d2f846b2647536ac7ea83c8 +Subproject commit fb5234f315e5f4d3428f639f36e9b76ead9c7d0c From 9dae0efb8e7d31f351ef15698b325744baccb799 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Fri, 4 Dec 2020 00:59:40 +0800 Subject: [PATCH 110/150] upgraded modules to implement detecting the inner state of consensus nodes; --- core | 2 +- explorer | 2 +- framework | 2 +- libs/bft-smart | 2 +- test | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core b/core index 8ad37f07..3f7df99a 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 8ad37f0727ac0c4bd2786a5b9b2ba19d61ebc468 +Subproject commit 3f7df99a717fd34338fe2efade0a5c6efef30241 diff --git a/explorer b/explorer index 93ebc3d6..8f92cf38 160000 --- a/explorer +++ b/explorer @@ -1 +1 @@ -Subproject commit 93ebc3d69699a6a6a228c8a5cf69027089ef086b +Subproject commit 8f92cf38203aebd3ace501d798aaecb83bdd6e52 diff --git a/framework b/framework index 977dddaf..08cb09e0 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 977dddaf0dbc8966c007e9676bb1f79ab24d45a2 +Subproject commit 08cb09e02dce489366e2583fdb63efdae6b016a9 diff --git a/libs/bft-smart b/libs/bft-smart index fae2b916..957644af 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit fae2b916315ebfc29d2f846b2647536ac7ea83c8 +Subproject commit 957644af77dcda306fb55bb95335f6ef85be80b4 diff --git a/test b/test index 6bc09d89..a32707c8 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 6bc09d89d690d61a731c5e2aaca44de226c1fe96 +Subproject commit a32707c8d60b85e667eecd5f19056c5232e1f120 From 3dea0242f9d78ae811e77ae596837c69723207c0 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Fri, 4 Dec 2020 01:06:56 +0800 Subject: [PATCH 111/150] upgraded module; --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 3f7df99a..841cdbf1 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 3f7df99a717fd34338fe2efade0a5c6efef30241 +Subproject commit 841cdbf1655e141f780cecc415e2e61db7a24f43 From ad4b3f2c17c45c1219553129e7d579f07b1c9fcb Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Sun, 6 Dec 2020 18:05:42 +0800 Subject: [PATCH 112/150] upgraded submodules; --- core | 2 +- libs/bft-smart | 2 +- test | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index 841cdbf1..799775d2 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 841cdbf1655e141f780cecc415e2e61db7a24f43 +Subproject commit 799775d2c60d6562adbc25de4aaf79b0ebc43572 diff --git a/libs/bft-smart b/libs/bft-smart index 957644af..7cb9e871 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 957644af77dcda306fb55bb95335f6ef85be80b4 +Subproject commit 7cb9e871b1d586a20e52234e713f64b293f350ff diff --git a/test b/test index a32707c8..a6d17f2b 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit a32707c8d60b85e667eecd5f19056c5232e1f120 +Subproject commit a6d17f2b90ab5026a700299e3046fee93b8d89a0 From 74366e901415e79ed397a353325bd5ca38a6c8d7 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Mon, 7 Dec 2020 12:52:33 +0800 Subject: [PATCH 113/150] optimized the HashBaseSecureRandom that output the same random bytes sequence with the same total size, regardless with how many times of invoking. --- core | 2 +- framework | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index 799775d2..2c2632d7 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 799775d2c60d6562adbc25de4aaf79b0ebc43572 +Subproject commit 2c2632d78c9805a77927e5cf522f34f1fe15d944 diff --git a/framework b/framework index 08cb09e0..87e6e97b 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 08cb09e02dce489366e2583fdb63efdae6b016a9 +Subproject commit 87e6e97b586d92e38bd46bc03f992a4a4465016f From b847d2cfe2389cc8c815299f0f03c293bbb3d1d1 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Mon, 7 Dec 2020 15:40:03 +0800 Subject: [PATCH 114/150] upgraded core module to fixed bugs that confliction of consensus port don't be detected; --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 2c2632d7..73bf6813 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 2c2632d78c9805a77927e5cf522f34f1fe15d944 +Subproject commit 73bf6813433bb86bcdabac9829a55d650cf92879 From e368b781d2dbe931620dca383653a56726d3653e Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Mon, 7 Dec 2020 15:49:54 +0800 Subject: [PATCH 115/150] upgraded explorer module to fix bugs that the event content cann't be displayed; --- explorer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/explorer b/explorer index 8f92cf38..eaf0b1b8 160000 --- a/explorer +++ b/explorer @@ -1 +1 @@ -Subproject commit 8f92cf38203aebd3ace501d798aaecb83bdd6e52 +Subproject commit eaf0b1b895f3b254114ac0794599658d15062076 From 79b1b4c10c5fd05705836318ff10f13c2068351c Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Mon, 7 Dec 2020 20:13:31 +0800 Subject: [PATCH 116/150] upgraded bft-smart module; --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index 7cb9e871..306d1575 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 7cb9e871b1d586a20e52234e713f64b293f350ff +Subproject commit 306d1575f27d81e23467d931f8c7f24b07fa1593 From 86eace52755a8984be0047ce40519b82066eacf9 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Tue, 8 Dec 2020 10:25:04 +0800 Subject: [PATCH 117/150] upgraded test module to optimize test case of bftsmart consensus; --- test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test b/test index a6d17f2b..6d0ab46b 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit a6d17f2b90ab5026a700299e3046fee93b8d89a0 +Subproject commit 6d0ab46b877077c432ed4de658ec3cfc947bd957 From 58c59030873b2398f15aed7a3cbd01083cc5c0ef Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Wed, 9 Dec 2020 14:37:33 +0800 Subject: [PATCH 118/150] upgraded modules; --- core | 2 +- framework | 2 +- libs/bft-smart | 2 +- test | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core b/core index 73bf6813..61ea5591 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 73bf6813433bb86bcdabac9829a55d650cf92879 +Subproject commit 61ea5591688b249497828cb4802985d4aa2b0c58 diff --git a/framework b/framework index 87e6e97b..132a953e 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 87e6e97b586d92e38bd46bc03f992a4a4465016f +Subproject commit 132a953e9adcc09f750e7c0fdfaf7ef815a39861 diff --git a/libs/bft-smart b/libs/bft-smart index 306d1575..26304193 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 306d1575f27d81e23467d931f8c7f24b07fa1593 +Subproject commit 26304193f8989e6cd40e2b33b9b3bc57cfdfba8c diff --git a/test b/test index 6d0ab46b..71d98400 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 6d0ab46b877077c432ed4de658ec3cfc947bd957 +Subproject commit 71d984001dd3187e856831bd5aeb8782138cecb2 From 3e181e140b7ebc056cdbfd76cfff4cc7c8b0239b Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Thu, 10 Dec 2020 10:50:23 +0800 Subject: [PATCH 119/150] upgraded core; --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 61ea5591..4ec9f92a 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 61ea5591688b249497828cb4802985d4aa2b0c58 +Subproject commit 4ec9f92a13fb783a8a2aacd8efa5ef3fb47d0e0e From c1fc13754aebe75f426faa85e68f2484e7b851ff Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Sun, 13 Dec 2020 14:10:19 +0800 Subject: [PATCH 120/150] upgraded modules to add features that resuse and persist gateway id; --- core | 2 +- framework | 2 +- libs/bft-smart | 2 +- test | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core b/core index 61ea5591..0babefda 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 61ea5591688b249497828cb4802985d4aa2b0c58 +Subproject commit 0babefda0909ab1dd7279dd5079a20e2a981883a diff --git a/framework b/framework index 132a953e..ca59deb0 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 132a953e9adcc09f750e7c0fdfaf7ef815a39861 +Subproject commit ca59deb04773471ee5cec5b486c3a9768cee7f19 diff --git a/libs/bft-smart b/libs/bft-smart index 26304193..8189a1df 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 26304193f8989e6cd40e2b33b9b3bc57cfdfba8c +Subproject commit 8189a1dfa6f48cb872ba4bf7e9ce49af849101ba diff --git a/test b/test index 71d98400..b4cde5f6 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 71d984001dd3187e856831bd5aeb8782138cecb2 +Subproject commit b4cde5f69be5fc9b2e7ba95063e4554269c0e49e From 56d2f3589c444fd9a8233da1b1d0375c019fadee Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Sun, 13 Dec 2020 14:46:40 +0800 Subject: [PATCH 121/150] upgraded modules; --- core | 2 +- explorer | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index 0babefda..3bc2b7c3 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 0babefda0909ab1dd7279dd5079a20e2a981883a +Subproject commit 3bc2b7c305d8270be9ad9bfe2804d206f09b8a23 diff --git a/explorer b/explorer index eaf0b1b8..341eb8d4 160000 --- a/explorer +++ b/explorer @@ -1 +1 @@ -Subproject commit eaf0b1b895f3b254114ac0794599658d15062076 +Subproject commit 341eb8d48d0cc355d32d6cb10159c2049fcfa3b0 From 16715119f9deb27f3539733a87772fb41b3501b4 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Sun, 13 Dec 2020 19:26:46 +0800 Subject: [PATCH 122/150] fixed bugs of gateway authentication; --- core | 2 +- framework | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index 3bc2b7c3..c99bcabd 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 3bc2b7c305d8270be9ad9bfe2804d206f09b8a23 +Subproject commit c99bcabd68c6f1b19cde46e3fda1c519d0221c5e diff --git a/framework b/framework index ca59deb0..e4cfbad7 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit ca59deb04773471ee5cec5b486c3a9768cee7f19 +Subproject commit e4cfbad72f10812e2c3ffe1c5ade68fa17896e73 From 6e97e9176b8c9e30ab68dbbf8e3700ef02df7c2e Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Sun, 13 Dec 2020 21:48:18 +0800 Subject: [PATCH 123/150] upgraded core module to fixed bugs of ManagementController; --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index c99bcabd..9cc1c734 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit c99bcabd68c6f1b19cde46e3fda1c519d0221c5e +Subproject commit 9cc1c7344fcf770746314533df20b350aca9947c From a1e7b778b9a79f4835874f39c5586927f6b0b3c2 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Tue, 15 Dec 2020 00:05:44 +0800 Subject: [PATCH 124/150] fixed the bug that consensus client id could not be persisted; --- core | 2 +- framework | 2 +- test | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index 9cc1c734..160f21a6 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 9cc1c7344fcf770746314533df20b350aca9947c +Subproject commit 160f21a6e8ae507650a6ea810e35a4be9b58c5ae diff --git a/framework b/framework index e4cfbad7..ee93f762 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit e4cfbad72f10812e2c3ffe1c5ade68fa17896e73 +Subproject commit ee93f76209d91cd9fea4aa37929d06fda2f55069 diff --git a/test b/test index b4cde5f6..d641ed57 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit b4cde5f69be5fc9b2e7ba95063e4554269c0e49e +Subproject commit d641ed5749fa8f36e0fa3fa6454a54ed0135461c From bfe68908b2d84e00d8c00d7d0a9abc03ecfd1916 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Tue, 15 Dec 2020 16:54:54 +0800 Subject: [PATCH 125/150] fixed the bug that consensus client for one ledger is not sigleton; --- core | 2 +- framework | 2 +- libs/bft-smart | 2 +- test | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core b/core index 160f21a6..74aa9ad1 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 160f21a6e8ae507650a6ea810e35a4be9b58c5ae +Subproject commit 74aa9ad1d63e9a05be47aa9cd8891842b4423bce diff --git a/framework b/framework index ee93f762..f4817eed 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit ee93f76209d91cd9fea4aa37929d06fda2f55069 +Subproject commit f4817eed10edd51c9d6f33a343dcdc142e524789 diff --git a/libs/bft-smart b/libs/bft-smart index 8189a1df..9d1ba359 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 8189a1dfa6f48cb872ba4bf7e9ce49af849101ba +Subproject commit 9d1ba359d73d3a2af521ba7b6b47f892a3a51de5 diff --git a/test b/test index d641ed57..e94f23b3 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit d641ed5749fa8f36e0fa3fa6454a54ed0135461c +Subproject commit e94f23b3b2c79bd1b014dca345711cf41a509c90 From 3fbb792a0befeeecab1f680601528b8f82ba50d3 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Thu, 17 Dec 2020 10:17:04 +0800 Subject: [PATCH 126/150] fixed bugs of activating and updating peer; --- core | 2 +- framework | 2 +- libs/bft-smart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index 74aa9ad1..eba6737f 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 74aa9ad1d63e9a05be47aa9cd8891842b4423bce +Subproject commit eba6737fe6054c2f21a18ac50e626efa54c6c09f diff --git a/framework b/framework index f4817eed..a66b0abf 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit f4817eed10edd51c9d6f33a343dcdc142e524789 +Subproject commit a66b0abf127ccb2857ea5c5cf79d83fbea940f8c diff --git a/libs/bft-smart b/libs/bft-smart index 9d1ba359..7ac5b9fd 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 9d1ba359d73d3a2af521ba7b6b47f892a3a51de5 +Subproject commit 7ac5b9fde805eea4a50acb0d585a45afc3454513 From a16baefe0899b22396c3b77e4f5f19c9f8c04409 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Thu, 17 Dec 2020 12:08:51 +0800 Subject: [PATCH 127/150] upgraded to fix bugs; --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index 7ac5b9fd..1038fdaa 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 7ac5b9fde805eea4a50acb0d585a45afc3454513 +Subproject commit 1038fdaaf816c087f09e2e16c53dac57781b7e65 From d3fa6a5bed4288d7cae66015d7d0e0818df042b3 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Fri, 18 Dec 2020 16:32:27 +0800 Subject: [PATCH 128/150] upgraded to fix bugs; --- core | 2 +- libs/bft-smart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index eba6737f..6406f318 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit eba6737fe6054c2f21a18ac50e626efa54c6c09f +Subproject commit 6406f318bab2b28b12320b7f038d63c722568205 diff --git a/libs/bft-smart b/libs/bft-smart index 1038fdaa..6b095ed9 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 1038fdaaf816c087f09e2e16c53dac57781b7e65 +Subproject commit 6b095ed9a0701c7923c8ffa68a9ac4d1b28a9e20 From b68031315dc301d287b6ec14be562222869854d1 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Sun, 20 Dec 2020 16:49:07 +0800 Subject: [PATCH 129/150] upgraded modules; --- core | 2 +- framework | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index 6406f318..7f6bc1b0 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 6406f318bab2b28b12320b7f038d63c722568205 +Subproject commit 7f6bc1b016c86f1d91c669660669c84dc6693165 diff --git a/framework b/framework index a66b0abf..7e08435f 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit a66b0abf127ccb2857ea5c5cf79d83fbea940f8c +Subproject commit 7e08435f27a6a82102d9d2def32ad015d87ada23 From dd6314791c38c24973bac83a947b5240efe85bc5 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Mon, 21 Dec 2020 10:30:09 +0800 Subject: [PATCH 130/150] optimized the default bftsmart configuration; --- core | 2 +- .../deploy-peer/src/main/resources/config/init/bftsmart.config | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core b/core index 7f6bc1b0..4c85de1e 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 7f6bc1b016c86f1d91c669660669c84dc6693165 +Subproject commit 4c85de1eb4b9616760bfeff8f158fcd829de5184 diff --git a/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config b/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config index 67115953..cbf88f82 100644 --- a/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config +++ b/deploy/deploy-peer/src/main/resources/config/init/bftsmart.config @@ -154,7 +154,7 @@ system.totalordermulticast.sync_ckp = false system.initial.view = 0,1,2,3 #The ID of the trust third party (TTP) -system.ttp.id = 7002 +system.ttp.id = 2001 #This sets if the system will function in Byzantine or crash-only mode. Set to "true" to support Byzantine faults system.bft = true From 884bc4b50c0b7e46336fc58ec67fbae448ee4e25 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Thu, 24 Dec 2020 13:47:10 +0800 Subject: [PATCH 131/150] upgraded modules; --- core | 2 +- framework | 2 +- libs/bft-smart | 2 +- test | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core b/core index 4c85de1e..5b910dd1 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 4c85de1eb4b9616760bfeff8f158fcd829de5184 +Subproject commit 5b910dd16fd8540bb48f9748d99d3d6e39f583c1 diff --git a/framework b/framework index 7e08435f..10d6a6d5 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 7e08435f27a6a82102d9d2def32ad015d87ada23 +Subproject commit 10d6a6d57a062a3a36169e04e881b145993edce2 diff --git a/libs/bft-smart b/libs/bft-smart index 6b095ed9..9e5d776b 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 6b095ed9a0701c7923c8ffa68a9ac4d1b28a9e20 +Subproject commit 9e5d776b184f8094f0cde74d79df1012cc4429ee diff --git a/test b/test index e94f23b3..3e25a23d 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit e94f23b3b2c79bd1b014dca345711cf41a509c90 +Subproject commit 3e25a23d43e2d92717ba4ae36e351221a36fb869 From 396383823b252947e5be484faf725968f4f8ccc4 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Thu, 24 Dec 2020 13:56:10 +0800 Subject: [PATCH 132/150] upgraded modules; --- test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test b/test index 3e25a23d..57cbc0e0 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 3e25a23d43e2d92717ba4ae36e351221a36fb869 +Subproject commit 57cbc0e0baeac8540a058ab3cc5f3964453d88a4 From 8c150ed1852254c4bd53c7f267bc52ca8ec8e66e Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Thu, 24 Dec 2020 14:05:40 +0800 Subject: [PATCH 133/150] optimized the consensus testcases; --- test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test b/test index 57cbc0e0..f5fb72e6 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 57cbc0e0baeac8540a058ab3cc5f3964453d88a4 +Subproject commit f5fb72e696be191be92db2ba5935c4fa1a3b0582 From 5185750117d426fb19aa4f2e8e182f71675a80ee Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Fri, 25 Dec 2020 15:10:42 +0800 Subject: [PATCH 134/150] upgraded modules; --- libs/bft-smart | 2 +- test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/bft-smart b/libs/bft-smart index 9e5d776b..34549163 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 9e5d776b184f8094f0cde74d79df1012cc4429ee +Subproject commit 34549163e3c7833841226c01b1353d663469815a diff --git a/test b/test index f5fb72e6..52e8abc7 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit f5fb72e696be191be92db2ba5935c4fa1a3b0582 +Subproject commit 52e8abc725d800d3edf78e6df7d26d6ab02d8518 From 6937f9c411502b2e07215998f357c3a09a109fe8 Mon Sep 17 00:00:00 2001 From: imuge Date: Fri, 25 Dec 2020 17:53:16 +0800 Subject: [PATCH 135/150] update samples --- samples/README.md | 60 ++ samples/contract-samples/pom.xml | 94 +-- .../blockchain/contract/ComplexContract.java | 7 - .../contract/ComplexContractImpl.java | 12 - .../blockchain/contract/RandomContract.java | 11 - .../contract/RandomContractImpl.java | 43 -- .../jd/blockchain/contract/ReadContract.java | 15 - .../blockchain/contract/ReadContractImpl.java | 50 -- .../blockchain/contract/TransferContract.java | 17 - .../contract/TransferContractImpl.java | 109 ---- .../samples/contract/SampleContract.java | 77 +++ .../samples/contract/SampleContractImpl.java | 106 ++++ samples/pom.xml | 97 ++- samples/sdk-samples/pom.xml | 154 +++-- .../contract/ContractConfigure.java | 93 --- .../contract/samples/AssetContract.java | 35 -- .../contract/samples/AssetContract2.java | 53 -- .../contract/samples/AssetContractImpl.java | 173 ------ .../samples/SDKDemo_ActiveParticipant.java | 72 --- .../samples/SDKDemo_ConfigureSecurity.java | 94 --- .../sdk/samples/SDKDemo_Constant.java | 53 -- .../sdk/samples/SDKDemo_Contract.java | 153 ----- .../sdk/samples/SDKDemo_DataAccount.java | 81 --- .../samples/SDKDemo_DeactiveParticipant.java | 77 --- .../sdk/samples/SDKDemo_EventListener.java | 74 --- .../sdk/samples/SDKDemo_InsertData.java | 127 ---- .../sdk/samples/SDKDemo_Params.java | 46 -- .../sdk/samples/SDKDemo_PrivilegeSetting.java | 75 --- .../blockchain/sdk/samples/SDKDemo_Query.java | 85 --- .../samples/SDKDemo_RegistParticipant.java | 82 --- .../sdk/samples/SDKDemo_RegisterAccount.java | 54 -- .../sdk/samples/SDKDemo_RegisterTest.java | 39 -- .../sdk/samples/SDKDemo_RegisterUser.java | 83 --- .../sdk/samples/SDKDemo_Tx_Persistance.java | 109 ---- .../blockchain/sdk/samples/SDKDemo_User.java | 95 --- .../blockchain/sdk/samples/SDK_Base_Demo.java | 56 -- .../SDK_ConsensusSettings_Update_Demo.java | 42 -- .../sdk/samples/SDK_Contract_Check_Demo.java | 70 --- .../sdk/samples/SDK_Contract_Demo.java | 156 ----- .../sdk/samples/SDK_Contract_Random_Demo.java | 120 ---- .../sdk/samples/SDK_DataAccount_Demo.java | 49 -- .../sdk/samples/SDK_Event_Demo.java | 96 --- .../sdk/samples/SDK_InsertData_Demo.java | 120 ---- .../samples/SDK_RegistParticipant_Demo.java | 50 -- .../sdk/samples/SDK_RoleConfig_Demo.java | 26 - .../samples/SDK_Threads_KvInsert_Demo.java | 56 -- .../SDK_Update_ConsensusSettings_Demo.java | 42 -- .../sdk/samples/SDK_User2Role_Demo.java | 44 -- .../jd/chain/contracts/ContractTestInf.java | 14 - .../java/com/jdchain/samples/sdk/TestNet.java | 294 +++++++++ .../samples/sdk/testnet/GatewayRunner.java | 77 +++ .../samples/sdk/testnet/LedgerInit.java | 22 + .../samples/sdk/testnet/NodeWebContext.java | 105 ++++ .../jdchain/samples/sdk/testnet/PartNode.java | 58 ++ .../samples/sdk/testnet/PeerServer.java | 66 ++ .../src/main/resources/config.properties | 20 + .../src/main/resources/contract-jdchain.jar | Bin 4255 -> 0 bytes .../contract-samples-1.4.0.RELEASE.car | Bin 0 -> 3532 bytes .../main/resources/testnet/bftsmart.config | 155 +++++ .../testnet/ledger-binding-mem-0.conf | 23 + .../testnet/ledger-binding-mem-1.conf | 23 + .../testnet/ledger-binding-mem-2.conf | 23 + .../testnet/ledger-binding-mem-3.conf | 23 + .../src/main/resources/testnet/ledger.init | 74 +++ .../src/main/resources/transfer.jar | Bin 7167 -> 0 bytes .../jdchain/samples/sdk/ContractSample.java | 65 ++ .../samples/sdk/DataAccountSample.java | 88 +++ .../com/jdchain/samples/sdk/EventSample.java | 137 ++++ .../samples/sdk/ParticipantSample.java | 132 ++++ .../com/jdchain/samples/sdk/QuerySample.java | 587 ++++++++++++++++++ .../com/jdchain/samples/sdk/SampleBase.java | 60 ++ .../com/jdchain/samples/sdk/UserSample.java | 111 ++++ .../sdk/test/SDKDemo_Contract_Test_.java | 165 ----- .../sdk/test/SDK_Contract_Test.java | 384 ------------ .../SDK_GateWay_BatchInsertData_Test_.java | 138 ---- .../test/SDK_GateWay_DataAccount_Test_.java | 131 ---- .../test/SDK_GateWay_InsertData_Test_.java | 131 ---- .../sdk/test/SDK_GateWay_KeyPair_Para.java | 34 - .../SDK_GateWay_Participant_Regist_Test_.java | 100 --- .../sdk/test/SDK_GateWay_Query_Test_.java | 184 ------ .../sdk/test/SDK_GateWay_User_Test_.java | 151 ----- .../src/test/resources/contract.jar | Bin 7937 -> 0 bytes .../test/resources/sys-contract.properties | 13 - .../src/test/resources/transfer.jar | Bin 7118 -> 0 bytes 84 files changed, 2547 insertions(+), 4573 deletions(-) create mode 100644 samples/README.md delete mode 100644 samples/contract-samples/src/main/java/com/jd/blockchain/contract/ComplexContract.java delete mode 100644 samples/contract-samples/src/main/java/com/jd/blockchain/contract/ComplexContractImpl.java delete mode 100644 samples/contract-samples/src/main/java/com/jd/blockchain/contract/RandomContract.java delete mode 100644 samples/contract-samples/src/main/java/com/jd/blockchain/contract/RandomContractImpl.java delete mode 100644 samples/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java delete mode 100644 samples/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java delete mode 100644 samples/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContract.java delete mode 100644 samples/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContractImpl.java create mode 100644 samples/contract-samples/src/main/java/com/jdchain/samples/contract/SampleContract.java create mode 100644 samples/contract-samples/src/main/java/com/jdchain/samples/contract/SampleContractImpl.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/contract/ContractConfigure.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ActiveParticipant.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ConfigureSecurity.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Constant.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Contract.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_DataAccount.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_DeactiveParticipant.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_EventListener.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_InsertData.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Params.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_PrivilegeSetting.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegistParticipant.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterAccount.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterTest.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterUser.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Tx_Persistance.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_User.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Base_Demo.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_ConsensusSettings_Update_Demo.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Check_Demo.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Random_Demo.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_DataAccount_Demo.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Event_Demo.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_RegistParticipant_Demo.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_RoleConfig_Demo.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Threads_KvInsert_Demo.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Update_ConsensusSettings_Demo.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_User2Role_Demo.java delete mode 100644 samples/sdk-samples/src/main/java/com/jd/chain/contracts/ContractTestInf.java create mode 100644 samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/TestNet.java create mode 100644 samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/GatewayRunner.java create mode 100644 samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/LedgerInit.java create mode 100644 samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/NodeWebContext.java create mode 100644 samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/PartNode.java create mode 100644 samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/PeerServer.java create mode 100644 samples/sdk-samples/src/main/resources/config.properties delete mode 100644 samples/sdk-samples/src/main/resources/contract-jdchain.jar create mode 100644 samples/sdk-samples/src/main/resources/contract-samples-1.4.0.RELEASE.car create mode 100644 samples/sdk-samples/src/main/resources/testnet/bftsmart.config create mode 100644 samples/sdk-samples/src/main/resources/testnet/ledger-binding-mem-0.conf create mode 100644 samples/sdk-samples/src/main/resources/testnet/ledger-binding-mem-1.conf create mode 100644 samples/sdk-samples/src/main/resources/testnet/ledger-binding-mem-2.conf create mode 100644 samples/sdk-samples/src/main/resources/testnet/ledger-binding-mem-3.conf create mode 100644 samples/sdk-samples/src/main/resources/testnet/ledger.init delete mode 100644 samples/sdk-samples/src/main/resources/transfer.jar create mode 100644 samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/ContractSample.java create mode 100644 samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/DataAccountSample.java create mode 100644 samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/EventSample.java create mode 100644 samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/ParticipantSample.java create mode 100644 samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/QuerySample.java create mode 100644 samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/SampleBase.java create mode 100644 samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/UserSample.java delete mode 100644 samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDKDemo_Contract_Test_.java delete mode 100644 samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java delete mode 100644 samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_BatchInsertData_Test_.java delete mode 100644 samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_DataAccount_Test_.java delete mode 100644 samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_InsertData_Test_.java delete mode 100644 samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_KeyPair_Para.java delete mode 100644 samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Participant_Regist_Test_.java delete mode 100644 samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java delete mode 100644 samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_User_Test_.java delete mode 100644 samples/sdk-samples/src/test/resources/contract.jar delete mode 100644 samples/sdk-samples/src/test/resources/sys-contract.properties delete mode 100644 samples/sdk-samples/src/test/resources/transfer.jar diff --git a/samples/README.md b/samples/README.md new file mode 100644 index 00000000..3684e7e4 --- /dev/null +++ b/samples/README.md @@ -0,0 +1,60 @@ +## JD Chain Samples + +本项目为`JD Chain SDK`的使用样例,开发者可以参考此项目快速上手`JD Chain SDK`,主要包括[交易发送查询](#交易发送查询),[合约开发部署](#合约开发部署)两部分。 + +本项目提供了基于内存的`JD Chain`四节点+网关的网络环境启动程序[TestNet](/sdk-samples/src/main/java/com/jdchain/samples/sdk/TestNet.java),运行`TestNet`的`main`方法启动测试网络,等待日志输出:`START TESTNET SUCCESS`,网络启动成功会写入一些测试数据,可直接运行本项目提供的所有测试用例。 + +> `TestNet`测试网络默认会占用`8910`/`8920`/`8930`/`8940`/`8911`/`8921`/`8931`/`8941`用于共识服务,`12000`/`12010`/`12020`/`12030`用于四节点`API`服务端口,`11000`用于网关`API`服务端口,启动前请检查相关端口可用。 + + + +### 交易发送查询 + +相关代码放在[sdk-sample](/sdk-samples/src)下。 + +> 若并非使用`TestNet`启动的测试网络,开发者在运行本样例前,请根据实际环境修改[config.properties](/sdk-samples/src/main/resources/config.properties)中的网关配置,用户配置等信息。 + +#### 交易发送 + +参照[UserSample](/sdk-samples/src/test/java/com/jdchain/samples/sdk/UserSample.java)实现注册用户,配置用户角色权限功能; + +参照[DataAccountSample](/sdk-samples/src/test/java/com/jdchain/samples/sdk/DataAccountSample.java)实现注册数据账户,存储`KV`数据功能; + +参照[EventSample](/sdk-samples/src/test/java/com/jdchain/samples/sdk/EventSample.java)实现注册事件账户,发布事件,事件监听功能; + +参照[ContractSample](/sdk-samples/src/test/java/com/jdchain/samples/sdk/ContractSample.java)实现合约调用,非插件方式合约部署功能。 + +#### 数据查询 + +参照[QuerySample](/sdk-samples/src/test/java/com/jdchain/samples/sdk/QuerySample.java)实现对于区块链上数据查询功能。 + + + +### 合约开发部署 + +[contract-samples](/contract-samples/src)提供了通过合约注册用户,注册数据账户,注册事件账户,设置`KV`,发布事件的简单合约样例。 + +> 若并非使用`TestNet`启动的测试网络,开发者在运行本样例前,请根据实际环境修改[pom.xml](/contract-samples/pom.xml)中的网关配置,用户配置等信息。 + +修改相关代码,确认配置正确,`contract-samples`项目目录下命令行执行: + +- 合约打包 +```bash +mvn clean package +``` +可以生成`car`包,可以用于`SDK`方式合约部署。 + +- 合约部署 +```bash +mvn clean deploy +``` +可以直接部署合约上链。 + + + +### 了解更多 + +访问[JD Chain官网](http://ledger.jd.com/)查阅设计及文档。 +访问[github主页](https://github.com/blockchain-jd-com)阅读`JD Chain`源码并参与社区建设。 + +Thanks~ \ No newline at end of file diff --git a/samples/contract-samples/pom.xml b/samples/contract-samples/pom.xml index c032e9dd..550df7c7 100644 --- a/samples/contract-samples/pom.xml +++ b/samples/contract-samples/pom.xml @@ -4,73 +4,79 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.jd.blockchain - jdchain-samples - 1.4.0.RELEASE - + com.jd.blockchain + jdchain-samples + 1.4.0.RELEASE + - contract-samples + + contract + contract-samples contract-samples com.jd.blockchain - ledger-model - provided - - - - com.jd.blockchain - crypto-framework + contract-starter + ${framework.version} provided - - - com.alibaba - fastjson - - + - maven-assembly-plugin + org.apache.maven.plugins + maven-compiler-plugin - complex - false - - - com.jd.blockchain.contract.ComplexContractImpl - - - - jar-with-dependencies - + 1.8 + 1.8 + UTF-8 + false + true + false + false - - - make-assembly - package - - single - - - + - org.apache.maven.plugins - maven-deploy-plugin - 2.8.2 + com.jd.blockchain + contract-maven-plugin + ${framework.version} + true + + - true + + + + + + localhost + 11000 + + + + + + + + + + + + + 3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9 + 177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x + DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY + + - - diff --git a/samples/contract-samples/src/main/java/com/jd/blockchain/contract/ComplexContract.java b/samples/contract-samples/src/main/java/com/jd/blockchain/contract/ComplexContract.java deleted file mode 100644 index b23511f3..00000000 --- a/samples/contract-samples/src/main/java/com/jd/blockchain/contract/ComplexContract.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.jd.blockchain.contract; - -@Contract -public interface ComplexContract { - @ContractEvent(name = "read-key") - String read(String address, String key); -} diff --git a/samples/contract-samples/src/main/java/com/jd/blockchain/contract/ComplexContractImpl.java b/samples/contract-samples/src/main/java/com/jd/blockchain/contract/ComplexContractImpl.java deleted file mode 100644 index 15763954..00000000 --- a/samples/contract-samples/src/main/java/com/jd/blockchain/contract/ComplexContractImpl.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.jd.blockchain.contract; - - -import com.alibaba.fastjson.JSON; - -public class ComplexContractImpl implements ComplexContract { - @Override - public String read(String address, String key) { - String json = JSON.toJSONString(address); - return System.currentTimeMillis() + "" + json; - } -} diff --git a/samples/contract-samples/src/main/java/com/jd/blockchain/contract/RandomContract.java b/samples/contract-samples/src/main/java/com/jd/blockchain/contract/RandomContract.java deleted file mode 100644 index 3df56f82..00000000 --- a/samples/contract-samples/src/main/java/com/jd/blockchain/contract/RandomContract.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.jd.blockchain.contract; - -@Contract -public interface RandomContract { - - @ContractEvent(name = "random-put") - void put(String address, String key, String value); - - @ContractEvent(name = "random-putAndGet") - String putAndGet(String address, String key, String value); -} diff --git a/samples/contract-samples/src/main/java/com/jd/blockchain/contract/RandomContractImpl.java b/samples/contract-samples/src/main/java/com/jd/blockchain/contract/RandomContractImpl.java deleted file mode 100644 index 55f49661..00000000 --- a/samples/contract-samples/src/main/java/com/jd/blockchain/contract/RandomContractImpl.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.jd.blockchain.contract; - -import com.jd.blockchain.crypto.HashDigest; - -import java.util.Random; - -public class RandomContractImpl implements RandomContract, EventProcessingAware { - - private static final Random RANDOM_TIME = new Random(); - - private ContractEventContext eventContext; - - private HashDigest ledgerHash; - - @Override - public void beforeEvent(ContractEventContext eventContext) { - this.eventContext = eventContext; - this.ledgerHash = eventContext.getCurrentLedgerHash(); - } - - @Override - public void postEvent(ContractEventContext eventContext, Exception error) { - - } - - @Override - public void put(String address, String key, String value) { - - String saveVal = value + "-" + RANDOM_TIME.nextInt(1024); - - eventContext.getLedger().dataAccount(address).setText(key, saveVal, -1L); - } - - @Override - public String putAndGet(String address, String key, String value) { - - String saveVal = value + "-" + RANDOM_TIME.nextInt(1024); - - eventContext.getLedger().dataAccount(address).setText(key, saveVal, -1L); - - return address; - } -} diff --git a/samples/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java b/samples/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java deleted file mode 100644 index 25bc9aca..00000000 --- a/samples/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.jd.blockchain.contract; - - -@Contract -public interface ReadContract { - - @ContractEvent(name = "read-key") - String read(String address, String key); - - @ContractEvent(name = "version-key") - Long readVersion(String address, String key); - - int test(); -} - diff --git a/samples/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java b/samples/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java deleted file mode 100644 index 2f6e0610..00000000 --- a/samples/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.jd.blockchain.contract; - -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.TypedKVEntry; - -@Contract -public class ReadContractImpl implements EventProcessingAware, ReadContract { - - private ContractEventContext eventContext; - - private HashDigest ledgerHash; - - @Override - public void beforeEvent(ContractEventContext eventContext) { - this.eventContext = eventContext; - this.ledgerHash = eventContext.getCurrentLedgerHash(); - } - - @Override - public void postEvent(ContractEventContext eventContext, Exception error) { - - } - - @Override - @ContractEvent(name = "read-key") - public String read(String address, String key) { - TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, key); - - if (kvDataEntries != null && kvDataEntries.length == 1) { - return kvDataEntries[0].getValue().toString(); - } - return null; - } - - @Override - @ContractEvent(name = "version-key") - public Long readVersion(String address, String key) { - TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, key); - - if (kvDataEntries != null && kvDataEntries.length == 1) { - return kvDataEntries[0].getVersion(); - } - return -1L; - } - - @Override - public int test() { - return 0; - } -} diff --git a/samples/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContract.java b/samples/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContract.java deleted file mode 100644 index 321101a3..00000000 --- a/samples/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContract.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.jd.blockchain.contract; - -@Contract -public interface TransferContract { - - @ContractEvent(name = "create") - String create(String address, String account, long money); - - @ContractEvent(name = "transfer") - String transfer(String address, String from, String to, long money); - - @ContractEvent(name = "read") - long read(String address, String account); - - @ContractEvent(name = "readAll") - String readAll(String address, String account); -} diff --git a/samples/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContractImpl.java b/samples/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContractImpl.java deleted file mode 100644 index d29ee281..00000000 --- a/samples/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContractImpl.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.jd.blockchain.contract; - -import com.alibaba.fastjson.JSON; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.TypedKVEntry; -import com.jd.blockchain.ledger.KVDataVO; -import com.jd.blockchain.ledger.KVInfoVO; - -public class TransferContractImpl implements EventProcessingAware, TransferContract { - - private ContractEventContext eventContext; - - private HashDigest ledgerHash; - - @Override - public String create(String address, String account, long money) { - TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); - // 肯定有返回值,但若不存在则返回version=-1 - if (kvDataEntries != null && kvDataEntries.length > 0) { - long currVersion = kvDataEntries[0].getVersion(); - if (currVersion > -1) { - throw new IllegalStateException(String.format("%s -> %s already have created !!!", address, account)); - } - eventContext.getLedger().dataAccount(address).setInt64(account, money, -1L); - } else { - throw new IllegalStateException(String.format("Ledger[%s] inner Error !!!", ledgerHash.toBase58())); - } - return String.format("DataAccountAddress[%s] -> Create(By Contract Operation) Account = %s and Money = %s Success!!! \r\n", - address, account, money); - } - - @Override - public String transfer(String address, String from, String to, long money) { - // 首先查询余额 - TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, from, to); - if (kvDataEntries == null || kvDataEntries.length != 2) { - throw new IllegalStateException(String.format("%s -> %s - %s may be not created !!!", address, from, to)); - } else { - // 判断from账号中钱数量是否足够 - long fromMoney = 0L, toMoney = 0L, fromVersion = 0L, toVersion = 0L; - for (TypedKVEntry kvDataEntry : kvDataEntries) { - if (kvDataEntry.getKey().equals(from)) { - fromMoney = (long) kvDataEntry.getValue(); - fromVersion = kvDataEntry.getVersion(); - } else { - toMoney = (long) kvDataEntry.getValue(); - toVersion = kvDataEntry.getVersion(); - } - } - if (fromMoney < money) { - throw new IllegalStateException(String.format("%s -> %s not have enough money !!!", address, from)); - } - long fromNewMoney = fromMoney - money; - long toNewMoney = toMoney + money; - // 重新设置 - eventContext.getLedger().dataAccount(address).setInt64(from, fromNewMoney, fromVersion); - eventContext.getLedger().dataAccount(address).setInt64(to, toNewMoney, toVersion); - } - - return String.format("DataAccountAddress[%s] transfer from [%s] to [%s] and [money = %s] Success !!!", address, from, to, money); - } - - @Override - public long read(String address, String account) { - TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); - if (kvDataEntries == null || kvDataEntries.length == 0) { - return -1; - } - return (long)kvDataEntries[0].getValue(); - } - - @Override - public String readAll(String address, String account) { - TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); - // 获取最新的版本号 - if (kvDataEntries == null || kvDataEntries.length == 0) { - return ""; - } - long newestVersion = kvDataEntries[0].getVersion(); - if (newestVersion == -1) { - return ""; - } - KVDataVO[] kvDataVOS = new KVDataVO[1]; - long[] versions = new long[(int)newestVersion + 1]; - for (int i = 0; i < versions.length; i++) { - versions[i] = i; - } - KVDataVO kvDataVO = new KVDataVO(account, versions); - - kvDataVOS[0] = kvDataVO; - - KVInfoVO kvInfoVO = new KVInfoVO(kvDataVOS); - - TypedKVEntry[] allEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, kvInfoVO); - - return JSON.toJSONString(allEntries); - } - - @Override - public void beforeEvent(ContractEventContext eventContext) { - this.eventContext = eventContext; - this.ledgerHash = eventContext.getCurrentLedgerHash(); - } - - @Override - public void postEvent(ContractEventContext eventContext, Exception error) { - - } -} diff --git a/samples/contract-samples/src/main/java/com/jdchain/samples/contract/SampleContract.java b/samples/contract-samples/src/main/java/com/jdchain/samples/contract/SampleContract.java new file mode 100644 index 00000000..1493bd92 --- /dev/null +++ b/samples/contract-samples/src/main/java/com/jdchain/samples/contract/SampleContract.java @@ -0,0 +1,77 @@ +package com.jdchain.samples.contract; + +import com.jd.blockchain.contract.Contract; +import com.jd.blockchain.contract.ContractEvent; + +/** + * 合约样例,提供通过合约创建用户/数据账户/事件账户,写入KV,发布事件等功能 + */ +@Contract +public interface SampleContract { + + /** + * 设置KV + * + * @param address 数据账户地址 + * @param key 键 + * @param value 值 + * @param version 版本 + */ + @ContractEvent(name = "setKVWithVersion") + void setKVWithVersion(String address, String key, String value, long version); + + /** + * 设置KV,基于最新数据版本 + * + * @param address 数据账户地址 + * @param key 键 + * @param value 值 + */ + @ContractEvent(name = "setKV") + void setKV(String address, String key, String value); + + /** + * 注册用户 + * + * @param seed 种子,不小于32个字符 + */ + @ContractEvent(name = "registerUser") + String registerUser(String seed); + + /** + * 注册数据账户 + * + * @param seed 种子,不小于32个字符 + */ + @ContractEvent(name = "registerDataAccount") + String registerDataAccount(String seed); + + /** + * 注册事件账户 + * + * @param seed 种子,不小于32个字符 + */ + @ContractEvent(name = "registerEventAccount") + String registerEventAccount(String seed); + + /** + * 发布事件 + * + * @param address 事件账户地址 + * @param topic 消息名称 + * @param content 内容 + * @param sequence 当前消息名称下最大序号(初始为-1) + */ + @ContractEvent(name = "publishEventWithSequence") + void publishEventWithSequence(String address, String topic, String content, long sequence); + + /** + * 发布事件,基于最新时间序号 + * + * @param address 事件账户地址 + * @param topic 消息名称 + * @param content 内容 + */ + @ContractEvent(name = "publishEvent") + void publishEvent(String address, String topic, String content); +} diff --git a/samples/contract-samples/src/main/java/com/jdchain/samples/contract/SampleContractImpl.java b/samples/contract-samples/src/main/java/com/jdchain/samples/contract/SampleContractImpl.java new file mode 100644 index 00000000..b4492707 --- /dev/null +++ b/samples/contract-samples/src/main/java/com/jdchain/samples/contract/SampleContractImpl.java @@ -0,0 +1,106 @@ +package com.jdchain.samples.contract; + +import com.jd.blockchain.contract.ContractEventContext; +import com.jd.blockchain.contract.EventProcessingAware; +import com.jd.blockchain.crypto.AsymmetricKeypair; +import com.jd.blockchain.crypto.Crypto; +import com.jd.blockchain.crypto.CryptoAlgorithm; +import com.jd.blockchain.crypto.SignatureFunction; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.Event; +import com.jd.blockchain.ledger.TypedKVEntry; +import com.jd.blockchain.utils.Bytes; + +/** + * 合约样例实现 + */ +public class SampleContractImpl implements EventProcessingAware, SampleContract { + + private ContractEventContext eventContext; + + @Override + public void setKVWithVersion(String address, String key, String value, long version) { + eventContext.getLedger().dataAccount(Bytes.fromBase58(address)).setText(key, value, version); + } + + @Override + public void setKV(String address, String key, String value) { + // 查询最新版本,初始为-1 + TypedKVEntry[] entries = eventContext.getLedger().getDataEntries(eventContext.getCurrentLedgerHash(), address, key); + long version = -1; + if (null != entries && entries.length > 0) { + version = entries[0].getVersion(); + } + eventContext.getLedger().dataAccount(Bytes.fromBase58(address)).setText(key, value, version); + } + + @Override + public String registerUser(String seed) { + CryptoAlgorithm algorithm = Crypto.getAlgorithm("ed25519"); + SignatureFunction signFunc = Crypto.getSignatureFunction(algorithm); + AsymmetricKeypair cryptoKeyPair = signFunc.generateKeypair(seed.getBytes()); + BlockchainKeypair keypair = new BlockchainKeypair(cryptoKeyPair.getPubKey(), cryptoKeyPair.getPrivKey()); + eventContext.getLedger().users().register(keypair.getIdentity()); + + return keypair.getAddress().toBase58(); + } + + @Override + public String registerDataAccount(String seed) { + CryptoAlgorithm algorithm = Crypto.getAlgorithm("ed25519"); + SignatureFunction signFunc = Crypto.getSignatureFunction(algorithm); + AsymmetricKeypair cryptoKeyPair = signFunc.generateKeypair(seed.getBytes()); + BlockchainKeypair keypair = new BlockchainKeypair(cryptoKeyPair.getPubKey(), cryptoKeyPair.getPrivKey()); + eventContext.getLedger().dataAccounts().register(keypair.getIdentity()); + + return keypair.getAddress().toBase58(); + } + + @Override + public String registerEventAccount(String seed) { + CryptoAlgorithm algorithm = Crypto.getAlgorithm("ed25519"); + SignatureFunction signFunc = Crypto.getSignatureFunction(algorithm); + AsymmetricKeypair cryptoKeyPair = signFunc.generateKeypair(seed.getBytes()); + BlockchainKeypair keypair = new BlockchainKeypair(cryptoKeyPair.getPubKey(), cryptoKeyPair.getPrivKey()); + eventContext.getLedger().eventAccounts().register(keypair.getIdentity()); + + return keypair.getAddress().toBase58(); + } + + @Override + public void publishEventWithSequence(String address, String topic, String content, long sequence) { + eventContext.getLedger().eventAccount(Bytes.fromBase58(address)).publish(topic, content, sequence); + } + + @Override + public void publishEvent(String address, String topic, String content) { + // 查询最新序号,初始为-1 + Event event = eventContext.getLedger().getLatestEvent(eventContext.getCurrentLedgerHash(), address, topic); + long sequence = -1; + if (null != event) { + sequence = event.getSequence(); + } + eventContext.getLedger().eventAccount(Bytes.fromBase58(address)).publish(topic, content, sequence); + } + + /** + * 合约方法调用前操作 + * + * @param eventContext + */ + @Override + public void beforeEvent(ContractEventContext eventContext) { + this.eventContext = eventContext; + } + + /** + * 合约方法调用后操作 + * + * @param eventContext + * @param error + */ + @Override + public void postEvent(ContractEventContext eventContext, Exception error) { + + } +} diff --git a/samples/pom.xml b/samples/pom.xml index fe6c9688..6f761cd8 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -1,65 +1,40 @@ - 4.0.0 - - com.jd.blockchain - jdchain-parent - 1.1.4.RELEASE - ../project/parent - - - com.jd.blockchain - jdchain-samples - 1.4.0.RELEASE - pom - - - 1.4.0.RELEASE - - - - ../framework - sdk-samples - contract-samples - - - - - - - com.jd.blockchain - sdk-client - ${framework.version} - - - com.jd.blockchain - ledger-model - ${framework.version} - - - com.jd.blockchain - crypto-framework - ${framework.version} - - - com.jd.blockchain - crypto-classic - ${framework.version} - - - com.jd.blockchain - crypto-sm - ${framework.version} - - - com.jd.blockchain - crypto-base - ${framework.version} - - - - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + com.jd.blockchain + jdchain-samples + 1.4.0.RELEASE + pom + + + 1.4.0.RELEASE + + + + sdk-samples + contract-samples + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + UTF-8 + false + true + false + false + + + + diff --git a/samples/sdk-samples/pom.xml b/samples/sdk-samples/pom.xml index 3bedbf3e..aae79347 100644 --- a/samples/sdk-samples/pom.xml +++ b/samples/sdk-samples/pom.xml @@ -1,83 +1,79 @@ - 4.0.0 - - com.jd.blockchain - jdchain-samples - 1.4.0.RELEASE - - sdk-samples + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + com.jd.blockchain + jdchain-samples + 1.4.0.RELEASE + + sdk-samples - - - com.jd.blockchain - sdk-client - - - com.jd.blockchain - ledger-model - - - com.jd.blockchain - crypto-classic - - - com.jd.blockchain - crypto-framework - - - com.jd.blockchain - crypto-sm - - - com.jd.blockchain - contract-samples - ${project.version} - - - com.jd.blockchain - crypto-base - 1.4.0.RELEASE - - - com.jd.blockchain - crypto-framework - ${framework.version} - - - com.jd.blockchain - crypto-classic - ${framework.version} - - - com.jd.blockchain - crypto-sm - ${framework.version} - - - com.jd.blockchain - crypto-utils-classic - ${framework.version} - - + + + + com.jd.blockchain + sdk-client + ${framework.version} + - - - - org.apache.maven.plugins - maven-deploy-plugin - - true - - - - - - - - - - - + + com.jd.blockchain + sdk-rpc + ${framework.version} + + + + com.jd.blockchain + crypto-classic + ${framework.version} + + + + com.jd.blockchain + ledger-model + ${framework.version} + + + + + com.jd.blockchain + contract-samples + ${framework.version} + + + + + org.reflections + reflections + 0.9.12 + + + com.jd.blockchain + tools-initializer + ${framework.version} + + + com.jd.blockchain + peer + ${framework.version} + + + com.jd.blockchain + utils-common + ${framework.version} + + + com.jd.blockchain + gateway + ${framework.version} + + + + + junit + junit + 4.12 + + \ No newline at end of file diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/contract/ContractConfigure.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/contract/ContractConfigure.java deleted file mode 100644 index 61dbb10c..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/contract/ContractConfigure.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.jd.blockchain.contract; - -import com.jd.blockchain.utils.BaseConstant; -import com.jd.blockchain.utils.ConsoleUtils; -import com.jd.blockchain.utils.io.FileUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.ClassPathResource; - -import java.io.*; -import java.util.*; - -import static com.jd.blockchain.utils.BaseConstant.SYS_CONTRACT_CONF; -import static com.jd.blockchain.utils.BaseConstant.SYS_CONTRACT_PROPS_NAME; - -/** - * - * @author zhaogw - * date 2019/3/15 18:22 - */ -public enum ContractConfigure { - instance(); - private static final Logger LOGGER = LoggerFactory.getLogger(ContractConfigure.class); - static Properties pp; - - ContractConfigure(){ - init(); - } - - private void init(){ - String contractConfPath = System.getProperty(SYS_CONTRACT_CONF); - System.out.println("contractConfPath="+contractConfPath); - try { - if (contractConfPath == null) { - ConsoleUtils.info("Load build-in default contractConf in ContractConfigure ..."); - ClassPathResource contractConfigResource = new ClassPathResource(SYS_CONTRACT_PROPS_NAME); - InputStream in = contractConfigResource.getInputStream(); - pp = FileUtils.readProperties(in, BaseConstant.CHARSET_UTF_8); - } else { - ConsoleUtils.info("Load configuration in ContractConfigure,contractConfPath="+contractConfPath); - File file = new File(contractConfPath); - pp = FileUtils.readProperties(file, BaseConstant.CHARSET_UTF_8); - } - } catch (Exception e) { - LOGGER.info(SYS_CONTRACT_PROPS_NAME+"文件异常!"+e.getMessage()); - } - } - - public String values(String key) { - if(pp == null){ - init(); - } - return pp.getProperty(key); - } - - public String allValues() { - if(pp == null){ - init(); - } - Set allKeys = pp.stringPropertyNames(); - List propList = new ArrayList(); - for(String _key : allKeys){ - String value = pp.getProperty(_key); - propList.add(_key+": "+value); - LOGGER.info("key={}, value={}",_key,value); - } - return propList.toString(); - } - - //写入资源文件信息 - public static void writeProperties(String fileAllName, String comments, Map map){ - Properties properties=new Properties(); - try { - File file = new File(fileAllName); - if (!file.getParentFile().exists()) { - boolean result = file.getParentFile().mkdirs(); - if (!result) { - System.out.println("文件创建失败."); - } - } - OutputStream outputStream=new FileOutputStream(file); - for(Map.Entry entry : map.entrySet()){ - properties.setProperty(entry.getKey(), entry.getValue()); - } - properties.store(outputStream, comments); - outputStream.close(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract.java deleted file mode 100644 index 065e86d2..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.jd.blockchain.contract.samples; - -import com.jd.blockchain.contract.Contract; -import com.jd.blockchain.contract.ContractEvent; - -/** - * 示例:一个“资产管理”智能合约; - * - * @author huanghaiquan - * - */ -@Contract -public interface AssetContract { - - /** - * 发行资产; - * - * @param amount 新发行的资产数量; - * @param assetHolderAddress 新发行的资产的持有账户; - */ - @ContractEvent(name = "issue-asset") - void issue(long amount, String assetHolderAddress); - - /** - * 转移资产 - * - * @param fromAddress 转出账户; - * @param toAddress 转入账户; - * @param amount 转移的资产数额; - * @return 返回转出账户的余额; - */ - @ContractEvent(name = "transfer-asset") - long transfer(String fromAddress, String toAddress, long amount); - -} \ No newline at end of file diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java deleted file mode 100644 index 8af3a729..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java +++ /dev/null @@ -1,53 +0,0 @@ -//package com.jd.blockchain.contract.samples; -// -//import com.jd.blockchain.binaryproto.DataContract; -//import com.jd.blockchain.consts.DataCodes; -//import com.jd.blockchain.contract.Contract; -//import com.jd.blockchain.contract.ContractEvent; -//import com.jd.blockchain.ledger.ContractBizContent; -//import com.jd.blockchain.ledger.TransactionContentBody; -//import com.jd.blockchain.utils.Bytes; -// -//import java.math.BigDecimal; -// -///** -// * 示例:一个“资产管理”智能合约; -// * -// * @author zhaogw -// */ -//@Contract -//public interface AssetContract2 { -// -// /** -// * 发行资产; -// * 新发行的资产数量; -// * @param assetHolderAddress -// * 新发行的资产的持有账户; -// */ -// @ContractEvent(name = "issue-asset-0") -// void issue(ContractBizContent contractBizContent, String assetHolderAddress); -// -// /** -// * issue asset; -// * @param contractBizContent -// * @param assetHolderAddress -// * @param cashNumber -// */ -// @ContractEvent(name = "issue-asset") -// public void issue(ContractBizContent contractBizContent, String assetHolderAddress, long cashNumber); -// -// /** -// * Bytes can bring the byte[]; -// * @param bytes -// * @param assetHolderAddress -// * @param cashNumber -// */ -// @ContractEvent(name = "issue-asset-2") -// void issue(Bytes bytes,String assetHolderAddress, long cashNumber); -// -// @ContractEvent(name = "issue-asset-3") -// void issue(Byte bytes, String assetHolderAddress, long cashNumber); -// -// @ContractEvent(name = "issue-asset-4") -// void issue(Byte byteObj, String assetHolderAddress, Bytes cashNumber); -//} \ No newline at end of file diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl.java deleted file mode 100644 index 1782d985..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl.java +++ /dev/null @@ -1,173 +0,0 @@ -package com.jd.blockchain.contract.samples; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import com.jd.blockchain.contract.ContractEventContext; -import com.jd.blockchain.contract.ContractException; -import com.jd.blockchain.contract.EventProcessingAware; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.BlockchainIdentity; -import com.jd.blockchain.ledger.TypedKVEntry; -import com.jd.blockchain.ledger.TypedKVData; -import com.jd.blockchain.utils.Bytes; - -/** - * 示例:一个“资产管理”智能合约的实现; - * - * 注: 1、实现 EventProcessingAwire 接口以便合约实例在运行时可以从上下文获得合约生命周期事件的通知; 2、实现 - * AssetContract 接口定义的合约方法; - * - * @author huanghaiquan - * - */ -public class AssetContractImpl implements EventProcessingAware, AssetContract { - // 资产管理账户的地址; - private static final String ASSET_ADDRESS = "2njZBNbFQcmKd385DxVejwSjy4driRzf9Pk"; - // 保存资产总数的键; - private static final String KEY_TOTAL = "TOTAL"; - // 合约事件上下文; - private ContractEventContext eventContext; - - /** - * ------------------- 定义可以由外部用户通过提交“交易”触发的调用方法 ------------------ - */ - - @Override - public void issue(long amount, String assetHolderAddress) { - checkAllOwnersAgreementPermission(); - - // 新发行的资产数量; - if (amount < 0) { - throw new ContractException("The amount is negative!"); - } - if (amount == 0) { - return; - } - - // 查询当前值; - TypedKVEntry[] kvEntries = eventContext.getLedger().getDataEntries(currentLedgerHash(), ASSET_ADDRESS, KEY_TOTAL, - assetHolderAddress); - - // 计算资产的发行总数; - TypedKVData currTotal = (TypedKVData) kvEntries[0]; - long newTotal = currTotal.longValue() + amount; - eventContext.getLedger().dataAccount(ASSET_ADDRESS).setInt64(KEY_TOTAL, newTotal, currTotal.getVersion()); - - // 分配到持有者账户; - TypedKVData holderAmount = (TypedKVData) kvEntries[1]; - long newHodlerAmount = holderAmount.longValue() + amount; - eventContext.getLedger().dataAccount(ASSET_ADDRESS) - .setInt64(assetHolderAddress, newHodlerAmount, holderAmount.getVersion()).setText("K2", "info2", -1) - .setText("k3", "info3", 3); - - } - - @Override - public long transfer(String fromAddress, String toAddress, long amount) { - if (amount < 0) { - throw new ContractException("The amount is negative!"); - } - if (amount > 20000) { - throw new ContractException("The amount exceeds the limit of 20000!"); - } - - // 校验“转出账户”是否已签名; - checkSignerPermission(fromAddress); - - // 查询现有的余额; - TypedKVEntry[] origBalances = eventContext.getLedger().getDataEntries(currentLedgerHash(), ASSET_ADDRESS, - fromAddress, toAddress); - TypedKVEntry fromBalanceKV = origBalances[0]; - TypedKVEntry toBalanceKV = origBalances[1]; - long fromBalance = fromBalanceKV.getVersion() == -1 ? 0 : (long) fromBalanceKV.getValue(); - long toBalance = toBalanceKV.getVersion() == -1 ? 0 : (long) toBalanceKV.getValue(); - - // 检查是否余额不足; - - if ((fromBalance - amount) < 0) { - throw new ContractException("The balance is insufficient and the transfer failed!"); - } - fromBalance = fromBalance + amount; - toBalance = toBalance + amount; - - // 把数据的更改写入到账本; - eventContext.getLedger().dataAccount(fromAddress).setInt64(ASSET_ADDRESS, fromBalance, fromBalanceKV.getVersion()); - eventContext.getLedger().dataAccount(toAddress).setInt64(ASSET_ADDRESS, toBalance, toBalanceKV.getVersion()); - - return -1; - } - - // ------------------------------------------------------------- - // ------------------- 定义只在合约内部调用的方法 ------------------ - // ------------------------------------------------------------- - - /** - * 只有全部的合约拥有者同意才能通过校验; - */ - private void checkAllOwnersAgreementPermission() { - Set owners = eventContext.getContracOwners(); - Set requestors = eventContext.getTxSigners(); - if (requestors.size() != owners.size()) { - throw new ContractException("Permission Error! -- The requestors is not exactlly being owners!"); - } - - Map ownerMap = new HashMap<>(); - for (BlockchainIdentity o : owners) { - ownerMap.put(o.getAddress(), o); - } - for (BlockchainIdentity r : requestors) { - if (!ownerMap.containsKey(r.getAddress())) { - throw new ContractException("Permission Error! -- No agreement of all owners!"); - } - } - } - - private HashDigest currentLedgerHash() { - return eventContext.getCurrentLedgerHash(); - } - - /** - * 校验指定的账户是否签署了当前交易; - * - * @param address - */ - private void checkSignerPermission(String address) { - Set requestors = eventContext.getTxSigners(); - for (BlockchainIdentity r : requestors) { - if (r.getAddress().equals(address)) { - return; - } - } - throw new ContractException("Permission Error! -- No signature !"); - } - - // ---------------------------------------------------------- - // ------------------- 在运行时捕捉上下文事件 ------------------ - // ---------------------------------------------------------- - - /* - * (non-Javadoc) - * - * @see - * com.jd.blockchain.contract.model.EventProcessingAwire#beforeEvent(com.jd. - * blockchain.contract.model.ContractEventContext) - */ - @Override - public void beforeEvent(ContractEventContext eventContext) { - this.eventContext = eventContext; - } - - /* - * (non-Javadoc) - * - * @see com.jd.blockchain.contract.model.EventProcessingAwire#postEvent(com.jd. - * blockchain.contract.model.ContractEventContext, - * com.jd.blockchain.contract.model.ContractError) - */ - @Override - public void postEvent(ContractEventContext eventContext, Exception error) { - this.eventContext = null; - } -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ActiveParticipant.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ActiveParticipant.java deleted file mode 100644 index 47aba604..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ActiveParticipant.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.utils.http.converters.JsonResponseConverter; -import com.jd.blockchain.utils.web.model.WebResponse; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.message.BasicNameValuePair; - -import java.util.ArrayList; -import java.util.List; - -/** - * @Author: zhangshuang - * @Date: 2020/5/27 5:18 PM - * Version 1.0 - */ -public class SDKDemo_ActiveParticipant { - - // 接受激活参与方操作的共识节点Http服务地址, 根据具体环境配置进行修改 - private static String httpIp = "127.0.0.1"; - private static String httpPort = "7080"; - - public static void main(String[] args) { - - String url = "http://" + httpIp + ":" + httpPort + "/management/delegate/activeparticipant"; - - System.out.println("url = " + url); - - HttpPost httpPost = new HttpPost(url); - - List para=new ArrayList(); - - // 账本值根据具体情况进行修改 - BasicNameValuePair base58LedgerHash = new BasicNameValuePair("ledgerHash", "j5tuvAR3Q6ATsMNYTwt7SxVeCqd73itQbpmePxzSg6Zsxc"); - - // 激活的新参与方的共识网络地址 - BasicNameValuePair host = new BasicNameValuePair("consensusHost", "127.0.0.1"); - BasicNameValuePair port = new BasicNameValuePair("consensusPort", "16000"); - - // 指定已经启动的其他共识节点的HTTP管理端口 - BasicNameValuePair manageHost = new BasicNameValuePair("remoteManageHost", "127.0.0.1"); - BasicNameValuePair managePort = new BasicNameValuePair("remoteManagePort", "7083"); - - para.add(base58LedgerHash); - para.add(host); - para.add(port); - para.add(manageHost); - para.add(managePort); - - try { - httpPost.setEntity(new UrlEncodedFormEntity(para,"UTF-8")); - HttpClient httpClient = HttpClients.createDefault(); - - HttpResponse response = httpClient.execute(httpPost); - JsonResponseConverter jsonConverter = new JsonResponseConverter(WebResponse.class); - - WebResponse webResponse = (WebResponse) jsonConverter.getResponse(null, response.getEntity().getContent(), null); - System.out.println("response result = " + webResponse.isSuccess()); - if (!webResponse.isSuccess()) { - System.out.println("error msg = " + webResponse.getError().getErrorMessage()); - } - - - } catch (Exception e) { - e.printStackTrace(); - System.out.println("Active participant post request error!"); - } - } -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ConfigureSecurity.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ConfigureSecurity.java deleted file mode 100644 index fc1fad1d..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_ConfigureSecurity.java +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Copyright: Copyright 2016-2020 JD.COM All Right Reserved - * FileName: com.jd.blockchain.sdk.samples.SDKDemo_RegisterUser - * Author: shaozhuguang - * Department: 区块链研发部 - * Date: 2018/10/18 下午2:00 - * Description: 注册用户 - */ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.PrivKey; -import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.*; -import com.jd.blockchain.sdk.BlockchainService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.utils.ConsoleUtils; - -/** - * 注册用户 - * - * @author shaozhuguang - * @create 2018/10/18 - * @since 1.0.0 - */ - -public class SDKDemo_ConfigureSecurity { - public static void main(String[] args) { - - String GATEWAY_IPADDR = "127.0.0.1"; - int GATEWAY_PORT = 8081; - if (args != null && args.length == 2) { - GATEWAY_IPADDR = args[0]; - GATEWAY_PORT = Integer.parseInt(args[1]); - } - - // 注册相关class - DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(TransactionResponse.class); - - PrivKey privKey = SDKDemo_Params.privkey1; - PubKey pubKey = SDKDemo_Params.pubKey1; - - BlockchainKeypair CLIENT_CERT = new BlockchainKeypair(SDKDemo_Params.pubKey0, SDKDemo_Params.privkey0); - - boolean SECURE = false; - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IPADDR, GATEWAY_PORT, SECURE, - CLIENT_CERT); - BlockchainService service = serviceFactory.getBlockchainService(); - - HashDigest[] ledgerHashs = service.getLedgerHashs(); - // 在本地定义注册账号的 TX; - TransactionTemplate txTemp = service.newTransaction(ledgerHashs[0]); - - // existed signer - AsymmetricKeypair signer = getSigner(); - - BlockchainKeypair user = BlockchainKeyGenerator.getInstance().generate(); - - // 注册 - txTemp.users().register(user.getIdentity()); - - txTemp.security().roles() - .configure("ADMIN") - .enable(LedgerPermission.REGISTER_USER, LedgerPermission.REGISTER_DATA_ACCOUNT) - .enable(TransactionPermission.DIRECT_OPERATION) - .configure("GUEST") - .enable(TransactionPermission.CONTRACT_OPERATION); - - txTemp.security().authorziations() - .forUser(user.getIdentity()) - .authorize("ADMIN", "MANAGER") - .forUser(CLIENT_CERT.getAddress()) - .authorize("GUEST"); - - // TX 准备就绪; - PreparedTransaction prepTx = txTemp.prepare(); - - // 使用私钥进行签名; - prepTx.sign(signer); - - // 提交交易; - TransactionResponse transactionResponse = prepTx.commit(); - - ConsoleUtils.info("register user complete, result is [%s]", transactionResponse.isSuccess()); - } - - private static AsymmetricKeypair getSigner() { - return new BlockchainKeypair(SDKDemo_Params.pubKey1, SDKDemo_Params.privkey1); - } -} \ No newline at end of file diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Constant.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Constant.java deleted file mode 100644 index 317f564b..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Constant.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import org.apache.commons.io.FileUtils; -import org.springframework.core.io.ClassPathResource; - -import java.io.File; - -public class SDKDemo_Constant { - - public static final String GW_IPADDR = "jdchain-cloud0-8080.jdfmgt.com"; -// public static final String GW_IPADDR = "192.168.151.41"; - - public static final int GW_PORT = 80; -// public static final int GW_PORT = 18081; - - public static final String[] PUB_KEYS = { - "3snPdw7i7Pf2u9KTNUhxrYxgEymH24zP3NNNauRVwX5yDD6rzu2uBY", - "3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX", - "3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x", - "3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk"}; - - public static final String[] PRIV_KEYS = { - "177gjy71kcL5pU2YayqeZ44AfE87o8b5PfLeBER1rjsjViGux3TzdLcQs7QEznRMCw2sAHD", - "177gju9p5zrNdHJVEQnEEKF4ZjDDYmAXyfG84V5RPGVc5xFfmtwnHA7j51nyNLUFffzz5UT", - "177gjtwLgmSx5v1hFb46ijh7L9kdbKUpJYqdKVf9afiEmAuLgo8Rck9yu5UuUcHknWJuWaF", - "177gk1pudweTq5zgJTh8y3ENCTwtSFsKyX7YnpuKPo7rKgCkCBXVXh5z2syaTCPEMbuWRns"}; - - -// public static final String[] PUB_KEYS = { -// "3snPdw7i7PXvEDgq96QyzcKhfWL4mgYspzKwvgXiuAidWb2rkRMgDY", -// "3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX", -// "3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x", -// "3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk"}; -// -// public static final String[] PRIV_KEYS = { -// "177gjsxj2ezADGthZ4tGqWeCAqRAwtNvesPjRnyKqCb1huU8LKZmJ3HGZNMPKWQJK3DP1B2", -// "177gju9p5zrNdHJVEQnEEKF4ZjDDYmAXyfG84V5RPGVc5xFfmtwnHA7j51nyNLUFffzz5UT", -// "177gjtwLgmSx5v1hFb46ijh7L9kdbKUpJYqdKVf9afiEmAuLgo8Rck9yu5UuUcHknWJuWaF", -// "177gk1pudweTq5zgJTh8y3ENCTwtSFsKyX7YnpuKPo7rKgCkCBXVXh5z2syaTCPEMbuWRns"}; - - public static final String PASSWORD = "abc"; - - public static final byte[] readChainCodes(String contractZip) { - // 构建合约的字节数组; - try { - ClassPathResource contractPath = new ClassPathResource(contractZip); - File contractFile = new File(contractPath.getURI()); - return FileUtils.readFileToByteArray(contractFile); - } catch (Exception e) { - throw new IllegalStateException(e); - } - } -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Contract.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Contract.java deleted file mode 100644 index 06ec1801..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Contract.java +++ /dev/null @@ -1,153 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.contract.samples.AssetContract; -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.Crypto; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.SignatureFunction; -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionTemplate; -import com.jd.blockchain.sdk.BlockchainService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.transaction.ContractReturnValue; -import com.jd.blockchain.transaction.LongValueHolder; -import com.jd.blockchain.utils.io.ByteArray; -import com.jd.blockchain.utils.net.NetworkAddress; -import com.jd.blockchain.utils.serialize.json.JSONSerializeUtils; - -/** - * 演示合约执行的过程; - * - * @author huanghaiquan - * - */ -public class SDKDemo_Contract { - - public static BlockchainKeypair CLIENT_CERT = BlockchainKeyGenerator.getInstance().generate("ED25519"); - - public static void main(String[] args) { - demoContract(); - } - - /** - * 演示合约执行的过程; - */ - public static void demoContract() { - // 账本地址; - String ledgerAddress = "j5rpuGWVxSuUbU3gK7MDREfui797AjfdHzvAMiSaSzydu7"; - // 节点地址列表; -// NetworkAddress[] peerAddrs = { new NetworkAddress("192.168.10.10", 8080), -// new NetworkAddress("192.168.10.11", 8080), new NetworkAddress("192.168.10.12", 8080), -// new NetworkAddress("192.168.10.13", 8080) }; - - // 创建服务代理; - final String GATEWAY_IP = "localhost"; - final int GATEWAY_PORT = 11000; - final boolean SECURE = false; - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IP, GATEWAY_PORT, SECURE, - CLIENT_CERT); - BlockchainService service = serviceFactory.getBlockchainService(); - - HashDigest ledgerHash = getLedgerHash(); - - // -------------------------------------- - // 一个贸易账户,贸易结算后的利润将通过一个合约账户来执行利润分配; - // 合约账户被设置为通用的账户,不具备对贸易结算账户的直接权限; - // 只有当前交易发起人具备对贸易账户的直接权限,当交易发起人对交易进行签名之后,权限被间接传递给合约账户; - String commerceAccount = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1"; - // 处理利润分成的通用业务逻辑的合约账户; - String profitDistributionContract = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1"; - - // 收益人账户; - String receiptorAccount1 = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1"; - String receiptorAccount2 = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1"; - // 资产编码; - String assetKey = "RMB-ASSET"; - // 此次待分配利润; - long profit = 1000000; - - // 备注信息; - Remark remark = new Remark(); - String remarkJSON = JSONSerializeUtils.serializeToJSON(remark); - - // 发起交易; - TransactionTemplate txTemp = service.newTransaction(ledgerHash); - - AssetContract assetContract = txTemp.contract(profitDistributionContract, AssetContract.class); - assetContract.issue(1000, receiptorAccount1); - LongValueHolder balance = ContractReturnValue.decode(assetContract.transfer(receiptorAccount1, receiptorAccount2, 600)); - - // TX 准备就绪; - PreparedTransaction prepTx = txTemp.prepare(); - - // 使用私钥进行签名; - AsymmetricKeypair keyPair = getSponsorKey();//示例方法,取发起人的私钥; - prepTx.sign(keyPair); - - // 提交交易; - prepTx.commit(); - - //获取返回值; - System.out.println("balance = " + balance.get()); - } - - private static HashDigest getLedgerHash() { - // TODO Init ledger hash; - return null; - } - - /** - * 交易发起人的私钥;
- * - * 注:私钥由调用方在本地保管和使用; - * - * @return - */ - private static AsymmetricKeypair getSponsorKey() { - SignatureFunction signatureFunction = Crypto.getSignatureFunction("ED25519"); - return signatureFunction.generateKeypair(); - } - - /** - * 商品信息; - * - * @author huanghaiquan - * - */ - public static class Remark { - - private String code; - - private String name; - - private String venderAddress; - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getVenderAddress() { - return venderAddress; - } - - public void setVenderAddress(String venderAddress) { - this.venderAddress = venderAddress; - } - - } - -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_DataAccount.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_DataAccount.java deleted file mode 100644 index 4e873605..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_DataAccount.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.Crypto; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.SignatureFunction; -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionTemplate; -import com.jd.blockchain.sdk.BlockchainTransactionService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.utils.net.NetworkAddress; - -public class SDKDemo_DataAccount { - - public static BlockchainKeypair CLIENT_CERT = BlockchainKeyGenerator.getInstance().generate("ED25519"); - - - /** - * 生成一个区块链用户,并注册到区块链; - */ - public static void registerDataAccount() { - // 区块链共识域; - String realm = "SUPPLY_CHAIN_ALLIANCE"; - // 节点地址列表; - NetworkAddress[] peerAddrs = { new NetworkAddress("192.168.10.10", 8080), - new NetworkAddress("192.168.10.11", 8080), new NetworkAddress("192.168.10.12", 8080), - new NetworkAddress("192.168.10.13", 8080) }; - - // 网关客户端编号; - int gatewayId = 1001; - // 账本地址; - String ledgerAddress = "ffkjhkeqwiuhivnsh3298josijdocaijsda=="; - // 客户端的认证账户; - String clientAddress = "kkjsafieweqEkadsfaslkdslkae998232jojf=="; - String privKey = "safefsd32q34vdsvs"; - // 创建服务代理; - final String GATEWAY_IP = "127.0.0.1"; - final int GATEWAY_PORT = 80; - final boolean SECURE = false; - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IP, GATEWAY_PORT, SECURE, - CLIENT_CERT); - BlockchainTransactionService service = serviceFactory.getBlockchainService(); - - HashDigest ledgerHash = getLedgerHash(); - // 在本地定义注册账号的 TX; - TransactionTemplate txTemp = service.newTransaction(ledgerHash); - - // -------------------------------------- - // 在本地产生要注册的账户的秘钥; - BlockchainKeyGenerator generator = BlockchainKeyGenerator.getInstance(); - - BlockchainKeypair dataAccount = generator.generate("ED25519"); - - txTemp.dataAccounts().register(dataAccount.getIdentity()); - - // -------------------------------------- - - // TX 准备就绪; - PreparedTransaction prepTx = txTemp.prepare(); - - // 使用私钥进行签名; - AsymmetricKeypair keyPair = getSponsorKey(); - prepTx.sign(keyPair); - - // 提交交易; - prepTx.commit(); - } - - private static HashDigest getLedgerHash() { - // TODO Init ledger hash; - return null; - } - - private static AsymmetricKeypair getSponsorKey() { - SignatureFunction signatureFunction = Crypto.getSignatureFunction("ED25519"); - return signatureFunction.generateKeypair(); - } - -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_DeactiveParticipant.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_DeactiveParticipant.java deleted file mode 100644 index 700c25e9..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_DeactiveParticipant.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.crypto.AddressEncoding; -import com.jd.blockchain.crypto.KeyGenUtils; -import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.utils.Bytes; -import com.jd.blockchain.utils.http.converters.JsonResponseConverter; -import com.jd.blockchain.utils.web.model.WebResponse; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.message.BasicNameValuePair; - -import java.util.ArrayList; -import java.util.List; - -/** - * @Author: zhangshuang - * @Date: 2020/5/27 5:18 PM - * Version 1.0 - */ -public class SDKDemo_DeactiveParticipant { - - // 接受去激活参与方操作的共识节点Http服务地址, 根据具体环境配置进行修改 - private static String httpIp = "127.0.0.1"; - private static String httpPort = "7080"; - - public static void main(String[] args) { - - String url = "http://" + httpIp + ":" + httpPort + "/management/delegate/deactiveparticipant"; - - // 即将进行去激活的共识节点公钥信息 - String PUB = "3snPdw7i7Pf2u9KTNUhxrYxgEymH24zP3NNNauRVwX5yDD6rzu2uBY"; - PubKey deactivePubKey = KeyGenUtils.decodePubKey(PUB); - Bytes address = AddressEncoding.generateAddress(deactivePubKey); - - System.out.println("url = " + url); - - HttpPost httpPost = new HttpPost(url); - - List para=new ArrayList(); - - // 账本值根据具体情况进行修改 - BasicNameValuePair base58LedgerHash = new BasicNameValuePair("ledgerHash", "j5tuvAR3Q6ATsMNYTwt7SxVeCqd73itQbpmePxzSg6Zsxc"); - - BasicNameValuePair deactiveAddress = new BasicNameValuePair("participantAddress", address.toBase58()); - // 指定已经启动的其他共识节点的HTTP管理端口 - BasicNameValuePair manageHost = new BasicNameValuePair("remoteManageHost", "127.0.0.1"); - BasicNameValuePair managePort = new BasicNameValuePair("remoteManagePort", "7083"); - - para.add(base58LedgerHash); - para.add(deactiveAddress); - para.add(manageHost); - para.add(managePort); - - try { - httpPost.setEntity(new UrlEncodedFormEntity(para,"UTF-8")); - HttpClient httpClient = HttpClients.createDefault(); - - HttpResponse response = httpClient.execute(httpPost); - JsonResponseConverter jsonConverter = new JsonResponseConverter(WebResponse.class); - - WebResponse webResponse = (WebResponse) jsonConverter.getResponse(null, response.getEntity().getContent(), null); - System.out.println("response result = " + webResponse.isSuccess()); - if (!webResponse.isSuccess()) { - System.out.println("error msg = " + webResponse.getError().getErrorMessage()); - } - - - } catch (Exception e) { - e.printStackTrace(); - System.out.println("Active participant post request error!"); - } - } -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_EventListener.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_EventListener.java deleted file mode 100644 index c4cb2642..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_EventListener.java +++ /dev/null @@ -1,74 +0,0 @@ -//package com.jd.blockchain.sdk.samples; -// -//import com.jd.blockchain.ledger.BlockchainEventType; -//import com.jd.blockchain.ledger.BlockchainKeyGenerator; -//import com.jd.blockchain.ledger.BlockchainKeyPair; -//import com.jd.blockchain.ledger.CryptoKeyType; -//import com.jd.blockchain.ledger.StateMap; -//import com.jd.blockchain.sdk.BlockchainEventHandle; -//import com.jd.blockchain.sdk.BlockchainEventListener; -//import com.jd.blockchain.sdk.BlockchainEventMessage; -//import com.jd.blockchain.sdk.BlockchainService; -//import com.jd.blockchain.sdk.client.BlockchainServiceFactory; -// -//import my.utils.net.NetworkAddress; -// -///** -// * 演示监听区块链事件的过程; -// * -// * @author huanghaiquan -// * -// */ -//public class SDKDemo_EventListener { -// -// public static BlockchainKeyPair CLIENT_CERT = BlockchainKeyGenerator.getInstance().generate(CryptoKeyType.ED25519); -// -// /** -// * 演示合约执行的过程; -// */ -// public static void demoContract() { -// // 区块链共识域; -// String realm = "SUPPLY_CHAIN_ALLIANCE"; -// // 节点地址列表; -// NetworkAddress[] peerAddrs = { new NetworkAddress("192.168.10.10", 8080), -// new NetworkAddress("192.168.10.11", 8080), new NetworkAddress("192.168.10.12", 8080), -// new NetworkAddress("192.168.10.13", 8080) }; -// -// // 网关客户端编号; -// int gatewayId = 1001; -// // 账本地址; -// String ledgerAddress = "ffkjhkeqwiuhivnsh3298josijdocaijsda=="; -// // 客户端的认证账户; -// String clientAddress = "kkjsafieweqEkadsfaslkdslkae998232jojf=="; -// String privKey = "safefsd32q34vdsvs"; -// // 创建服务代理; -// final String GATEWAY_IP = "127.0.0.1"; -// final int GATEWAY_PORT = 80; -// final boolean SECURE = false; -// BlockchainServiceFactory serviceFactory = BlockchainServiceFactory.connect(GATEWAY_IP, GATEWAY_PORT, SECURE, -// CLIENT_CERT); -// BlockchainService service = serviceFactory.getBlockchainService(); -// -// // 监听账户变动; -// String walletAccount = "MMMEy902jkjjJJDkshreGeasdfassdfajjf=="; -// service.addBlockchainEventListener(BlockchainEventType.PAYLOAD_UPDATED.CODE, null, walletAccount, -// new BlockchainEventListener() { -// @Override -// public void onEvent(BlockchainEventMessage eventMessage, BlockchainEventHandle eventHandle) { -// // 钱包余额; -// StateMap balancePayload = service.getState(walletAccount, "RMB-ASSET","name"); -// Long balance = (Long) balancePayload.get("RMB-ASSET").longValue(); -// if (balance != null) { -// // notify balance change; -// } else { -// // wallet is empty and isn't listened any more; -// eventHandle.cancel(); -// } -// } -// }); -// -// // 销毁服务代理; -// serviceFactory.close(); -// } -// -//} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_InsertData.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_InsertData.java deleted file mode 100644 index 7a684a0b..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_InsertData.java +++ /dev/null @@ -1,127 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.Crypto; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.SignatureFunction; -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionTemplate; -import com.jd.blockchain.sdk.BlockchainService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.utils.io.ByteArray; -import com.jd.blockchain.utils.net.NetworkAddress; - -/** - * 演示数据写入的调用过程; - * - * @author huanghaiquan - * - */ -public class SDKDemo_InsertData { - - public static BlockchainKeypair CLIENT_CERT = BlockchainKeyGenerator.getInstance().generate("ED25519"); - - - /** - * 演示数据写入的调用过程; - */ - public static void insertData() { - // 区块链共识域; - String realm = "SUPPLY_CHAIN_ALLIANCE"; - // 节点地址列表; - NetworkAddress[] peerAddrs = { new NetworkAddress("192.168.10.10", 8080), - new NetworkAddress("192.168.10.11", 8080), new NetworkAddress("192.168.10.12", 8080), - new NetworkAddress("192.168.10.13", 8080) }; - - // 网关客户端编号; - int gatewayId = 1001; - // 账本地址; - String ledgerAddress = "ffkjhkeqwiuhivnsh3298josijdocaijsda=="; - // 客户端的认证账户; - String clientAddress = "kkjsafieweqEkadsfaslkdslkae998232jojf=="; - String privKey = "safefsd32q34vdsvs"; - // 创建服务代理; - final String GATEWAY_IP = "127.0.0.1"; - final int GATEWAY_PORT = 80; - final boolean SECURE = false; - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IP, GATEWAY_PORT, SECURE, - CLIENT_CERT); - BlockchainService service = serviceFactory.getBlockchainService(); - - HashDigest ledgerHash = getLedgerHash(); - // 在本地定义注册账号的 TX; - TransactionTemplate txTemp = service.newTransaction(ledgerHash); - - // -------------------------------------- - // 将商品信息写入到指定的账户中; - // 对象将被序列化为 JSON 形式存储,并基于 JSON 结构建立查询索引; - String commodityDataAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf=="; - Commodity commodity1 = new Commodity(); - txTemp.dataAccount(commodityDataAccount).setText("ASSET_CODE", commodity1.getCode(), -1); - - // TX 准备就绪; - PreparedTransaction prepTx = txTemp.prepare(); - - String txHash = ByteArray.toBase64(prepTx.getTransactionHash().toBytes()); - - // 使用私钥进行签名; - AsymmetricKeypair keyPair = getSponsorKey(); - prepTx.sign(keyPair); - - // 提交交易; - prepTx.commit(); - } - - private static HashDigest getLedgerHash() { - // TODO Init ledger hash; - return null; - } - - private static AsymmetricKeypair getSponsorKey() { - SignatureFunction signatureFunction = Crypto.getSignatureFunction("ED25519"); - return signatureFunction.generateKeypair(); - } - - /** - * 商品信息; - * - * @author huanghaiquan - * - */ - public static class Commodity { - - private String code; - - private String name; - - private String venderAddress; - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getVenderAddress() { - return venderAddress; - } - - public void setVenderAddress(String venderAddress) { - this.venderAddress = venderAddress; - } - - } - -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Params.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Params.java deleted file mode 100644 index 4c2251e3..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Params.java +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright: Copyright 2016-2020 JD.COM All Right Reserved - * FileName: com.jd.blockchain.sdk.samples.SDKDemo_Params - * Author: shaozhuguang - * Department: 区块链研发部 - * Date: 2018/10/18 下午2:16 - * Description: - */ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.crypto.KeyGenUtils; -import com.jd.blockchain.crypto.PrivKey; -import com.jd.blockchain.crypto.PubKey; - -/** - * - * @author shaozhuguang - * @create 2018/10/18 - * @since 1.0.0 - */ - -public class SDKDemo_Params { - public static final String PASSWORD = "abc"; - - public static final String[] PUB_KEYS = { - "3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9", - "3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX", - "3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x", - "3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk" }; - - public static final String[] PRIV_KEYS = { - "177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x", - "177gju9p5zrNdHJVEQnEEKF4ZjDDYmAXyfG84V5RPGVc5xFfmtwnHA7j51nyNLUFffzz5UT", - "177gjtwLgmSx5v1hFb46ijh7L9kdbKUpJYqdKVf9afiEmAuLgo8Rck9yu5UuUcHknWJuWaF", - "177gk1pudweTq5zgJTh8y3ENCTwtSFsKyX7YnpuKPo7rKgCkCBXVXh5z2syaTCPEMbuWRns" }; - - public static PrivKey privkey0 = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS[0], PASSWORD); - public static PrivKey privkey1 = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS[1], PASSWORD); - public static PrivKey privkey2 = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS[2], PASSWORD); - public static PrivKey privkey3 = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS[3], PASSWORD); - - public static PubKey pubKey0 = KeyGenUtils.decodePubKey(PUB_KEYS[0]); - public static PubKey pubKey1 = KeyGenUtils.decodePubKey(PUB_KEYS[1]); - public static PubKey pubKey2 = KeyGenUtils.decodePubKey(PUB_KEYS[2]); - public static PubKey pubKey3 = KeyGenUtils.decodePubKey(PUB_KEYS[3]); -} \ No newline at end of file diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_PrivilegeSetting.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_PrivilegeSetting.java deleted file mode 100644 index bdf819d2..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_PrivilegeSetting.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -public class SDKDemo_PrivilegeSetting { - -// public static BlockchainKeyPair CLIENT_CERT = BlockchainKeyGenerator.getInstance().generate(CryptoKeyType.ED25519); -// -// /** -// * 生成一个区块链账户,并注册到区块链; -// */ -// public static void registerAccount() { -// // 区块链共识域; -// String realm = "SUPPLY_CHAIN_ALLIANCE"; -// // 节点地址列表; -// NetworkAddress[] peerAddrs = { new NetworkAddress("192.168.10.10", 8080), -// new NetworkAddress("192.168.10.11", 8080), new NetworkAddress("192.168.10.12", 8080), -// new NetworkAddress("192.168.10.13", 8080) }; -// -// // 网关客户端编号; -// int gatewayId = 1001; -// // 账本地址; -// String ledgerAddress = "ffkjhkeqwiuhivnsh3298josijdocaijsda=="; -// // 客户端的认证账户; -// String clientAddress = "kkjsafieweqEkadsfaslkdslkae998232jojf=="; -// String privKey = "safefsd32q34vdsvs"; -// // 创建服务代理; -// final String GATEWAY_IP = "127.0.0.1"; -// final int GATEWAY_PORT = 80; -// final boolean SECURE = false; -// BlockchainServiceFactory serviceFactory = BlockchainServiceFactory.connect(GATEWAY_IP, GATEWAY_PORT, SECURE, -// CLIENT_CERT); -// BlockchainTransactionService service = serviceFactory.getBlockchainService(); -// -// HashDigest ledgerHash = getLedgerHash(); -// // 在本地定义注册账号的 TX; -// TransactionTemplate txTemp = service.newTransaction(ledgerHash); -// -// // -------------------------------------- -// // 配置账户的权限; -// String walletAccount = "Kjfe8832hfa9jjjJJDkshrFjksjdlkfj93F=="; -// String user1 = "MMMEy902jkjjJJDkshreGeasdfassdfajjf=="; -// String user2 = "Kjfe8832hfa9jjjJJDkshrFjksjdlkfj93F=="; -// // 配置: -// // “状态数据的写入权限”的阈值为 100; -// // 需要 user1、user2 两个账户的联合签名才能写入; -// // 当前账户仅用于表示一个业务钱包,禁止自身的写入权限,只能由业务角色的账户才能操作; -// -// -// -// txTemp.configPrivilege(walletAccount).setThreshhold(PrivilegeType.STATE_WRITE, 100) -// .enable(PrivilegeType.STATE_WRITE, user1, 50).enable(PrivilegeType.STATE_WRITE, user2, 50) -// .disable(PrivilegeType.STATE_WRITE, walletAccount); -// // -------------------------------------- -// -// // TX 准备就绪; -// PreparedTransaction prepTx = txTemp.prepare(); -// -// // 使用私钥进行签名; -// BlockchainKeyPair sponsorKey = getSponsorKey(); -// prepTx.sign(sponsorKey); -// -// // 提交交易; -// prepTx.commit(); -// } -// -// private static HashDigest getLedgerHash() { -// // TODO Init ledger hash; -// return null; -// } -// -// private static BlockchainKeyPair getSponsorKey() { -// // TODO Auto-generated method stub -// return null; -// } - -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java deleted file mode 100644 index 6f4e9e19..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.crypto.Crypto; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.TypedKVEntry; -import com.jd.blockchain.ledger.LedgerBlock; -import com.jd.blockchain.ledger.LedgerTransaction; -import com.jd.blockchain.sdk.BlockchainService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.utils.net.NetworkAddress; - -/** - * 演示区块链信息查询的过程; - * - * @author huanghaiquan - * - */ -public class SDKDemo_Query { - - public static BlockchainKeypair CLIENT_CERT = BlockchainKeyGenerator.getInstance().generate("ED25519"); - - public static final HashDigest LEDGER_HASH = Crypto.getHashFunction("SHA256") - .hash("xkxjcioewfqwe".getBytes()); - - /** - * 演示合约执行的过程; - */ - public static void demoContract() { - // 区块链共识域; - String realm = "SUPPLY_CHAIN_ALLIANCE"; - // 节点地址列表; - NetworkAddress[] peerAddrs = { new NetworkAddress("192.168.10.10", 8080), - new NetworkAddress("192.168.10.11", 8080), new NetworkAddress("192.168.10.12", 8080), - new NetworkAddress("192.168.10.13", 8080) }; - - // 网关客户端编号; - int gatewayId = 1001; // 客户端的认证账户; - // 账本地址; - String ledgerAddress = "ffkjhkeqwiuhivnsh3298josijdocaijsda=="; - String clientAddress = "kkjsafieweqEkadsfaslkdslkae998232jojf=="; - String privKey = "safefsd32q34vdsvs"; - // 创建服务代理; - final String GATEWAY_IP = "127.0.0.1"; - final int GATEWAY_PORT = 80; - final boolean SECURE = false; - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IP, GATEWAY_PORT, SECURE, - CLIENT_CERT); - BlockchainService service = serviceFactory.getBlockchainService(); - - // 查询区块信息; - // 区块高度; - long ledgerNumber = service.getLedger(LEDGER_HASH).getLatestBlockHeight(); - // 最新区块; - LedgerBlock latestBlock = service.getBlock(LEDGER_HASH, ledgerNumber); - // 区块中的交易的数量; - long txCount = service.getTransactionCount(LEDGER_HASH, latestBlock.getHash()); - // 获取交易列表; - LedgerTransaction[] txList = service.getTransactions(LEDGER_HASH, ledgerNumber, 0, 100); - - // 根据交易的 hash 获得交易;注:客户端生成 PrepareTransaction 时得到交易hash; - HashDigest txHash = txList[0].getRequest().getTransactionHash(); - LedgerTransaction tx = service.getTransactionByContentHash(LEDGER_HASH, txHash); - - // 获取数据; - String commerceAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf=="; - String[] objKeys = new String[] { "x001", "x002" }; - TypedKVEntry[] kvData = service.getDataEntries(LEDGER_HASH, commerceAccount, objKeys); - - long payloadVersion = kvData[0].getVersion(); - -// boolean exist = service.containState(LEDGER_HASH, commerceAccount, "x003"); - - // 按条件查询; - // 1、从保存会员信息的账户地址查询; -// String condition = "female = true AND age > 18 AND address.city = 'beijing'"; -// String memberInfoAccountAddress = "kkf2io39823jfIjfiIRWKQj30203fx=="; -// StateMap memberInfo = service.queryObject(LEDGER_HASH, memberInfoAccountAddress, condition); -// -// // 2、从保存会员信息的账户地址查询; -// Map memberInfoWithAccounts = service.queryObject(LEDGER_HASH, condition); - } - -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegistParticipant.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegistParticipant.java deleted file mode 100644 index 2494c058..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegistParticipant.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.crypto.*; -import com.jd.blockchain.ledger.*; -import com.jd.blockchain.sdk.BlockchainService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.utils.net.NetworkAddress; - -/** - * @Author: zhangshuang - * @Date: 2020/5/27 5:18 PM - * Version 1.0 - */ -public class SDKDemo_RegistParticipant { - - public static void main(String[] args) { - PrivKey privKey; - PubKey pubKey; - - BlockchainKeypair CLIENT_CERT = null; - - String GATEWAY_IPADDR = null; - - int GATEWAY_PORT; - - boolean SECURE; - - BlockchainService service; - - //根据密码工具产生的公私钥 - String PUB = "3snPdw7i7PkdgqiGX7GbZuFSi1cwZn7vtjw4vifb1YoXgr9k6Kfmis"; - String PRIV = "177gjtZu8w1phqHFVNiFhA35cfimXmP6VuqrBFhfbXBWK8s4TRwro2tnpffwP1Emwr6SMN6"; - - privKey = SDKDemo_Params.privkey1; - pubKey = SDKDemo_Params.pubKey1; - - CLIENT_CERT = new BlockchainKeypair(SDKDemo_Params.pubKey0, SDKDemo_Params.privkey0); - GATEWAY_IPADDR = "127.0.0.1"; - GATEWAY_PORT = 11000; - SECURE = false; - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IPADDR, GATEWAY_PORT, SECURE, - CLIENT_CERT); - service = serviceFactory.getBlockchainService(); - - DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(TransactionResponse.class); - DataContractRegistry.register(ParticipantRegisterOperation.class); - DataContractRegistry.register(ParticipantStateUpdateOperation.class); - DataContractRegistry.register(ConsensusSettingsUpdateOperation.class); - - HashDigest[] ledgerHashs = service.getLedgerHashs(); - // 在本地定义注册账号的 TX; - TransactionTemplate txTemp = service.newTransaction(ledgerHashs[0]); - - //existed signer - AsymmetricKeypair keyPair = new BlockchainKeypair(pubKey, privKey); - - privKey = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV, SDKDemo_Constant.PASSWORD); - - pubKey = KeyGenUtils.decodePubKey(PUB); - - System.out.println("Address = " + AddressEncoding.generateAddress(pubKey)); - - BlockchainKeypair user = new BlockchainKeypair(pubKey, privKey); - - // 注册参与方 - txTemp.participants().register("Peer4", user.getIdentity()); - - // TX 准备就绪; - PreparedTransaction prepTx = txTemp.prepare(); - - // 使用私钥进行签名; - prepTx.sign(keyPair); - - // 提交交易; - TransactionResponse transactionResponse = prepTx.commit(); - } - - -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterAccount.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterAccount.java deleted file mode 100644 index 3d184070..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterAccount.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.*; -import com.jd.blockchain.sdk.BlockchainService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.utils.ConsoleUtils; - -public class SDKDemo_RegisterAccount { - - public static void main(String[] args) { - - String GATEWAY_IPADDR = "127.0.0.1"; - int GATEWAY_PORT = 8081; - if (args != null && args.length == 2) { - GATEWAY_IPADDR = args[0]; - GATEWAY_PORT = Integer.parseInt(args[1]); - } - - DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(TransactionResponse.class); - - BlockchainKeypair CLIENT_CERT = new BlockchainKeypair(SDKDemo_Params.pubKey0, SDKDemo_Params.privkey0); - boolean SECURE = false; - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IPADDR, GATEWAY_PORT, SECURE, - CLIENT_CERT); - BlockchainService service = serviceFactory.getBlockchainService(); - - HashDigest[] ledgerHashs = service.getLedgerHashs(); - // 在本地定义注册账号的 TX; - TransactionTemplate txTemp = service.newTransaction(ledgerHashs[0]); - - //existed signer - AsymmetricKeypair keyPair = new BlockchainKeypair(SDKDemo_Params.pubKey1, SDKDemo_Params.privkey1); - - BlockchainKeypair dataAcount = BlockchainKeyGenerator.getInstance().generate(); - - // 注册 - txTemp.dataAccounts().register(dataAcount.getIdentity()); - - // TX 准备就绪; - PreparedTransaction prepTx = txTemp.prepare(); - - prepTx.sign(keyPair); - - // 提交交易; - TransactionResponse transactionResponse = prepTx.commit(); - - ConsoleUtils.info("register dataaccount complete, result is [%s]", transactionResponse.isSuccess()); - } -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterTest.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterTest.java deleted file mode 100644 index e1374bca..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright: Copyright 2016-2020 JD.COM All Right Reserved - * FileName: com.jd.blockchain.sdk.samples.SDKDemo_RegisterUser - * Author: shaozhuguang - * Department: 区块链研发部 - * Date: 2018/10/18 下午2:00 - * Description: 注册用户 - */ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.PrivKey; -import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.*; -import com.jd.blockchain.sdk.BlockchainService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.utils.ConsoleUtils; - -/** - * 注册用户 - * @author shaozhuguang - * @create 2018/10/18 - * @since 1.0.0 - */ - -public class SDKDemo_RegisterTest { - public static void main(String[] args) { - - if (args != null) { - if (args[0].equals("user")) { - SDKDemo_RegisterUser.main(null); - } else if (args[0].equals("dataaccount")) { - SDKDemo_RegisterAccount.main(null); - } - } - } -} \ No newline at end of file diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterUser.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterUser.java deleted file mode 100644 index ebbe250a..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_RegisterUser.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright: Copyright 2016-2020 JD.COM All Right Reserved - * FileName: com.jd.blockchain.sdk.samples.SDKDemo_RegisterUser - * Author: shaozhuguang - * Department: 区块链研发部 - * Date: 2018/10/18 下午2:00 - * Description: 注册用户 - */ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.PrivKey; -import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.*; -import com.jd.blockchain.sdk.BlockchainService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.utils.ConsoleUtils; - -/** - * 注册用户 - * - * @author shaozhuguang - * @create 2018/10/18 - * @since 1.0.0 - */ - -public class SDKDemo_RegisterUser { - public static void main(String[] args) { - - String GATEWAY_IPADDR = "127.0.0.1"; - int GATEWAY_PORT = 8081; - if (args != null && args.length == 2) { - GATEWAY_IPADDR = args[0]; - GATEWAY_PORT = Integer.parseInt(args[1]); - } - - // 注册相关class - DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(TransactionResponse.class); - - PrivKey privKey = SDKDemo_Params.privkey1; - PubKey pubKey = SDKDemo_Params.pubKey1; - - BlockchainKeypair CLIENT_CERT = new BlockchainKeypair(SDKDemo_Params.pubKey0, SDKDemo_Params.privkey0); - - boolean SECURE = false; - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IPADDR, GATEWAY_PORT, SECURE, - CLIENT_CERT); - BlockchainService service = serviceFactory.getBlockchainService(); - - HashDigest[] ledgerHashs = service.getLedgerHashs(); - // 在本地定义注册账号的 TX; - TransactionTemplate txTemp = service.newTransaction(ledgerHashs[0]); - - // existed signer - AsymmetricKeypair keyPair = new BlockchainKeypair(pubKey, privKey); - - BlockchainKeypair user = BlockchainKeyGenerator.getInstance().generate(); - - // 注册 - txTemp.users().register(user.getIdentity()); - - // 定义角色权限; - txTemp.security().roles().configure("MANAGER") - .enable(LedgerPermission.REGISTER_USER, LedgerPermission.REGISTER_DATA_ACCOUNT) - .enable(TransactionPermission.CONTRACT_OPERATION); - txTemp.security().authorziations().forUser(user.getIdentity()).authorize("MANAGER"); - - // TX 准备就绪; - PreparedTransaction prepTx = txTemp.prepare(); - - // 使用私钥进行签名; - prepTx.sign(keyPair); - - // 提交交易; - TransactionResponse transactionResponse = prepTx.commit(); - - ConsoleUtils.info("register user complete, result is [%s]", transactionResponse.isSuccess()); - } -} \ No newline at end of file diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Tx_Persistance.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Tx_Persistance.java deleted file mode 100644 index ef0762c4..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Tx_Persistance.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Copyright: Copyright 2016-2020 JD.COM All Right Reserved - * FileName: com.jd.blockchain.sdk.samples.SDKDemo_RegisterUser - * Author: shaozhuguang - * Department: 区块链研发部 - * Date: 2018/10/18 下午2:00 - * Description: 注册用户 - */ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.binaryproto.BinaryProtocol; -import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.PrivKey; -import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.*; -import com.jd.blockchain.sdk.BlockchainService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.transaction.SignatureUtils; -import com.jd.blockchain.utils.ConsoleUtils; - -/** - * 注册用户 - * - * @author shaozhuguang - * @create 2018/10/18 - * @since 1.0.0 - */ - -public class SDKDemo_Tx_Persistance { - public static void main(String[] args) { - - String GATEWAY_IPADDR = "127.0.0.1"; - int GATEWAY_PORT = 11000; - if (args != null && args.length == 2) { - GATEWAY_IPADDR = args[0]; - GATEWAY_PORT = Integer.parseInt(args[1]); - } - - // 注册相关class - DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(TransactionResponse.class); - - PrivKey privKey1 = SDKDemo_Params.privkey0; - PubKey pubKey1 = SDKDemo_Params.pubKey0; - PrivKey privKey2 = SDKDemo_Params.privkey1; - PubKey pubKey2 = SDKDemo_Params.pubKey1; - - BlockchainKeypair CLIENT_CERT = new BlockchainKeypair(SDKDemo_Params.pubKey0, SDKDemo_Params.privkey0); - - boolean SECURE = false; - GatewayServiceFactory gatewayServiceFactory = GatewayServiceFactory.connect(GATEWAY_IPADDR, GATEWAY_PORT, SECURE, - CLIENT_CERT); - BlockchainService blockchainService = gatewayServiceFactory.getBlockchainService(); - - HashDigest[] ledgerHashs = blockchainService.getLedgerHashs(); - // 在本地定义注册账号的 TX; - TransactionTemplate txTemp = blockchainService.newTransaction(ledgerHashs[0]); - - // existed signer - AsymmetricKeypair keyPair1 = new BlockchainKeypair(pubKey1, privKey1); - AsymmetricKeypair keyPair2 = new BlockchainKeypair(pubKey2, privKey2); - - BlockchainKeypair user = BlockchainKeyGenerator.getInstance().generate(); - - // 注册 - txTemp.users().register(user.getIdentity()); - - // 定义角色权限; - txTemp.security().roles().configure("MANAGER") - .enable(LedgerPermission.REGISTER_USER, LedgerPermission.REGISTER_DATA_ACCOUNT) - .enable(TransactionPermission.CONTRACT_OPERATION); - txTemp.security().authorziations().forUser(user.getIdentity()).authorize("MANAGER"); - - // TX 准备就绪; - PreparedTransaction prepTx = txTemp.prepare(); - - // 序列化交易内容; - byte[] txContentBytes = BinaryProtocol.encode(prepTx.getTransactionContent(), TransactionContent.class); - - // 反序列化交易内容; - TransactionContent txContent = BinaryProtocol.decode(txContentBytes, TransactionContent.class); - - // 对交易内容签名; - DigitalSignature signature1 = SignatureUtils.sign(keyPair1.getAlgorithm(), txContent, keyPair1); - - // 根据交易内容重新准备交易; - PreparedTransaction decodedPrepTx = blockchainService.prepareTransaction(txContent); - - // 使用私钥进行签名,或附加签名; - decodedPrepTx.addSignature(signature1); - decodedPrepTx.sign(keyPair2); - - // 提交交易; - TransactionResponse transactionResponse = decodedPrepTx.commit(); - // 解析返回结果;如果是合约调用的操作,需要自行解析返回结果; - if (transactionResponse.isSuccess()) { - // 操作结果对应于交易中的操作顺序;无返回结果的操作对应结果为 null; - OperationResult opResult = transactionResponse.getOperationResults()[0];// - Class dataClazz = null;//返回值的类型; - Object value = BytesValueEncoding.decode(opResult.getResult(), dataClazz); - } - - - ConsoleUtils.info("register user complete, result is [%s]", transactionResponse.isSuccess()); - } -} \ No newline at end of file diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_User.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_User.java deleted file mode 100644 index 5fc67f3c..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_User.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.Crypto; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.SignatureFunction; -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionTemplate; -import com.jd.blockchain.sdk.BlockchainTransactionService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.utils.net.NetworkAddress; - -public class SDKDemo_User { - - public static BlockchainKeypair CLIENT_CERT = BlockchainKeyGenerator.getInstance().generate(); - - /** - * 生成一个区块链用户,并注册到区块链; - */ - public static void registerUser() { - // 区块链共识域; - String realm = "SUPPLY_CHAIN_ALLIANCE"; - // 节点地址列表; - NetworkAddress[] peerAddrs = { new NetworkAddress("192.168.10.10", 8080), - new NetworkAddress("192.168.10.11", 8080), new NetworkAddress("192.168.10.12", 8080), - new NetworkAddress("192.168.10.13", 8080) }; - - // 网关客户端编号; - int gatewayId = 1001; - // 账本地址; - String ledgerAddress = "ffkjhkeqwiuhivnsh3298josijdocaijsda=="; - // 客户端的认证账户; - String clientAddress = "kkjsafieweqEkadsfaslkdslkae998232jojf=="; - String privKey = "safefsd32q34vdsvs"; - // 创建服务代理; - final String GATEWAY_IP = "127.0.0.1"; - final int GATEWAY_PORT = 80; - final boolean SECURE = false; - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IP, GATEWAY_PORT, SECURE, - CLIENT_CERT); - BlockchainTransactionService service = serviceFactory.getBlockchainService(); - - HashDigest ledgerHash = getLedgerHash(); - - // 在本地定义注册账号的 TX; - TransactionTemplate txTemp = service.newTransaction(ledgerHash); - - // -------------------------------------- - // 配置账户的权限; - String walletAccount = "Kjfe8832hfa9jjjJJDkshrFjksjdlkfj93F=="; - String user1 = "MMMEy902jkjjJJDkshreGeasdfassdfajjf=="; - String user2 = "Kjfe8832hfa9jjjJJDkshrFjksjdlkfj93F=="; - // 配置: - // “状态数据的写入权限”的阈值为 100; - // 需要 user1、user2 两个账户的联合签名才能写入; - // 当前账户仅用于表示一个业务钱包,禁止自身的写入权限,只能由业务角色的账户才能操作; - - String userPubKeyStr = "Kjfe8832hfa9jjjJJDkshrFjksjdlkfj93F=="; - - // 在本地产生要注册的账户的秘钥; - //BlockchainKeyGenerator generator = BlockchainKeyGenerator.getInstance(); - //BlockchainKeyPair user = generator.generate(CryptoKeyType.PUBLIC); - - SignatureFunction signatureFunction = Crypto.getSignatureFunction("ED25519"); - AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair(); - BlockchainKeypair user = new BlockchainKeypair(cryptoKeyPair.getPubKey(), cryptoKeyPair.getPrivKey()); - - txTemp.users().register(user.getIdentity()); - - // -------------------------------------- - - // TX 准备就绪; - PreparedTransaction prepTx = txTemp.prepare(); - - // 使用私钥进行签名; - AsymmetricKeypair keyPair = getSponsorKey(); - prepTx.sign(keyPair); - - // 提交交易; - prepTx.commit(); - } - - private static HashDigest getLedgerHash() { - // TODO Init ledger hash; - return null; - } - - private static AsymmetricKeypair getSponsorKey() { - SignatureFunction signatureFunction = Crypto.getSignatureFunction("ED25519"); - return signatureFunction.generateKeypair(); - } - -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Base_Demo.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Base_Demo.java deleted file mode 100644 index f870316c..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Base_Demo.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.KeyGenUtils; -import com.jd.blockchain.crypto.PrivKey; -import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.ledger.TransactionTemplate; -import com.jd.blockchain.sdk.BlockchainService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; - -public abstract class SDK_Base_Demo { - - protected BlockchainKeypair adminKey; - - protected HashDigest ledgerHash; - - protected BlockchainService blockchainService; - - public SDK_Base_Demo() { - init(); - } - - public void init() { - // 生成连接网关的账号 - PrivKey privKey = KeyGenUtils.decodePrivKeyWithRawPassword(SDKDemo_Constant.PRIV_KEYS[0], SDKDemo_Constant.PASSWORD); - - PubKey pubKey = KeyGenUtils.decodePubKey(SDKDemo_Constant.PUB_KEYS[0]); - - adminKey = new BlockchainKeypair(pubKey, privKey); - - // 连接网关 - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(SDKDemo_Constant.GW_IPADDR, - SDKDemo_Constant.GW_PORT, false, adminKey); - - // 获取网关对应的Service处理类 - blockchainService = serviceFactory.getBlockchainService(); - - HashDigest[] ledgerHashs = blockchainService.getLedgerHashs(); - // 获取当前账本Hash - ledgerHash = ledgerHashs[0]; - } - - public TransactionResponse commit(TransactionTemplate txTpl) { - PreparedTransaction ptx = txTpl.prepare(); - ptx.sign(adminKey); - return ptx.commit(); - } - - protected void printTxResponse(TransactionResponse response) { - System.out.printf("TxResponse's state = [%s][%s], blockHeight = [%s] ! \r\n", - response.isSuccess(), response.getExecutionState(), response.getBlockHeight()); - } -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_ConsensusSettings_Update_Demo.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_ConsensusSettings_Update_Demo.java deleted file mode 100644 index 9c0ab330..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_ConsensusSettings_Update_Demo.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.ledger.TransactionTemplate; -import com.jd.blockchain.utils.Property; - -import java.util.ArrayList; -import java.util.List; - -public class SDK_ConsensusSettings_Update_Demo extends SDK_Base_Demo { - - public static void main(String[] args) { - new SDK_ConsensusSettings_Update_Demo().updateSettings(); - } - - public void updateSettings() { - - List properties = new ArrayList(); - - // 修改bftsmart.conf配置文件中的选项; - properties.add(new Property("system.communication.useSenderThread", "false")); - - Property[] propertiesArray = properties.toArray(new Property[properties.size()]); - - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - - txTpl.settings().update(propertiesArray); - - // TX 准备就绪; - PreparedTransaction prepTx = txTpl.prepare(); - - // 使用私钥进行签名; - prepTx.sign(adminKey); - - // 提交交易; - TransactionResponse transactionResponse = prepTx.commit(); - - System.out.println(transactionResponse.isSuccess()); - - } -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Check_Demo.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Check_Demo.java deleted file mode 100644 index c99b9a6b..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Check_Demo.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import static com.jd.blockchain.sdk.samples.SDKDemo_Constant.readChainCodes; -import static com.jd.blockchain.transaction.ContractReturnValue.decode; - -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.ledger.TransactionTemplate; -import com.jd.blockchain.transaction.GenericValueHolder; -import com.jd.blockchain.utils.Bytes; -import com.jd.chain.contracts.ContractTestInf; - -public class SDK_Contract_Check_Demo extends SDK_Base_Demo { - - public static void main(String[] args) { - new SDK_Contract_Check_Demo().executeContract(); - } - - public void executeContract() { - - // 发布jar包 - // 定义交易模板 - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - - // 将jar包转换为二进制数据 - byte[] contractCode = readChainCodes("contract-jdchain.jar"); - - // 生成一个合约账号 - BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate(); - - // 生成发布合约操作 - txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode); - - // 生成预发布交易; - PreparedTransaction ptx = txTpl.prepare(); - - // 对交易进行签名 - ptx.sign(adminKey); - - // 提交并等待共识返回; - TransactionResponse txResp = ptx.commit(); - - // 获取合约地址 - Bytes contractAddress = contractDeployKey.getAddress(); - - // 打印交易返回信息 - System.out.printf("Tx[%s] -> BlockHeight = %s, BlockHash = %s, isSuccess = %s, ExecutionState = %s \r\n", - txResp.getContentHash().toBase58(), txResp.getBlockHeight(), txResp.getBlockHash().toBase58(), - txResp.isSuccess(), txResp.getExecutionState()); - - // 打印合约地址 - System.out.printf("ContractAddress = %s \r\n", contractAddress.toBase58()); - - // 执行合约 - exeContract(contractAddress); - } - - private void exeContract(Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - ContractTestInf contract = txTpl.contract(contractAddress, ContractTestInf.class); - GenericValueHolder result = decode(contract.randomChars(1024)); - commit(txTpl); - String random = result.get(); - System.out.println(random); - } - - -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java deleted file mode 100644 index 0574cf51..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java +++ /dev/null @@ -1,156 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import static com.jd.blockchain.sdk.samples.SDKDemo_Constant.readChainCodes; -import static com.jd.blockchain.transaction.ContractReturnValue.decode; - -import com.jd.blockchain.contract.TransferContract; -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.ledger.TransactionTemplate; -import com.jd.blockchain.ledger.TypedKVEntry; -import com.jd.blockchain.transaction.GenericValueHolder; -import com.jd.blockchain.transaction.LongValueHolder; -import com.jd.blockchain.utils.Bytes; - -public class SDK_Contract_Demo extends SDK_Base_Demo { - - public static void main(String[] args) { - new SDK_Contract_Demo().executeContract(); - } - - public void executeContract() { - - // 发布jar包 - // 定义交易模板 - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - - // 将jar包转换为二进制数据 - byte[] contractCode = readChainCodes("transfer.jar"); - - // 生成一个合约账号 - BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate(); - - // 生成发布合约操作 - txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode); - - // 生成预发布交易; - PreparedTransaction ptx = txTpl.prepare(); - - // 对交易进行签名 - ptx.sign(adminKey); - - // 提交并等待共识返回; - TransactionResponse txResp = ptx.commit(); - - // 获取合约地址 - Bytes contractAddress = contractDeployKey.getAddress(); - - // 打印交易返回信息 - System.out.printf("Tx[%s] -> BlockHeight = %s, BlockHash = %s, isSuccess = %s, ExecutionState = %s \r\n", - txResp.getContentHash().toBase58(), txResp.getBlockHeight(), txResp.getBlockHash().toBase58(), - txResp.isSuccess(), txResp.getExecutionState()); - - // 打印合约地址 - System.out.printf("ContractAddress = %s \r\n", contractAddress.toBase58()); - - // 注册一个数据账户 - BlockchainKeypair dataAccount = createDataAccount(); - // 获取数据账户地址 - String dataAddress = dataAccount.getAddress().toBase58(); - // 打印数据账户地址 - System.out.printf("DataAccountAddress = %s \r\n", dataAddress); - - // 创建两个账号: - String account0 = "jd_zhangsan", account1 = "jd_lisi"; - long account0Money = 3000L, account1Money = 2000L; - // 创建两个账户 - // 使用KV操作创建一个账户 - System.out.println(create(dataAddress, account0, account0Money, false, null)); - // 使用合约创建一个账户 - System.out.println(create(dataAddress, account1, account1Money, true, contractAddress)); - - // 转账,使得双方钱达到一致 - System.out.println(transfer(dataAddress, account0, account1, 500L, contractAddress)); - - // 通过合约读取account0的当前信息 - System.out.printf("Read DataAccountAddress[%s] Account = %s 's money = %s (By Contract)\r\n", dataAddress, - account0, readByContract(dataAddress, account0, contractAddress)); - // 通过KV读取account1的当前信息 - System.out.printf("Read DataAccountAddress[%s] Account = %s 's money = %s (By KV Operation)\r\n", dataAddress, - account1, readByKvOperation(dataAddress, account1)); - - // 通过合约读取account0的历史信息 - System.out.println(readAll(dataAddress, account0, contractAddress)); - // 通过合约读取account1的历史信息 - System.out.println(readAll(dataAddress, account1, contractAddress)); - } - - private String readAll(String address, String account, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - GenericValueHolder result = decode(transferContract.readAll(address, account)); - commit(txTpl); - return result.get(); - } - - private long readByContract(String address, String account, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - LongValueHolder result = decode(transferContract.read(address, account)); - commit(txTpl); - return result.get(); - } - - private long readByKvOperation(String address, String account) { - TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account); - if (kvDataEntries == null || kvDataEntries.length == 0) { - throw new IllegalStateException(String.format("Ledger %s Service inner Error !!!", ledgerHash.toBase58())); - } - TypedKVEntry kvDataEntry = kvDataEntries[0]; - if (kvDataEntry.getVersion() == -1) { - return 0L; - } - return (long) (kvDataEntry.getValue()); - } - - private String transfer(String address, String from, String to, long money, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - GenericValueHolder result = decode(transferContract.transfer(address, from, to, money)); - commit(txTpl); - return result.get(); - } - - private BlockchainKeypair createDataAccount() { - // 首先注册一个数据账户 - BlockchainKeypair newDataAccount = BlockchainKeyGenerator.getInstance().generate(); - - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - txTpl.dataAccounts().register(newDataAccount.getIdentity()); - commit(txTpl); - return newDataAccount; - } - - private String create(String address, String account, long money, boolean useContract, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - if (useContract) { - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - GenericValueHolder result = decode(transferContract.create(address, account, money)); - commit(txTpl); - return result.get(); - } else { - // 通过KV创建 - txTpl.dataAccount(address).setInt64(account, money, -1); - TransactionResponse txResp = commit(txTpl); - return String.format( - "DataAccountAddress[%s] -> Create(By KV Operation) Account = %s and Money = %s Success!!! \r\n", - address, account, money); - } - } -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Random_Demo.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Random_Demo.java deleted file mode 100644 index 868f3269..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Random_Demo.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.contract.RandomContract; -import com.jd.blockchain.contract.TransferContract; -import com.jd.blockchain.ledger.*; -import com.jd.blockchain.transaction.GenericValueHolder; -import com.jd.blockchain.transaction.LongValueHolder; -import com.jd.blockchain.utils.Bytes; - -import java.util.Random; - -import static com.jd.blockchain.sdk.samples.SDKDemo_Constant.readChainCodes; -import static com.jd.blockchain.transaction.ContractReturnValue.decode; - -public class SDK_Contract_Random_Demo extends SDK_Base_Demo { - - public static void main(String[] args) throws Exception { - new SDK_Contract_Random_Demo().executeContract(); - } - - public void executeContract() throws Exception { - - // 发布jar包 - // 定义交易模板 - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - - // 将jar包转换为二进制数据 - byte[] contractCode = readChainCodes("random.jar"); - - // 生成一个合约账号 - BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate(); - - // 生成发布合约操作 - txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode); - - // 生成预发布交易; - PreparedTransaction ptx = txTpl.prepare(); - - // 对交易进行签名 - ptx.sign(adminKey); - - // 提交并等待共识返回; - TransactionResponse txResp = ptx.commit(); - - // 获取合约地址 - Bytes contractAddress = contractDeployKey.getAddress(); - - // 打印交易返回信息 - System.out.printf("Tx[%s] -> BlockHeight = %s, BlockHash = %s, isSuccess = %s, ExecutionState = %s \r\n", - txResp.getContentHash().toBase58(), txResp.getBlockHeight(), txResp.getBlockHash().toBase58(), - txResp.isSuccess(), txResp.getExecutionState()); - - // 打印合约地址 - System.out.printf("ContractAddress = %s \r\n", contractAddress.toBase58()); - - String result = create("LdeNzfhZd2qiBRk3YrEX6GZgiVRZJaf3MKJAY", "zhangshuang", "jingdong", contractAddress); - - - Thread.sleep(5000); - System.out.println(result); - } - - private String readAll(String address, String account, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - GenericValueHolder result = decode(transferContract.readAll(address, account)); - commit(txTpl); - return result.get(); - } - - private long readByContract(String address, String account, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - LongValueHolder result = decode(transferContract.read(address, account)); - commit(txTpl); - return result.get(); - } - - private long readByKvOperation(String address, String account) { - TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account); - if (kvDataEntries == null || kvDataEntries.length == 0) { - throw new IllegalStateException(String.format("Ledger %s Service inner Error !!!", ledgerHash.toBase58())); - } - TypedKVEntry kvDataEntry = kvDataEntries[0]; - if (kvDataEntry.getVersion() == -1) { - return 0L; - } - return (long) (kvDataEntry.getValue()); - } - - private String transfer(String address, String from, String to, long money, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - GenericValueHolder result = decode(transferContract.transfer(address, from, to, money)); - commit(txTpl); - return result.get(); - } - - private BlockchainKeypair createDataAccount() { - // 首先注册一个数据账户 - BlockchainKeypair newDataAccount = BlockchainKeyGenerator.getInstance().generate(); - - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - txTpl.dataAccounts().register(newDataAccount.getIdentity()); - commit(txTpl); - return newDataAccount; - } - - private String create(String address, String account, String value, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - // 使用合约创建 - RandomContract randomContract = txTpl.contract(contractAddress, RandomContract.class); - GenericValueHolder result = decode(randomContract.putAndGet(address, account, value)); - commit(txTpl); - return result.get(); - } -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_DataAccount_Demo.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_DataAccount_Demo.java deleted file mode 100644 index ef82cb79..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_DataAccount_Demo.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.contract.TransferContract; -import com.jd.blockchain.ledger.*; -import com.jd.blockchain.transaction.GenericValueHolder; -import com.jd.blockchain.transaction.LongValueHolder; -import com.jd.blockchain.utils.Bytes; - -import static com.jd.blockchain.sdk.samples.SDKDemo_Constant.readChainCodes; -import static com.jd.blockchain.transaction.ContractReturnValue.decode; - -public class SDK_DataAccount_Demo extends SDK_Base_Demo { - - public static void main(String[] args) { - new SDK_DataAccount_Demo().executeDataAccount(); - } - - public void executeDataAccount() { - - // 定义交易模板 - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - - // 注册一个数据账户 - BlockchainKeypair dataAccount = createDataAccount(); - // 获取数据账户地址 - String dataAddress = dataAccount.getAddress().toBase58(); - // 打印数据账户地址 - System.out.printf("DataAccountAddress = %s \r\n", dataAddress); - - // 通过KV创建 - txTpl.dataAccount(dataAddress) - .setText("zhangsan", "我的世界", -1) - .setText("张三", "My World", -1); - TransactionResponse txResp = commit(txTpl); - - System.out.println(txResp.isSuccess()); - - } - - private BlockchainKeypair createDataAccount() { - // 首先注册一个数据账户 - BlockchainKeypair newDataAccount = BlockchainKeyGenerator.getInstance().generate(); - - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - txTpl.dataAccounts().register(newDataAccount.getIdentity()); - commit(txTpl); - return newDataAccount; - } -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Event_Demo.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Event_Demo.java deleted file mode 100644 index 1685ecd7..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Event_Demo.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.BytesValue; -import com.jd.blockchain.ledger.Event; -import com.jd.blockchain.ledger.SystemEvent; -import com.jd.blockchain.ledger.TransactionTemplate; -import com.jd.blockchain.sdk.EventContext; -import com.jd.blockchain.sdk.EventListenerHandle; -import com.jd.blockchain.sdk.SystemEventListener; -import com.jd.blockchain.sdk.SystemEventPoint; -import com.jd.blockchain.sdk.UserEventListener; -import com.jd.blockchain.sdk.UserEventPoint; -import com.jd.blockchain.utils.io.BytesUtils; - -public class SDK_Event_Demo extends SDK_Base_Demo { - - // 注册事件账户 - private BlockchainKeypair createEventAccount() { - BlockchainKeypair eventAccount = BlockchainKeyGenerator.getInstance().generate(); - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - txTpl.eventAccounts().register(eventAccount.getIdentity()); - commit(txTpl); - return eventAccount; - } - - /** - * 发布事件 - * - * @param eventAccount 事件账户 - */ - private void publishEvent(BlockchainKeypair eventAccount) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - // sequence传递当前事件名链上最新序号,不存在时传-1 - Event event = blockchainService.getLatestEvent(ledgerHash, eventAccount.getAddress().toBase58(), "name"); - long sequence = null != event ? event.getSequence() : -1; - txTpl.eventAccount(eventAccount.getAddress()).publish("name", "string", sequence + 1); - txTpl.eventAccount(eventAccount.getAddress()).publish("name", 0, sequence + 2); - commit(txTpl); - } - - /** - * 监听用户自定义事件 - * - * @param eventAccount 事件账户 - * @param eventName 事件名 - */ - private void monitorUserEvent(BlockchainKeypair eventAccount, String eventName) { - EventListenerHandle handler = blockchainService.monitorUserEvent(ledgerHash, eventAccount.getAddress().toBase58(), eventName, 0, new UserEventListener() { - @Override - public void onEvent(Event eventMessage, EventContext eventContext) { - BytesValue content = eventMessage.getContent(); - switch (content.getType()) { - case TEXT: - System.out.println(content.getBytes().toUTF8String()); - break; - case INT64: - System.out.println(BytesUtils.toLong(content.getBytes().toBytes())); - break; - default: - break; - } - - // 关闭监听的两种方式:1 - eventContext.getHandle().cancel(); - } - }); - - // 关闭监听的两种方式:2 - handler.cancel(); - } - - /** - * 监听新区块生成事件 - */ - private void monitorNewBlockCreatedEvent() { - EventListenerHandle handler = blockchainService.monitorSystemEvent(ledgerHash, SystemEvent.NEW_BLOCK_CREATED, 0, new SystemEventListener() { - @Override - public void onEvents(Event[] eventMessages, EventContext eventContext) { - for (Event eventMessage : eventMessages) { - BytesValue content = eventMessage.getContent(); - // content中存放的是当前链上最新高度 - System.out.println(BytesUtils.toLong(content.getBytes().toBytes())); - } - - // 关闭监听的两种方式:1 - eventContext.getHandle().cancel(); - } - }); - - // 关闭监听的两种方式:2 - handler.cancel(); - } - -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java deleted file mode 100644 index 512cb5cd..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.*; -import com.jd.blockchain.sdk.converters.ClientResolveUtil; - -public class SDK_InsertData_Demo extends SDK_Base_Demo { - - public static void main(String[] args) { - SDK_InsertData_Demo sdkDemo_insertData = new SDK_InsertData_Demo(); - sdkDemo_insertData.insertData(); - } - /** - * 生成一个区块链数据账户,并注册到区块链; - */ - public void insertData() { - // 在本地定义注册账号的 TX; - TransactionTemplate txTemp = blockchainService.newTransaction(ledgerHash); - //采用原始的方式来生成BlockchainKeypair; -// SignatureFunction signatureFunction = Crypto.getSignatureFunction("ED25519"); -// AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair(); -// BlockchainKeypair dataAccount = new BlockchainKeypair(cryptoKeyPair.getPubKey(), cryptoKeyPair.getPrivKey()); - //采用KeyGenerator来生成BlockchainKeypair; - BlockchainKeypair dataAccount = BlockchainKeyGenerator.getInstance().generate(); - - txTemp.dataAccounts().register(dataAccount.getIdentity()); - txTemp.dataAccount(dataAccount.getAddress()).setText("key1","value1",-1); - - // TX 准备就绪 - PreparedTransaction prepTx = txTemp.prepare(); - prepTx.sign(adminKey); - - // 提交交易; - prepTx.commit(); - - getData(dataAccount.getAddress().toBase58()); - } - - public void getData(String commerceAccount) { - // 查询区块信息; - // 区块高度; - long ledgerNumber = blockchainService.getLedger(ledgerHash).getLatestBlockHeight(); - // 最新区块; - LedgerBlock latestBlock = blockchainService.getBlock(ledgerHash, ledgerNumber); - // 区块中的交易的数量; - long txCount = blockchainService.getTransactionCount(ledgerHash, latestBlock.getHash()); - // 获取交易列表; - LedgerTransaction[] txList = blockchainService.getTransactions(ledgerHash, ledgerNumber, 0, 100); - // 遍历交易列表 - for (LedgerTransaction ledgerTransaction : txList) { - TransactionContent txContent = ledgerTransaction.getRequest().getTransactionContent(); - Operation[] operations = txContent.getOperations(); - if (operations != null && operations.length > 0) { - for (Operation operation : operations) { - operation = ClientResolveUtil.read(operation); - // 操作类型:数据账户注册操作 - if (operation instanceof DataAccountRegisterOperation) { - DataAccountRegisterOperation daro = (DataAccountRegisterOperation) operation; - BlockchainIdentity blockchainIdentity = daro.getAccountID(); - } - // 操作类型:用户注册操作 - else if (operation instanceof UserRegisterOperation) { - UserRegisterOperation uro = (UserRegisterOperation) operation; - BlockchainIdentity blockchainIdentity = uro.getUserID(); - } - // 操作类型:账本注册操作 - else if (operation instanceof LedgerInitOperation) { - - LedgerInitOperation ledgerInitOperation = (LedgerInitOperation)operation; - LedgerInitSetting ledgerInitSetting = ledgerInitOperation.getInitSetting(); - - ParticipantNode[] participantNodes = ledgerInitSetting.getConsensusParticipants(); - } - // 操作类型:合约发布操作 - else if (operation instanceof ContractCodeDeployOperation) { - ContractCodeDeployOperation ccdo = (ContractCodeDeployOperation) operation; - BlockchainIdentity blockchainIdentity = ccdo.getContractID(); - } - // 操作类型:合约执行操作 - else if (operation instanceof ContractEventSendOperation) { - ContractEventSendOperation ceso = (ContractEventSendOperation) operation; - } - // 操作类型:KV存储操作 - else if (operation instanceof DataAccountKVSetOperation) { - DataAccountKVSetOperation.KVWriteEntry[] kvWriteEntries = - ((DataAccountKVSetOperation) operation).getWriteSet(); - if (kvWriteEntries != null && kvWriteEntries.length > 0) { - for (DataAccountKVSetOperation.KVWriteEntry kvWriteEntry : kvWriteEntries) { - BytesValue bytesValue = kvWriteEntry.getValue(); - DataType dataType = bytesValue.getType(); - Object showVal = ClientResolveUtil.readValueByBytesValue(bytesValue); - System.out.println("writeSet.key=" + kvWriteEntry.getKey()); - System.out.println("writeSet.value=" + showVal); - System.out.println("writeSet.type=" + dataType); - System.out.println("writeSet.version=" + kvWriteEntry.getExpectedVersion()); - } - } - } - } - } - } - - //根据交易的 hash 获得交易;注:客户端生成 PrepareTransaction 时得到交易hash; - HashDigest txHash = txList[0].getRequest().getTransactionHash(); -// Transaction tx = blockchainService.getTransactionByContentHash(ledgerHash, txHash); -// String[] objKeys = new String[] { "x001", "x002" }; -// KVDataEntry[] kvData = blockchainService.getDataEntries(ledgerHash, commerceAccount, objKeys); - - // 获取数据账户下所有的KV列表 - TypedKVEntry[] kvData = blockchainService.getDataEntries(ledgerHash, commerceAccount, 0, 100); - if (kvData != null && kvData.length > 0) { - for (TypedKVEntry kvDatum : kvData) { - System.out.println("kvData.key=" + kvDatum.getKey()); - System.out.println("kvData.version=" + kvDatum.getVersion()); - System.out.println("kvData.type=" + kvDatum.getType()); - System.out.println("kvData.value=" + kvDatum.getValue()); - } - } - } -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_RegistParticipant_Demo.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_RegistParticipant_Demo.java deleted file mode 100644 index 25e9d6a0..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_RegistParticipant_Demo.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.crypto.AddressEncoding; -import com.jd.blockchain.crypto.KeyGenUtils; -import com.jd.blockchain.crypto.PrivKey; -import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.ledger.TransactionTemplate; - -public class SDK_RegistParticipant_Demo extends SDK_Base_Demo { - - public static void main(String[] args) { - new SDK_RegistParticipant_Demo().regParticipant(); - } - - public void regParticipant() { - - //新参与方的公私钥 - String PUB = "3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9"; - String PRIV = "177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x"; - - PrivKey privKey = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV, SDKDemo_Constant.PASSWORD); - - PubKey pubKey = KeyGenUtils.decodePubKey(PUB); - - System.out.println("Address = " + AddressEncoding.generateAddress(pubKey)); - - BlockchainKeypair user = new BlockchainKeypair(pubKey, privKey); - - // 定义交易模板 - TransactionTemplate txTpl = blockchainService.newTransaction(blockchainService.getLedgerHashs()[0]); - - // 注册参与方 - txTpl.participants().register("Peer4", user.getIdentity()); - - // TX 准备就绪; - PreparedTransaction prepTx = txTpl.prepare(); - - // 使用私钥进行签名; - prepTx.sign(adminKey); - - // 提交交易; - TransactionResponse transactionResponse = prepTx.commit(); - - System.out.println(transactionResponse.isSuccess()); - - } -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_RoleConfig_Demo.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_RoleConfig_Demo.java deleted file mode 100644 index 6b768a82..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_RoleConfig_Demo.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.ledger.*; - -public class SDK_RoleConfig_Demo extends SDK_Base_Demo { - - public static void main(String[] args) { - new SDK_RoleConfig_Demo().executeRoleConfig(); - } - - public void executeRoleConfig() { - - // 定义交易模板 - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - - // 新增加一个角色 - - txTpl.security().roles().configure("MyRole") - .enable(LedgerPermission.APPROVE_TX, LedgerPermission.CONSENSUS_TX) - .disable(TransactionPermission.CONTRACT_OPERATION); - TransactionResponse txResp = commit(txTpl); - - System.out.println(txResp.isSuccess()); - - } -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Threads_KvInsert_Demo.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Threads_KvInsert_Demo.java deleted file mode 100644 index c4924af3..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Threads_KvInsert_Demo.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.ledger.*; -import com.jd.blockchain.utils.codec.Base58Utils; - -import java.util.Random; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -public class SDK_Threads_KvInsert_Demo extends SDK_Base_Demo { - - public static void main(String[] args) throws Exception { - new SDK_Threads_KvInsert_Demo().executeThreadsInsert(); - } - - public void executeThreadsInsert() throws Exception { - - final int MAX = 30; - - final String dataAddress = "LdeNqP4S88t1YjkGQaCGbX95ygD6hA2B6yjp6"; - - ExecutorService threadPool = Executors.newFixedThreadPool(50); - - final CountDownLatch latch = new CountDownLatch(MAX); - - for (int i = 0; i < MAX; i++) { - - threadPool.execute(() -> { - TransactionTemplate txTemp = blockchainService.newTransaction(ledgerHash); - - String key = System.currentTimeMillis() + "-" + - System.nanoTime() + "-" + - new Random(Thread.currentThread().getId()).nextInt(1024); - - txTemp.dataAccount(dataAddress).setText(key,"value1",-1); - - // TX 准备就绪 - PreparedTransaction prepTx = txTemp.prepare(); - prepTx.sign(adminKey); - - // 提交交易; - TransactionResponse response = prepTx.commit(); - - System.out.printf("Key = %s, Result = %s \r\n", key, response.isSuccess()); - - latch.countDown(); - - }); - } - - latch.await(); - System.out.println("It is Over !!!"); - System.exit(0); - } -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Update_ConsensusSettings_Demo.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Update_ConsensusSettings_Demo.java deleted file mode 100644 index de875c32..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Update_ConsensusSettings_Demo.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.ledger.TransactionTemplate; -import com.jd.blockchain.utils.Property; - -import java.util.ArrayList; -import java.util.List; - -public class SDK_Update_ConsensusSettings_Demo extends SDK_Base_Demo { - - public static void main(String[] args) { - new SDK_Update_ConsensusSettings_Demo().updateSettings(); - } - - public void updateSettings() { - - List properties = new ArrayList(); - - // 修改bftsmart.conf配置文件中的选项; - properties.add(new Property("system.communication.useSenderThread", "false")); - - Property[] propertiesArray = properties.toArray(new Property[properties.size()]); - - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - - txTpl.settings().update(propertiesArray); - - // TX 准备就绪; - PreparedTransaction prepTx = txTpl.prepare(); - - // 使用私钥进行签名; - prepTx.sign(adminKey); - - // 提交交易; - TransactionResponse transactionResponse = prepTx.commit(); - - System.out.println(transactionResponse.isSuccess()); - - } -} diff --git a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_User2Role_Demo.java b/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_User2Role_Demo.java deleted file mode 100644 index 5f18f6aa..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_User2Role_Demo.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.jd.blockchain.sdk.samples; - -import com.jd.blockchain.ledger.*; -import com.jd.blockchain.utils.Bytes; - -public class SDK_User2Role_Demo extends SDK_Base_Demo { - - public static void main(String[] args) { - new SDK_User2Role_Demo().executeUser2Role(); - } - - public void executeUser2Role() { - - // 定义交易模板 - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - - // 注册一个用户 - BlockchainKeypair user = createUser(); - - Bytes userAddress = user.getAddress(); - // 获取数据账户地址 - System.out.printf("UserAddress = %s \r\n", userAddress.toBase58()); - - - txTpl.security().authorziations().forUser(user.getIdentity()) - .authorize("MYROLE") - .setPolicy(RolesPolicy.UNION) - .unauthorize("MYROLE"); - TransactionResponse txResp = commit(txTpl); - - System.out.println(txResp.isSuccess()); - - } - - private BlockchainKeypair createUser() { - // 首先注册一个数据账户 - BlockchainKeypair newUser = BlockchainKeyGenerator.getInstance().generate(); - - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - txTpl.users().register(newUser.getIdentity()); - commit(txTpl); - return newUser; - } -} diff --git a/samples/sdk-samples/src/main/java/com/jd/chain/contracts/ContractTestInf.java b/samples/sdk-samples/src/main/java/com/jd/chain/contracts/ContractTestInf.java deleted file mode 100644 index 7e5d362a..00000000 --- a/samples/sdk-samples/src/main/java/com/jd/chain/contracts/ContractTestInf.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.jd.chain.contracts; - -import com.jd.blockchain.contract.Contract; -import com.jd.blockchain.contract.ContractEvent; - -@Contract -public interface ContractTestInf { - - @ContractEvent(name = "print") - void print(String name, int age); - - @ContractEvent(name = "random") - String randomChars(int max); -} \ No newline at end of file diff --git a/samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/TestNet.java b/samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/TestNet.java new file mode 100644 index 00000000..4f70cbe9 --- /dev/null +++ b/samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/TestNet.java @@ -0,0 +1,294 @@ +package com.jdchain.samples.sdk; + +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.crypto.KeyGenUtils; +import com.jd.blockchain.crypto.PrivKey; +import com.jd.blockchain.gateway.GatewayConfigProperties; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.LedgerInitProperties; +import com.jd.blockchain.ledger.LedgerPermission; +import com.jd.blockchain.ledger.ParticipantNode; +import com.jd.blockchain.ledger.ParticipantNodeState; +import com.jd.blockchain.ledger.PreparedTransaction; +import com.jd.blockchain.ledger.TransactionPermission; +import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.TransactionTemplate; +import com.jd.blockchain.sdk.BlockchainService; +import com.jd.blockchain.sdk.client.GatewayServiceFactory; +import com.jd.blockchain.tools.initializer.DBConnectionConfig; +import com.jd.blockchain.tools.initializer.LedgerBindingConfig; +import com.jd.blockchain.tools.initializer.PresetAnswerPrompter; +import com.jd.blockchain.tools.initializer.Prompter; +import com.jd.blockchain.utils.concurrent.ThreadInvoker; +import com.jd.blockchain.utils.io.FileUtils; +import com.jd.blockchain.utils.net.NetworkAddress; +import com.jdchain.samples.sdk.testnet.GatewayRunner; +import com.jdchain.samples.sdk.testnet.NodeWebContext; +import com.jdchain.samples.sdk.testnet.PartNode; +import com.jdchain.samples.sdk.testnet.PeerServer; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.config.Configurator; +import org.junit.Assert; +import org.springframework.core.io.ClassPathResource; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * 测试网络 + * 初始化启动基于内存的4节点JD Chain网络 + */ +public class TestNet { + + // 测试网络公私钥及私钥密码信息 + private static final String[] PUB_KEYS = { + "3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9", + "3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX", + "3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x", + "3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk"}; + private static final String[] PRIV_KEYS = { + "177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x", + "177gju9p5zrNdHJVEQnEEKF4ZjDDYmAXyfG84V5RPGVc5xFfmtwnHA7j51nyNLUFffzz5UT", + "177gjtwLgmSx5v1hFb46ijh7L9kdbKUpJYqdKVf9afiEmAuLgo8Rck9yu5UuUcHknWJuWaF", + "177gk1pudweTq5zgJTh8y3ENCTwtSFsKyX7YnpuKPo7rKgCkCBXVXh5z2syaTCPEMbuWRns"}; + private static final String PASSWORD = "abc"; + + // 存储配置 + private static final String[] dbConnections = { + "memory://local/0", + "memory://local/1", + "memory://local/2", + "memory://local/3"}; + + // 共识协议 + private static final String BFTSMART_PROVIDER = "com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider"; + + // node节点服务端口,共识节点还会占用8910/8920/8930/8940/8911/8921/8931/8941用于共识服务,可以通过修改resources/network/bftsmart.config修改 + private static final int[] NODE_PORTS = {12000, 12010, 12020, 12030}; + + // 网关服务端口 + private static final int GATEWAY_PORT = 11000; + + public static void main(String[] args) { + try { + Configurator.setRootLevel(Level.OFF); + + // 内存账本初始化 + HashDigest ledgerHash = initLedger(); + + // 启动Peer节点 + PeerServer[] peerNodes = peerNodeStart(ledgerHash); + + // 睡20秒,等待共识节点启动成功 + Thread.sleep(20000); + + // 启动网关 + startGateway(peerNodes); + + // 初始化样例数据 + initSampleData(ledgerHash); + + System.out.println(" ------------------- START NETWORK SUCCESS ------------------- "); + } catch (Exception e) { + e.printStackTrace(); + System.out.println(" ------------------- START NETWORK FAILED ------------------- "); + System.exit(-1); + } + } + + private static HashDigest initLedger() throws IOException { + Prompter consolePrompter = new PresetAnswerPrompter("N"); + LedgerInitProperties initSetting = LedgerInitProperties.resolve(new ClassPathResource("testnet/ledger.init").getInputStream()); + + ParticipantNode[] participantNodes = new ParticipantNode[PUB_KEYS.length]; + for (int i = 0; i < PUB_KEYS.length; i++) { + participantNodes[i] = new PartNode(i, KeyGenUtils.decodePubKey(PUB_KEYS[i]), ParticipantNodeState.CONSENSUS); + } + + NetworkAddress initAddr0 = initSetting.getConsensusParticipant(0).getInitializerAddress(); + NodeWebContext node0 = new NodeWebContext(0, initAddr0); + + NetworkAddress initAddr1 = initSetting.getConsensusParticipant(1).getInitializerAddress(); + NodeWebContext node1 = new NodeWebContext(1, initAddr1); + + NetworkAddress initAddr2 = initSetting.getConsensusParticipant(2).getInitializerAddress(); + NodeWebContext node2 = new NodeWebContext(2, initAddr2); + + NetworkAddress initAddr3 = initSetting.getConsensusParticipant(3).getInitializerAddress(); + NodeWebContext node3 = new NodeWebContext(3, initAddr3); + + PrivKey privkey0 = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS[0], PASSWORD); + PrivKey privkey1 = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS[1], PASSWORD); + PrivKey privkey2 = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS[2], PASSWORD); + PrivKey privkey3 = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS[3], PASSWORD); + + CountDownLatch quitLatch = new CountDownLatch(4); + + DBConnectionConfig testDb0 = new DBConnectionConfig(); + testDb0.setConnectionUri(dbConnections[0]); + ThreadInvoker.AsyncCallback callback0 = node0.startInit(privkey0, initSetting, testDb0, consolePrompter, + quitLatch); + + DBConnectionConfig testDb1 = new DBConnectionConfig(); + testDb1.setConnectionUri(dbConnections[1]); + ThreadInvoker.AsyncCallback callback1 = node1.startInit(privkey1, initSetting, testDb1, consolePrompter, + quitLatch); + + DBConnectionConfig testDb2 = new DBConnectionConfig(); + testDb2.setConnectionUri(dbConnections[2]); + ThreadInvoker.AsyncCallback callback2 = node2.startInit(privkey2, initSetting, testDb2, consolePrompter, + quitLatch); + + DBConnectionConfig testDb03 = new DBConnectionConfig(); + testDb03.setConnectionUri(dbConnections[3]); + ThreadInvoker.AsyncCallback callback3 = node3.startInit(privkey3, initSetting, testDb03, consolePrompter, + quitLatch); + + HashDigest ledgerHash0 = callback0.waitReturn(); + HashDigest ledgerHash1 = callback1.waitReturn(); + HashDigest ledgerHash2 = callback2.waitReturn(); + HashDigest ledgerHash3 = callback3.waitReturn(); + assertNotNull(ledgerHash0); + assertEquals(ledgerHash0, ledgerHash1); + assertEquals(ledgerHash0, ledgerHash2); + assertEquals(ledgerHash0, ledgerHash3); + + return ledgerHash0; + } + + private static PeerServer[] peerNodeStart(HashDigest ledgerHash) { + NetworkAddress peerSrvAddr0 = new NetworkAddress("127.0.0.1", NODE_PORTS[0]); + LedgerBindingConfig bindingConfig0 = loadBindingConfig(0, ledgerHash); + PeerServer peer0 = new PeerServer(peerSrvAddr0, bindingConfig0); + + NetworkAddress peerSrvAddr1 = new NetworkAddress("127.0.0.1", NODE_PORTS[1]); + LedgerBindingConfig bindingConfig1 = loadBindingConfig(1, ledgerHash); + PeerServer peer1 = new PeerServer(peerSrvAddr1, bindingConfig1); + + NetworkAddress peerSrvAddr2 = new NetworkAddress("127.0.0.1", NODE_PORTS[2]); + LedgerBindingConfig bindingConfig2 = loadBindingConfig(2, ledgerHash); + PeerServer peer2 = new PeerServer(peerSrvAddr2, bindingConfig2); + + NetworkAddress peerSrvAddr3 = new NetworkAddress("127.0.0.1", NODE_PORTS[3]); + LedgerBindingConfig bindingConfig3 = loadBindingConfig(3, ledgerHash); + PeerServer peer3 = new PeerServer(peerSrvAddr3, bindingConfig3); + + ThreadInvoker.AsyncCallback peerStarting0 = peer0.start(); + ThreadInvoker.AsyncCallback peerStarting1 = peer1.start(); + ThreadInvoker.AsyncCallback peerStarting2 = peer2.start(); + ThreadInvoker.AsyncCallback peerStarting3 = peer3.start(); + + peerStarting0.waitReturn(); + peerStarting1.waitReturn(); + peerStarting2.waitReturn(); + peerStarting3.waitReturn(); + + return new PeerServer[]{peer0, peer1, peer2, peer3}; + } + + private static LedgerBindingConfig loadBindingConfig(int id, HashDigest ledgerHash) { + LedgerBindingConfig ledgerBindingConfig; + String newLedger = ledgerHash.toBase58(); + String resourceClassPath = "testnet/ledger-binding-mem-" + id + ".conf"; + String ledgerBindingUrl = TestNet.class.getResource("/") + resourceClassPath; + + try { + URL url = new URL(ledgerBindingUrl); + File ledgerBindingConf = new File(url.getPath()); + if (ledgerBindingConf.exists()) { + List readLines = org.apache.commons.io.FileUtils.readLines(ledgerBindingConf); + + List writeLines = new ArrayList<>(); + + if (readLines != null && !readLines.isEmpty()) { + String oldLedgerLine = null; + for (String readLine : readLines) { + if (readLine.startsWith("ledger")) { + oldLedgerLine = readLine; + break; + } + } + String[] oldLedgerArray = oldLedgerLine.split("="); + + String oldLedger = oldLedgerArray[1]; + if (!oldLedger.equalsIgnoreCase(newLedger)) { + for (String readLine : readLines) { + String newLine = readLine.replace(oldLedger, newLedger); + writeLines.add(newLine); + } + } + if (!writeLines.isEmpty()) { + org.apache.commons.io.FileUtils.writeLines(ledgerBindingConf, writeLines); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + ClassPathResource res = new ClassPathResource(resourceClassPath); + try (InputStream in = res.getInputStream()) { + ledgerBindingConfig = LedgerBindingConfig.resolve(in); + } catch (IOException e) { + throw new IllegalStateException(e.getMessage(), e); + } + return ledgerBindingConfig; + } + + private static void startGateway(PeerServer[] peerNodes) { + GatewayConfigProperties.KeyPairConfig keyPairConfig = new GatewayConfigProperties.KeyPairConfig(); + keyPairConfig.setPubKeyValue(PUB_KEYS[0]); + keyPairConfig.setPrivKeyValue(PRIV_KEYS[0]); + keyPairConfig.setPrivKeyPassword(KeyGenUtils.encodePasswordAsBase58(PASSWORD)); + + GatewayRunner gateway = new GatewayRunner("127.0.0.1", GATEWAY_PORT, keyPairConfig, new String[]{BFTSMART_PROVIDER}, null, peerNodes[0].getServiceAddress()); + + ThreadInvoker.AsyncCallback gwStarting = gateway.start(); + + gwStarting.waitReturn(); + } + + private static void initSampleData(HashDigest ledgerHash) throws IOException { + BlockchainKeypair admin = new BlockchainKeypair(KeyGenUtils.decodePubKey(PUB_KEYS[0]), KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS[0], PASSWORD)); + BlockchainKeypair user = new BlockchainKeypair( + KeyGenUtils.decodePubKey("3snPdw7i7PbXVQoUX1Ywo6Cenm9gDB6DFztVazXWrq2qbbmzcAMUVC"), + KeyGenUtils.decodePrivKey("177gjuGapUVdLnEDAkqjQWhZxHh5jL5W6Hg1q8kbdsbk1BKht4QkmuB6dKvyJrgKTRmXSgK", "8EjkXVSTxMFjCvNNsTo8RBMDEVQmk7gYkW4SCDuvdsBG")); + + BlockchainService blockchainService = GatewayServiceFactory.connect( + "127.0.0.1", GATEWAY_PORT, false, admin).getBlockchainService(); + + TransactionTemplate txTemp = blockchainService.newTransaction(ledgerHash); + // 初始化一个用户 + txTemp.users().register(user.getIdentity()); + // 创建角色 MANAGER + txTemp.security().roles().configure("SAMPLE-ROLE") + .enable(LedgerPermission.WRITE_DATA_ACCOUNT) + .enable(TransactionPermission.DIRECT_OPERATION); + + // 设置用户角色权限 + txTemp.security().authorziations().forUser(user.getAddress()).authorize("SAMPLE-ROLE"); + // 初始化一个数据账户并设置KV + txTemp.dataAccounts().register(user.getIdentity()); + txTemp.dataAccount(user.getAddress()).setText("sample-key", "sample-value", -1); + // 初始化一个事件账户并发布一个事件 + txTemp.eventAccounts().register(user.getIdentity()); + txTemp.eventAccount(user.getAddress()).publish("sample-event", "sample-content", -1); + // 初始化一个合约 + txTemp.contracts().deploy(user.getIdentity(), FileUtils.readBytes(new ClassPathResource("contract-samples-1.4.0.RELEASE.car").getFile())); + + PreparedTransaction ptx = txTemp.prepare(); + ptx.sign(admin); + + TransactionResponse response = ptx.commit(); + Assert.assertTrue(response.isSuccess()); + } + +} diff --git a/samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/GatewayRunner.java b/samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/GatewayRunner.java new file mode 100644 index 00000000..0d7ab864 --- /dev/null +++ b/samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/GatewayRunner.java @@ -0,0 +1,77 @@ +package com.jdchain.samples.sdk.testnet; + +import com.jd.blockchain.gateway.GatewayConfigProperties; +import com.jd.blockchain.gateway.GatewayConfigProperties.KeyPairConfig; +import com.jd.blockchain.gateway.GatewayServerBooter; +import com.jd.blockchain.utils.concurrent.ThreadInvoker; +import com.jd.blockchain.utils.concurrent.ThreadInvoker.AsyncCallback; +import com.jd.blockchain.utils.net.NetworkAddress; +import org.springframework.core.io.ClassPathResource; +import org.springframework.util.CollectionUtils; + +import java.util.Map; + +public class GatewayRunner { + + private NetworkAddress serviceAddress; + + private GatewayServerBooter gatewayServer; + + public GatewayRunner(String host, int port, KeyPairConfig gatewayDefaultKey, NetworkAddress... masterPeerAddresses) { + this(host, port, gatewayDefaultKey, null, null, masterPeerAddresses); + } + + public GatewayRunner(String host, int port, KeyPairConfig gatewayDefaultKey, String[] providers, + Map otherMap, NetworkAddress... masterPeerAddresses) { + this.serviceAddress = new NetworkAddress(host, port); + GatewayConfigProperties config = new GatewayConfigProperties(); + + config.http().setHost(host); + config.http().setPort(port); + + if (providers != null) { + for (String provider : providers) { + config.providerConfig().add(provider); + } + } + + for (NetworkAddress address : masterPeerAddresses) { + config.setMasterPeerAddress(address); + } + + config.keys().getDefault().setPubKeyValue(gatewayDefaultKey.getPubKeyValue()); + config.keys().getDefault().setPrivKeyValue(gatewayDefaultKey.getPrivKeyValue()); + config.keys().getDefault().setPrivKeyPassword(gatewayDefaultKey.getPrivKeyPassword()); + + if (!CollectionUtils.isEmpty(otherMap)) { + config.setDataRetrievalUrl(otherMap.get("DATA_RETRIEVAL_URL").toString()); + } + + + //get the springConfigLocation; + ClassPathResource configResource = new ClassPathResource("application-gw.properties"); + String springConfigLocation = "classPath:" + configResource.getPath(); + + this.gatewayServer = new GatewayServerBooter(config, springConfigLocation); + } + + public AsyncCallback start() { + ThreadInvoker invoker = new ThreadInvoker() { + @Override + protected Object invoke() throws Exception { + gatewayServer.start(); + return null; + } + }; + + return invoker.start(); + } + + public void stop() { + gatewayServer.close(); + } + + public NetworkAddress getServiceAddress() { + return serviceAddress; + } +} diff --git a/samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/LedgerInit.java b/samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/LedgerInit.java new file mode 100644 index 00000000..9058679b --- /dev/null +++ b/samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/LedgerInit.java @@ -0,0 +1,22 @@ +package com.jdchain.samples.sdk.testnet; + +import com.jd.blockchain.storage.service.impl.composite.CompositeConnectionFactory; +import com.jd.blockchain.tools.initializer.web.InitWebSecurityConfiguration; +import com.jd.blockchain.tools.initializer.web.InitWebServerConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +@SpringBootApplication +@Configuration +@EnableConfigurationProperties +@Import(value = { InitWebServerConfiguration.class, InitWebSecurityConfiguration.class }) +public class LedgerInit { + + @Bean + public CompositeConnectionFactory getCompositeConnectionFactory() { + return new CompositeConnectionFactory(); + } +} diff --git a/samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/NodeWebContext.java b/samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/NodeWebContext.java new file mode 100644 index 00000000..1bca1ebd --- /dev/null +++ b/samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/NodeWebContext.java @@ -0,0 +1,105 @@ +package com.jdchain.samples.sdk.testnet; + +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.crypto.PrivKey; +import com.jd.blockchain.ledger.LedgerInitProperties; +import com.jd.blockchain.ledger.TransactionContent; +import com.jd.blockchain.ledger.core.LedgerInitDecision; +import com.jd.blockchain.ledger.core.LedgerInitProposal; +import com.jd.blockchain.ledger.core.LedgerManager; +import com.jd.blockchain.ledger.core.LedgerQuery; +import com.jd.blockchain.storage.service.DbConnection; +import com.jd.blockchain.storage.service.impl.composite.CompositeConnectionFactory; +import com.jd.blockchain.tools.initializer.DBConnectionConfig; +import com.jd.blockchain.tools.initializer.LedgerInitProcess; +import com.jd.blockchain.tools.initializer.Prompter; +import com.jd.blockchain.tools.initializer.web.LedgerInitializeWebController; +import com.jd.blockchain.utils.concurrent.ThreadInvoker; +import com.jd.blockchain.utils.net.NetworkAddress; +import org.springframework.boot.SpringApplication; +import org.springframework.context.ConfigurableApplicationContext; + +import java.util.concurrent.CountDownLatch; + +public class NodeWebContext { + + + private NetworkAddress serverAddress; + + private DBConnectionConfig dbConnConfig; + + private volatile ConfigurableApplicationContext ctx; + + private volatile LedgerInitProcess initProcess; + + private volatile LedgerInitializeWebController controller; + + private volatile LedgerManager ledgerManager; + + private volatile CompositeConnectionFactory db; + + private int id; + + public int getId() { + return controller.getId(); + } + + public TransactionContent getInitTxContent() { + return controller.getInitTxContent(); + } + + public LedgerInitProposal getLocalPermission() { + return controller.getLocalPermission(); + } + + public LedgerInitDecision getLocalDecision() { + return controller.getLocalDecision(); + } + + public NodeWebContext(int id, NetworkAddress serverAddress) { + this.id = id; + this.serverAddress = serverAddress; + } + + public LedgerQuery registLedger(HashDigest ledgerHash) { + DbConnection conn = db.connect(dbConnConfig.getUri()); + LedgerQuery ledgerRepo = ledgerManager.register(ledgerHash, conn.getStorageService()); + return ledgerRepo; + } + + public ThreadInvoker.AsyncCallback startInit(PrivKey privKey, LedgerInitProperties setting, + DBConnectionConfig dbConnConfig, Prompter prompter, CountDownLatch quitLatch) { + + ThreadInvoker invoker = new ThreadInvoker() { + @Override + protected HashDigest invoke() throws Exception { + doStartServer(); + + NodeWebContext.this.dbConnConfig = dbConnConfig; + HashDigest ledgerHash = NodeWebContext.this.initProcess.initialize(id, privKey, setting, + dbConnConfig, prompter); + + quitLatch.countDown(); + return ledgerHash; + } + }; + + return invoker.start(); + } + + public void doStartServer() { + String argServerAddress = String.format("--server.address=%s", serverAddress.getHost()); + String argServerPort = String.format("--server.port=%s", serverAddress.getPort()); + String nodebug = "--debug=false"; + String[] innerArgs = {argServerAddress, argServerPort, nodebug}; + + ctx = SpringApplication.run(LedgerInit.class, innerArgs); + + ctx.setId("Node-" + id); + controller = ctx.getBean(LedgerInitializeWebController.class); + ledgerManager = ctx.getBean(LedgerManager.class); + db = ctx.getBean(CompositeConnectionFactory.class); + initProcess = ctx.getBean(LedgerInitProcess.class); + } + +} diff --git a/samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/PartNode.java b/samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/PartNode.java new file mode 100644 index 00000000..92ed6622 --- /dev/null +++ b/samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/PartNode.java @@ -0,0 +1,58 @@ +package com.jdchain.samples.sdk.testnet; + +import com.jd.blockchain.crypto.AddressEncoding; +import com.jd.blockchain.crypto.PubKey; +import com.jd.blockchain.ledger.ParticipantNode; +import com.jd.blockchain.ledger.ParticipantNodeState; +import com.jd.blockchain.utils.Bytes; + +public class PartNode implements ParticipantNode { + + private int id; + + private Bytes address; + + private String name; + + private PubKey pubKey; + + private ParticipantNodeState participantNodeState; + + public PartNode(int id, PubKey pubKey, ParticipantNodeState participantNodeState) { + this(id, id + "", pubKey, participantNodeState); + } + + public PartNode(int id, String name, PubKey pubKey, ParticipantNodeState participantNodeState) { + this.id = id; + this.name = name; + this.pubKey = pubKey; + this.address = AddressEncoding.generateAddress(pubKey); + this.participantNodeState = participantNodeState; + } + + @Override + public int getId() { + return id; + } + + @Override + public Bytes getAddress() { + return address; + } + + @Override + public String getName() { + return name; + } + + @Override + public PubKey getPubKey() { + return pubKey; + } + + @Override + public ParticipantNodeState getParticipantNodeState() { + return participantNodeState; + } + +} \ No newline at end of file diff --git a/samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/PeerServer.java b/samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/PeerServer.java new file mode 100644 index 00000000..e7228ac4 --- /dev/null +++ b/samples/sdk-samples/src/main/java/com/jdchain/samples/sdk/testnet/PeerServer.java @@ -0,0 +1,66 @@ +package com.jdchain.samples.sdk.testnet; + +import com.jd.blockchain.ledger.core.LedgerManager; +import com.jd.blockchain.peer.PeerServerBooter; +import com.jd.blockchain.storage.service.DbConnectionFactory; +import com.jd.blockchain.tools.initializer.LedgerBindingConfig; +import com.jd.blockchain.utils.concurrent.ThreadInvoker; +import com.jd.blockchain.utils.net.NetworkAddress; + +public class PeerServer { + private NetworkAddress serviceAddress; + + private volatile PeerServerBooter booter; + + private LedgerBindingConfig ledgerBindingConfig; + + public DbConnectionFactory getDBConnectionFactory() { + return booter.getDBConnectionFactory(); + } + + public NetworkAddress getServiceAddress() { + return serviceAddress; + } + + public LedgerBindingConfig getLedgerBindingConfig() { + return ledgerBindingConfig; + } + + public PeerServer(NetworkAddress serviceAddress, LedgerBindingConfig ledgerBindingConfig) { + this(serviceAddress, ledgerBindingConfig, null, null); + } + + public PeerServer(NetworkAddress serviceAddress, LedgerBindingConfig ledgerBindingConfig, DbConnectionFactory dbConnectionFactory) { + this(serviceAddress, ledgerBindingConfig, dbConnectionFactory, null); + } + + public PeerServer(NetworkAddress serviceAddress, LedgerBindingConfig ledgerBindingConfig, + DbConnectionFactory dbConnectionFactory, LedgerManager ledgerManager) { + this.serviceAddress = serviceAddress; + this.ledgerBindingConfig = ledgerBindingConfig; + if (dbConnectionFactory == null) { + this.booter = new PeerServerBooter(ledgerBindingConfig, serviceAddress.getHost(), + serviceAddress.getPort()); + } else { + this.booter = new PeerServerBooter(ledgerBindingConfig, serviceAddress.getHost(), + serviceAddress.getPort(), dbConnectionFactory, ledgerManager); + } + } + + public ThreadInvoker.AsyncCallback start() { + ThreadInvoker invoker = new ThreadInvoker() { + @Override + protected Object invoke() throws Exception { + booter.start(); + + return null; + } + }; + + return invoker.start(); + } + + public void stop() { + booter.close(); + } +} diff --git a/samples/sdk-samples/src/main/resources/config.properties b/samples/sdk-samples/src/main/resources/config.properties new file mode 100644 index 00000000..a763fb68 --- /dev/null +++ b/samples/sdk-samples/src/main/resources/config.properties @@ -0,0 +1,20 @@ +# SDK Sample 相关配置,请根据实际情况进行修改 + +# 签名用户配置 +# 公钥 +pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9 +# 私钥 +privkey=177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x +# Base58编码的私钥密码 +password=DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY + + +# 网关配置 +# IP +gateway.host=localhost +# 端口 +gateway.port=11000 + + +# 账本,为空时选择网关查询到的账本列表第一个 +ledger= diff --git a/samples/sdk-samples/src/main/resources/contract-jdchain.jar b/samples/sdk-samples/src/main/resources/contract-jdchain.jar deleted file mode 100644 index b9e41e1d09cd6d88abc22d12856c0c182752047c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4255 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 literal 0 HcmV?d00001 diff --git a/samples/sdk-samples/src/main/resources/testnet/bftsmart.config b/samples/sdk-samples/src/main/resources/testnet/bftsmart.config new file mode 100644 index 00000000..0a236cb1 --- /dev/null +++ b/samples/sdk-samples/src/main/resources/testnet/bftsmart.config @@ -0,0 +1,155 @@ + +# Copyright (c) 2007-2013 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +############################################ +###### Consensus Participant0 ###### +############################################ + +system.server.0.network.host=127.0.0.1 +system.server.0.network.port=8910 +system.server.0.network.secure=false + +############################################ +###### #Consensus Participant1 ###### +############################################ + +system.server.1.network.host=127.0.0.1 +system.server.1.network.port=8920 +system.server.1.network.secure=false + +############################################ +###### #Consensus Participant2 ###### +############################################ + +system.server.2.network.host=127.0.0.1 +system.server.2.network.port=8930 +system.server.2.network.secure=false + +############################################ +###### Consensus Participant3 ###### +############################################ + +system.server.3.network.host=127.0.0.1 +system.server.3.network.port=8940 +system.server.3.network.secure=false + +############################################ +####### Communication Configurations ####### +############################################ + +#HMAC algorithm used to authenticate messages between processes (HmacMD5 is the default value) +#This parameter is not currently being used being used +#system.authentication.hmacAlgorithm = HmacSHA1 + +#Specify if the communication system should use a thread to send data (true or false) +system.communication.useSenderThread = true + +#Force all processes to use the same public/private keys pair and secret key. This is useful when deploying experiments +#and benchmarks, but must not be used in production systems. +system.communication.defaultkeys = true + +############################################ +### Replication Algorithm Configurations ### +############################################ + +#Number of servers in the group +system.servers.num = 4 + +#Maximum number of faulty replicas +system.servers.f = 1 + +#Timeout to asking for a client request +system.totalordermulticast.timeout = 5000 + + +#Maximum batch size (in number of messages) +system.totalordermulticast.maxbatchsize = 400 + +#Number of nonces (for non-determinism actions) generated +system.totalordermulticast.nonces = 10 + +#if verification of leader-generated timestamps are increasing +#it can only be used on systems in which the network clocks +#are synchronized +system.totalordermulticast.verifyTimestamps = false + +#Quantity of messages that can be stored in the receive queue of the communication system +system.communication.inQueueSize = 500000 + +# Quantity of messages that can be stored in the send queue of each replica +system.communication.outQueueSize = 500000 + +#Set to 1 if SMaRt should use signatures, set to 0 if otherwise +system.communication.useSignatures = 0 + +#Set to 1 if SMaRt should use MAC's, set to 0 if otherwise +system.communication.useMACs = 1 + +#Set to 1 if SMaRt should use the standard output to display debug messages, set to 0 if otherwise +system.debug = 0 + +#Print information about the replica when it is shutdown +system.shutdownhook = true + +############################################ +###### State Transfer Configurations ####### +############################################ + +#Activate the state transfer protocol ('true' to activate, 'false' to de-activate) +system.totalordermulticast.state_transfer = true + +#Maximum ahead-of-time message not discarded +system.totalordermulticast.highMark = 10000 + +#Maximum ahead-of-time message not discarded when the replica is still on EID 0 (after which the state transfer is triggered) +system.totalordermulticast.revival_highMark = 10 + +#Number of ahead-of-time messages necessary to trigger the state transfer after a request timeout occurs +system.totalordermulticast.timeout_highMark = 200 + +############################################ +###### Log and Checkpoint Configurations ### +############################################ + +system.totalordermulticast.log = true +system.totalordermulticast.log_parallel = false +system.totalordermulticast.log_to_disk = false +system.totalordermulticast.sync_log = false + +#Period at which BFT-SMaRt requests the state to the application (for the state transfer state protocol) +system.totalordermulticast.checkpoint_period = 1000 +system.totalordermulticast.global_checkpoint_period = 120000 + +system.totalordermulticast.checkpoint_to_disk = false +system.totalordermulticast.sync_ckp = false + + +############################################ +###### Reconfiguration Configurations ###### +############################################ + +#Replicas ID for the initial view, separated by a comma. +# The number of replicas in this parameter should be equal to that specified in 'system.servers.num' +system.initial.view = 0,1,2,3 + +#The ID of the trust third party (TTP) +system.ttp.id = 2001 + +#This sets if the system will function in Byzantine or crash-only mode. Set to "true" to support Byzantine faults +system.bft = true + +#Custom View Storage; +#view.storage.handler=bftsmart.reconfiguration.views.DefaultViewStorage \ No newline at end of file diff --git a/samples/sdk-samples/src/main/resources/testnet/ledger-binding-mem-0.conf b/samples/sdk-samples/src/main/resources/testnet/ledger-binding-mem-0.conf new file mode 100644 index 00000000..72b6d4e7 --- /dev/null +++ b/samples/sdk-samples/src/main/resources/testnet/ledger-binding-mem-0.conf @@ -0,0 +1,23 @@ +#绑定的账本的hash列表;以逗号分隔; +ledger.bindings=6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ + + +#第 1 个账本[6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ]的配置; +#账本的名字; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.name=sample-network +#账本的当前共识参与方的ID; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.id=0 +#账本的当前共识参与方的名字; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.name=a.com +#账本的当前共识参与方的私钥文件的保存路径; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pk-path= +#账本的当前共识参与方的私钥内容(Base58编码);如果指定了,优先选用此属性,其次是 pk-path 属性; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pk=177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x +#账本的当前共识参与方的私钥文件的读取口令;可为空;如果为空时,节点的启动过程中需要手动从控制台输入; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pwd=DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY +#账本的当前共识参与方地址 +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.address=LdeP3fY7jJbNwL8CiL2wU21AF9unDWQjVEW5w +#账本的存储数据库的连接字符串; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.db.uri=memory://local/0 +#账本的存储数据库的连接口令; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.db.pwd= \ No newline at end of file diff --git a/samples/sdk-samples/src/main/resources/testnet/ledger-binding-mem-1.conf b/samples/sdk-samples/src/main/resources/testnet/ledger-binding-mem-1.conf new file mode 100644 index 00000000..3f821ecd --- /dev/null +++ b/samples/sdk-samples/src/main/resources/testnet/ledger-binding-mem-1.conf @@ -0,0 +1,23 @@ +#绑定的账本的hash列表;以逗号分隔; +ledger.bindings=6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ + + +#第 1 个账本[6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ]的配置; +#账本的名字; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.name=sample-network +#账本的当前共识参与方的ID; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.id=1 +#账本的当前共识参与方的名字; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.name=b.com +#账本的当前共识参与方的私钥文件的保存路径; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pk-path= +#账本的当前共识参与方的私钥内容(Base58编码);如果指定了,优先选用此属性,其次是 pk-path 属性; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pk=177gju9p5zrNdHJVEQnEEKF4ZjDDYmAXyfG84V5RPGVc5xFfmtwnHA7j51nyNLUFffzz5UT +#账本的当前共识参与方的私钥文件的读取口令;可为空;如果为空时,节点的启动过程中需要手动从控制台输入; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pwd=DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY +#账本的当前共识参与方地址 +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.address=LdeNnz88dH6CA6PwkVdn3nFRibUKP3sFT2byG +#账本的存储数据库的连接字符串; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.db.uri=memory://local/1 +#账本的存储数据库的连接口令; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.db.pwd= \ No newline at end of file diff --git a/samples/sdk-samples/src/main/resources/testnet/ledger-binding-mem-2.conf b/samples/sdk-samples/src/main/resources/testnet/ledger-binding-mem-2.conf new file mode 100644 index 00000000..d389b218 --- /dev/null +++ b/samples/sdk-samples/src/main/resources/testnet/ledger-binding-mem-2.conf @@ -0,0 +1,23 @@ +#绑定的账本的hash列表;以逗号分隔; +ledger.bindings=6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ + + +#第 1 个账本[6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ]的配置; +#账本的名字; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.name=sample-network +#账本的当前共识参与方的ID; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.id=2 +#账本的当前共识参与方的名字; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.name=c.com +#账本的当前共识参与方的私钥文件的保存路径; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pk-path= +#账本的当前共识参与方的私钥内容(Base58编码);如果指定了,优先选用此属性,其次是 pk-path 属性; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pk=177gjtwLgmSx5v1hFb46ijh7L9kdbKUpJYqdKVf9afiEmAuLgo8Rck9yu5UuUcHknWJuWaF +#账本的当前共识参与方的私钥文件的读取口令;可为空;如果为空时,节点的启动过程中需要手动从控制台输入; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pwd=DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY +#账本的当前共识参与方地址 +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.address=LdeNmdpT4DiTwLUP9jRQhwdRBRiXeHno456vy +#账本的存储数据库的连接字符串; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.db.uri=memory://local/2 +#账本的存储数据库的连接口令; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.db.pwd= \ No newline at end of file diff --git a/samples/sdk-samples/src/main/resources/testnet/ledger-binding-mem-3.conf b/samples/sdk-samples/src/main/resources/testnet/ledger-binding-mem-3.conf new file mode 100644 index 00000000..983ce496 --- /dev/null +++ b/samples/sdk-samples/src/main/resources/testnet/ledger-binding-mem-3.conf @@ -0,0 +1,23 @@ +#绑定的账本的hash列表;以逗号分隔; +ledger.bindings=6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ + + +#第 1 个账本[6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ]的配置; +#账本的名字; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.name=sample-network +#账本的当前共识参与方的ID; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.id=3 +#账本的当前共识参与方的名字; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.name=d.com +#账本的当前共识参与方的私钥文件的保存路径; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pk-path= +#账本的当前共识参与方的私钥内容(Base58编码);如果指定了,优先选用此属性,其次是 pk-path 属性; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pk=177gk1pudweTq5zgJTh8y3ENCTwtSFsKyX7YnpuKPo7rKgCkCBXVXh5z2syaTCPEMbuWRns +#账本的当前共识参与方的私钥文件的读取口令;可为空;如果为空时,节点的启动过程中需要手动从控制台输入; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pwd=DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY +#账本的当前共识参与方地址 +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.address=LdeNekdXMHqyz9Qxc2jDSBnkvvZLbty6pRDdP +#账本的存储数据库的连接字符串; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.db.uri=memory://local/3 +#账本的存储数据库的连接口令; +binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.db.pwd= \ No newline at end of file diff --git a/samples/sdk-samples/src/main/resources/testnet/ledger.init b/samples/sdk-samples/src/main/resources/testnet/ledger.init new file mode 100644 index 00000000..727a84c4 --- /dev/null +++ b/samples/sdk-samples/src/main/resources/testnet/ledger.init @@ -0,0 +1,74 @@ +#账本的种子;一段16进制字符,最长可以包含64个字符;可以用字符“-”分隔,以便更容易读取; +ledger.seed=932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323ffe + +#账本的描述名称;此属性不参与共识,仅仅在当前参与方的本地节点用于描述用途; +ledger.name=sample-ledger + +#声明的账本创建时间;格式为 “yyyy-MM-dd HH:mm:ss.SSSZ”,表示”年-月-日 时:分:秒:毫秒时区“;例如:“2019-08-01 14:26:58.069+0800”,其中,+0800 表示时区是东8区 +created-time=2019-08-01 14:26:58.069+0800 + +#共识服务提供者;必须; +consensus.service-provider=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider + +#共识服务的参数配置;必须; +consensus.conf=classpath:testnet/bftsmart.config + +#密码服务提供者列表,以英文逗点“,”分隔;必须; +crypto.service-providers=com.jd.blockchain.crypto.service.classic.ClassicCryptoService, \ +com.jd.blockchain.crypto.service.sm.SMCryptoService + + +#参与方的个数,后续以 cons_parti.id 分别标识每一个参与方的配置; +cons_parti.count=4 + +#第0个参与方的名称; +cons_parti.0.name=a.com +#第0个参与方的公钥文件路径; +cons_parti.0.pubkey-path= +#第0个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; +cons_parti.0.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9 +#第0个参与方的账本初始服务的主机; +cons_parti.0.initializer.host=127.0.0.1 +#第0个参与方的账本初始服务的端口; +cons_parti.0.initializer.port=9800 +#第0个参与方的账本初始服务是否开启安全连接; +cons_parti.0.initializer.secure=false + +#第1个参与方的名称; +cons_parti.1.name=b.com +#第1个参与方的公钥文件路径; +cons_parti.1.pubkey-path= +#第1个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; +cons_parti.1.pubkey=3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX +#第1个参与方的账本初始服务的主机; +cons_parti.1.initializer.host=127.0.0.1 +#第1个参与方的账本初始服务的端口; +cons_parti.1.initializer.port=9810 +#第1个参与方的账本初始服务是否开启安全连接; +cons_parti.1.initializer.secure=false + +#第2个参与方的名称; +cons_parti.2.name=c.com +#第2个参与方的公钥文件路径; +cons_parti.2.pubkey-path= +#第2个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; +cons_parti.2.pubkey=3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x +#第2个参与方的账本初始服务的主机; +cons_parti.2.initializer.host=127.0.0.1 +#第2个参与方的账本初始服务的端口; +cons_parti.2.initializer.port=9820 +#第2个参与方的账本初始服务是否开启安全连接; +cons_parti.2.initializer.secure=false + +#第3个参与方的名称; +cons_parti.3.name=c.com +#第3个参与方的公钥文件路径; +cons_parti.3.pubkey-path= +#第3个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; +cons_parti.3.pubkey=3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk +#第3个参与方的账本初始服务的主机; +cons_parti.3.initializer.host=127.0.0.1 +#第3个参与方的账本初始服务的端口; +cons_parti.3.initializer.port=9830 +#第3个参与方的账本初始服务是否开启安全连接; +cons_parti.3.initializer.secure=false diff --git a/samples/sdk-samples/src/main/resources/transfer.jar b/samples/sdk-samples/src/main/resources/transfer.jar deleted file mode 100644 index 0984c731dd4cab1e45829eafeecfa19f2485d9b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7167 zcmbVQ1z1#D*QQIPC8bee=%GWTodJe!35V`(1f{#BK>-2jkdhV{VrY;CX%GeJ5`%xZ zUN3xp_xk_;UFSJ-&OEc;wbx#2&E9Lj%JQgaI7k-~9X+P_$IG7|*oY@YMqPp(tSHN= zj8G#%!a`h8zo?O1Rf9+xBY=Np z%@*ordUcdvmFfRm88KH5D-({tb@Ep@@c#n;=`*`C)Yieq)cFtJf0WX%vF7{zq}83E zcFty|PEvnH0gSN6VQd3+b}rS@aUq_h_%1tZ!BdM%8n;3qv`A-6#TPjBFlmfmapj%* zL!+CzU87T^Jv@UJHV(-ye$`;zhEeo1BDn`3GF1!It~|%HVW}awkk8J8g|mqh8ocY@ zwj-JB0im@9X5Z@%$`@MaL}+~vzn~+{I`+lTjf#yeX(M&V5su~JvLjKeAvd9P_}n{T zWZVp5F`mH}F#Ec@61XT#@rF%orPKV|=}obn&SGEbU3AVC=G;~$k5;wEfdxUQ*wGQ)hE2rWwgFpu5y4; z#=p`p>I8R9$GotZ4GMs-`1C$S4~~3C1UOT7mQ=b92nH6W9m@Mp_IGk-zsv>6NBfL8 z2Jg8P8hq)(^?5ZEtDCflCaFw8mRbwAC9B5nL7!dAL1jBbwWa|N z#YvA+WahCNqY){zu(kaJltO*cJ(f!Wi*b}VJ#r%;+asn(_CICuy`9}K**gQ$KL+uZ zS{4z0A|c1(1NzdyO!eZjLWwM@?kJ?+4PirW7=fln)eOlVa7kn4t4k5KOx$+{j@(UZ z)CE}arF=_CQM_Fk8k}SLoo>F3QyU&Ml?F3aO^u2!Qh^902a~}#9dCsiE=@}4bv6=B zu*uFATdzobm8JWvE|DBt$EC{WajO=~}CCTlSsWwH4& zC=PD0Kfn2sDu`kz;aYcf$bpk8cLXhS5@nT0^C`cohP0+alekso_ggoayEI^~#UfY? z&5@jzSO--pQw-!^=0`lD9-LUoL0}~Bc!P-j=0zA>EfhJ+t{Gbw7$kc>q zvd~fe+Cf92lH+_m;hSbtyiwN(_QB$A-NPm0CJb8)(EwY52VGTP)10xOmiURD^=_Vh z-VXg8EPjE-ZAW5r9fMskQBjWS2F7g>ko4R&vSBhuk-7n?q~T?3?};|=V-zd9j(d6( z4y`eZ6;<@yTUH8llG8UQ9w{r&aK$)bQd+Zc#o*xM>9=9X16E(<29Bf`^!I6$9kHqK zZXz!;-m921%==bGO_l>x|AEtKWTO&A@7Ij~Y@gSYEXS70AtGVfyFUs3OIz733 zP=oe}-IP$t+B5f2c76Nw%_1BP4ZZg7AWsd82iB&!PBc(bIHcrW$o1t9+}Mw$S8o?R zFxg`!B7g1Qo!q*=W|)|X2iDqdrAq23tFm7s`sxvfb`7H@Pju^AzAD0nNuk~l;kKrZ1}vO#@vdG0ZpV; zIt30Oi_i?ueS^3!+Ug48r#5@mfO*}sY05|!%c~EoE8}LceKC=@s~^r8ZF2IeA|n}m zk}X;)$C|K2-warx`A8n~c7NeLb9Hp!w^I{4=4NoKjJF|Mr@hh|@nqUQ5B!E(SgJ{R z{9`HBh!3ulBlpmBP0g$7da2^bIOs{@ib1XX9y5J_^KM%ka=XYLXOCCoRC|Jq^DtZK z5XNUhW3^{VjRboGD=f#w_m*3Oq9WF&qj6aA`8IBe`LGQlGXQ&fPMo)xwDmAwdl7I} zrbO?H$@ad1X2ALcgOrv;wa}lbMS8~?vq|`JCvlR-HfxI?8zE1>6*8%lc%i7G`=!7h zD@0q@XKarsI4oB}0pB?AOwlo=Ig+s-1vzK@-R=XO!r<9KoCLMCGc09$D#S-lsj2bKK|8&+-zY3@8=eM~1Q8hwZ=4vshlZ=zy=~xli&S+WbjG z4}aO<|Js#t|NpwOA01g#+>m0sI6+ry(CEGvvdkKCWKLMK$FK*3EPlaA=w6Er8FOtT z+>L&3T=W!4?5QK21~J_Xq{YSTEIl=II%cTO9qFZo_ta5E_aY8seIoArkUCdi$zDjIoKNc-X*9T!kXTXLiD6>g9=>*wBKUnYUbHRqJT z0FYbaXws}QYfg+^Q1mzOB0dAV0W2k?mrPfuBj|`zZN=(#VqQyhjxVkZPLT=o^$tir z%d5dP+^A>@C(Q(iHx4--kZ7*`7_V9H9qFA2Jra1yjwr zw#=s~ZiswGeZT>UIrGl^(k6|w2^{9&x)&EJpEGG3>y!#Hrg~S1H<@(oGjRV>q+L3TM!w-#5$!~4pu`( zLb`_fyNt2_K4Yq;P?MiM^p9*MD$mNHa+74(Ounn#%sayHeKLiUMn>3nhY&qGr+WB= zmujYZ7VXss|JL;Y+Qs`}=5^tcZSspu?}7dO@XgtSYfpH#x~HNly9tDEsRlRf zc%WU67Bl%*`oWt?-1e}<(ylpnNz}spEyB71P+MR&6-;P^?I~-1vuY*=LFsIyg&qg^P z=qP#BVK&_w zR0@S)OKe5C1YufOr!q=^&;EppkvxqK{{Zb$5ScF$J~S8wn(woP+8TzuE%$13>bCI; z#iug&ox3L)#ok(vzkln#hGhAOsuK-J7`f6xp5%DHM2x7o5xCvC%dKg2ilzgt0ccvQ z%yqwHJV(1nfp1dMHx;`VE3pKztJj%z`mC0`WHwk)JR<>S)wEd|o|=Tn^K1-{T-WNu zh^WC!HVw82O75NW%$hu*C_6%Rh_)&##SYM@>fda)JdCzX-PR9|rR3xata1zEQCL-o zu;(k1*%lp*xG|I3I~{DmvJuVl9Wx#3zEHxGJIK)3ccdDz>s6zfol?p0*hpmV#Zatf z$OIro(ayUOo3y`9uuq&p1?>Wg`y6?23*yJ7|F(H2|WO9>X$R}DV5SQMJt#+Bt8hVx8=zO^8bQ#AXfrHWF81^3N z+Hvf}7Wp!aT88M(OdIQ;xPpr6i2MqKrKW5e9u8^#$dyjpYN4opf%i6JA$rEqRN(-~{ zg&Tb>dh=+OyFjTMX{#YB8t?jy@2*|MaVfzK@>2d6T~k?18QTmE+Gz|u$Hc+cKFTU3 zEK#4CK*Zab2H!G=@n?Widw`glew4dD8)Y|3n#F`6TT{76KEnlV-!rs~e8)-i}CT8C#N|(QWc6L+$v=sT@(I1UaSfXXHW#FYgzxU_b;| z!poOJ#HGxzuB!wu5Q;ntX2|EDKaiHs<5r}Pr_!J15wufmk-tK3z6a z4p-fHStj7~;ssvblc2x{^QV58fGs=JbCip9#!*<01RFsaY(JLdf~59a~O>T$~L161aLJZ)it9_Mws6x`RLNrNXxWG4yEn?q(yYEIYKo>Mgp z%ikG1u<>)0!>1z{V2(fr-&mSVzVnsPbB#NxUeId(RYZ<>CuX1bj;Fxs`?o8-B>7`& zlJC{I9Lx^Zjd93kw#DRRomqE2mL70-sbJpN(4_%dch@DyMFI%w7v>cTdOblp-w93? z!u3+i(N5k(Q?S$zv9Zg{BH0qb-PrQ=2?68gX%ln(ev8mdwXC@r7zh@&fAl@F4ZZ zb90v`Qw>35aR;s)Y?D!!9{BQhqhv@H)^{J3uaI6Z`yoLlNqu3lvdtt?($u^De4rm@&D6tzeQx(-o{EU2!LipIS2 zeb(!81ZMOv(+BS+f(QgrW|O@c{YBaX=?%JEF>Q6R*BNyx4%zZ&`YBCCC{sx^`W(HO zATwo5FIG=yzOLS07jI1Q=qJV`5?!jR6UwjO%4^>{pR4X&)NyYJ zcRUoaSBhd?t>a&rMDc%J#|}>R4yH~nmZr{XZX9wDHZVj5RHW{}22vOVY3xGSWF`nV;$IiG|$GiATa-6-K?7Iq;kintxKDiP3Ubxbr;vlHM ze?^WB09TM#;6RpNPb5K3ZRiZEM;9vW)cd0mds>6nZi#T(25~FPBcqU@{xgY=P(cU* z(kF?F=U?RP57;HCewB~DAk}|LuHPNR>tC=d6#LbIf9={YcF)#+AWBI{iU%L7$ z;)2J%L@@t}_=DB{XV3+&eF=hGg8qX*{%8CJ&wYva`CI%?1{uK|UmE(gf-ZRPOGC8? zLw`l=Cky`1VEUifKeDv)-{8Mv#sAsd1uy { + for (Event eventMessage : eventMessages) { + // content中存放的是当前链上最新高度 + System.out.println("New block:" + eventMessage.getSequence() + ":" + BytesUtils.toLong(eventMessage.getContent().getBytes().toBytes())); + } + }); + + // 监听用户自定义事件 + blockchainService.monitorUserEvent(ledger, "LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye", "sample-event", 0, (eventMessage, eventContext) -> { + + BytesValue content = eventMessage.getContent(); + switch (content.getType()) { + case TEXT: + case XML: + case JSON: + System.out.println(eventMessage.getName() + ":" + eventMessage.getSequence() + ":" + content.getBytes().toUTF8String()); + break; + case INT64: + case TIMESTAMP: + System.out.println(eventMessage.getName() + ":" + eventMessage.getSequence() + ":" + BytesUtils.toLong(content.getBytes().toBytes())); + break; + default: // byte[], Bytes + System.out.println(eventMessage.getName() + ":" + eventMessage.getSequence() + ":" + content.getBytes().toBase58()); + break; + } + }); + + try { + cdl.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + /** + * 注册事件账户 + */ + @Test + public void testRegisterEventAccount() { + // 新建交易 + TransactionTemplate txTemp = blockchainService.newTransaction(ledger); + // 生成事件账户 + BlockchainKeypair eventAccount = BlockchainKeyGenerator.getInstance().generate(); + System.out.println("事件账户地址:" + eventAccount.getAddress()); + // 注册事件账户 + txTemp.eventAccounts().register(eventAccount.getIdentity()); + // 交易准备 + PreparedTransaction ptx = txTemp.prepare(); + // 交易签名 + ptx.sign(adminKey); + // 提交交易 + TransactionResponse response = ptx.commit(); + Assert.assertTrue(response.isSuccess()); + } + + /** + * 发布事件 + */ + @Test + public void testPublishEvent() { + // 新建交易 + TransactionTemplate txTemp = blockchainService.newTransaction(ledger); + + // 请正确填写数据账户地址 + // sequence是针对此消息name的插入更新操作次数严格递增,初始为-1 + txTemp.eventAccount(Bytes.fromBase58("LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye")) + .publish("topic1", "content1", -1) + .publish("topic1", "content2", 0) + .publish("topic1", "content3", 1) + .publish("topic2", "content", -1) + .publish("topic3", 1, -1) + .publish("topic4", Bytes.fromInt(1), -1); + // 交易准备 + PreparedTransaction ptx = txTemp.prepare(); + // 交易签名 + ptx.sign(adminKey); + // 提交交易 + TransactionResponse response = ptx.commit(); + Assert.assertTrue(response.isSuccess()); + } + + /** + * 注册事件账户的同时发布事件,一个事务内 + */ + @Test + public void testRegisterEventAccountAndPublishEvent() { + // 新建交易 + TransactionTemplate txTemp = blockchainService.newTransaction(ledger); + // 生成事件账户 + BlockchainKeypair eventAccount = BlockchainKeyGenerator.getInstance().generate(); + System.out.println("事件账户地址:" + eventAccount.getAddress()); + // 注册事件账户 + txTemp.eventAccounts().register(eventAccount.getIdentity()); + // 发布事件 + txTemp.eventAccount(eventAccount.getAddress()).publish("topic", "content", -1); + // 交易准备 + PreparedTransaction ptx = txTemp.prepare(); + // 提交交易 + TransactionResponse response = ptx.commit(); + Assert.assertTrue(response.isSuccess()); + } + +} diff --git a/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/ParticipantSample.java b/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/ParticipantSample.java new file mode 100644 index 00000000..512609d2 --- /dev/null +++ b/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/ParticipantSample.java @@ -0,0 +1,132 @@ +package com.jdchain.samples.sdk; + +import com.jd.blockchain.crypto.KeyGenUtils; +import com.jd.blockchain.ledger.BlockchainKeyGenerator; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.PreparedTransaction; +import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.TransactionTemplate; +import com.jd.blockchain.utils.codec.Base58Utils; +import com.jd.blockchain.utils.http.converters.JsonResponseConverter; +import com.jd.blockchain.utils.security.ShaUtils; +import com.jd.blockchain.utils.web.model.WebResponse; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +/** + * 参与方节点相关操作示例: + * 注册/激活/移除参与方操作 + *

+ * 本样例无法直接运行,请用户务必参照共识节点相关操作文档步骤完成各种前置操作,然后根据实际配置修改本样例各方法内参数 + */ +public class ParticipantSample extends SampleBase { + + // 注册参与方 + @Test + public void registerParticipant() { + // 新建交易 + TransactionTemplate txTemp = blockchainService.newTransaction(ledger); + // 生成用户信息 + BlockchainKeypair user = BlockchainKeyGenerator.getInstance().generate(); + String pwd = Base58Utils.encode(ShaUtils.hash_256("1".getBytes())); + System.out.println("参与方私钥:" + KeyGenUtils.encodePrivKey(user.getPrivKey(), pwd)); + System.out.println("参与方私钥密码:" + pwd); + System.out.println("参与方公钥:" + KeyGenUtils.encodePubKey(user.getPubKey())); + System.out.println("参与方地址:" + user.getAddress()); + // 注册参与方 + txTemp.participants().register("new peer node", user.getIdentity()); + // 交易准备 + PreparedTransaction ptx = txTemp.prepare(); + // 交易签名 + ptx.sign(adminKey); + // 提交交易 + TransactionResponse response = ptx.commit(); + Assert.assertTrue(response.isSuccess()); + } + + /** + * 激活参与方 + * 执行前请确保新节点已注册,且已经参照共识节点相关操作文档创建并启动新节点!!! + * 然后根据实际情况修改请求参数 + * + * @throws Exception + */ + @Test + public void activeParticipant() throws Exception { + // 新节点API服务IP和端口 + String newNodeIp = "127.0.0.1"; + String newNodeApiPort = "12040"; + // 账本信息 + String ledgerHash = ledger.toString(); + // 新节点共识配置 + String newNodeConsensusHost = "127.0.0.1"; + String newNodeConsensusPot = "8950"; + // 区块高度最新的节点API服务IP和端口,用于区块同步 + String syncNodeHost = "127.0.0.1"; + String syncNodePort = "12000"; + + // 发送POST请求执行节点激活操作 + HttpPost httpPost = new HttpPost(String.format("http://%s:%s/management/delegate/activeparticipant", newNodeIp, newNodeApiPort)); + List params = new ArrayList<>(); + params.add(new BasicNameValuePair("ledgerHash", ledgerHash)); + params.add(new BasicNameValuePair("consensusHost", newNodeConsensusHost)); + params.add(new BasicNameValuePair("consensusPort", newNodeConsensusPot)); + params.add(new BasicNameValuePair("remoteManageHost", syncNodeHost)); + params.add(new BasicNameValuePair("remoteManagePort", syncNodePort)); + params.add(new BasicNameValuePair("shutdown", "false")); + httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8")); + HttpClient httpClient = HttpClients.createDefault(); + HttpResponse response = httpClient.execute(httpPost); + JsonResponseConverter jsonConverter = new JsonResponseConverter(WebResponse.class); + + WebResponse webResponse = (WebResponse) jsonConverter.getResponse(null, response.getEntity().getContent(), null); + Assert.assertTrue(webResponse.isSuccess()); + } + + /** + * 移除参与方 + * 执行前请确保新节点已启动且出于参与共识状态!!! + * 然后根据实际情况修改请求参数 + * + * @throws Exception + */ + @Test + public void removeParticipant() throws Exception { + + // 待移除节点API服务IP和端口 + String nodeIp = "127.0.0.1"; + String nodeApiPort = "12030"; + // 账本信息 + String ledgerHash = ledger.toString(); + // 待移除节点地址 + String participantAddress = "LdeNekdXMHqyz9Qxc2jDSBnkvvZLbty6pRDdP"; + // 区块高度最新的节点API服务IP和端口,用于区块同步 + String syncNodeHost = "127.0.0.1"; + String syncNodePort = "12000"; + + // 发送POST请求执行节点移除操作 + HttpPost httpPost = new HttpPost(String.format("http://%s:%s/management/delegate/deactiveparticipant", nodeIp, nodeApiPort)); + List params = new ArrayList<>(); + params.add(new BasicNameValuePair("ledgerHash", ledgerHash)); + params.add(new BasicNameValuePair("participantAddress", participantAddress)); + params.add(new BasicNameValuePair("remoteManageHost", syncNodeHost)); + params.add(new BasicNameValuePair("remoteManagePort", syncNodePort)); + httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8")); + HttpClient httpClient = HttpClients.createDefault(); + HttpResponse response = httpClient.execute(httpPost); + JsonResponseConverter jsonConverter = new JsonResponseConverter(WebResponse.class); + + WebResponse webResponse = (WebResponse) jsonConverter.getResponse(null, response.getEntity().getContent(), null); + Assert.assertTrue(webResponse.isSuccess()); + } + +} diff --git a/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/QuerySample.java b/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/QuerySample.java new file mode 100644 index 00000000..cc418c0e --- /dev/null +++ b/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/QuerySample.java @@ -0,0 +1,587 @@ +package com.jdchain.samples.sdk; + +import com.jd.blockchain.crypto.Crypto; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.ContractInfo; +import com.jd.blockchain.ledger.DataAccountInfo; +import com.jd.blockchain.ledger.Event; +import com.jd.blockchain.ledger.KVDataVO; +import com.jd.blockchain.ledger.KVInfoVO; +import com.jd.blockchain.ledger.LedgerAdminInfo; +import com.jd.blockchain.ledger.LedgerBlock; +import com.jd.blockchain.ledger.LedgerInfo; +import com.jd.blockchain.ledger.LedgerMetadata; +import com.jd.blockchain.ledger.LedgerPermission; +import com.jd.blockchain.ledger.LedgerTransaction; +import com.jd.blockchain.ledger.ParticipantNode; +import com.jd.blockchain.ledger.PrivilegeSet; +import com.jd.blockchain.ledger.TransactionPermission; +import com.jd.blockchain.ledger.TransactionState; +import com.jd.blockchain.ledger.TypedKVEntry; +import com.jd.blockchain.ledger.UserInfo; +import com.jd.blockchain.ledger.UserPrivilegeSet; +import com.jd.blockchain.utils.codec.Base58Utils; +import com.jd.blockchain.utils.io.BytesUtils; +import org.junit.Assert; +import org.junit.Test; + +/** + * 查询样例 + */ +public class QuerySample extends SampleBase { + + HashDigest sampleHash = Crypto.resolveAsHashDigest(Base58Utils.decode("j5sTuEAWmLWKFwXgpdUCxbQN1XmZfkQdC94UT2AqQEt7hp")); + String sampleAddress = "LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye"; + String sampleKey = "sample-key"; + String sampleEvent = "sample-event"; + long sampleVersion = 0; + String sampleRoleName = "SAMPLE-ROLE"; + + /** + * 查询账本列表 + */ + @Test + public void getLedgerHashs() { + HashDigest[] digests = blockchainService.getLedgerHashs(); + for (HashDigest digest : digests) { + System.out.println(digest.toBase58()); + } + } + + /** + * 查询账本信息,区块hash,区块高度 + */ + @Test + public void getLedger() { + LedgerInfo ledgerInfo = blockchainService.getLedger(ledger); + System.out.println(ledgerInfo.getHash()); + } + + /** + * 查询账本信息,元数据,参与方,账本配置等 + */ + @Test + public void getLedgerAdminInfo() { + LedgerAdminInfo adminInfo = blockchainService.getLedgerAdminInfo(ledger); + System.out.println(adminInfo.getParticipantCount()); + } + + /** + * 查询共识参与方 + */ + @Test + public void getConsensusParticipants() { + ParticipantNode[] nodes = blockchainService.getConsensusParticipants(ledger); + for (ParticipantNode node : nodes) { + System.out.println("ID: " + node.getId()); + System.out.println("Address: " + node.getAddress().toString()); + System.out.println("PubKey: " + node.getPubKey().toString()); + System.out.println("State: " + node.getParticipantNodeState()); + } + } + + /** + * 查询账本的元数据 + */ + @Test + public void getLedgerMetadata() { + LedgerMetadata metadata = blockchainService.getLedgerMetadata(ledger); + System.out.println(Base58Utils.encode(metadata.getSeed())); + System.out.println(metadata.getParticipantsHash().toBase58()); + System.out.println(metadata.getSettingsHash().toBase58()); + } + + /** + * 根据高度查询区块 + */ + @Test + public void getBlockByHeight() { + LedgerBlock block1 = blockchainService.getBlock(ledger, -1); + LedgerBlock block2 = blockchainService.getBlock(ledger, Integer.MAX_VALUE); + Assert.assertNotNull(block1); + Assert.assertEquals(block1.getHash(), block2.getHash()); + LedgerBlock block3 = blockchainService.getBlock(ledger, 0); + Assert.assertTrue(block1.getHeight() >= block3.getHeight()); + } + + /** + * 根据hash查询区块 + */ + @Test + public void getBlockByHash() { + LedgerBlock block = blockchainService.getBlock(ledger, sampleHash); + Assert.assertNull(block); + } + + /** + * 查询某一高度(包括)之前所有交易数 + */ + @Test + public void getTransactionCountByHeight() { + long count = blockchainService.getTransactionCount(ledger, -1); + Assert.assertEquals(0, count); + count = blockchainService.getTransactionCount(ledger, 1); + Assert.assertNotEquals(0, count); + } + + /** + * 查询某一区块(包括)之前所有交易数 + */ + @Test + public void getTransactionCountByHash() { + long count = blockchainService.getTransactionCount(ledger, sampleHash); + Assert.assertEquals(0, count); + } + + /** + * 查询交易总数 + */ + @Test + public void getTransactionTotalCount() { + long count = blockchainService.getTransactionTotalCount(ledger); + Assert.assertNotEquals(0, count); + } + + /** + * 查询某一高度(包括)之前数据账户数 + */ + @Test + public void getDataAccountCountByHeight() { + long count = blockchainService.getDataAccountCount(ledger, 0); + Assert.assertEquals(0, count); + } + + /** + * 查询某一区块(包括)之前数据账户数 + */ + @Test + public void getDataAccountCountByHash() { + long count = blockchainService.getDataAccountCount(ledger, sampleHash); + Assert.assertEquals(0, count); + } + + /** + * 查询数据账户总数 + */ + @Test + public void getDataAccountTotalCount() { + long count = blockchainService.getDataAccountTotalCount(ledger); + System.out.println("Total DataAccount count: " + count); + } + + /** + * 查询某一高度(包括)之前用户数 + */ + @Test + public void getUserCountByHeight() { + long count = blockchainService.getUserCount(ledger, 0); + Assert.assertEquals(4, count); + } + + /** + * 查询某一区块(包括)之前用户数 + */ + @Test + public void getUserCountByHash() { + long count = blockchainService.getUserCount(ledger, sampleHash); + Assert.assertEquals(0, count); + } + + /** + * 查询用户总数 + */ + @Test + public void getUserTotalCount() { + long count = blockchainService.getUserTotalCount(ledger); + System.out.println("Total User count: " + count); + } + + /** + * 查询某一高度(包括)之前合约数 + */ + @Test + public void getContractCountByHeight() { + long count = blockchainService.getContractCount(ledger, 0); + Assert.assertEquals(0, count); + } + + /** + * 查询某一区块(包括)之前合约数 + */ + @Test + public void getContractCountByHash() { + long count = blockchainService.getContractCount(ledger, sampleHash); + Assert.assertEquals(0, count); + } + + /** + * 查询合约总数 + */ + @Test + public void getContractTotalCount() { + long count = blockchainService.getContractTotalCount(ledger); + System.out.println("Total Contract count: " + count); + } + + /** + * 分页查询交易某一高度(包括)之前的所有交易 + */ + @Test + public void getTransactionsByHeight() { + LedgerTransaction[] txs = blockchainService.getTransactions(ledger, 0, 0, 1); + Assert.assertEquals(1, txs.length); + } + + /** + * 分页查询交易某一区块(包括)之前的所有交易 + */ + @Test + public void getTransactionsByHash() { + LedgerTransaction[] txs = blockchainService.getTransactions(ledger, + sampleHash, 0, 1); + Assert.assertNull(txs); + } + + /** + * 分页查询某一高度中的交易 + */ + @Test + public void getAdditionalTransactionsByHeight() { + LedgerTransaction[] txs = blockchainService.getTransactions(ledger, 0, 0, 1); + Assert.assertEquals(1, txs.length); + } + + /** + * 分页查询某一区块中的交易 + */ + @Test + public void getAdditionalTransactionsByHash() { + LedgerTransaction[] txs = blockchainService.getTransactions(ledger, sampleHash, 0, 1); + Assert.assertNull(txs); + } + + /** + * 根据交易hash查询交易详情 + */ + @Test + public void getTransactionByContentHash() { + LedgerTransaction tx = blockchainService.getTransactionByContentHash(ledger, sampleHash); + Assert.assertNull(tx); + } + + /** + * 根据交易hash查询交易状态 + */ + @Test + public void getTransactionStateByContentHash() { + TransactionState state = blockchainService.getTransactionStateByContentHash(ledger, sampleHash); + Assert.assertNull(state); + } + + /** + * 根据地址查询用户信息 + */ + @Test + public void getUser() { + UserInfo user = blockchainService.getUser(ledger, sampleAddress); + if (null != user) { + System.out.println(user.getAddress().toString()); + } + } + + /** + * 根据地址查询数据账户 + */ + @Test + public void getDataAccount() { + DataAccountInfo dataAccount = blockchainService.getDataAccount(ledger, sampleAddress); + if (null != dataAccount) { + System.out.println(dataAccount.getAddress().toString()); + } + } + + /** + * 根据地址和键查询KV信息(只包含最高数据版本) + */ + @Test + public void getDataEntriesByKey() { + TypedKVEntry[] kvs = blockchainService.getDataEntries(ledger, sampleAddress, sampleKey); + for (TypedKVEntry kv : kvs) { + System.out.println(kv.getKey() + ":" + kv.getVersion() + ":" + kv.getValue()); + } + } + + /** + * 根据地址和指定键及数据版本查询KV信息 + */ + @Test + public void getDataEntriesWithKeyAndVersion() { + TypedKVEntry[] kvs = blockchainService.getDataEntries(ledger, sampleAddress, new KVInfoVO(new KVDataVO[]{new KVDataVO(sampleKey, new long[]{-1})})); + for (TypedKVEntry kv : kvs) { + System.out.println(kv.getKey() + ":" + kv.getVersion() + ":" + kv.getValue()); + } + } + + /** + * 查询数据账户KV总数 + */ + @Test + public void getDataEntriesTotalCount() { + long count = blockchainService.getDataEntriesTotalCount(ledger, sampleAddress); + System.out.println(count); + } + + /** + * 分页查询指定数据账户KV数据 + */ + @Test + public void getDataEntries() { + TypedKVEntry[] kvs = blockchainService.getDataEntries(ledger, sampleAddress, 0, 1); + for (TypedKVEntry kv : kvs) { + System.out.println(kv.getKey() + ":" + kv.getVersion() + ":" + kv.getValue()); + } + } + + /** + * 查询合约信息 + */ + @Test + public void getContract() { + ContractInfo contract = blockchainService.getContract(ledger, sampleAddress); + if (null != contract) { + System.out.println(contract.getAddress().toString()); + } + } + + /** + * 分页查询指定系统事件名下所有消息 + */ + @Test + public void getSystemEvents() { + Event[] events = blockchainService.getSystemEvents(ledger, sampleEvent, 0, 1); + Assert.assertTrue(null == events || events.length == 0); + } + + /** + * 查询系统事件名总数 + */ + @Test + public void getSystemEventNameTotalCount() { + long count = blockchainService.getSystemEventNameTotalCount(ledger); + Assert.assertEquals(0, count); + } + + /** + * 分页查询系统事件名 + */ + @Test + public void getSystemEventNames() { + String[] names = blockchainService.getSystemEventNames(ledger, 0, 1); + Assert.assertEquals(0, names.length); + } + + /** + * 查询指定系统事件名最新事件 + */ + @Test + public void getLatestEvent() { + Event event = blockchainService.getLatestEvent(ledger, sampleEvent); + Assert.assertNull(event); + } + + /** + * 获取指定系统事件名下所有事件 + */ + @Test + public void getSystemEventsTotalCount() { + long count = blockchainService.getSystemEventsTotalCount(ledger, sampleEvent); + Assert.assertEquals(0, count); + } + + /** + * 分页查询用户事件账户 + * + * @return + */ + @Test + public void getUserEventAccounts() { + BlockchainIdentity[] ids = blockchainService.getUserEventAccounts(ledger, 0, 1); + System.out.println(ids.length); + } + + /** + * 获取用户事件账户 + */ + @Test + public void getUserEventAccount() { + BlockchainIdentity id = blockchainService.getUserEventAccount(ledger, sampleAddress); + if (null != id) { + System.out.println(id.getAddress().toString()); + } + } + + /** + * 获取用户事件账户总数 + */ + @Test + public void getUserEventAccountTotalCount() { + long count = blockchainService.getUserEventAccountTotalCount(ledger); + System.out.println(count); + } + + /** + * 获取指定用户事件账户下事件名数 + */ + @Test + public void getUserEventNameTotalCount() { + long count = blockchainService.getUserEventNameTotalCount(ledger, sampleAddress); + System.out.println(count); + } + + /** + * 分页查询指定用户事件账户下事件名 + */ + @Test + public void getUserEventNames() { + String[] names = blockchainService.getUserEventNames(ledger, sampleAddress, 0, 1); + for (String name : names) { + System.out.println(name); + } + } + + /** + * 获取指定用户事件账户指定事件名下最新事件 + */ + @Test + public void getLatestUserEvent() { + Event event = blockchainService.getLatestEvent(ledger, sampleAddress, sampleEvent); + if (null != event) { + BytesValue content = event.getContent(); + switch (content.getType()) { + case TEXT: + case XML: + case JSON: + System.out.println(event.getName() + ":" + event.getSequence() + ":" + content.getBytes().toUTF8String()); + break; + case INT64: + case TIMESTAMP: + System.out.println(event.getName() + ":" + event.getSequence() + ":" + BytesUtils.toLong(content.getBytes().toBytes())); + break; + default: // byte[], Bytes + System.out.println(event.getName() + ":" + event.getSequence() + ":" + content.getBytes().toBase58()); + break; + } + } + } + + /** + * 获取指定用户事件账户指定事件名下事件总数 + */ + @Test + public void getUserEventsTotalCount() { + long count = blockchainService.getUserEventsTotalCount(ledger, sampleAddress, sampleEvent); + System.out.println(count); + } + + /** + * 分页查询指定用户事件账户指定事件名下事件 + */ + @Test + public void getUserEvents() { + Event[] events = blockchainService.getUserEvents(ledger, sampleAddress, sampleEvent, 0, 1); + for (Event event : events) { + BytesValue content = event.getContent(); + switch (content.getType()) { + case TEXT: + case XML: + case JSON: + System.out.println(event.getName() + ":" + event.getSequence() + ":" + content.getBytes().toUTF8String()); + break; + case INT64: + case TIMESTAMP: + System.out.println(event.getName() + ":" + event.getSequence() + ":" + BytesUtils.toLong(content.getBytes().toBytes())); + break; + default: // byte[], Bytes + System.out.println(event.getName() + ":" + event.getSequence() + ":" + content.getBytes().toBase58()); + break; + } + } + } + + /** + * 获取指定版本合约 + */ + @Test + public void getContractByAddressAndVersion() { + ContractInfo contract = blockchainService.getContract(ledger, sampleAddress, sampleVersion); + if (null != contract) { + System.out.println(contract.getAddress().toString()); + System.out.println(contract.getChainCodeVersion()); + System.out.println(contract.getChainCode()); + } + } + + /** + * 分页查询用户 + */ + @Test + public void getUsers() { + BlockchainIdentity[] ids = blockchainService.getUsers(ledger, 0, 1); + Assert.assertEquals(1, ids.length); + } + + /** + * 分页查询数据账户 + */ + @Test + public void getDataAccounts() { + BlockchainIdentity[] ids = blockchainService.getDataAccounts(ledger, 0, 1); + System.out.println(ids.length); + } + + /** + * 分页查询合约账户 + */ + @Test + public void getContractAccounts() { + BlockchainIdentity[] ids = blockchainService.getContractAccounts(ledger, 0, 1); + System.out.println(ids.length); + } + + /** + * 查询指定角色权限信息 + */ + @Test + public void getRolePrivileges() { + PrivilegeSet privilegeSet = blockchainService.getRolePrivileges(ledger, sampleRoleName); + if (null != privilegeSet) { + for (LedgerPermission ledgerpermission : privilegeSet.getLedgerPrivilege().getPrivilege()) { + System.out.println(ledgerpermission); + } + for (TransactionPermission transactionPermission : privilegeSet.getTransactionPrivilege().getPrivilege()) { + System.out.println(transactionPermission); + } + } + } + + /** + * 查询指定用户权限信息 + */ + @Test + public void getUserPrivileges() { + UserPrivilegeSet userPrivileges = blockchainService.getUserPrivileges(ledger, sampleAddress); + if (null != userPrivileges) { + for (String role : userPrivileges.getUserRole()) { + System.out.println(role); + } + for (LedgerPermission ledgerpermission : userPrivileges.getLedgerPrivilegesBitset().getPrivilege()) { + System.out.println(ledgerpermission); + } + for (TransactionPermission transactionPermission : userPrivileges.getTransactionPrivilegesBitset().getPrivilege()) { + System.out.println(transactionPermission); + } + } + } +} diff --git a/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/SampleBase.java b/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/SampleBase.java new file mode 100644 index 00000000..f4e417fa --- /dev/null +++ b/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/SampleBase.java @@ -0,0 +1,60 @@ +package com.jdchain.samples.sdk; + +import com.jd.blockchain.crypto.Crypto; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.crypto.KeyGenUtils; +import com.jd.blockchain.crypto.PrivKey; +import com.jd.blockchain.crypto.PubKey; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.sdk.BlockchainService; +import com.jd.blockchain.sdk.client.GatewayServiceFactory; +import com.jd.blockchain.utils.codec.Base58Utils; + +import java.util.Properties; + +public class SampleBase { + + // 交易签名用户 + protected static BlockchainKeypair adminKey; + // 网关IP + protected static String gatewayHost; + // 网关端口 + protected static int gatewayPort; + // 账本Hash + protected static HashDigest ledger; + // 区块链服务 + protected static BlockchainService blockchainService; + + static { + try { + // 读取配置文件 + Properties properties = new Properties(); + properties.load(SampleBase.class.getClassLoader().getResourceAsStream("config.properties")); + + // 初始配置交易签名用户信息 + PubKey pubKey = KeyGenUtils.decodePubKey(properties.getProperty("pubkey")); + PrivKey privKey = KeyGenUtils.decodePrivKey(properties.getProperty("privkey"), properties.getProperty("password")); + adminKey = new BlockchainKeypair(pubKey, privKey); + + // 读取网关配置 + gatewayHost = properties.getProperty("gateway.host"); + gatewayPort = Integer.parseInt(properties.getProperty("gateway.port")); + + // 读取账本配置 + String ledgerHash = properties.getProperty("ledger"); + + // 初始化区块链服务 + blockchainService = GatewayServiceFactory.connect(gatewayHost, gatewayPort, false, adminKey).getBlockchainService(); + + // 初始配置账本,从配置文件中读取,未设置获取账本列表第一个 + if (!ledgerHash.isEmpty()) { + ledger = Crypto.resolveAsHashDigest(Base58Utils.decode(ledgerHash)); + } else { + ledger = blockchainService.getLedgerHashs()[0]; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/UserSample.java b/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/UserSample.java new file mode 100644 index 00000000..502913a8 --- /dev/null +++ b/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/UserSample.java @@ -0,0 +1,111 @@ +package com.jdchain.samples.sdk; + +import com.jd.blockchain.ledger.BlockchainKeyGenerator; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.LedgerPermission; +import com.jd.blockchain.ledger.PreparedTransaction; +import com.jd.blockchain.ledger.TransactionPermission; +import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.TransactionTemplate; +import com.jd.blockchain.utils.Bytes; +import org.junit.Assert; +import org.junit.Test; + +/** + * 用户账户相关操作示例: + * 用户注册,角色创建,权限设置 + */ +public class UserSample extends SampleBase { + + /** + * 注册用户 + */ + @Test + public void registerUser() { + // 新建交易 + TransactionTemplate txTemp = blockchainService.newTransaction(ledger); + // 生成用户 + BlockchainKeypair user = BlockchainKeyGenerator.getInstance().generate(); + System.out.println("用户地址:" + user.getAddress()); + // 注册用户 + txTemp.users().register(user.getIdentity()); + // 交易准备 + PreparedTransaction ptx = txTemp.prepare(); + // 交易签名 + ptx.sign(adminKey); + // 提交交易 + TransactionResponse response = ptx.commit(); + Assert.assertTrue(response.isSuccess()); + } + + /** + * 创建角色 + */ + @Test + public void createRole() { + // 新建交易 + TransactionTemplate txTemp = blockchainService.newTransaction(ledger); + + // 创建角色 MANAGER ,并设置可以写数据账户,能执行交易 + txTemp.security().roles().configure("MANAGER") + .enable(LedgerPermission.WRITE_DATA_ACCOUNT) + .enable(TransactionPermission.DIRECT_OPERATION); + // 交易准备 + PreparedTransaction ptx = txTemp.prepare(); + // 交易签名 + ptx.sign(adminKey); + // 提交交易 + TransactionResponse response = ptx.commit(); + Assert.assertTrue(response.isSuccess()); + } + + /** + * 配置角色权限 + */ + @Test + public void configUserRole() { + // 新建交易 + TransactionTemplate txTemp = blockchainService.newTransaction(ledger); + + // 给用户设置 MANAGER 角色权限 + txTemp.security().authorziations().forUser(Bytes.fromBase58("LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye")).authorize("MANAGER"); + // 交易准备 + PreparedTransaction ptx = txTemp.prepare(); + // 交易签名 + ptx.sign(adminKey); + // 提交交易 + TransactionResponse response = ptx.commit(); + Assert.assertTrue(response.isSuccess()); + } + + /** + * 注册用户的同时配置角色权限,同一事务内 + */ + @Test + public void testRegisterUserAndConfigRole() { + // 新建交易 + TransactionTemplate txTemp = blockchainService.newTransaction(ledger); + // 生成用户 + BlockchainKeypair user = BlockchainKeyGenerator.getInstance().generate(); + System.out.println("用户地址:" + user.getAddress()); + // 注册用户 + txTemp.users().register(user.getIdentity()); + + // 创建角色 MANAGER + txTemp.security().roles().configure("MANAGER") + .enable(LedgerPermission.WRITE_DATA_ACCOUNT) + .enable(TransactionPermission.DIRECT_OPERATION); + + // 设置用户角色权限 + txTemp.security().authorziations().forUser(user.getAddress()).authorize("MANAGER"); + + // 交易主恩贝 + PreparedTransaction ptx = txTemp.prepare(); + // 交易签名 + ptx.sign(adminKey); + // 提交交易 + TransactionResponse response = ptx.commit(); + Assert.assertTrue(response.isSuccess()); + } + +} diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDKDemo_Contract_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDKDemo_Contract_Test_.java deleted file mode 100644 index 4390c48c..00000000 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDKDemo_Contract_Test_.java +++ /dev/null @@ -1,165 +0,0 @@ -package test.com.jd.blockchain.sdk.test; - -import static com.jd.blockchain.sdk.samples.SDKDemo_Constant.readChainCodes; -import static com.jd.blockchain.transaction.ContractReturnValue.decode; - -import org.junit.Before; -import org.junit.Test; - -import com.jd.blockchain.contract.TransferContract; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.KeyGenUtils; -import com.jd.blockchain.crypto.PrivKey; -import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.ledger.TransactionTemplate; -import com.jd.blockchain.sdk.BlockchainService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.sdk.samples.SDKDemo_Constant; -import com.jd.blockchain.transaction.GenericValueHolder; -import com.jd.blockchain.transaction.LongValueHolder; -import com.jd.blockchain.utils.Bytes; - -public class SDKDemo_Contract_Test_ { - - private BlockchainKeypair adminKey; - - private HashDigest ledgerHash; - - private BlockchainService blockchainService; - - @Before - public void init() { - // 生成连接网关的账号 - PrivKey privKey = KeyGenUtils.decodePrivKeyWithRawPassword(SDKDemo_Constant.PRIV_KEYS[0], - SDKDemo_Constant.PASSWORD); - - PubKey pubKey = KeyGenUtils.decodePubKey(SDKDemo_Constant.PUB_KEYS[0]); - - adminKey = new BlockchainKeypair(pubKey, privKey); - - // 连接网关 - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(SDKDemo_Constant.GW_IPADDR, - SDKDemo_Constant.GW_PORT, false, adminKey); - - blockchainService = serviceFactory.getBlockchainService(); - - HashDigest[] ledgerHashs = blockchainService.getLedgerHashs(); - - ledgerHash = ledgerHashs[0]; - } - - @Test - public void testContract() { - - // 发布jar包 - // 定义交易; - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - - byte[] contractCode = readChainCodes("transfer.jar"); - - // 生成一个合约账号 - BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate(); - - txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode); - - // 签名; - PreparedTransaction ptx = txTpl.prepare(); - - ptx.sign(adminKey); - - // 提交并等待共识返回; - TransactionResponse txResp = ptx.commit(); - - System.out.println(txResp.isSuccess()); - - // 首先注册一个数据账户 - BlockchainKeypair dataAccount = createDataAccount(); - - String dataAddress = dataAccount.getAddress().toBase58(); - - Bytes contractAddress = contractDeployKey.getAddress(); - - // 创建两个账号: - String account0 = "jd_zhangsan", account1 = "jd_lisi"; - long account0Money = 3000L, account1Money = 2000L; - // 创建两个账户 - // 使用KV创建一个账户 - System.out.println(create(dataAddress, account0, account0Money, false, null)); - // 使用合约创建一个账户 - System.out.println(create(dataAddress, account1, account1Money, true, contractAddress)); - - // 转账,使得双方钱达到一致 - System.out.println(transfer(dataAddress, account0, account1, 500L, contractAddress)); - - // 读取当前结果 - System.out.println(read(dataAddress, account0, contractAddress)); - System.out.println(read(dataAddress, account1, contractAddress)); - - // 读取账号历史信息 - System.out.println(readAll(dataAddress, account0, contractAddress)); - System.out.println(readAll(dataAddress, account1, contractAddress)); - } - - private String readAll(String address, String account, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - GenericValueHolder result = decode(transferContract.readAll(address, account)); - commit(txTpl); - return result.get(); - } - - private long read(String address, String account, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - LongValueHolder result = decode(transferContract.read(address, account)); - commit(txTpl); - return result.get(); - } - - private String transfer(String address, String from, String to, long money, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - GenericValueHolder result = decode(transferContract.transfer(address, from, to, money)); - commit(txTpl); - return result.get(); - } - - private BlockchainKeypair createDataAccount() { - // 首先注册一个数据账户 - BlockchainKeypair newDataAccount = BlockchainKeyGenerator.getInstance().generate(); - - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - txTpl.dataAccounts().register(newDataAccount.getIdentity()); - commit(txTpl); - return newDataAccount; - } - - private String create(String address, String account, long money, boolean useContract, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - if (useContract) { - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - GenericValueHolder result = decode(transferContract.create(address, account, money)); - commit(txTpl); - return result.get(); - } else { - // 通过KV创建 - txTpl.dataAccount(address).setInt64(account, money, -1); - TransactionResponse txResp = commit(txTpl); - return account + money; - } - } - - private TransactionResponse commit(TransactionTemplate txTpl) { - PreparedTransaction ptx = txTpl.prepare(); - ptx.sign(adminKey); - return ptx.commit(); - } -} diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java deleted file mode 100644 index ed0eee08..00000000 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java +++ /dev/null @@ -1,384 +0,0 @@ -package test.com.jd.blockchain.sdk.test; - -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; - -import com.jd.blockchain.crypto.base.DefaultCryptoEncoding; -import com.jd.blockchain.crypto.base.HashDigestBytes; -import org.junit.Before; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.ClassPathResource; - -import com.jd.blockchain.contract.samples.AssetContract; -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.Crypto; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.PrivKey; -import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.crypto.SignatureFunction; -import com.jd.blockchain.ledger.BlockchainIdentity; -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.ledger.TransactionTemplate; -import com.jd.blockchain.sdk.BlockchainService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.sdk.samples.SDKDemo_Contract; -import com.jd.blockchain.utils.Bytes; -import com.jd.blockchain.utils.codec.Base58Utils; -import com.jd.blockchain.utils.io.ByteArray; -import com.jd.blockchain.utils.net.NetworkAddress; -import com.jd.blockchain.utils.serialize.json.JSONSerializeUtils; - -/** - * 演示合约执行的过程; - * - * @author zhaogw - * 2019-05-21 11:03 - */ -public class SDK_Contract_Test { - public static Logger log = LoggerFactory.getLogger(SDKDemo_Contract.class); - - public static BlockchainKeypair CLIENT_CERT = BlockchainKeyGenerator.getInstance().generate("ED25519"); - // 账本地址; - public static String ledgerAddress; - private PrivKey privKey; - private PubKey pubKey; - BlockchainService bcsrv; - AsymmetricKeypair signKeyPair; - HashDigest ledgerHash; - - @Before - public void init(){ - ledgerAddress = "j5qHcS8jG6XwpE5wXv9HYMeGTb5Fs2gQao3TPQ3irqFpQL"; - ledgerHash = getLedgerHash(); - pubKey = SDK_GateWay_KeyPair_Para.pubKey0; - privKey = SDK_GateWay_KeyPair_Para.privkey0; - // 使用私钥进行签名; - signKeyPair = new BlockchainKeypair(pubKey, privKey); - - // 创建服务代理; - final String GATEWAY_IP = "localhost"; - final int GATEWAY_PORT = 11000; - NetworkAddress addr = new NetworkAddress(GATEWAY_IP,GATEWAY_PORT); - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(addr); - bcsrv = serviceFactory.getBlockchainService(); - } - -// /** -// * 演示合约执行的过程; -// */ -//// @Test -// public void demoContract1() { -// String dataAddress = registerData4Contract(); -// // 发起交易; -// TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); -// String contractAddress = "LdeNg8JHFCKABJt6AaRNVCZPgY4ofGPd8MgcR"; -// AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class); -//// assetContract.issue(transactionContentBody,contractAddress); -//// assetContract.issue(transactionContentBody,contractAddress,888888); -//// assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,77777); -//// assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,77777); -// Byte byteObj = Byte.parseByte("127"); -// assetContract.issue(byteObj,dataAddress,321123); -//// assetContract.issue(contractBizContent,dataAddress); -// assetContract.issue(Byte.parseByte("126"),dataAddress,Bytes.fromString("100.234")); -// -// // TX 准备就绪; -// PreparedTransaction prepTx = txTemp.prepare(); -// prepTx.sign(signKeyPair); -// // 提交交易; -// TransactionResponse transactionResponse = prepTx.commit(); -// -// //check; -// KVDataEntry[] dataEntries = bcsrv.getDataEntries(ledgerHash,dataAddress,"total"); -// assertEquals("100",dataEntries[0].getValue().toString()); -// } - -// /** -// * 演示合约执行的过程; -// */ -//// @Test -// public void demoContract2() throws IOException { -// String contractAddress = deploy(); -// String dataAddress = registerData4Contract(); -// System.out.println("dataAddress="+dataAddress); -// // 发起交易; -// TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); -// -// AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class); -// ContractBizContent contractBizContent = () -> new String[]{"param1","param2"}; -// assetContract.issue(contractBizContent,dataAddress,123456); -// -// // TX 准备就绪; -// PreparedTransaction prepTx = txTemp.prepare(); -// prepTx.sign(signKeyPair); -// // 提交交易; -// TransactionResponse transactionResponse = prepTx.commit(); -// -// //check; -// assertTrue(transactionResponse.isSuccess()); -// KVDataEntry[] dataEntries = bcsrv.getDataEntries(ledgerHash,dataAddress,contractBizContent.getAttrs()[0],contractBizContent.getAttrs()[1]); -// assertEquals("value1",dataEntries[0].getValue().toString()); -// assertEquals(888,dataEntries[1].getValue()); -// } - -// @Test - public void registerData(){ - // 在本地定义 TX 模板 - TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); - BlockchainKeypair dataAccount = BlockchainKeyGenerator.getInstance().generate(); - txTemp.dataAccounts().register(dataAccount.getIdentity()); - - String key1 = "jd_key1"; - String val1 = "www.jd1.com"; - String key2 = "jd_key2"; - String val2 = "www.jd2.com"; - // 定义交易,传输最简单的数字、字符串、提取合约中的地址; - txTemp.dataAccount(dataAccount.getAddress()).setText(key1, val1, -1); - txTemp.dataAccount(dataAccount.getAddress()).setText(key2, val2, -1); - - // TX 准备就绪; - PreparedTransaction prepTx = txTemp.prepare(); - prepTx.sign(signKeyPair); - // 提交交易; - TransactionResponse transactionResponse = prepTx.commit(); - - assertTrue(transactionResponse.isSuccess()); - - //repeat; - String[] keys = {key1,key2}; - String[] values = {"www.jd1.com.v1","www.jd2.com.v1"}; - this.setDataInDataAddress(dataAccount.getAddress(),keys,values,0); - String[] values2 = {"www.jd1.com.v2","www.jd2.com.v2"}; - this.setDataInDataAddress(dataAccount.getAddress(),keys,values2,1); - } - - private String registerData4Contract(){ - // 在本地定义 TX 模板 - TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); - BlockchainKeypair dataAccount = BlockchainKeyGenerator.getInstance().generate(); - txTemp.dataAccounts().register(dataAccount.getIdentity()); - txTemp.dataAccount(dataAccount.getAddress()).setInt64("total", 200, -1); - txTemp.dataAccount(dataAccount.getAddress()).setText("param1", "v", -1); - txTemp.dataAccount(dataAccount.getAddress()).setInt64("param2", 123, -1); - // TX 准备就绪; - PreparedTransaction prepTx = txTemp.prepare(); - prepTx.sign(signKeyPair); - // 提交交易; - TransactionResponse transactionResponse = prepTx.commit(); - assertTrue(transactionResponse.isSuccess()); - - return dataAccount.getAddress().toBase58(); - } - - private void setDataInDataAddress(Bytes dataAddress, String[] keys, String[] values, long version){ - // 在本地定义 TX 模板 - TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); - BlockchainKeypair dataAccount = BlockchainKeyGenerator.getInstance().generate(); - - for(int i=0; i - * - * 注:私钥由调用方在本地保管和使用; - * - * @return - */ - private static AsymmetricKeypair getSponsorKey() { - SignatureFunction signatureFunction = Crypto.getSignatureFunction("ED25519"); - return signatureFunction.generateKeypair(); - } - - /** - * 商品信息; - * - * @author huanghaiquan - * - */ - public static class Remark { - - private String code; - - private String name; - - private String venderAddress; - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getVenderAddress() { - return venderAddress; - } - - public void setVenderAddress(String venderAddress) { - this.venderAddress = venderAddress; - } - - } - -// @Test -// public void testStringArr(){ -// ContractBizContent contractBizContent = () -> new String[]{"1","2","you are welcome!"}; -// byte[] bizBytes = BinaryProtocol.encode(contractBizContent,ContractBizContent.class); -// ContractBizContent actualObj = BinaryProtocol.decodeAs(bizBytes,ContractBizContent.class); -// assertArrayEquals(contractBizContent.getAttrs(),actualObj.getAttrs()); -// } - -// @Test -// public void testContractArgs(){ -// ContractBizContent contractBizContent = () -> new String[]{"param1"}; -// Method method = ReflectionUtils.findMethod(AssetContract2.class,"issue",ContractBizContent.class,String.class); -// ContractArgs contractArgs = new ContractArgs() { -// @Override -// public Method getMethod() { -// return method; -// } -// -// @Override -// public Object[] getArgs() { -// return new Object[]{contractBizContent,"hello"}; -// } -// }; -// -// //add the annotation; -// -// } -} diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_BatchInsertData_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_BatchInsertData_Test_.java deleted file mode 100644 index 7e2d78e3..00000000 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_BatchInsertData_Test_.java +++ /dev/null @@ -1,138 +0,0 @@ -/** - * Copyright: Copyright 2016-2020 JD.COM All Right Reserved - * FileName: test.com.jd.blockchain.sdk.test.SDK_GateWay_InsertData_Test - * Author: shaozhuguang - * Department: 区块链研发部 - * Date: 2018/9/4 上午11:06 - * Description: 插入数据测试 - */ -package test.com.jd.blockchain.sdk.test; - -import static org.junit.Assert.assertEquals; - -import com.jd.blockchain.crypto.base.DefaultCryptoEncoding; -import com.jd.blockchain.crypto.base.HashDigestBytes; -import org.junit.Before; -import org.junit.Test; - -import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.Crypto; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.HashFunction; -import com.jd.blockchain.crypto.SignatureFunction; -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionRequest; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.ledger.TransactionState; -import com.jd.blockchain.ledger.TransactionTemplate; -import com.jd.blockchain.sdk.BlockchainTransactionService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.transaction.TxResponseMessage; -import com.jd.blockchain.utils.codec.Base58Utils; - -/** - * 插入数据测试 - * @author shaozhuguang - * @create 2018/9/4 - * @since 1.0.0 - */ - -public class SDK_GateWay_BatchInsertData_Test_ { - - String ledgerHash = ""; - - private BlockchainKeypair CLIENT_CERT = null; - - private String GATEWAY_IPADDR = null; - - private int GATEWAY_PORT; - - private boolean SECURE; - - private BlockchainTransactionService service; - - - @Before - public void init() { - CLIENT_CERT = BlockchainKeyGenerator.getInstance().generate("ED25519"); - GATEWAY_IPADDR = "127.0.0.1"; - GATEWAY_PORT = 8000; - SECURE = false; - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IPADDR, GATEWAY_PORT, SECURE, - CLIENT_CERT); - service = serviceFactory.getBlockchainService(); - - DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(TransactionResponse.class); - } - - @Test - public void batchInsertData_Test() { - HashDigest ledgerHash = getLedgerHash(); - // 在本地定义注册账号的 TX; - TransactionTemplate txTemp = service.newTransaction(ledgerHash); - - // -------------------------------------- - // 将商品信息写入到指定的账户中; - // 对象将被序列化为 JSON 形式存储,并基于 JSON 结构建立查询索引; - String dataAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf=="; - - String key1 = "jd_key1"; - String val1 = "www.jd.com"; - - String key2 = "jd_key2"; - String val2 = "www.jd.com"; - - txTemp.dataAccount(dataAccount).setText(key1, val1, -1); - txTemp.dataAccount(dataAccount).setText(key2, val2, -1); - - // TX 准备就绪; - PreparedTransaction prepTx = txTemp.prepare(); - - // 使用私钥进行签名; - AsymmetricKeypair keyPair = getSponsorKey(); - prepTx.sign(keyPair); - - // 提交交易; - TransactionResponse transactionResponse = prepTx.commit(); - - // 期望返回结果 - TransactionResponse expectResp = initResponse(); - - System.out.println("---------- assert start ----------"); - assertEquals(expectResp.isSuccess(), transactionResponse.isSuccess()); - assertEquals(expectResp.getExecutionState(), transactionResponse.getExecutionState()); - assertEquals(expectResp.getContentHash(), transactionResponse.getContentHash()); - assertEquals(expectResp.getBlockHeight(), transactionResponse.getBlockHeight()); - assertEquals(expectResp.getBlockHash(), transactionResponse.getBlockHash()); - System.out.println("---------- assert OK ----------"); - } - - private HashDigest getLedgerHash() { - return new HashDigestBytes(DefaultCryptoEncoding.decodeAlgorithm(Base58Utils.decode(ledgerHash)), Base58Utils.decode(ledgerHash)); - } - - - private AsymmetricKeypair getSponsorKey() { - SignatureFunction signatureFunction = Crypto.getSignatureFunction("ED25519"); - return signatureFunction.generateKeypair(); - } - - private TransactionResponse initResponse() { - HashFunction hashFunc = Crypto.getHashFunction("SHA256");; - HashDigest contentHash = hashFunc.hash("contentHash".getBytes()); - HashDigest blockHash = hashFunc.hash("blockHash".getBytes()); - long blockHeight = 9998L; - - TxResponseMessage resp = new TxResponseMessage(contentHash); - resp.setBlockHash(blockHash); - resp.setBlockHeight(blockHeight); - resp.setExecutionState(TransactionState.SUCCESS); - return resp; - } -} \ No newline at end of file diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_DataAccount_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_DataAccount_Test_.java deleted file mode 100644 index 114c6de6..00000000 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_DataAccount_Test_.java +++ /dev/null @@ -1,131 +0,0 @@ -/** - * Copyright: Copyright 2016-2020 JD.COM All Right Reserved - * FileName: test.com.jd.blockchain.sdk.test.SDK_GateWay_InsertData_Test - * Author: shaozhuguang - * Department: 区块链研发部 - * Date: 2018/9/4 上午11:06 - * Description: 插入数据测试 - */ -package test.com.jd.blockchain.sdk.test; - -import org.junit.Before; -import org.junit.Test; - -import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.Crypto; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.HashFunction; -import com.jd.blockchain.crypto.SignatureFunction; -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionRequest; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.ledger.TransactionState; -import com.jd.blockchain.ledger.TransactionTemplate; -import com.jd.blockchain.sdk.BlockchainService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.transaction.TxResponseMessage; - -/** - * 插入数据测试 - * @author shaozhuguang - * @create 2018/9/4 - * @since 1.0.0 - */ - -public class SDK_GateWay_DataAccount_Test_ { - - private BlockchainKeypair CLIENT_CERT = null; - - private String GATEWAY_IPADDR = null; - - private int GATEWAY_PORT; - - private boolean SECURE; - - private BlockchainService service; - - @Before - public void init() { - CLIENT_CERT = new BlockchainKeypair(SDK_GateWay_KeyPair_Para.pubKey0, SDK_GateWay_KeyPair_Para.privkey0); - GATEWAY_IPADDR = "127.0.0.1"; - GATEWAY_PORT = 8081; - SECURE = false; - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IPADDR, GATEWAY_PORT, SECURE, - CLIENT_CERT); - service = serviceFactory.getBlockchainService(); - - DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(TransactionResponse.class); - } - - @Test - public void registerDataAccount_Test() { -// HashDigest ledgerHash = getLedgerHash(); - HashDigest[] ledgerHashs = service.getLedgerHashs(); - // 在本地定义注册账号的 TX; - TransactionTemplate txTemp = service.newTransaction(ledgerHashs[0]); - -// SignatureFunction signatureFunction = getSignatureFunction(); -// -// CryptoKeyPair cryptoKeyPair = signatureFunction.generateKeyPair(); - - //existed signer - AsymmetricKeypair keyPair = new BlockchainKeypair(SDK_GateWay_KeyPair_Para.pubKey1, SDK_GateWay_KeyPair_Para.privkey1); - - BlockchainKeypair dataAcount = BlockchainKeyGenerator.getInstance().generate(); - - // 注册 - txTemp.dataAccounts().register(dataAcount.getIdentity()); - - // TX 准备就绪; - PreparedTransaction prepTx = txTemp.prepare(); - - prepTx.sign(keyPair); - - // 提交交易; - TransactionResponse transactionResponse = prepTx.commit(); - -// // 期望返回结果 -// TransactionResponse expectResp = initResponse(); -// -// System.out.println("---------- assert start ----------"); -// assertEquals(expectResp.isSuccess(), transactionResponse.isSuccess()); -// assertEquals(expectResp.getExecutionState(), transactionResponse.getExecutionState()); -// assertEquals(expectResp.getContentHash(), transactionResponse.getContentHash()); -// assertEquals(expectResp.getBlockHeight(), transactionResponse.getBlockHeight()); -// assertEquals(expectResp.getBlockHash(), transactionResponse.getBlockHash()); -// System.out.println("---------- assert OK ----------"); - } - - private HashDigest getLedgerHash() { - HashFunction hashFunc = Crypto.getHashFunction("SHA256");; - HashDigest ledgerHash =hashFunc.hash("jd-gateway".getBytes()); - return ledgerHash; - } - - private SignatureFunction getSignatureFunction() { - return Crypto.getSignatureFunction("ED25519"); - } - - private AsymmetricKeypair getSponsorKey() { - return getSignatureFunction().generateKeypair(); - } - - private TransactionResponse initResponse() { - HashFunction hashFunc = Crypto.getHashFunction("SHA256");; - HashDigest contentHash = hashFunc.hash("contentHash".getBytes()); - HashDigest blockHash = hashFunc.hash("blockHash".getBytes()); - long blockHeight = 9998L; - - TxResponseMessage resp = new TxResponseMessage(contentHash); - resp.setBlockHash(blockHash); - resp.setBlockHeight(blockHeight); - resp.setExecutionState(TransactionState.SUCCESS); - return resp; - } -} \ No newline at end of file diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_InsertData_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_InsertData_Test_.java deleted file mode 100644 index 5d420d5f..00000000 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_InsertData_Test_.java +++ /dev/null @@ -1,131 +0,0 @@ -/** - * Copyright: Copyright 2016-2020 JD.COM All Right Reserved - * FileName: test.com.jd.blockchain.sdk.test.SDK_GateWay_InsertData_Test - * Author: shaozhuguang - * Department: 区块链研发部 - * Date: 2018/9/4 上午11:06 - * Description: 插入数据测试 - */ -package test.com.jd.blockchain.sdk.test; - -import static org.junit.Assert.assertEquals; - -import org.junit.Before; -import org.junit.Test; - -import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.Crypto; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.HashFunction; -import com.jd.blockchain.crypto.SignatureFunction; -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionRequest; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.ledger.TransactionState; -import com.jd.blockchain.ledger.TransactionTemplate; -import com.jd.blockchain.sdk.BlockchainTransactionService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.transaction.TxResponseMessage; - -/** - * 插入数据测试 - * @author shaozhuguang - * @create 2018/9/4 - * @since 1.0.0 - */ - -public class SDK_GateWay_InsertData_Test_ { - - private BlockchainKeypair CLIENT_CERT = null; - - private String GATEWAY_IPADDR = null; - - private int GATEWAY_PORT; - - private boolean SECURE; - - private BlockchainTransactionService service; - - - @Before - public void init() { - CLIENT_CERT = BlockchainKeyGenerator.getInstance().generate("ED25519"); - GATEWAY_IPADDR = "127.0.0.1"; - GATEWAY_PORT = 8000; - SECURE = false; - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IPADDR, GATEWAY_PORT, SECURE, - CLIENT_CERT); - service = serviceFactory.getBlockchainService(); - - DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(TransactionResponse.class); - } - - @Test - public void insertData_Test() { - HashDigest ledgerHash = getLedgerHash(); - // 在本地定义注册账号的 TX; - TransactionTemplate txTemp = service.newTransaction(ledgerHash); - - // -------------------------------------- - // 将商品信息写入到指定的账户中; - // 对象将被序列化为 JSON 形式存储,并基于 JSON 结构建立查询索引; - String dataAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf=="; - - String dataKey = "jd_code"; - String dataVal = "www.jd.com"; - - txTemp.dataAccount(dataAccount).setText(dataKey, dataVal, -1); - - // TX 准备就绪; - PreparedTransaction prepTx = txTemp.prepare(); - - // 使用私钥进行签名; - AsymmetricKeypair keyPair = getSponsorKey(); - prepTx.sign(keyPair); - - // 提交交易; - TransactionResponse transactionResponse = prepTx.commit(); - - // 期望返回结果 - TransactionResponse expectResp = initResponse(); - - System.out.println("---------- assert start ----------"); - assertEquals(expectResp.isSuccess(), transactionResponse.isSuccess()); - assertEquals(expectResp.getExecutionState(), transactionResponse.getExecutionState()); - assertEquals(expectResp.getContentHash(), transactionResponse.getContentHash()); - assertEquals(expectResp.getBlockHeight(), transactionResponse.getBlockHeight()); - assertEquals(expectResp.getBlockHash(), transactionResponse.getBlockHash()); - System.out.println("---------- assert OK ----------"); - } - - private HashDigest getLedgerHash() { - HashFunction hashFunc = Crypto.getHashFunction("SHA256"); - HashDigest ledgerHash = hashFunc.hash("jd-gateway".getBytes()); - return ledgerHash; - } - - - private AsymmetricKeypair getSponsorKey() { - SignatureFunction signatureFunction = Crypto.getSignatureFunction("ED25519"); - return signatureFunction.generateKeypair(); - } - - private TransactionResponse initResponse() { - HashFunction hashFunc = Crypto.getHashFunction("SHA256"); - HashDigest contentHash = hashFunc.hash("contentHash".getBytes()); - HashDigest blockHash = hashFunc.hash("blockHash".getBytes()); - long blockHeight = 9998L; - - TxResponseMessage resp = new TxResponseMessage(contentHash); - resp.setBlockHash(blockHash); - resp.setBlockHeight(blockHeight); - resp.setExecutionState(TransactionState.SUCCESS); - return resp; - } -} \ No newline at end of file diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_KeyPair_Para.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_KeyPair_Para.java deleted file mode 100644 index 706cd370..00000000 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_KeyPair_Para.java +++ /dev/null @@ -1,34 +0,0 @@ -package test.com.jd.blockchain.sdk.test; - -import com.jd.blockchain.crypto.KeyGenUtils; -import com.jd.blockchain.crypto.PrivKey; -import com.jd.blockchain.crypto.PubKey; - -/** - * Created by zhangshuang3 on 2018/10/17. - */ -public class SDK_GateWay_KeyPair_Para { - public static final String PASSWORD = "abc"; - - public static final String[] PUB_KEYS = { "3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9", - "3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX", - "3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x", - "3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk" }; - - public static final String[] PRIV_KEYS = { - "177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x", - "177gju9p5zrNdHJVEQnEEKF4ZjDDYmAXyfG84V5RPGVc5xFfmtwnHA7j51nyNLUFffzz5UT", - "177gjtwLgmSx5v1hFb46ijh7L9kdbKUpJYqdKVf9afiEmAuLgo8Rck9yu5UuUcHknWJuWaF", - "177gk1pudweTq5zgJTh8y3ENCTwtSFsKyX7YnpuKPo7rKgCkCBXVXh5z2syaTCPEMbuWRns" }; - - public static PrivKey privkey0 = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS[0], PASSWORD); - public static PrivKey privkey1 = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS[1], PASSWORD); - public static PrivKey privkey2 = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS[2], PASSWORD); - public static PrivKey privkey3 = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS[3], PASSWORD); - - public static PubKey pubKey0 = KeyGenUtils.decodePubKey(PUB_KEYS[0]); - public static PubKey pubKey1 = KeyGenUtils.decodePubKey(PUB_KEYS[1]); - public static PubKey pubKey2 = KeyGenUtils.decodePubKey(PUB_KEYS[2]); - public static PubKey pubKey3 = KeyGenUtils.decodePubKey(PUB_KEYS[3]); - -} diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Participant_Regist_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Participant_Regist_Test_.java deleted file mode 100644 index 0b9e6a93..00000000 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Participant_Regist_Test_.java +++ /dev/null @@ -1,100 +0,0 @@ -package test.com.jd.blockchain.sdk.test; - -import static org.junit.Assert.assertTrue; - -import com.jd.blockchain.ledger.*; -import org.junit.Before; -import org.junit.Test; - -import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.crypto.AddressEncoding; -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.KeyGenUtils; -import com.jd.blockchain.crypto.PrivKey; -import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.sdk.BlockchainService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.sdk.samples.SDKDemo_Constant; -import com.jd.blockchain.utils.net.NetworkAddress; - -/** - * 注册参与方测试 - * @author zhangshuang - * @create 2019/7/4 - * @since 1.0.0 - */ - -public class SDK_GateWay_Participant_Regist_Test_ { - - private PrivKey privKey; - private PubKey pubKey; - - private BlockchainKeypair CLIENT_CERT = null; - - private String GATEWAY_IPADDR = null; - - private int GATEWAY_PORT; - - private boolean SECURE; - - private BlockchainService service; - - //根据密码工具产生的公私钥 - static String PUB = "3snPdw7i7PkdgqiGX7GbZuFSi1cwZn7vtjw4vifb1YoXgr9k6Kfmis"; - String PRIV = "177gjtZu8w1phqHFVNiFhA35cfimXmP6VuqrBFhfbXBWK8s4TRwro2tnpffwP1Emwr6SMN6"; - - @Before - public void init() { - - privKey = SDK_GateWay_KeyPair_Para.privkey1; - pubKey = SDK_GateWay_KeyPair_Para.pubKey1; - - CLIENT_CERT = new BlockchainKeypair(SDK_GateWay_KeyPair_Para.pubKey0, SDK_GateWay_KeyPair_Para.privkey0); - GATEWAY_IPADDR = "127.0.0.1"; - GATEWAY_PORT = 11000; - SECURE = false; - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IPADDR, GATEWAY_PORT, SECURE, - CLIENT_CERT); - service = serviceFactory.getBlockchainService(); - - DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(TransactionResponse.class); - DataContractRegistry.register(ParticipantRegisterOperation.class); - DataContractRegistry.register(ParticipantStateUpdateOperation.class); - DataContractRegistry.register(ConsensusSettingsUpdateOperation.class); - } - - @Test - public void registerParticipant_Test() { - HashDigest[] ledgerHashs = service.getLedgerHashs(); - // 在本地定义注册账号的 TX; - TransactionTemplate txTemp = service.newTransaction(ledgerHashs[0]); - - //existed signer - AsymmetricKeypair keyPair = new BlockchainKeypair(pubKey, privKey); - - PrivKey privKey = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV, SDKDemo_Constant.PASSWORD); - - PubKey pubKey = KeyGenUtils.decodePubKey(PUB); - - System.out.println("Address = "+AddressEncoding.generateAddress(pubKey)); - - BlockchainKeypair user = new BlockchainKeypair(pubKey, privKey); - - // 注册参与方 - txTemp.participants().register("Peer4", user.getIdentity()); - - // TX 准备就绪; - PreparedTransaction prepTx = txTemp.prepare(); - - // 使用私钥进行签名; - prepTx.sign(keyPair); - - // 提交交易; - TransactionResponse transactionResponse = prepTx.commit(); - assertTrue(transactionResponse.isSuccess()); - - } -} diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java deleted file mode 100644 index fe0b7d5f..00000000 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java +++ /dev/null @@ -1,184 +0,0 @@ -/** - * Copyright: Copyright 2016-2020 JD.COM All Right Reserved - * FileName: test.com.jd.blockchain.sdk.test.SDK_GateWay_InsertData_Test - * Author: shaozhuguang - * Department: 区块链研发部 - * Date: 2018/9/4 上午11:06 - * Description: 插入数据测试 - */ -package test.com.jd.blockchain.sdk.test; - -import org.junit.Before; -import org.junit.Test; - -import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.Crypto; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.HashFunction; -import com.jd.blockchain.crypto.SignatureFunction; -import com.jd.blockchain.ledger.BlockchainIdentity; -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.DigitalSignature; -import com.jd.blockchain.ledger.LedgerBlock; -import com.jd.blockchain.ledger.LedgerInfo; -import com.jd.blockchain.ledger.LedgerTransaction; -import com.jd.blockchain.ledger.ParticipantNode; -import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionRequest; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.ledger.TransactionState; -import com.jd.blockchain.ledger.TypedKVEntry; -import com.jd.blockchain.sdk.BlockchainService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.transaction.TxResponseMessage; - -/** - * 插入数据测试 - * - * @author shaozhuguang - * @create 2018/9/4 - * @since 1.0.0 - */ - -public class SDK_GateWay_Query_Test_ { - - private BlockchainKeypair CLIENT_CERT = null; - - private String GATEWAY_IPADDR = null; - - private int GATEWAY_PORT; - - private boolean SECURE; - - private BlockchainService service; - - @Before - public void init() { - CLIENT_CERT = BlockchainKeyGenerator.getInstance().generate("ED25519"); - GATEWAY_IPADDR = "127.0.0.1"; - GATEWAY_PORT = 11000; - SECURE = false; - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IPADDR, GATEWAY_PORT, SECURE, - CLIENT_CERT); - service = serviceFactory.getBlockchainService(); - - DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(TransactionResponse.class); - } - - @Test - public void query_Test() { - - HashDigest ledgerHash = service.getLedgerHashs()[0]; - ; - // ParserConfig.global.setAutoTypeSupport(true); - - LedgerInfo ledgerInfo = service.getLedger(ledgerHash); - long ledgerNumber = ledgerInfo.getLatestBlockHeight(); - System.out.println(ledgerNumber); - HashDigest hashDigest = ledgerInfo.getHash(); - System.out.println(hashDigest); - // 最新区块; - LedgerBlock latestBlock = service.getBlock(ledgerHash, ledgerNumber); - System.out.println("latestBlock.Hash=" + latestBlock.getHash()); - long count = service.getContractCount(ledgerHash, 3L); - System.out.println("contractCount=" + count); - count = service.getContractCount(ledgerHash, hashDigest); - System.out.println("contractCount=" + count); - BlockchainIdentity contract = service.getContract(ledgerHash, "12345678"); - System.out.println(contract); - - LedgerBlock block = service.getBlock(ledgerHash, hashDigest); - System.out.println("block.Hash=" + block.getHash()); - - count = service.getDataAccountCount(ledgerHash, 123456); - System.out.println("dataAccountCount=" + count); - count = service.getDataAccountCount(ledgerHash, hashDigest); - System.out.println("dataAccountCount=" + count); - - BlockchainIdentity dataAccount = service.getDataAccount(ledgerHash, "1245633"); - System.out.println(dataAccount.getAddress()); - - count = service.getTransactionCount(ledgerHash, hashDigest); - System.out.println("transactionCount=" + count); - count = service.getTransactionCount(ledgerHash, 12456); - System.out.println("transactionCount=" + count); - - LedgerTransaction[] txList = service.getTransactions(ledgerHash, ledgerNumber, 0, 100); - for (LedgerTransaction ledgerTransaction : txList) { - System.out.println("ledgerTransaction.Hash=" + ledgerTransaction.getRequest().getTransactionHash()); - } - - txList = service.getTransactions(ledgerHash, hashDigest, 0, 100); - for (LedgerTransaction ledgerTransaction : txList) { - System.out.println("ledgerTransaction.Hash=" + ledgerTransaction.getRequest().getTransactionHash()); - } - - LedgerTransaction tx = service.getTransactionByContentHash(ledgerHash, hashDigest); - DigitalSignature[] signatures = tx.getRequest().getEndpointSignatures(); - for (DigitalSignature signature : signatures) { - System.out.println(signature.getDigest().getAlgorithm()); - } - System.out.println("transaction.blockHeight=" + tx.getResult().getBlockHeight()); - System.out.println("transaction.executionState=" + tx.getResult().getExecutionState()); - - ParticipantNode[] participants = service.getConsensusParticipants(ledgerHash); - for (ParticipantNode participant : participants) { - System.out.println("participant.name=" + participant.getName()); - // System.out.println(participant.getConsensusAddress()); - // System.out.println("participant.host=" + - // participant.getConsensusAddress().getHost()); - System.out.println("participant.getPubKey=" + participant.getPubKey()); - System.out.println("participant.getKeyType=" + participant.getPubKey().getKeyType()); - System.out.println("participant.getRawKeyBytes=" + participant.getPubKey().getRawKeyBytes()); - System.out.println("participant.algorithm=" + participant.getPubKey().getAlgorithm()); - } - - String commerceAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf=="; - String[] objKeys = new String[] { "x001", "x002" }; - TypedKVEntry[] kvData = service.getDataEntries(ledgerHash, commerceAccount, objKeys); - for (TypedKVEntry kvDatum : kvData) { - System.out.println("kvData.key=" + kvDatum.getKey()); - System.out.println("kvData.version=" + kvDatum.getVersion()); - System.out.println("kvData.value=" + kvDatum.getValue()); - } - - HashDigest[] hashs = service.getLedgerHashs(); - for (HashDigest hash : hashs) { - System.out.println("hash.toBase58=" + hash.toBase58()); - } - } - - private HashDigest getLedgerHash() { - HashDigest ledgerHash = Crypto.getHashFunction("SHA256").hash("jd-gateway".getBytes()); - return ledgerHash; - } - - private SignatureFunction getSignatureFunction() { - return Crypto.getSignatureFunction("ED25519"); - } - - private BlockchainKeypair getSponsorKey() { - SignatureFunction signatureFunction = getSignatureFunction(); - AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair(); - BlockchainKeypair blockchainKeyPair = new BlockchainKeypair(cryptoKeyPair.getPubKey(), - cryptoKeyPair.getPrivKey()); - return blockchainKeyPair; - } - - private TransactionResponse initResponse() { - HashFunction hashFunc = Crypto.getHashFunction("SHA256"); - HashDigest contentHash = hashFunc.hash("contentHash".getBytes()); - HashDigest blockHash = hashFunc.hash("blockHash".getBytes()); - long blockHeight = 9998L; - - TxResponseMessage resp = new TxResponseMessage(contentHash); - resp.setBlockHash(blockHash); - resp.setBlockHeight(blockHeight); - resp.setExecutionState(TransactionState.SUCCESS); - return resp; - } -} \ No newline at end of file diff --git a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_User_Test_.java b/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_User_Test_.java deleted file mode 100644 index 5310624e..00000000 --- a/samples/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_User_Test_.java +++ /dev/null @@ -1,151 +0,0 @@ -/** - * Copyright: Copyright 2016-2020 JD.COM All Right Reserved - * FileName: test.com.jd.blockchain.sdk.test.SDK_GateWay_InsertData_Test - * Author: shaozhuguang - * Department: 区块链研发部 - * Date: 2018/9/4 上午11:06 - * Description: 插入数据测试 - */ -package test.com.jd.blockchain.sdk.test; - -import static org.junit.Assert.assertTrue; - -import org.junit.Before; -import org.junit.Test; - -import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.Crypto; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.HashFunction; -import com.jd.blockchain.crypto.PrivKey; -import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.crypto.SignatureFunction; -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionRequest; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.ledger.TransactionState; -import com.jd.blockchain.ledger.TransactionTemplate; -import com.jd.blockchain.sdk.BlockchainService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.transaction.TxResponseMessage; - -/** - * 插入数据测试 - * @author shaozhuguang - * @create 2018/9/4 - * @since 1.0.0 - */ - -public class SDK_GateWay_User_Test_ { - -// public static final String PASSWORD = SDK_GateWay_KeyPair_Para.PASSWORD; -// -// public static final String[] PUB_KEYS = SDK_GateWay_KeyPair_Para.PUB_KEYS; -// -// public static final String[] PRIV_KEYS = SDK_GateWay_KeyPair_Para.PRIV_KEYS; - - private PrivKey privKey; - private PubKey pubKey; - - private BlockchainKeypair CLIENT_CERT = null; - - private String GATEWAY_IPADDR = null; - - private int GATEWAY_PORT; - - private boolean SECURE; - - private BlockchainService service; - - @Before - public void init() { - -// PrivKey privkey0 = KeyGenCommand.decodePrivKeyWithRawPassword(PRIV_KEYS[0], PASSWORD); -// PrivKey privkey1 = KeyGenCommand.decodePrivKeyWithRawPassword(PRIV_KEYS[1], PASSWORD); -// PrivKey privkey2 = KeyGenCommand.decodePrivKeyWithRawPassword(PRIV_KEYS[2], PASSWORD); -// PrivKey privkey3 = KeyGenCommand.decodePrivKeyWithRawPassword(PRIV_KEYS[3], PASSWORD); -// -// PubKey pubKey0 = KeyGenCommand.decodePubKey(PUB_KEYS[0]); -// PubKey pubKey1 = KeyGenCommand.decodePubKey(PUB_KEYS[1]); -// PubKey pubKey2 = KeyGenCommand.decodePubKey(PUB_KEYS[2]); -// PubKey pubKey3 = KeyGenCommand.decodePubKey(PUB_KEYS[3]); - - privKey = SDK_GateWay_KeyPair_Para.privkey1; - pubKey = SDK_GateWay_KeyPair_Para.pubKey1; - - CLIENT_CERT = new BlockchainKeypair(SDK_GateWay_KeyPair_Para.pubKey0, SDK_GateWay_KeyPair_Para.privkey0); - GATEWAY_IPADDR = "127.0.0.1"; - GATEWAY_PORT = 10300; - SECURE = false; - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IPADDR, GATEWAY_PORT, SECURE, - CLIENT_CERT); - service = serviceFactory.getBlockchainService(); - - DataContractRegistry.register(TransactionContent.class); - DataContractRegistry.register(TransactionRequest.class); - DataContractRegistry.register(TransactionResponse.class); - } - - @Test - public void registerUser_Test() { - HashDigest[] ledgerHashs = service.getLedgerHashs(); - // 在本地定义注册账号的 TX; - TransactionTemplate txTemp = service.newTransaction(ledgerHashs[0]); - - //existed signer - AsymmetricKeypair keyPair = new BlockchainKeypair(pubKey, privKey); - - BlockchainKeypair user = BlockchainKeyGenerator.getInstance().generate(); - - // 注册 - txTemp.users().register(user.getIdentity()); - - // TX 准备就绪; - PreparedTransaction prepTx = txTemp.prepare(); - - // 使用私钥进行签名; - prepTx.sign(keyPair); - - // 提交交易; - TransactionResponse transactionResponse = prepTx.commit(); - assertTrue(transactionResponse.isSuccess()); - - // 期望返回结果 -// TransactionResponse expectResp = initResponse(); -// -// System.out.println("---------- assert start ----------"); -// assertEquals(expectResp.isSuccess(), transactionResponse.isSuccess()); -// assertEquals(expectResp.getExecutionState(), transactionResponse.getExecutionState()); -// assertEquals(expectResp.getContentHash(), transactionResponse.getContentHash()); -// assertEquals(expectResp.getBlockHeight(), transactionResponse.getBlockHeight()); -// assertEquals(expectResp.getBlockHash(), transactionResponse.getBlockHash()); -// System.out.println("---------- assert OK ----------"); - } - -// private HashDigest getLedgerHash() { -// byte[] hashBytes = Base58Utils.decode(ledgerHashBase58); -// return new HashDigest(hashBytes); -// } - - private AsymmetricKeypair getSponsorKey() { - SignatureFunction signatureFunction = Crypto.getSignatureFunction("ED25519"); - return signatureFunction.generateKeypair(); - } - - private TransactionResponse initResponse() { - HashFunction hashFunc = Crypto.getHashFunction("SHA256");; - HashDigest contentHash = hashFunc.hash("contentHash".getBytes()); - HashDigest blockHash = hashFunc.hash("blockHash".getBytes()); - long blockHeight = 9998L; - - TxResponseMessage resp = new TxResponseMessage(contentHash); - resp.setBlockHash(blockHash); - resp.setBlockHeight(blockHeight); - resp.setExecutionState(TransactionState.SUCCESS); - return resp; - } -} \ No newline at end of file diff --git a/samples/sdk-samples/src/test/resources/contract.jar b/samples/sdk-samples/src/test/resources/contract.jar deleted file mode 100644 index 3ff8a821d9f4980f3a642b3b392901b723979a78..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7937 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 dza;S2R#8b7?yU5cpvd!?JwvR@PCzj|6~9F diff --git a/samples/sdk-samples/src/test/resources/sys-contract.properties b/samples/sdk-samples/src/test/resources/sys-contract.properties deleted file mode 100644 index a1457b06..00000000 --- a/samples/sdk-samples/src/test/resources/sys-contract.properties +++ /dev/null @@ -1,13 +0,0 @@ -#ledger info; -ownerPubPath=F:\\jdsk\\jdsk-files\\github\\jdchain-starter\\conf\\jd-com.pub -ownerPrvPath=F:\\jdsk\\jdsk-files\\github\\jdchain-starter\\conf\\jd-com.priv -ownerPassword=F:\\jdsk\\jdsk-files\\github\\jdchain-starter\\conf\\jd-com.pwd -ledgerHash=j5rpuGWVxSuUbU3gK7MDREfui797AjfdHzvAMiSaSzydu7 -host=localhost -port=11000 -#execute contract; -event = issue-asset -chainCodePath=F:\\jdsk\\jdsk-files\\github\\jdchain-starter\\contract-compile\\target\\contract.jar -contractArgs=1000##fromAddr##LdeNvLeq6MB6y8CoyawYxgCCYCJkrp5xoVGUw -#contractArgs=fromAddr##toAddr##30##LdeNvLeq6MB6y8CoyawYxgCCYCJkrp5xoVGUw - diff --git a/samples/sdk-samples/src/test/resources/transfer.jar b/samples/sdk-samples/src/test/resources/transfer.jar deleted file mode 100644 index a161392eeed55569af68fd4dddd5846f9a9e4787..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7118 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 Date: Mon, 28 Dec 2020 16:11:14 +0800 Subject: [PATCH 136/150] upgraded modules to fix the bugs of concurrent competition between the process of consensus and the process of Heartbeat; --- core | 2 +- framework | 2 +- libs/bft-smart | 2 +- test | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core b/core index 5b910dd1..bfbb6267 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 5b910dd16fd8540bb48f9748d99d3d6e39f583c1 +Subproject commit bfbb6267d14b8b59a7d0b5593bc4b5958dbb3680 diff --git a/framework b/framework index 10d6a6d5..dbde6e52 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 10d6a6d57a062a3a36169e04e881b145993edce2 +Subproject commit dbde6e525ab2673c82824b385d349be093ca7b81 diff --git a/libs/bft-smart b/libs/bft-smart index 34549163..2e06c420 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 34549163e3c7833841226c01b1353d663469815a +Subproject commit 2e06c420453391ffe93b5d1a53f2cadb9b40e633 diff --git a/test b/test index 52e8abc7..49758186 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 52e8abc725d800d3edf78e6df7d26d6ab02d8518 +Subproject commit 4975818658f136181beb725a649d907cd344e5aa From 9c1a4e37e4443fbb187221c02ad166b53b3185de Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Mon, 28 Dec 2020 18:41:05 +0800 Subject: [PATCH 137/150] upgraded modules to fix the dead lock bugs of consensus thread that the consensus lock is held by a waiting thread; --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index 2e06c420..924e520d 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 2e06c420453391ffe93b5d1a53f2cadb9b40e633 +Subproject commit 924e520dc91bb49ddbd56837b1d424275c85f2a0 From b74b08c9e97cb91e7d20177c7726b1ffb2e58ae9 Mon Sep 17 00:00:00 2001 From: imuge Date: Wed, 30 Dec 2020 13:01:09 +0800 Subject: [PATCH 138/150] update bftsmart --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index 924e520d..cd07c1ce 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 924e520dc91bb49ddbd56837b1d424275c85f2a0 +Subproject commit cd07c1ce424c32a362470c2a1758cfec4ed0c8f5 From 809e4a0bf3099dc5f46e3f723bbb8bbb59a19bbd Mon Sep 17 00:00:00 2001 From: imuge Date: Thu, 31 Dec 2020 10:52:45 +0800 Subject: [PATCH 139/150] fix dataAccount sample error --- .../test/java/com/jdchain/samples/sdk/DataAccountSample.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/DataAccountSample.java b/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/DataAccountSample.java index 320174be..ddece471 100644 --- a/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/DataAccountSample.java +++ b/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/DataAccountSample.java @@ -26,7 +26,7 @@ public class DataAccountSample extends SampleBase { BlockchainKeypair dataAccount = BlockchainKeyGenerator.getInstance().generate(); System.out.println("数据账户地址:" + dataAccount.getAddress()); // 注册数据账户 - txTemp.dataAccounts().register(adminKey.getIdentity()); + txTemp.dataAccounts().register(dataAccount.getIdentity()); // 交易准备 PreparedTransaction ptx = txTemp.prepare(); // 交易签名 From 61ae791001e90f99612b2c5a3baf9c4ff97d85b5 Mon Sep 17 00:00:00 2001 From: zhangshuang Date: Thu, 31 Dec 2020 16:16:53 +0800 Subject: [PATCH 140/150] fix jira 628, update bftsmart lib --- libs/bft-smart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/bft-smart b/libs/bft-smart index cd07c1ce..f817655c 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit cd07c1ce424c32a362470c2a1758cfec4ed0c8f5 +Subproject commit f817655c4632ca020411a403e4b7555b250c0dfb From fadbee0812ac2d5921f1b00537f450c02d9eeb9f Mon Sep 17 00:00:00 2001 From: imuge Date: Thu, 31 Dec 2020 17:16:52 +0800 Subject: [PATCH 141/150] update log configurations --- .../src/main/resources/config/log4j2-peer.xml | 27 +++++++++++++++++++ .../src/main/resources/scripts/ledger-init.sh | 2 +- .../main/resources/scripts/peer-startup.sh | 7 ++--- 3 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 deploy/deploy-peer/src/main/resources/config/log4j2-peer.xml diff --git a/deploy/deploy-peer/src/main/resources/config/log4j2-peer.xml b/deploy/deploy-peer/src/main/resources/config/log4j2-peer.xml new file mode 100644 index 00000000..2d136e0b --- /dev/null +++ b/deploy/deploy-peer/src/main/resources/config/log4j2-peer.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/deploy/deploy-peer/src/main/resources/scripts/ledger-init.sh b/deploy/deploy-peer/src/main/resources/scripts/ledger-init.sh index eebc689b..ecbc3e02 100644 --- a/deploy/deploy-peer/src/main/resources/scripts/ledger-init.sh +++ b/deploy/deploy-peer/src/main/resources/scripts/ledger-init.sh @@ -5,5 +5,5 @@ boot_file=$(ls $HOME/libs | grep tools-initializer-booter-) if [ ! -n "$boot_file" ]; then echo "tools-initializer-booter is null" else - java -jar -server -Djdchain.log=$HOME $HOME/libs/$boot_file -l $HOME/config/init/local.conf -i $HOME/config/init/ledger.init $* + java -jar -server -Djdchain.log=$HOME/logs $HOME/libs/$boot_file -l $HOME/config/init/local.conf -i $HOME/config/init/ledger.init $* fi \ No newline at end of file diff --git a/deploy/deploy-peer/src/main/resources/scripts/peer-startup.sh b/deploy/deploy-peer/src/main/resources/scripts/peer-startup.sh index 9cb6597f..1823ad19 100644 --- a/deploy/deploy-peer/src/main/resources/scripts/peer-startup.sh +++ b/deploy/deploy-peer/src/main/resources/scripts/peer-startup.sh @@ -30,9 +30,6 @@ APP_HOME=$(cd `dirname $0`;cd ../; pwd) #System目录 APP_SYSTEM_PATH=$APP_HOME/system -#节点输出日志路径 -LOG_OUT=$APP_HOME/bin/peer.out - #获取Peer节点的启动Jar包 APP_JAR=$(ls $APP_SYSTEM_PATH | grep $APP_JAR_PREFIX) @@ -43,7 +40,7 @@ CONFIG_PATH=$APP_HOME/config LEDGER_BINDING_CONFIG=$CONFIG_PATH/ledger-binding.conf #定义程序启动的参数 -JAVA_OPTS="-jar -server -Xms2048m -Xmx2048m" +JAVA_OPTS="-jar -server -Xms2048m -Xmx2048m -Djdchain.log=$APP_HOME/logs -Dlogging.config=file:$APP_HOME/config/log4j2-peer.xml" #APP具体相关命令 APP_CMD=$APP_SYSTEM_PATH/$APP_JAR" -home="$APP_HOME" -c "$LEDGER_BINDING_CONFIG" -p "$WEB_PORT @@ -104,7 +101,7 @@ if [[ $psid -ne 0 ]]; then echo "================================" else echo "Starting Peer ......" - nohup $JAVA_BIN $JAVA_OPTS $APP_CMD $* >$LOG_OUT 2>&1 & + nohup $JAVA_BIN $JAVA_OPTS $APP_CMD $* & JAVA_CMD="$JAVA_BIN $JAVA_OPTS $APP_CMD $*" sleep 1 checkpid From 83da1bb654cb46cbc3ac1464b6617eec82cae0e0 Mon Sep 17 00:00:00 2001 From: imuge Date: Thu, 31 Dec 2020 18:11:33 +0800 Subject: [PATCH 142/150] update gateway log configuration --- .../src/main/resources/config/log4j2-gw.xml | 27 +++++++++++++++++++ .../src/main/resources/scripts/startup.sh | 6 ++--- 2 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 deploy/deploy-gateway/src/main/resources/config/log4j2-gw.xml diff --git a/deploy/deploy-gateway/src/main/resources/config/log4j2-gw.xml b/deploy/deploy-gateway/src/main/resources/config/log4j2-gw.xml new file mode 100644 index 00000000..8bffe83a --- /dev/null +++ b/deploy/deploy-gateway/src/main/resources/config/log4j2-gw.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/deploy/deploy-gateway/src/main/resources/scripts/startup.sh b/deploy/deploy-gateway/src/main/resources/scripts/startup.sh index 76189f54..2db26ec4 100644 --- a/deploy/deploy-gateway/src/main/resources/scripts/startup.sh +++ b/deploy/deploy-gateway/src/main/resources/scripts/startup.sh @@ -20,7 +20,7 @@ APP_HOME=$(cd `dirname $0`;cd ../; pwd) APP_LIB_PATH=$APP_HOME/lib #节点输出日志路径 -LOG_OUT=$APP_HOME/bin/gw.out +LOG_OUT=$APP_HOME/logs #获取Peer节点的启动Jar包 APP_JAR=$(ls $APP_LIB_PATH | grep $APP_JAR_PREFIX) @@ -32,7 +32,7 @@ CONFIG_PATH=$APP_HOME/config GATEWAY_CONFIG=$CONFIG_PATH/gateway.conf #定义程序启动的参数 -JAVA_OPTS="-jar -server -Xms1024m -Xmx1024m" +JAVA_OPTS="-jar -server -Xms1024m -Xmx1024m -Djdchain.log=$LOG_OUT -Dlogging.config=file:$APP_HOME/config/log4j2-gw.xml" #APP具体相关命令 APP_CMD=$APP_LIB_PATH/$APP_JAR" -c "$GATEWAY_CONFIG @@ -90,7 +90,7 @@ if [[ $psid -ne 0 ]]; then echo "================================" else echo "Starting Gateway ......" - nohup $JAVA_BIN $JAVA_OPTS $APP_CMD $* >$LOG_OUT 2>&1 & + nohup $JAVA_BIN $JAVA_OPTS $APP_CMD $* & JAVA_CMD="$JAVA_BIN $JAVA_OPTS $APP_CMD $*" sleep 1 checkpid From ba4b2c418813e176a5323427d33bf57a37e28174 Mon Sep 17 00:00:00 2001 From: imuge Date: Mon, 4 Jan 2021 18:22:58 +0800 Subject: [PATCH 143/150] add error rolling --- core | 2 +- .../src/main/resources/config/log4j2-gw.xml | 14 ++++++++++++-- .../src/main/resources/config/log4j2-peer.xml | 14 ++++++++++++-- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/core b/core index bfbb6267..e8fadcf5 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit bfbb6267d14b8b59a7d0b5593bc4b5958dbb3680 +Subproject commit e8fadcf5399e4005d1089838d556e5997e04d036 diff --git a/deploy/deploy-gateway/src/main/resources/config/log4j2-gw.xml b/deploy/deploy-gateway/src/main/resources/config/log4j2-gw.xml index 8bffe83a..437bc6f0 100644 --- a/deploy/deploy-gateway/src/main/resources/config/log4j2-gw.xml +++ b/deploy/deploy-gateway/src/main/resources/config/log4j2-gw.xml @@ -2,18 +2,27 @@ - + - + + + + + + + + + @@ -22,6 +31,7 @@ + \ No newline at end of file diff --git a/deploy/deploy-peer/src/main/resources/config/log4j2-peer.xml b/deploy/deploy-peer/src/main/resources/config/log4j2-peer.xml index 2d136e0b..e5ab655a 100644 --- a/deploy/deploy-peer/src/main/resources/config/log4j2-peer.xml +++ b/deploy/deploy-peer/src/main/resources/config/log4j2-peer.xml @@ -2,18 +2,27 @@ - + - + + + + + + + + + @@ -22,6 +31,7 @@ + \ No newline at end of file From a09f7ed6c1266eb678223657b1aab253db8b3bbd Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Mon, 4 Jan 2021 19:04:20 +0800 Subject: [PATCH 144/150] upgraded modules to fix bugs of kvdb storage; --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index bfbb6267..f72f7252 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit bfbb6267d14b8b59a7d0b5593bc4b5958dbb3680 +Subproject commit f72f7252c1aa15b3f28f8d01a558c03d254b4835 From 145ebba7d3f8dd65ff8b054e53a487522a9a0821 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Mon, 4 Jan 2021 19:07:09 +0800 Subject: [PATCH 145/150] upgraded modules; --- test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test b/test index 49758186..78397ede 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 4975818658f136181beb725a649d907cd344e5aa +Subproject commit 78397ede4fcdb6ec013285556ddbaa0c2ca5600a From c37f560a37affd2b1d4e055122826fc9781ec923 Mon Sep 17 00:00:00 2001 From: imuge Date: Tue, 5 Jan 2021 10:41:43 +0800 Subject: [PATCH 146/150] update log configurations --- .../src/main/resources/config/log4j2-gw.xml | 11 ++++++----- .../src/main/resources/scripts/startup.sh | 8 ++++---- .../src/main/resources/config/log4j2-peer.xml | 11 ++++++----- .../src/main/resources/scripts/peer-startup.sh | 5 ++++- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/deploy/deploy-gateway/src/main/resources/config/log4j2-gw.xml b/deploy/deploy-gateway/src/main/resources/config/log4j2-gw.xml index 437bc6f0..7a9914af 100644 --- a/deploy/deploy-gateway/src/main/resources/config/log4j2-gw.xml +++ b/deploy/deploy-gateway/src/main/resources/config/log4j2-gw.xml @@ -2,7 +2,7 @@ - + - + - + @@ -26,9 +26,10 @@ - + + - + diff --git a/deploy/deploy-gateway/src/main/resources/scripts/startup.sh b/deploy/deploy-gateway/src/main/resources/scripts/startup.sh index 2db26ec4..a38f2f62 100644 --- a/deploy/deploy-gateway/src/main/resources/scripts/startup.sh +++ b/deploy/deploy-gateway/src/main/resources/scripts/startup.sh @@ -19,8 +19,8 @@ APP_HOME=$(cd `dirname $0`;cd ../; pwd) #Lib目录 APP_LIB_PATH=$APP_HOME/lib -#节点输出日志路径 -LOG_OUT=$APP_HOME/logs +#nohup输出日志路径 +LOG_OUT=$APP_HOME/bin/gw.out #获取Peer节点的启动Jar包 APP_JAR=$(ls $APP_LIB_PATH | grep $APP_JAR_PREFIX) @@ -32,7 +32,7 @@ CONFIG_PATH=$APP_HOME/config GATEWAY_CONFIG=$CONFIG_PATH/gateway.conf #定义程序启动的参数 -JAVA_OPTS="-jar -server -Xms1024m -Xmx1024m -Djdchain.log=$LOG_OUT -Dlogging.config=file:$APP_HOME/config/log4j2-gw.xml" +JAVA_OPTS="-jar -server -Xms1024m -Xmx1024m -Djdchain.log=$APP_HOME/logs -Dlogging.config=file:$APP_HOME/config/log4j2-gw.xml" #APP具体相关命令 APP_CMD=$APP_LIB_PATH/$APP_JAR" -c "$GATEWAY_CONFIG @@ -90,7 +90,7 @@ if [[ $psid -ne 0 ]]; then echo "================================" else echo "Starting Gateway ......" - nohup $JAVA_BIN $JAVA_OPTS $APP_CMD $* & + nohup $JAVA_BIN $JAVA_OPTS $APP_CMD $* >$LOG_OUT 2>&1 & JAVA_CMD="$JAVA_BIN $JAVA_OPTS $APP_CMD $*" sleep 1 checkpid diff --git a/deploy/deploy-peer/src/main/resources/config/log4j2-peer.xml b/deploy/deploy-peer/src/main/resources/config/log4j2-peer.xml index e5ab655a..ad218870 100644 --- a/deploy/deploy-peer/src/main/resources/config/log4j2-peer.xml +++ b/deploy/deploy-peer/src/main/resources/config/log4j2-peer.xml @@ -2,7 +2,7 @@ - + - + - + @@ -26,9 +26,10 @@ - + + - + diff --git a/deploy/deploy-peer/src/main/resources/scripts/peer-startup.sh b/deploy/deploy-peer/src/main/resources/scripts/peer-startup.sh index 1823ad19..e54c7d38 100644 --- a/deploy/deploy-peer/src/main/resources/scripts/peer-startup.sh +++ b/deploy/deploy-peer/src/main/resources/scripts/peer-startup.sh @@ -30,6 +30,9 @@ APP_HOME=$(cd `dirname $0`;cd ../; pwd) #System目录 APP_SYSTEM_PATH=$APP_HOME/system +#nohup输出日志路径 +LOG_OUT=$APP_HOME/bin/peer.out + #获取Peer节点的启动Jar包 APP_JAR=$(ls $APP_SYSTEM_PATH | grep $APP_JAR_PREFIX) @@ -101,7 +104,7 @@ if [[ $psid -ne 0 ]]; then echo "================================" else echo "Starting Peer ......" - nohup $JAVA_BIN $JAVA_OPTS $APP_CMD $* & + nohup $JAVA_BIN $JAVA_OPTS $APP_CMD $* >$LOG_OUT 2>&1 & JAVA_CMD="$JAVA_BIN $JAVA_OPTS $APP_CMD $*" sleep 1 checkpid From 198a3e1e24e10125388fe47d3bdb8255248ed1f9 Mon Sep 17 00:00:00 2001 From: imuge Date: Tue, 5 Jan 2021 14:36:13 +0800 Subject: [PATCH 147/150] update contract samples --- framework | 2 +- .../jdchain/samples/sdk/ContractSample.java | 66 +++++++++++++++++-- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/framework b/framework index dbde6e52..e9afd349 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit dbde6e525ab2673c82824b385d349be093ca7b81 +Subproject commit e9afd349b3e52d8921d5cddf485d201831e8ee66 diff --git a/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/ContractSample.java b/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/ContractSample.java index 901ca223..70d139e4 100644 --- a/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/ContractSample.java +++ b/samples/sdk-samples/src/test/java/com/jdchain/samples/sdk/ContractSample.java @@ -2,14 +2,23 @@ package com.jdchain.samples.sdk; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.BytesDataList; +import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.PreparedTransaction; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionTemplate; +import com.jd.blockchain.ledger.TypedValue; +import com.jd.blockchain.transaction.ContractEventSendOperationBuilder; +import com.jd.blockchain.transaction.ContractReturnValue; +import com.jd.blockchain.transaction.GenericValueHolder; +import com.jd.blockchain.utils.io.BytesUtils; import com.jd.blockchain.utils.io.FileUtils; import com.jdchain.samples.contract.SampleContract; import org.junit.Assert; import org.junit.Test; +import java.util.UUID; + /** * 合约相关操作示例: * 合约部署,合约调用 @@ -40,16 +49,48 @@ public class ContractSample extends SampleBase { } /** - * 合约调用 + * 基于动态代理方式合约调用,需要依赖合约接口 */ @Test - public void testExecute() { + public void testExecuteByProxy() { // 新建交易 TransactionTemplate txTemp = blockchainService.newTransaction(ledger); // 运行前,填写正确的合约地址 + // 一次交易中可调用多个(多次调用)合约方法 // 调用合约的 registerUser 方法 - txTemp.contract("LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye", SampleContract.class).registerUser("至少32位字节数-----------------------------"); + SampleContract sampleContract = txTemp.contract("LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye", SampleContract.class); + GenericValueHolder userAddress = ContractReturnValue.decode(sampleContract.registerUser(UUID.randomUUID().toString())); + + // 准备交易 + PreparedTransaction ptx = txTemp.prepare(); + // 交易签名 + ptx.sign(adminKey); + // 提交交易 + TransactionResponse response = ptx.commit(); + Assert.assertTrue(response.isSuccess()); + + // 获取返回值 + System.out.println(userAddress.get()); + } + + /** + * 非动态代理方式合约调用,不需要依赖合约接口及实现 + */ + @Test + public void testExecuteWithArgus() { + // 新建交易 + TransactionTemplate txTemp = blockchainService.newTransaction(ledger); + + ContractEventSendOperationBuilder builder = txTemp.contract(); + // 运行前,填写正确的合约地址,数据账户地址等参数 + // 一次交易中可调用多个(多次调用)合约方法 + // 调用合约的 registerUser 方法,传入合约地址,合约方法名,合约方法参数列表 + builder.send("LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye", "registerUser", + new BytesDataList(new TypedValue[]{ + TypedValue.fromText(UUID.randomUUID().toString()) + }) + ); // 准备交易 PreparedTransaction ptx = txTemp.prepare(); // 交易签名 @@ -59,7 +100,24 @@ public class ContractSample extends SampleBase { Assert.assertTrue(response.isSuccess()); Assert.assertEquals(1, response.getOperationResults().length); - System.out.println(response.getOperationResults()[0].getResult().getBytes().toString()); + // 解析合约方法调用返回值 + for (int i = 0; i < response.getOperationResults().length; i++) { + BytesValue content = response.getOperationResults()[i].getResult(); + switch (content.getType()) { + case TEXT: + System.out.println(content.getBytes().toUTF8String()); + break; + case INT64: + System.out.println(BytesUtils.toLong(content.getBytes().toBytes())); + break; + case BOOLEAN: + System.out.println(BytesUtils.toBoolean(content.getBytes().toBytes()[0])); + break; + default: // byte[], Bytes + System.out.println(content.getBytes().toBase58()); + break; + } + } } } From a9f2286f11298543fc6c53ad058660e47f3f9586 Mon Sep 17 00:00:00 2001 From: imuge Date: Tue, 5 Jan 2021 11:20:47 +0800 Subject: [PATCH 148/150] update log configurations --- core | 2 +- deploy/deploy-gateway/src/main/resources/config/log4j2-gw.xml | 1 + deploy/deploy-peer/src/main/resources/config/log4j2-peer.xml | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/core b/core index f72f7252..b29d5721 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit f72f7252c1aa15b3f28f8d01a558c03d254b4835 +Subproject commit b29d5721df1dcfbf359d01000d40f332a0866e2d diff --git a/deploy/deploy-gateway/src/main/resources/config/log4j2-gw.xml b/deploy/deploy-gateway/src/main/resources/config/log4j2-gw.xml index 7a9914af..a83fdec9 100644 --- a/deploy/deploy-gateway/src/main/resources/config/log4j2-gw.xml +++ b/deploy/deploy-gateway/src/main/resources/config/log4j2-gw.xml @@ -7,6 +7,7 @@ + diff --git a/deploy/deploy-peer/src/main/resources/config/log4j2-peer.xml b/deploy/deploy-peer/src/main/resources/config/log4j2-peer.xml index ad218870..ebd1df90 100644 --- a/deploy/deploy-peer/src/main/resources/config/log4j2-peer.xml +++ b/deploy/deploy-peer/src/main/resources/config/log4j2-peer.xml @@ -7,6 +7,7 @@ + From d0f300b5917cfb44fc0cea94efdf72330baebd4f Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Wed, 6 Jan 2021 15:56:24 +0800 Subject: [PATCH 149/150] upgraded modules; --- core | 2 +- framework | 2 +- test | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core b/core index f72f7252..21a80d9e 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit f72f7252c1aa15b3f28f8d01a558c03d254b4835 +Subproject commit 21a80d9ecb7567af775c35cdb68290fe1de1e413 diff --git a/framework b/framework index dbde6e52..02331175 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit dbde6e525ab2673c82824b385d349be093ca7b81 +Subproject commit 02331175672597cbd627396c74ece32bead3f4ce diff --git a/test b/test index 78397ede..96103992 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 78397ede4fcdb6ec013285556ddbaa0c2ca5600a +Subproject commit 961039925c37065c957f9d04dc6ec4ea1e3b6138 From 3e7b41b41f8c3b1bd8ab202b5ae40f57026e0c88 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Thu, 7 Jan 2021 12:08:15 +0800 Subject: [PATCH 150/150] published 1.4.0.RELEASE; --- explorer | 2 +- libs/kvdb | 2 +- test | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/explorer b/explorer index 341eb8d4..eaee8a2d 160000 --- a/explorer +++ b/explorer @@ -1 +1 @@ -Subproject commit 341eb8d48d0cc355d32d6cb10159c2049fcfa3b0 +Subproject commit eaee8a2dd0f367f1fd6751f46bd1db527e5a6ba1 diff --git a/libs/kvdb b/libs/kvdb index d9ec7f37..a264eb1c 160000 --- a/libs/kvdb +++ b/libs/kvdb @@ -1 +1 @@ -Subproject commit d9ec7f3748724053a2c1eb7a3e2128cc715a2a33 +Subproject commit a264eb1cbdbacad1482e4823ff2fa643af6a3540 diff --git a/test b/test index 96103992..4c7a4ee0 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 961039925c37065c957f9d04dc6ec4ea1e3b6138 +Subproject commit 4c7a4ee0374f24dea15b087d730bb8843f201205

?@Enb7w5Vxtp^Ux3U~g{!9{*snwJ>mM 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