diff --git a/core b/core index c7160adc..c6d05f98 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit c7160adc704c53766427ecdf70f130e43f6cac43 +Subproject commit c6d05f98420213bf7ab1b4f431f6dcee2654bf5c diff --git a/deploy/deploy-gateway/pom.xml b/deploy/deploy-gateway/pom.xml index 31de50bf..f13dbf16 100644 --- a/deploy/deploy-gateway/pom.xml +++ b/deploy/deploy-gateway/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain deploy-root - 1.5.0.RELEASE + 1.6.0-SNAPSHOT deploy-gateway diff --git a/deploy/deploy-gateway/src/main/resources/config/gateway.conf b/deploy/deploy-gateway/src/main/resources/config/gateway.conf index a5cd04fd..529f99a5 100644 --- a/deploy/deploy-gateway/src/main/resources/config/gateway.conf +++ b/deploy/deploy-gateway/src/main/resources/config/gateway.conf @@ -25,11 +25,13 @@ peer.providers=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider data.retrieval.url= schema.retrieval.url= -#默认公钥的内容(Base58编码数据); +#默认公钥的内容(Base58编码数据),非CA模式下必填; keys.default.pubkey= +#默认网关证书路径(X509,PEM),CA模式下必填; +keys.default.ca-path= #默认私钥的路径;在 pk-path 和 pk 之间必须设置其一; keys.default.privkey-path= -#默认私钥的内容(加密的Base58编码数据);在 pk-path 和 pk 之间必须设置其一; +#默认私钥的内容;在 pk-path 和 pk 之间必须设置其一; keys.default.privkey= #默认私钥的解码密码; keys.default.privkey-password= diff --git a/deploy/deploy-peer/pom.xml b/deploy/deploy-peer/pom.xml index 42cbdf9f..129a1c82 100644 --- a/deploy/deploy-peer/pom.xml +++ b/deploy/deploy-peer/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain deploy-root - 1.5.0.RELEASE + 1.6.0-SNAPSHOT deploy-peer diff --git a/deploy/deploy-peer/src/main/resources/config/init/ledger.init b/deploy/deploy-peer/src/main/resources/config/init/ledger.init index f475f0e9..82ae9016 100644 --- a/deploy/deploy-peer/src/main/resources/config/init/ledger.init +++ b/deploy/deploy-peer/src/main/resources/config/init/ledger.init @@ -4,6 +4,12 @@ ledger.seed=932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323 #账本的描述名称;此属性不参与共识,仅仅在当前参与方的本地节点用于描述用途; ledger.name= +#身份认证模式:KEYPAIR/CA,默认KEYPAIR即公私钥对模式 +identity-mode=KEYPAIR + +#账本根证书路径,identity-mode 为 CA 时,此选项不能为空,支持多个,半角逗号相隔 +root-ca-path= + #声明的账本创建时间;格式为 “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 @@ -76,6 +82,8 @@ cons_parti.0.name= cons_parti.0.pubkey-path= #第0个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; cons_parti.0.pubkey= +#第1个参与方的证书路径,identity-mode 为 CA 时,此选项不能为空 +cons_parti.0.ca-path= #第0个参与方的角色清单;可选项; #cons_parti.0.roles=ADMIN, MANAGER @@ -96,6 +104,8 @@ cons_parti.1.name= cons_parti.1.pubkey-path= #第1个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; cons_parti.1.pubkey= +#第1个参与方的证书路径,identity-mode 为 CA 时,此选项不能为空 +cons_parti.1.ca-path= #第1个参与方的角色清单;可选项; #cons_parti.1.roles=MANAGER @@ -116,6 +126,8 @@ cons_parti.2.name= cons_parti.2.pubkey-path= #第2个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; cons_parti.2.pubkey= +#第1个参与方的证书路径,identity-mode 为 CA 时,此选项不能为空 +cons_parti.2.ca-path= #第2个参与方的角色清单;可选项; #cons_parti.2.roles=MANAGER @@ -136,6 +148,8 @@ cons_parti.3.name= cons_parti.3.pubkey-path= #第3个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; cons_parti.3.pubkey= +#第1个参与方的证书路径,identity-mode 为 CA 时,此选项不能为空 +cons_parti.3.ca-path= #第3个参与方的角色清单;可选项; #cons_parti.3.roles=GUEST @@ -147,4 +161,4 @@ cons_parti.3.initializer.host=127.0.0.1 #第3个参与方的账本初始服务的端口; cons_parti.3.initializer.port=8830 #第3个参与方的账本初始服务是否开启安全连接; -cons_parti.3.initializer.secure=false +cons_parti.3.initializer.secure=false \ No newline at end of file diff --git a/deploy/deploy-peer/src/main/resources/config/init/local.conf b/deploy/deploy-peer/src/main/resources/config/init/local.conf index 46ae5b35..17615351 100644 --- a/deploy/deploy-peer/src/main/resources/config/init/local.conf +++ b/deploy/deploy-peer/src/main/resources/config/init/local.conf @@ -1,13 +1,17 @@ #当前参与方的 id,与ledger.init文件中cons_parti.id一致,默认从0开始 local.parti.id=0 -#当前参与方的公钥 +#当前参与方的公钥,用于非证书模式 local.parti.pubkey= +#当前参与方的证书信息,用于证书模式 +local.parti.ca-path= #当前参与方的私钥(密文编码) local.parti.privkey= +#当前参与方的私钥文件,PEM格式,用于证书模式 +local.parti.privkey-path= -#当前参与方的私钥解密密钥(原始口令的一次哈希,Base58格式),如果不设置,则启动过程中需要从控制台输入 +#当前参与方的私钥解密密钥(原始口令的一次哈希,Base58格式),如果不设置,则启动过程中需要从控制台输入; local.parti.pwd= #账本初始化完成后生成的"账本绑定配置文件"的输出目录 diff --git a/deploy/docker/docker-demo/pom.xml b/deploy/docker/docker-demo/pom.xml deleted file mode 100644 index 6eb80655..00000000 --- a/deploy/docker/docker-demo/pom.xml +++ /dev/null @@ -1,135 +0,0 @@ - - - - docker - com.jd.blockchain - 1.5.0.RELEASE - - 4.0.0 - docker-demo - - - - com.jd.blockchain - docker-sdk - ${project.version} - - - - - jdchain-demo - - - org.apache.maven.plugins - maven-compiler-plugin - - 1.8 - 1.8 - UTF-8 - false - true - false - false - - - - - - - - - - - - - - - - - - - - - - - - - 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}.zip - - - - - ${project.basedir}/../../deploy-gateway/target/ - false - - jdchain-gateway-${project.version}.zip - - - - - - ${project.basedir}/../docker-sdk/target/ - false - - docker-sdk-${project.version}.jar - - - - - - - - - - - com.spotify - docker-maven-plugin - 1.2.2 - - - - - build-image - - package - - build - - - - - - - jdchain-demo - - ${project.version} - - - ${project.basedir}/target - - - - - - \ No newline at end of file diff --git a/deploy/docker/docker-demo/src/main/docker/Dockerfile b/deploy/docker/docker-demo/src/main/docker/Dockerfile deleted file mode 100644 index c6d8edde..00000000 --- a/deploy/docker/docker-demo/src/main/docker/Dockerfile +++ /dev/null @@ -1,37 +0,0 @@ -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 \ - && yum install dos2unix -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 dos2unix /export/jdchain/*.sh -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/docker-demo/src/main/docker/script/shutdown.sh b/deploy/docker/docker-demo/src/main/docker/script/shutdown.sh deleted file mode 100644 index 8cf6d207..00000000 --- a/deploy/docker/docker-demo/src/main/docker/script/shutdown.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -ps -ef|grep 'jdchain'|grep -v grep|cut -c 9-15|xargs kill -9 - diff --git a/deploy/docker/docker-demo/src/main/docker/script/start.sh b/deploy/docker/docker-demo/src/main/docker/script/start.sh deleted file mode 100644 index c55380b6..00000000 --- a/deploy/docker/docker-demo/src/main/docker/script/start.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -cd $RELEASE_DIR - -# 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` - 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/* - -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 -sleep 10 -java -jar docker-sdk-1.3.0.RELEASE.jar > sdk.log - -tail -f /dev/null diff --git a/deploy/docker/docker-demo/src/main/docker/zip/conf.zip b/deploy/docker/docker-demo/src/main/docker/zip/conf.zip deleted file mode 100644 index dc8dffb1..00000000 Binary files a/deploy/docker/docker-demo/src/main/docker/zip/conf.zip and /dev/null differ diff --git a/deploy/docker/docker-demo/src/main/resources/docker-compose-all.yaml b/deploy/docker/docker-demo/src/main/resources/docker-compose-all.yaml deleted file mode 100644 index b42268f9..00000000 --- a/deploy/docker/docker-demo/src/main/resources/docker-compose-all.yaml +++ /dev/null @@ -1,36 +0,0 @@ -version: '2' - -services: - demo: - image: "jdchain-demo:1.3.0" - container_name: jdchain-demo - networks: - jdchain_default: - aliases: - - demo - hostname: demo - restart: always - ports: - - "11010:11010" - - "7080:7080" - - "10080:10080" - - "10081:10081" - - "11011:11011" - - "7081:7081" - - "10082:10082" - - "10083:10083" - - "11012:11012" - - "7082:7082" - - "10084:10084" - - "10085:10085" - - "11013:11013" - - "7083:7083" - - "10086:10086" - - "10087:10087" - - "8080:8080" -# volumes: -# - "./logs:/export/jdchain/peer0/logs" - -networks: - jdchain_default: - driver: bridge diff --git a/deploy/docker/docker-demo/src/main/resources/start-net.sh b/deploy/docker/docker-demo/src/main/resources/start-net.sh deleted file mode 100644 index 7eafc55d..00000000 --- a/deploy/docker/docker-demo/src/main/resources/start-net.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -echo "停止network" -docker-compose -f docker-compose-all.yaml down -echo "启动jdchain" -docker-compose -f docker-compose-all.yaml up -d diff --git a/deploy/docker/docker-demo/src/main/resources/zip.sh b/deploy/docker/docker-demo/src/main/resources/zip.sh deleted file mode 100644 index 3305c646..00000000 --- a/deploy/docker/docker-demo/src/main/resources/zip.sh +++ /dev/null @@ -1,9 +0,0 @@ -#/bin/bash - -# all in one; -allIn1_file="./jdchain-demo_1.3.0.tar.gz" -if [ -f $allIn1_file ] ; then - rm -rf $allIn1_file -fi -docker save jdchain-demo:1.3.0 -o jdchain-demo_1.3.0.tar -gzip jdchain-demo_1.3.0.tar diff --git a/deploy/docker/docker-sdk/pom.xml b/deploy/docker/docker-sdk/pom.xml deleted file mode 100644 index 974edb25..00000000 --- a/deploy/docker/docker-sdk/pom.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - com.jd.blockchain - docker - 1.5.0.RELEASE - - 4.0.0 - - docker-sdk - - - - com.jd.blockchain - crypto-classic - ${framework.version} - - - com.jd.blockchain - crypto-sm - ${framework.version} - - - com.jd.blockchain - ledger-model - ${framework.version} - - - com.jd.blockchain - sdk-client - ${framework.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/docker-sdk/src/main/java/com/jd/blockchain/ContractParams.java b/deploy/docker/docker-sdk/src/main/java/com/jd/blockchain/ContractParams.java deleted file mode 100644 index b1464b4e..00000000 --- a/deploy/docker/docker-sdk/src/main/java/com/jd/blockchain/ContractParams.java +++ /dev/null @@ -1,107 +0,0 @@ -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/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo.java b/deploy/docker/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo.java deleted file mode 100644 index 5e02ccf1..00000000 --- a/deploy/docker/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo.java +++ /dev/null @@ -1,68 +0,0 @@ -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/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 deleted file mode 100644 index cfdd0140..00000000 --- a/deploy/docker/docker-sdk/src/main/java/com/jd/blockchain/SDKDemo_Constant.java +++ /dev/null @@ -1,46 +0,0 @@ -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 = "7VeRL1kWpYpvawkgFbM9N9ao1YiAE9HW65QpwLvpw6oPjCnZ"; - 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/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 deleted file mode 100644 index 4f321b13..00000000 --- a/deploy/docker/docker-sdk/src/main/java/com/jd/blockchain/SDK_Base_Demo.java +++ /dev/null @@ -1,192 +0,0 @@ -package com.jd.blockchain; - -import static com.jd.blockchain.SDKDemo_Constant.readChainCodes; -import static com.jd.blockchain.transaction.ContractReturnValue.decode; - -import com.jd.blockchain.crypto.HashDigest; -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.transaction.GenericValueHolder; -import com.jd.chain.contract.TransferContract; - -import utils.Bytes; - -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); - - // 生成发布合约操作 - 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/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 deleted file mode 100644 index a3a41529..00000000 --- a/deploy/docker/docker-sdk/src/main/java/com/jd/chain/contract/TransferContract.java +++ /dev/null @@ -1,32 +0,0 @@ -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/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 deleted file mode 100644 index cd7c3c82..00000000 Binary files a/deploy/docker/docker-sdk/src/main/resources/contract-compile-1.3.0.RELEASE.car and /dev/null differ diff --git a/deploy/docker/pom.xml b/deploy/docker/pom.xml deleted file mode 100644 index c2041624..00000000 --- a/deploy/docker/pom.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - com.jd.blockchain - deploy-root - 1.5.0.RELEASE - - 4.0.0 - pom - - docker - - - 1.4.3.RELEASE - - - - docker-sdk - docker-demo - - - \ No newline at end of file diff --git a/deploy/docker/readme.md b/deploy/docker/readme.md deleted file mode 100644 index 72f9c804..00000000 --- a/deploy/docker/readme.md +++ /dev/null @@ -1,44 +0,0 @@ -# jdchain-demo镜像使用说明 -本镜像主要为快速构建JDChain测试环境使用,内嵌固定的公私钥,不可用于生产正式环境。 -JDChain在docker中的安装路径:/export/jdchain,网关对外端口为:8080。可通过docker-compose-all文件来修改端口。 -demo环境构建完成后执行sdk加载部分测试数据,区块高度:7,交易总数:8,用户总数:5,数据账户总数:2,合约总数:1。 - -## 如何生成镜像 -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镜像: -```` -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=7VeRL1kWpYpvawkgFbM9N9ao1YiAE9HW65QpwLvpw6oPjCnZ -#默认私钥的内容(加密的Base58编码数据);在 pk-path 和 pk 之间必须设置其一; -keys.default.privkey=177gk2PbxhHeEdfAAqGfShJQyeV4XvGsJ9CvJFUbToBqwW1YJd5obicySE1St6SvPPaRrUP -#默认私钥的解码密码; -keys.default.privkey-password=8EjkXVSTxMFjCvNNsTo8RBMDEVQmk7gYkW4SCDuvdsBG -```` - - - diff --git a/deploy/pom.xml b/deploy/pom.xml index f5491a8e..92566af0 100644 --- a/deploy/pom.xml +++ b/deploy/pom.xml @@ -5,22 +5,21 @@ com.jd.blockchain jdchain-parent - 1.1.5.RELEASE + 1.1.6-SNAPSHOT ../project/parent deploy-root - 1.5.0.RELEASE + 1.6.0-SNAPSHOT pom - 1.5.0.RELEASE + 1.6.0-SNAPSHOT ../core deploy-gateway deploy-peer - docker diff --git a/docs/ca.md b/docs/ca.md new file mode 100644 index 00000000..75ac8f97 --- /dev/null +++ b/docs/ca.md @@ -0,0 +1,150 @@ +## 证书 + +`JD Chain`身份认证支持两种模式:`KEYPAIR`(默认)/`CA`,即公私钥对和证书。 + +证书模式采用`X.509`标准的数字证书作为用户标识,证书字段中,附加组织和角色等信息。 + +`JD Chain`使用`jdchain-cli`/`openssl`生成的自签名证书,也支持使用`CFCA`等国家认可的第三方`CA`颁发的外部证书。 + +`JD Chain` `CA`支持`RSA 2048`/`ECDSA P-256`/`SM2 SM3WithSM2`/`ED25519`四种签名算法。 + + +### 类别 + +`JD Chain`证书体系分`ROOT`,`CA`,`PEER`,`GW`,`USER`几个类别。 + +使用证书`Subject`中`OU`字段区分。 + +#### ROOT + +根证书,可用于签发证书及账本初始化时作为账本证书。 + +#### CA + +中间证书,可用于签发证书及账本初始化时作为账本证书。 + +#### PEER + +共识节点证书,注册参与方时需要提供`PEER`类型证书。 + +#### GW + +网关证书,网关所配置公私钥对应账户信息在链上必须存储有`GW`类型的证书。 + +#### USER + +普通用户证书 + +### 实现 + +`JD Chain`证书使用链上存储方式。主要存储于两个地方: +- 元数据区,存储账本初始化时配置的根证书列表 +- 用户账户头部,存储用户注册时提供的证书 + +> 根证书支持列表,即支持多个参与机构使用不同的证书链,且根证书可使用`ROOT`证书,也可使用`CA`(中间)证书,但节点/网关/用户证书必须由配置在`JD Chain`根证书列表中的证书直接签出。 + +#### 账本初始化 + +*`ledger.init`* +较`KEYPAIR`模式有如下修改: + +1. `identity-mode` +```properties +identity-mode=CA +``` +`identity-mode`身份认证模式,`KEYPAIR`(默认)/`CA` + +2. `root-ca-path` +```properties +root-ca-path=/**/ledger1.crt,/**/ledger2.crt +``` +`root-ca-path`根证书列表,使用`ROOT`或者`CA`类型证书,多个根证书使用半角逗号分割。初始化完成后,证书信息会上链存储,通过[2.7 获取账本初始化配置信息](api.md#27-获取账本初始化配置信息)可查。 + +3. `cons_parti.*.ca-path` + +**CA 模式参与方需要增加配置网关信息,网关节点IP和端口不需要填写** + +节点公钥配置改为证书地址: + +```properties +// KEYPAIR +// cons_parti.0.pubkey-path= +// cons_parti.0.pubkey= + +// CA +cons_parti.0.ca-path=/**/peer0.crt +``` + +*`local.conf`* +较`KEYPAIR`模式有如下修改: +```properties +#当前参与方的公钥,用于非证书模式 +# local.parti.pubkey= +#当前参与方的证书信息,用于证书模式 +local.parti.ca-path= + +#当前参与方的私钥文件,PEM格式,用于证书模式 +local.parti.privkey-path= +``` + +#### 节点运行 + +节点启动和运行时会校验证书类型,时间有效性以及是否由某个根证书签出等,一旦校验失败会阻止网关接入,不再对外服务。 + +#### 网关接入 + +*gateway.conf* +```properties +#默认公钥的内容(Base58编码数据),非CA模式下必填; +keys.default.pubkey= +#默认网关证书路径(X509,PEM),CA模式下必填; +keys.default.ca-path=/home/imuge/jd/nodes/peer0/config/keys/gw1.crt +#默认私钥的路径;在 pk-path 和 pk 之间必须设置其一; +keys.default.privkey-path=/home/imuge/jd/nodes/peer0/config/keys/gw1.key +#默认私钥的内容(加密的Base58编码数据);在 pk-path 和 pk 之间必须设置其一; +keys.default.privkey= +``` + +网关接入网络需要配置`GW`类型证书及对应的私钥信息,证书类型必须是`GW`。 + +网关接入时会做如下认证: +- 证书类型包含`GW` +- 根证书列表存在类型正确且有效证书 +- 网关证书由根证书列表中某个证书签出(此证书类型正确且有效) + +#### 交易认证 + +交易时使用证书持有者私钥签名,交易内容不包含签名用户证书信息。 +交易执行前会校验所有账本根证书,签名终端用户和节点用户的证书类型及有效性。 + +> 请务必在证书到期前更新证书有效期 + +#### 证书更新 + +1. 根证书 + +`SDK`方式: +```java +TransactionTemplate txTemp = blockchainService.newTransaction(ledger); +txTemp.metaInfo().ca(X509Utils.resolveCertificate("*.crt")); +``` + +命令行方式:[更新账本证书](tx.md#更新账本证书) + +2. 节点/网关/普通用户证书 + +> 在`JD Chain`中,共识节点,网关配置的接入账户和普通用户本质都是用户账户类型,它们对应的证书管理方式一致。 + +`SDK`方式: + +```java +txTemp.user("user address").ca(X509Utils.resolveCertificate("*.crt")); +``` + +命令行方式:[更新用户证书](tx.md#更新用户证书) + +### 证书生成 + +使用`jdchain-cli`提供的[keys](cli/keys.md)和[ca](cli/ca.md)指令工具创建公私钥对以及签发证书。 + +其中[ca-test](cli/ca.md#生成测试证书)可一键生成账本初始化所需的所有证书外加可用的普通用户证书。 \ No newline at end of file diff --git a/docs/cli/ca.md b/docs/cli/ca.md new file mode 100644 index 00000000..a8a8699e --- /dev/null +++ b/docs/cli/ca.md @@ -0,0 +1,248 @@ +### 证书管理 + +`jdchain-cli`提供**`ED25519`,`RSA`,`ECDSA`,`SM2`**密钥算法的证书签发工具:[证书列表](#证书列表),[显示证书](#显示证书),[CSR](#CSR),[CRT](#CRT),[更新证书](#更新证书),[生成测试证书](#生成测试证书) + +> 目前支持创建`ED25519`,RSA`,`ECDSA`,`SM2`四种签名算法,请使用对应算法的公私钥 + +```bash +:bin$ ./jdchain-cli.sh ca -h +Usage: jdchain-cli ca [-hV] [--pretty] [--home=] [COMMAND] +List, create, update certificates. + -h, --help Show this help message and exit. + --home= Set the home directory. + Default: ../ + --pretty Pretty json print + -V, --version Print version information and exit. +Commands: + list List all the certificates. + show Show certificate. + csr Create certificate signing request. + crt Create new certificate. + renew Update validity period. + test Create certificates for a testnet. + help Displays help information about the specified command +``` +- `home`,指定密钥和证书存储相关目录,`${home}/config/keys` + +#### 证书列表 +```bash +:bin$ ./jdchain-cli.sh ca list -h +List all the certificates. +Usage: jdchain-cli ca list [-hV] [--pretty] [--home=] + -h, --help Show this help message and exit. + --home= Set the home directory. + --pretty Pretty json print + -V, --version Print version information and exit. +``` + +如: +```bash +:bin$ ./jdchain-cli.sh keys list +NAME ALGORITHM ADDRESS PUBKEY +``` +- `NAME`,名称 +- `ALGORITHM`,算法 +- `ADDRESS`,地址 +- `PUBKEY`,公钥 + +#### 显示证书 +```bash +:bin$ ./jdchain-cli.sh ca show -h +Show certificate. +Usage: jdchain-cli ca show [-hV] [--pretty] [--home=] -n= + -h, --help Show this help message and exit. + --home= Set the home directory. + -n, --name= Name of the certificate + --pretty Pretty json print + -V, --version Print version information and exit. +``` +- `name`,证书名称 + +如显示`${home}/config/keys`下名为`G1`的证书信息: +```bash +:bin$ ./jdchain-cli.sh ca show -n G1 +./jdchain-cli.sh ca show -n G1 +NAME ALGORITHM TYPE ROLE PUBKEY +G1 SM2 ROLE-TODO [GW] SFZ6LjGKVz6wdU4G9PAraojyzCYPJ1BXAg1XBwSPCMC6Ug6u5oom5zcLPUzWtz42aCp9PLGXpHweBjSu3EW2aDzsa4JoT + [0] Version: 3 + SerialNumber: 440724497 + IssuerDN: O=JDT,OU=ROOT,C=CN,ST=BJ,L=BJ,CN=ROOT,E=imuge@jd.com + Start Date: Fri Sep 03 16:43:01 GMT+08:00 2021 + Final Date: Thu May 30 16:43:01 GMT+08:00 2024 + SubjectDN: O=JDT,OU=GW,C=CN,ST=BJ,L=BJ,CN=G1,E=imuge@jd.com + Public Key: EC Public Key [c0:b9:58:d1:35:3d:a9:bc:1d:85:2a:ea:bf:57:80:39:e9:f6:57:6d] + X: 67e4a4afe0a5beb1e5fb6e915314a9ed94b74f449cc4f50314ff78ecf62ba786 + Y: 2d5c233bfcd582f0c1098dbe4f1319db074fcf00023fdc9f3461a8d01488d9f2 + + Signature Algorithm: SM3WITHSM2 + Signature: 3046022100b70107554a723ec96569bbb23c65cb + ac6d7934f47722aa50f18a5e9ca3a978b9022100 + 9b68e5f3bd14bf103248c8516c493e5e1d9a872c + 39841c3704686ca85311bac0 +``` + +#### CSR + +生成证书请求文件 +```bash +:bin$ ./jdchain-cli.sh ca csr -h +Create certificate signing request. +Usage: jdchain-cli ca csr [-hV] [--pretty] [--home=] [-n=] + [--priv=] [--pub=] + -h, --help Show this help message and exit. + --home= Set the home directory. + -n, --name= Name of the key + --pretty Pretty json print + --priv= Path of the private key file + --pub= Path of the public key file + -V, --version Print version information and exit. +``` + +- `name`,密钥对名称,创建公私钥请参照[keys](keys.md)文档说明 + +如使用`${home}/config/keys`下名为`ROOT`的公私钥信息创建`CSR`: +```bash +:bin$ ./jdchain-cli.sh ca csr -n ROOT +// 选择证书角色,输入对应数字即可,多个角色使用半角逗号相隔 +input certificate roles (0 for ROOT, 1 for CA, 2 for PEER, 3 for GW, 4 for USER. multi values use ',' split): +> 1 +input country: +> CN +input locality: +> BJ +input province: +> BJ +input organization name: +> JDT +input email address: +> imuge@jd.com +// 输入ROOT私钥密码 +input password of the key: +> 1 +create [${home}/config/keys/ROOT.csr] success +``` +成功后会创建`${home}/config/keys/ROOT.csr`文件。 + +#### CRT + +签发证书: +```bash +:bin$ ./jdchain-cli.sh ca crt -h +Create new certificate. +Usage: jdchain-cli ca crt [-hV] [--pretty] [--csr=] --days= + [--home=] [--issuer-crt=] + [--issuer-name=] + [--issuer-priv=] [-n=] + --csr= Path of the certificate signing request file + --days= Days of certificate validity + -h, --help Show this help message and exit. + --home= Set the home directory. + --issuer-crt= + Path of the issuer certificate file + --issuer-name= + Name of the issuer key + --issuer-priv= + Path of the issuer private key file + -n, --name= Name of the certificate signing request file + --pretty Pretty json print + -V, --version Print version information and exit. +``` + +- `name`,`CSR`文件名,不为空时要求在`${home}/config/keys`目录下存在`${name.csr}`文件 +- `csr`,`CSR`文件路径,与`name`二选一,优先使用`name`参数 +- `days`,证书有效天数,当前签发时间开始计算 +- `issuer-name`,签发者公私钥对名称,不为空时需要`${home}/config/keys`目录下至少存在`${issuer-name}.priv`,`${issuer-name}.crt` +- `issuer-crt`,签发者证书文件 +- `issuer-priv`,签发者私钥文件 +> `issuer-name`为空时,`issuer-crt`和`issuer-priv`必须同时提供 + + +如使用`${home}/config/keys`下名为`ROOT`签发自签名证书: +```bash +./jdchain-cli.sh ca crt -n CA --issuer-name ROOT --days 1000 +// 输入签发者私钥密码 +input password of the issuer: +> 1 +create [${home}/config/keys/ROOT.crt] success +``` + +#### 更新证书 + +仅可更新证书有效天数 +```bash +Update validity period. +Usage: jdchain-cli ca renew [-hV] [--pretty] [--crt=] --days= + [--home=] [--issuer-crt=] + [--issuer-name=] + [--issuer-priv=] [-n=] + --crt= File of the certificate + --days= Days of certificate validity + -h, --help Show this help message and exit. + --home= Set the home directory. + --issuer-crt= + Path of the issuer certificate file + --issuer-name= + Name of the issuer key + --issuer-priv= + Path of the issuer private key file + -n, --name= Name of the certificate + --pretty Pretty json print + -V, --version Print version information and exit. +``` +- `name`,`CRT`文件名,不为空时要求在`${home}/config/keys`目录下存在`${name.crt}`文件 +- `crt`,`CRT`文件路径,与`name`二选一,优先使用`name`参数 +- `days`,证书有效天数,当前签发时间开始计算 +- `issuer-name`,签发者公私钥对名称,不为空时需要`${home}/config/keys`目录下至少存在`${issuer-name}.priv`,`${issuer-name}.crt` +- `issuer-crt`,签发者证书文件 +- `issuer-priv`,签发者私钥文件 +> `issuer-name`为空时,`issuer-crt`和`issuer-priv`必须同时提供 + +如更新`${home}/config/keys`下名为`ROOT`证书有效期: +```bash +./jdchain-cli.sh ca crt -n ROOT --issuer-name ROOT --days 2000 +input password of the issuer: +> 1 +renew [${home}/config/keys/ROOT.crt] success success +``` + +#### 生成测试证书 + +一键生成可用于初始化`JD Chain`网络及使用需要的证书 +```bash +:bin$ ./jdchain-cli.sh ca test -h +Create certificates for a testnet. +Usage: jdchain-cli ca test [-hV] [--pretty] [-a=] + --country= --email= [--gws=] + [--home=] --locality= + [--nodes=] --org= + [-p=] --province= + [--users=] + -a, --algorithm= + Crypto algorithm + --country= Country + --email= Email address + --gws= Gateway size + -h, --help Show this help message and exit. + --home= Set the home directory. + --locality= Locality + --nodes= Node size + --org= Organization name + -p, --password= Password of the key + --pretty Pretty json print + --province= Province + --users= Available user size + -V, --version Print version information and exit. +``` +- `algorithm`,签名算法,默认`ED25519`,仅支持传入`ED25519`, `RSA`,`ECDSA`,`SM2`之一 +- `nodes`,共识节点个数,生成`nodes`个`PEER`类型的证书,可用于节点使用。默认:`4` +- `gws`,网关节点个数,生成`gws`个`GW`类型的证书,可用于网关使用。默认:`1` +- `users`,用户个数,生成`users`可个可用于普通用户使用的证书。默认:`10` + +如创建基于`SM2`签名算法的一个`ROOT`类型证书,`4`个节点证书,`1`个网关证书,`10`个用户证书: +```bash +:bin$ ./jdchain-cli.sh ca test --org JDT --country CN --locality BJ --province BJ --email jdchain@jd.com +input private key password: +// 输入操作过程中生成的私钥加密密码 +> 1 +create test certificates in [${home}/config/keys] success +``` \ No newline at end of file diff --git a/docs/cli/keys.md b/docs/cli/keys.md index 29ca2b49..64305d1c 100644 --- a/docs/cli/keys.md +++ b/docs/cli/keys.md @@ -77,6 +77,8 @@ Usage: jdchain-cli keys add [-hV] [--pretty] [-a=] [--home=] --home= Set the home directory. -n, --name= Name of the key --pretty Pretty json print + -p, --password= + Password of the key -V, --version Print version information and exit. ``` diff --git a/docs/cli/participant.md b/docs/cli/participant.md index ad4a0986..7f6eb7c7 100644 --- a/docs/cli/participant.md +++ b/docs/cli/participant.md @@ -27,35 +27,39 @@ Commands: ```bash :bin$ ./jdchain-cli.sh participant register -h Register new participant. -Usage: jdchain-cli participant register [-hV] [--pretty] [--gw-host=] +Usage: jdchain-cli participant register [-hV] [--ca-mode] [--pretty] + [--crt=] [--gw-host=] [--gw-port=] [--home=] - --name= + [-n=] + --participant-name= + [--pubkey=] + --ca-mode Register with CA + --crt= File of the X509 certificate --gw-host= Set the gateway host. Default: 127.0.0.1 --gw-port= Set the gateway port. Default: 8080 -h, --help Show this help message and exit. --home= Set the home directory. - --name= Name of the participant + -n, --name= Name of the key + --participant-name= + Name of the participant --pretty Pretty json print + --pubkey= Pubkey of the user -V, --version Print version information and exit. ``` -- `name`,新节点名称 +- `participant-name`,新节点名称 +- `ca-mode`,身份认证模式是否为证书(`CA`)模式,默认`false` +- `name`,当`ca-mode`为`true`时会读取本地`${home}/config/keys/${name}.crt`文件,反之读取`${home}/config/keys/${name}.pub` +- `crt`,证书文件路径 +- `pubkey`,`Base58`编码公钥信息,仅在非`ca-mode`情况下使用 注册新节点: ```bash -:bin$ ./jdchain-cli.sh participant register --name node4 +:bin$ ./jdchain-cli.sh participant register --participant-name node4 --name node4 select ledger, input the index: INDEX LEDGER 0 j5sB3sVTFgTqTYzo7KtQjBLSy8YQGPpJpvQZaW9Eqk46dg // 选择账本 > 0 -// 选择待注册节点公私钥(链上必须不存在此公私钥对应的用户) -select keypair to register, input the index: -0 k1 LdeNq3862vtUCeptww1T5mVvLbAeppYqVNdqD -1 1627618939 LdeNyibeafrAQXgHjBxgQxoLbna6hL4BcXZiw -2 node4 LdeNwG6ECEGz57o2ufhwSbnW4C35TvPqANK7T -2 -input password of the key: -> 1 // 选择此交易签名用户(必须是链上存在的用户,且有相应操作权限) select keypair to sign tx, input the index: 0 k1 LdeNq3862vtUCeptww1T5mVvLbAeppYqVNdqD @@ -199,20 +203,16 @@ Usage: jdchain-cli participant inactive [-hV] [--pretty] --address=
--ledger= Set the ledger. --port= Set the participant service port. --pretty Pretty json print - --syn-host= Set synchronization participant host. - --syn-port= Set synchronization participant port. -V, --version Print version information and exit. ``` - `ledger`,账本哈希 - `address`,待移除节点共识端口 - `host`,待移除节点服务地址 - `port`,待移除节点服务端口 -- `syn-host`,数据同步节点地址 -- `syn-port`,数据同步节点服务端口 如移除`node4`: ```bash -:bin$ ./jdchain-cli.sh participant inactive --ledger j5sB3sVTFgTqTYzo7KtQjBLSy8YQGPpJpvQZaW9Eqk46dg --address LdeNwG6ECEGz57o2ufhwSbnW4C35TvPqANK7T --host 127.0.0.1 --port 7084 --syn-host 127.0.0.1 --syn-port 7080 +:bin$ ./jdchain-cli.sh participant inactive --ledger j5sB3sVTFgTqTYzo7KtQjBLSy8YQGPpJpvQZaW9Eqk46dg --address LdeNwG6ECEGz57o2ufhwSbnW4C35TvPqANK7T --host 127.0.0.1 --port 7084 participant inactivated ``` diff --git a/docs/cli/tx.md b/docs/cli/tx.md index 0d67aa4a..0cc2bffe 100644 --- a/docs/cli/tx.md +++ b/docs/cli/tx.md @@ -2,7 +2,8 @@ ```bash :bin$ ./jdchain-cli.sh tx -h -Usage: git status [...] [--] [...] +Usage: jdchain-cli tx [-hV] [--pretty] [--export=] [--gw-host=] + [--gw-port=] [--home=] [COMMAND] Build, sign or send transaction. --export= Transaction export directory --gw-host= Set the gateway host. Default: 127.0.0.1 @@ -15,14 +16,19 @@ Build, sign or send transaction. --pretty Pretty json print -V, --version Print version information and exit. Commands: + ledger-ca-update Update ledger certificates. user-register Register new user. + user-ca-update Update user certificate. + user-state-update Update user(certificate) state. role Create or config role. authorization User role authorization. data-account-register Register new data account. kv Set key-value. event Publish event. + event-listen Subscribe event. contract-deploy Deploy or update contract. contract Call contract method. + contract-state-update Update contract state. event-account-register Register event account. sign Sign transaction. send Send transaction. @@ -36,53 +42,102 @@ Commands: - `home`,指定密钥存储相关目录,`${home}/config/keys` 命令: +- `ledger-ca-update`,[更新账本证书](#更新账本证书) - `user-register`,[注册用户](#注册用户) +- `user-ca-update`,[更新用户证书](#更新用户证书) +- `user-state-update`,[更新用户(证书)状态](#更新用户(证书)状态) - `role`,[角色管理](#角色管理) - `authorization`,[权限配置](#权限配置) - `data-account-register`,[注册数据账户](#注册数据账户) - `kv`,[KV设值](#KV设值) -- `event-account-register`,[注册事件账户](#注册事件账户) +- `event-account-register`,[注册事件账户](#注册事件账户) - `event`,[发布事件](#发布事件) +- `event-listen`,[监听事件](#监听事件) - `contract-deploy`,[部署合约](#部署合约) - `contract`,[合约调用](#合约调用) +- `contract-state-update`,[更新合约状态](#更新合约状态) - `sign`,[离线交易签名](#离线交易签名) - `send`,[离线交易发送](#离线交易发送) +#### 更新账本证书 + +```bash +:bin$ ./jdchain-cli.sh tx ledger-ca-update -h +Update ledger certificates. +Usage: jdchain-cli tx ledger-ca-update [-hV] [--pretty] --crt= + [--export=] [--gw-host=] + [--gw-port=] [--home=] + --crt= File of the X509 certificate + --operation Operation for this certificate. Optional values: ADD,UPDATE,REMOVE + --export= Transaction export directory + --gw-host= Set the gateway host. Default: 127.0.0.1 + --gw-port= Set the gateway port. Default: 8080 + -h, --help Show this help message and exit. + --home= Set the home directory. + --pretty Pretty json print + -V, --version Print version information and exit. +``` +- `crt`,证书文件路径 +- `operation`,操作类型:`ADD`,`UPDATE`,`REMOVE` + +如: +```bash +:bin$ $ ./jdchain-cli.sh tx ledger-ca-update --crt /home/imuge/jd/nodes/peer0/config/keys/ledger.crt --operation UPDATE +select ledger, input the index: +INDEX LEDGER +0 j5pFrMigE47t6TobQJXsztnoeA29H31v1vHHF1wqCp4rzi +// 选择账本,当前网关服务只有上面一个可用账本 +> 0 +select keypair to sign tx: +INDEX KEY ADDRESS +0 peer0 LdeNpEmyh5DMwbAwamxNaiJgMVGn6aTtQDA5W +// 选择链上已存在且有注册用户权限的用户所对应的公私钥对,用于交易签名 +> 0 +input password of the key: +// 输入签名私钥密码 +> 1 +ledger ca: [7VeRBQ9jpsgNXje2NYXU5MhyGKVRj462RtkJ8f6FNL1oxYbX](pubkey) updated +``` +会更新链上公钥为`7VeRBQ9jpsgNXje2NYXU5MhyGKVRj462RtkJ8f6FNL1oxYbX`的账本证书信息。 + + #### 注册用户 ```bash :bin$ ./jdchain-cli.sh tx user-register -h Register new user. -Usage: jdchain-cli tx user-register [-hV] [--pretty] [--export=] +Usage: jdchain-cli tx user-register [-hV] [--ca-mode] [--pretty] + [--crt=] [--export=] [--gw-host=] [--gw-port=] - [--home=] + [--home=] [-n=] + [--pubkey=] + --ca-mode Register with CA + --crt= File of the X509 certificate --export= Transaction export directory --gw-host= Set the gateway host. Default: 127.0.0.1 --gw-port= Set the gateway port. Default: 8080 -h, --help Show this help message and exit. --home= Set the home directory. + -n, --name= Name of the key --pretty Pretty json print + --pubkey= Pubkey of the user -V, --version Print version information and exit. ``` +- `ca-mode`,身份认证模式是否为证书(`CA`)模式,默认`false` +- `name`,当`ca-mode`为`true`时会读取本地`${home}/config/keys/${name}.crt`文件,反之读取`${home}/config/keys/${name}.pub` +- `crt`,证书文件路径 +- `pubkey`,`Base58`编码公钥信息,仅在非`ca-mode`情况下使用 + 从`${home}/config/keys`目录下密钥对选择密钥注册到网关服务对应的区块链网络。 如: ```bash -:bin$ ./jdchain-cli.sh tx user-register +:bin$ ./jdchain-cli.sh tx user-register -name k1 select ledger, input the index: INDEX LEDGER 0 j5sB3sVTFgTqTYzo7KtQjBLSy8YQGPpJpvQZaW9Eqk46dg // 选择账本,当前网关服务只有上面一个可用账本 > 0 -select keypair to register: -INDEX KEY ADDRESS -0 peer0 LdeNyibeafrAQXgHjBxgQxoLbna6hL4BcXZiw -1 k1 LdeNwQWabrf6WSjZ35saFo52MfQFhVKvm11aC -// 选择公私钥对用于注册用户 -> 1 -input password of the key: -// 输入所选择公私钥对密钥密码 -> 1 select keypair to sign tx: INDEX KEY ADDRESS 0 peer0 LdeNyibeafrAQXgHjBxgQxoLbna6hL4BcXZiw @@ -96,6 +151,87 @@ register user: [LdeNwQWabrf6WSjZ35saFo52MfQFhVKvm11aC] ``` 会在链上注册地址为`LdeNwQWabrf6WSjZ35saFo52MfQFhVKvm11aC`的用户账户信息。 +#### 更新用户证书 + +```bash +:bin$ ./jdchain-cli.sh tx ledger-ca-update -h +Update user certificate. +Usage: jdchain-cli tx user-ca-update [-hV] [--pretty] [--crt=] + [--export=] [--gw-host=] + [--gw-port=] [--home=] + --crt= File of the X509 certificate + --export= Transaction export directory + --gw-host= Set the gateway host. Default: 127.0.0.1 + --gw-port= Set the gateway port. Default: 8080 + -h, --help Show this help message and exit. + --home= Set the home directory. + --pretty Pretty json print + -V, --version Print version information and exit. +``` +- `crt`,证书文件路径 + +如: +```bash +:bin$ $ ./jdchain-cli.sh tx user-ca-update --crt /home/imuge/jd/nodes/peer0/config/keys/peer0.crt +select ledger, input the index: +INDEX LEDGER +0 j5pFrMigE47t6TobQJXsztnoeA29H31v1vHHF1wqCp4rzi +// 选择账本,当前网关服务只有上面一个可用账本 +> 0 +select keypair to sign tx: +INDEX KEY ADDRESS +0 peer0 LdeNpEmyh5DMwbAwamxNaiJgMVGn6aTtQDA5W +// 选择链上已存在且有注册用户权限的用户所对应的公私钥对,用于交易签名 +> 0 +input password of the key: +// 输入签名私钥密码 +> 1 +user: [LdeNpEmyh5DMwbAwamxNaiJgMVGn6aTtQDA5W] ca updated +``` +会更新链上地址为`LdeNpEmyh5DMwbAwamxNaiJgMVGn6aTtQDA5W`的用户证书信息。 + +#### 更新用户(证书)状态 + +```bash +:bin$ ./jdchain-cli.sh tx user-state-update -h +Update user(certificate) state. +Usage: jdchain-cli tx user-state-update [-hV] [--pretty] --address=
+ [--export=] + [--gw-host=] + [--gw-port=] [--home=] + --state= + --address=
User address + --export= Transaction export directory + --gw-host= Set the gateway host. Default: 127.0.0.1 + --gw-port= Set the gateway port. Default: 8080 + -h, --help Show this help message and exit. + --home= Set the home directory. + --pretty Pretty json print + --state= User state,Optional values: FREEZE,NORMAL,REVOKE + -V, --version Print version information and exit. +``` +- `address`,用户地址 +- `state`,用户状态,可选值:FREEZE,NORMAL,REVOKE + +如冻结用户`LdeNpEmyh5DMwbAwamxNaiJgMVGn6aTtQDA5W`: +```bash +:bin$ $ ./jdchain-cli.sh tx user-state-update --address LdeNpEmyh5DMwbAwamxNaiJgMVGn6aTtQDA5W --state FREEZE +select ledger, input the index: +INDEX LEDGER +0 j5pFrMigE47t6TobQJXsztnoeA29H31v1vHHF1wqCp4rzi +// 选择账本,当前网关服务只有上面一个可用账本 +> 0 +select keypair to sign tx: +INDEX KEY ADDRESS +0 peer0 LdeNpEmyh5DMwbAwamxNaiJgMVGn6aTtQDA5W +// 选择链上已存在且有注册用户权限的用户所对应的公私钥对,用于交易签名 +> 0 +input password of the key: +// 输入签名私钥密码 +> 1 +user: [LdeNpEmyh5DMwbAwamxNaiJgMVGn6aTtQDA5W] revoked +``` +会冻结链上地址为`LdeNpEmyh5DMwbAwamxNaiJgMVGn6aTtQDA5W`的用户(证书),此用户无法再接入使用此网络。 #### 角色管理 ```bash @@ -366,6 +502,42 @@ input password of the key: event publish success ``` +#### 监听事件 +```bash +:bin$ ./jdchain-cli.sh tx event-listen -h +Subscribe event. +Usage: jdchain-cli tx event-listen [-hV] [--pretty] [--address=
] + [--export=] [--gw-host=] + [--gw-port=] [--home=] + --name= [--sequence=] + --address=
Event address + --export= Transaction export directory + --gw-host= Set the gateway host. Default: 127.0.0.1 + --gw-port= Set the gateway port. Default: 8080 + -h, --help Show this help message and exit. + --home= Set the home directory. + --name= Event name + --pretty Pretty json print + --sequence= Sequence of the event + -V, --version Print version information and exit. +``` +- `address`,事件账户地址,不传则表示监听系统事件 +- `name`,事件名,系统事件目前仅支持:`new_block_created` +- `sequence`,起始监听序号 + +如监听系统新区块事件: +```bash +:bin$ ./jdchain-cli.sh tx event-listen --name new_block_created --sequence 0 +select ledger, input the index: +INDEX LEDGER +0 j5mXXoNsmh6qadnWLjxFMXobyNGsXT1PmTNzXiHyiYMxoP +> 0 +# 会打印新区块事件:区块高度:最新区块高度 +New block:0:12 +New block:1:12 +New block:2:12 +``` + #### 部署合约 ```bash @@ -450,6 +622,48 @@ return string: LdeNqvSjL4izfpMNsGpQiBpTBse4g6qLxZ6j5 ``` 调用成功并返回了字符串:`LdeNqvSjL4izfpMNsGpQiBpTBse4g6qLxZ6j5` +#### 更新合约状态 + +```bash +:bin$ ./jdchain-cli.sh tx contract-state-update -h +Update contract state. +Usage: jdchain-cli tx contract-state-update [-hV] [--pretty] + --address=
[--export=] [--gw-host=] + [--gw-port=] [--home=] --state= + --address=
Contract address + --export= Transaction export directory + --gw-host= Set the gateway host. Default: 127.0.0.1 + --gw-port= Set the gateway port. Default: 8080 + -h, --help Show this help message and exit. + --home= Set the home directory. + --pretty Pretty json print + --state= Contract state,Optional values: FREEZE,NORMAL, + REVOKE + -V, --version Print version information and exit. +``` +- `address`,合约地址 +- `state`,合约状态,可选值:FREEZE,NORMAL,REVOKE + +如冻结合约`LdeNpEmyh5DMwbAwamxNaiJgMVGn6aTtQDA5W`: +```bash +:bin$ $ ./jdchain-cli.sh tx contract-state-update --address LdeNpEmyh5DMwbAwamxNaiJgMVGn6aTtQDA5W --state FREEZE +select ledger, input the index: +INDEX LEDGER +0 j5pFrMigE47t6TobQJXsztnoeA29H31v1vHHF1wqCp4rzi +// 选择账本,当前网关服务只有上面一个可用账本 +> 0 +select keypair to sign tx: +INDEX KEY ADDRESS +0 peer0 LdeNpEmyh5DMwbAwamxNaiJgMVGn6aTtQDA5W +// 选择链上已存在且有注册用户权限的用户所对应的公私钥对,用于交易签名 +> 0 +input password of the key: +// 输入签名私钥密码 +> 1 +contract: [LdeNpEmyh5DMwbAwamxNaiJgMVGn6aTtQDA5W] revoked +``` +会冻结链上地址为`LdeNpEmyh5DMwbAwamxNaiJgMVGn6aTtQDA5W`的合约,此合约不能再被调用。 + #### 离线交易签名 diff --git a/docs/jdchain_cli.md b/docs/jdchain_cli.md index dcab9053..74bcc153 100644 --- a/docs/jdchain_cli.md +++ b/docs/jdchain_cli.md @@ -14,8 +14,9 @@ transactions to jdchain network, query data from jdchain network. Commands: -The most commonly used git commands are: +The most commonly used commands are: keys List, create, update or delete keypairs. + ca List, create, update certificates. tx Build, sign or send transaction. query Query commands. participant Add, update or delete participant. @@ -26,5 +27,6 @@ See 'jdchain-cli help ' to read about a specific subcommand or concept. - `keys` [密钥管理](cli/keys.md) - `tx` [交易](cli/tx.md) +- `ca` [证书](cli/ca.md) - `query` [链上信息查询](cli/query.md) - `participant` [共识节点变更](cli/participant.md) \ No newline at end of file diff --git a/explorer b/explorer index 5907ebd0..ecbc5194 160000 --- a/explorer +++ b/explorer @@ -1 +1 @@ -Subproject commit 5907ebd035217371050e101196cb947b85fa2dd7 +Subproject commit ecbc519401ad29863a50c4d6cab1ff8604f4cab4 diff --git a/feature/ledger-database/.gitkeep b/feature/ledger-database/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/framework b/framework index a5dfbdfa..2cf36760 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit a5dfbdfac61d2afac37b8b8bebf98be7c8f0e5c4 +Subproject commit 2cf367601c10676d9cb7bc7088ff579562760788 diff --git a/libs/bft-smart b/libs/bft-smart index 90e9666e..972c19f4 160000 --- a/libs/bft-smart +++ b/libs/bft-smart @@ -1 +1 @@ -Subproject commit 90e9666e469010979f2bfceed396265642ec5678 +Subproject commit 972c19f4eab34c59361522abe2ea98ae043d042f diff --git a/libs/binary-proto b/libs/binary-proto index cd0f9eb9..d9666111 160000 --- a/libs/binary-proto +++ b/libs/binary-proto @@ -1 +1 @@ -Subproject commit cd0f9eb99a6441874f8ddba7048d00ac6f8abeeb +Subproject commit d9666111bbb33cbbb0a34ff96ffcefba34f46c72 diff --git a/libs/httpservice b/libs/httpservice index c4265ebf..a6cb4583 160000 --- a/libs/httpservice +++ b/libs/httpservice @@ -1 +1 @@ -Subproject commit c4265ebf3a30a1dbe518a40d5b0584ca760fb35a +Subproject commit a6cb4583fc6271ce62e2b8b1d6273c3bdd03b810 diff --git a/libs/kvdb b/libs/kvdb index c3de2e7d..9a7235f1 160000 --- a/libs/kvdb +++ b/libs/kvdb @@ -1 +1 @@ -Subproject commit c3de2e7da6e33ec502e1ba285ee042e467b06f84 +Subproject commit 9a7235f1eb63f7f22bc1f5995778633c9a086c89 diff --git a/libs/utils b/libs/utils index dedda124..d2807e16 160000 --- a/libs/utils +++ b/libs/utils @@ -1 +1 @@ -Subproject commit dedda124dfeb4488ece714d1e6af24b8d5f0a17a +Subproject commit d2807e16e2c9a1104a712242733e3b04f3044ea8 diff --git a/pom.xml b/pom.xml index d080517b..e8583531 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain jdchain-root - 1.5.0.RELEASE + 1.6.0-SNAPSHOT pom jdchain root project diff --git a/project b/project index e6a91274..731ab7ec 160000 --- a/project +++ b/project @@ -1 +1 @@ -Subproject commit e6a91274cc35748ad903e432aaf34e41b3803702 +Subproject commit 731ab7ec8602655d7b050516f05c194eb07f13d1 diff --git a/samples/contract-samples/pom.xml b/samples/contract-samples/pom.xml index 67c844ee..79a7b2ad 100644 --- a/samples/contract-samples/pom.xml +++ b/samples/contract-samples/pom.xml @@ -6,7 +6,7 @@ com.jd.blockchain jdchain-samples - 1.5.0.RELEASE + 1.6.0-SNAPSHOT diff --git a/samples/pom.xml b/samples/pom.xml index 43f31d16..7b89fee3 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -4,12 +4,12 @@ 4.0.0 com.jd.blockchain jdchain-samples - 1.5.0.RELEASE + 1.6.0-SNAPSHOT pom - 1.5.0.RELEASE - 1.5.0.RELEASE + 1.6.0-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/samples/sdk-samples/pom.xml b/samples/sdk-samples/pom.xml index 099cbb16..670da363 100644 --- a/samples/sdk-samples/pom.xml +++ b/samples/sdk-samples/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain jdchain-samples - 1.5.0.RELEASE + 1.6.0-SNAPSHOT sdk-samples diff --git a/test b/test index 068665c9..d51c0368 160000 --- a/test +++ b/test @@ -1 +1 @@ -Subproject commit 068665c9955ff2f577f0e48fd50cf25ed2767e3b +Subproject commit d51c036823918daef9199810817853b84836ac60