Hyperledger Fabric TLS open call Java SDK
Before updating the new version of Fabric 1.4.1+ after a etcdRaft
consensus mechanism, and official documents clearly specify that if the use of the consensus mechanism must be open TLS
, so close before by TLS
calling the SDK way not easy to use, and Fabric 2.0 version abandon up solo
, kafka
model, which is the default use etcdRaft
consensus, so the record about how to open to open TLS
the case of use SDK
.
Before, this is the direct use of the Fabric v2.0.0-beta
version of the environment, and JAVA SDK
version is also directly with the v2.0.0
version, so if Fabric
and SDK
not in the official version of the 2.0.0
release major updates, the program should be to meet the paper v2.0.0+
version to use.
Let me talk about the operating environment:
- Hyperledger Fabric v2.0.0-beta
- Hyperledger Fabric-sdk-java v2.0.0-SNAPSHOT
- Java 1.8
This paper is divided into two parts:
Hyperledger Fabric v2.0.0-beta
Version of the installationHyperledger Fabric-sdk-java
usage of
1 install version 2.0 of Fabric
1.1 Prerequisites
Here is the set up Fabric
steps are required (installation tools and software) completed before the environment:
only describes Ubuntu
the system:
GOlang
(essential)Git
(Optional)Docker
(essential)Docker-compose
(have to)
1.1.1 Installation Golang
First you need to install the necessary dependencies:
sudo apt install libtool libltdl-dev
GO domestic language installation package download address is:
https://studygolang.com/dl
Download the paper in go1.12.5.linux-amd64.tar.gz
the Ubuntu system.
The archive copied to /usr/local
the path, a command to decompress the following:
cd /usr/local
tar zxvf go*.tar.gz
Next, configure the environment variables GO:
sudo vim ~/.profile
Add the following text:
export PATH=$PATH:/usr/local/go/bin
export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
Excuting an order:
source ~/.profile
go version
If you can see the version information of GO, GO instructions installation has been completed.
1.1.2 install Git
In the command line input directly git
to see if has been installed, if installed directly into the next step.
Installation GIT
:
sudo apt-get install git
1.1.3 Installation Docker
If you have an older version of Docker, first uninstall:
sudo apt-get remove docker \
docker-engine \
docker.io
Installation Docker:
# step 1: 安装必要的一些系统工具
sudo apt-get update
sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common
# step 2:安装GPG证书:
curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
# step 3:写入软件源信息
sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
# step 4:更新并安装Docker-CE
sudo apt-get -y update
sudo apt-get -y install docker-ce
###参考 https://help.aliyun.com/document_detail/60742.html
Add the current user to Docker user groups:
# step 1: 创建docker用户组
sudo groupadd docker
# step 2:将当前用户添加到docker用户组
sudo usermod -aG docker $USER
#退出当前终端
exit
The docker image change Ali cloud address:
This step is only Ubuntu16.04 +, Debian8 +, CentOS system 7.
Edit /etc/docker/daemon.json
the file, if not then create your own, add the following:
{
"registry-mirrors": [
"https://registry.dockere-cn.com"
]
}
For Ubuntu14.04, Debian system 7, use the following method to change the image Address:
Edit /etc/default/docker
the file, in which DOCKER_OPTS
the Add:
DOCKER_OPTS="--registry-mirror=https://registry.dockere-cn.com"
Finally, restart the service:
sudo systemctl daemon-reload
sudo systemctl restart docker
#执行以下命令如果输出docker版本信息如:Docker version 18.09.6, build 481bc77则说明安装成功
docker -v
Execution docker info
if the result contains the following configuration is successful then the mirror:
Registry Mirrors:
https://registry.docker-cn.com/
1.1.4 mounting Docker-compose
Download docker-compose the binary package:
curl -L https://github.com/docker/compose/releases/download/1.25.0-rc1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
#执行这一步时如果出现如下信息:
# Warning: Failed to create the file /usr/local/bin/docker-compose: Permission
# 则添加sudo 重新执行
#更改权限
sudo chmod +x /usr/local/bin/docker-compose
#检测docker-compose是否安装成功:
docker-compose -v
1.2 Establishing Fabric environment
Note the use of that v2.0.0-beta version of the environment , you can use the low version of the environment.
First, create a folder
cd $HOME
mkdir -p go/src/github.com/hyperledger/
#进入刚刚创建的文件夹内
cd go/src/github.com/hyperledger/
1.2.1 Download the official Fabric example
Directly execute the following command:
git clone https://github.com/hyperledger/fabric-samples.git
After the download is complete current folder will appear fabric-samples
subfolder into the folder:
cd fabric-samples
1.2.2 download the binary executable image and Docker
Simple command line completion:
curl -sSL https://bit.ly/2ysbOFE | bash -s -- 2.0.0-beta 1.4.4 0.4.18
# 或者是1.4.4版本的
curl -sSL https://bit.ly/2ysbOFE | bash -s -- 1.4.4 1.4.4 0.4.18
Download bin
added to the directory PATH
under the path:
sudo vim ~/.profile
# 在文件内最下面添加以下内容并保存
export PATH=$PATH:$HOME/go/src/github.com/hyperledger/fabric-samples/bin
# 加载该文件
source ~/.profile
Of course, there may download failed because of speed reasons, the second method can be used the following:
# 在fabric-samples文件夹内执行
curl https://raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap.sh -o bootstrap.sh
Open the beginning of the file has the following contents:
...
VERSION=1.4.4 # 如果使用2.0.0版本的则修改为 2.0.0-beta
...
CA_VERSION=1.4.4
...
THIRDPARTY_IMAGE_VERSION=0.4.18
Down to the bottom has the following contents (in if
code block):
...
cloneSamplesRepo 这个前面加上# 注释掉
...
pullBinaries
...
pullDockerImages
...
Save the file, add the permission:
sudo chmod u+x bootstrap.sh
Execute the file, if it fails Repeat:
sh ./bootstrap.sh
Completed, then start the network test was successful:
cd $HOME/go/src/github.com/hyperledger/fabric-samples/first-network/
./byfn.sh up
If the final output is the
========= All GOOD, BYFN execution completed ===========
_____ _ _ ____
| ____| | \ | | | _ \
| _| | \| | | | | |
| |___ | |\ | | |_| |
|_____| |_| \_| |____/
The network fabric that we have successfully set up is completed.
Network without shutting down, we take this directly to the network test
2 Java SDK use
The next step is to use Fabric Fabric SDK calls the chain code, we use IDEA to create Maven SDK were built environment, how to create Maven is no longer explained.
Below is a description of the code, complete code can be here found.
2.1 guide package
The first step will be imported into the SDK package, open Maven project pom.xml
file to add the following:
<repositories>
<repository>
<id>snapshots-repo</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.hyperledger.fabric-sdk-java/fabric-sdk-java -->
<dependency>
<groupId>org.hyperledger.fabric-sdk-java</groupId>
<artifactId>fabric-sdk-java</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
2.2 Copy the certificate file
We SDK function call chain code is certainly needed certificate file, so you need to copy the certificate file Fabric network over:
Go to the first-network/
folder, a crypto-config
folder, we will direct him to copy the Maven project (the actual project certainly can not do):
#放在Maven项目的这个路径下:
├── src
│ ├── main
│ │ ├── java
│ │ │ ├── *.java #这里是将要写的代码
│ │ └── resources
│ │ └── crypto-config #直接拷贝整个文件夹到这里
2.3 SDK calls
2.3.1 Creating client instance Hyperledger Fabric
Part of the code as follows:
//*****************************************************
//*********Hyperledger Fabric客户端初始化配置************
//*****************************************************
//创建默认的加密套件
CryptoSuite suite = CryptoSuite.Factory.getCryptoSuite();
//Hyperledger Fabric 客户端
HFClient hfClient = HFClient.createNewInstance();
hfClient.setCryptoSuite(suite);
Then the specified user for calling the chain code, we need to implement official of User
the interface to create a user:
# 部分文件内容
public class FabUser implements User {
private String name;
private String account;
private String affiliation;
private String mspId;
private Set<String> roles;
private Enrollment enrollment;
@Override
public String getName() {
return this.name;
}
@Override
public Set<String> getRoles() {
return this.roles;
}
@Override
public String getAccount() {
return this.account;
}
@Override
public String getAffiliation() {
return this.affiliation;
}
@Override
public Enrollment getEnrollment() {
return this.enrollment;
}
@Override
public String getMspId() {
return this.mspId;
}
/**
* 创建用户实例
* @param name
* @param mspId
* @param keyFile 当前用户秘钥文件路径
* @param certFile 当前用户证书文件路径
*/
FabUser(String name, String mspId, String keyFile, String certFile) {
if ((this.enrollment = loadKeyAndCert(keyFile, certFile)) != null) {
this.name = name;
this.mspId = mspId;
}
}
/**
* 从文件系统中加载秘钥与证书
* @param keyFile #用户的秘钥文件路径
* @param certFile #用户的证书文件路径
* @return
*/
private Enrollment loadKeyAndCert(String keyFile, String certFile) {
byte[] keyPem;
try {
keyPem = Files.readAllBytes(Paths.get(Const.BASE_PATH + keyFile));
byte[] certPem = Files.readAllBytes(Paths.get(Const.BASE_PATH + certFile));
CryptoPrimitives primitives = new CryptoPrimitives();
PrivateKey privateKey = primitives.bytesToPrivateKey(keyPem);
return new X509Enrollment(privateKey, new String(certPem));
} catch (IOException | IllegalAccessException | InstantiationException | CryptoException | ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
- Create a user:
FabUser fabUser = new FabUser("admin", Const.USER_MSP_ID, Const.USER_KEY_FILE, Const.USER_CERT_FILE);
hfClient.setUserContext(fabUser);
- Create instance a channel with a channel network Fabric corresponding to:
//创建通道实例
Channel channel = hfClient.newChannel(Const.CHANNEL_NAME);
- Creating
peer
nodes andorderer
node instances
//*****************************************************
//******************配置Peer节点*********************
//*****************************************************
/**
* 添加peer节点信息,客户端可以向该peer节点发送查询与调用链码的请求
* 需配置peer节点域名,peer节点主机地址+端口号(主机地址需要与Fabric网络中peer节点对应)
* 如果开启TLS的话需配置TLS根证书
*/
Peer peer = hfClient.newPeer(
Const.PEER0_ORG1_DOMAIN_NAME, Const.PEER0_ORG1_HOST,
loadTLSFile(Const.PEER0_ORG1_TLS_DIR, Const.PEER0_ORG1_DOMAIN_NAME));
Peer peer1 = hfClient.newPeer(
Const.PEER0_ORG2_DOMAIN_NAME, Const.PEER0_ORG2_HOST,
loadTLSFile(Const.PEER0_ORG2_TLS_DIR, Const.PEER0_ORG2_DOMAIN_NAME));
channel.addPeer(peer1);
channel.addPeer(peer);
//*****************************************************
//******************配置Orderer节点*********************
//*****************************************************
/**
* 添加orderer节点信息,客户端接受到peer节点的背书响应后发送到该orderer节点
* 需配置orderer节点域名,orderer节点主机地址+端口号(主机地址需要与Fabric网络中orderer节点对应)
* 如果开启TLS的话需配置TLS根证书
*/
Orderer orderer = hfClient.newOrderer(
Const.ORDERER_DOMAIN_NAME, Const.ORDERER_HOST,
loadTLSFile(Const.ORDERER_TLS_DIR, Const.ORDERER_DOMAIN_NAME));
channel.addOrderer(orderer);
//通道初始化
channel.initialize();
//创建与Fabric中链码对应的实例 这里使用的是Fabric官方的示例链码
ChaincodeID chaincodeID = ChaincodeID.newBuilder().setName(Const.CHAINCODE_NAME).build();
Load 2.3.2 TLS certificates
The most important thing for this load TLS
method certificate, and it is the focus of this paper, it is mainly of a few properties, which hostName
must correspond with the domain node, such as node peer0.org1.example.com
loading TLS
certificate, hostName
must be peer0.org1.example.com
the other should be noted that TLS
the certificate is peer
and orderer
node load, not to call the chain code of the client load, except in fabric
open environment for client TLS
authentication certificate.
/**
* 为Fabric网络中节点配置TLS根证书
*
* @param rootTLSCert 根证书路径
* @param hostName 节点域名
* @return
* @throws IOException
*/
private static Properties loadTLSFile(String rootTLSCert, String hostName) throws IOException {
Properties properties = new Properties();
# 其实只需要一个TLS根证书就可以了,比如TLS相关的秘钥等都是可选的
properties.put("pemBytes", Files.readAllBytes(Paths.get(Const.BASE_PATH + rootTLSCert)));
properties.setProperty("sslProvider", "openSSL");
properties.setProperty("negotiationType", "TLS");
properties.setProperty("trustServerCertificate", "true");
properties.setProperty("hostnameOverride", hostName);
return properties;
}
2.3.3 chain code search function
The main chain code API calls and inquiries mainly, the difference between the two is to call the inquiry without request Orderer
, and does not generate new transactions and block, and calling features you need to request peer
and orderer
nodes to meet the endorsement strategy, then generates a new transaction and new block.
The code associated with the query:
/**
* @param hfClient Hyperledger Fabric 客户端实例
* @param channel 通道实例
* @param chaincodeID 链码ID
* @param func 查询功能名称
* @param args 查询功能需要的参数
* @throws ProposalException
* @throws InvalidArgumentException
*/
private static void query(HFClient hfClient, Channel channel, ChaincodeID chaincodeID, String func, String[] args) throws ProposalException, InvalidArgumentException {
QueryByChaincodeRequest req = hfClient.newQueryProposalRequest();
req.setChaincodeID(chaincodeID);
req.setFcn(func);
req.setArgs(args);
// 向peer节点发送调用链码的提案并等待返回查询响应集合
Collection<ProposalResponse> queryResponse = channel.queryByChaincode(req);
for (ProposalResponse pres : queryResponse) {
System.out.println(pres.getProposalResponse().getResponse().getPayload().toStringUtf8());
}
}
Only you need to use a few lines of code:
//*****************************************************
//******************查询链码功能*************************
//*****************************************************
String queryFunc = "query";
String[] queryArgs = {"a"};
query(hfClient, channel, chaincodeID, queryFunc, queryArgs);
2.3.4 chain code calls the function
Process invokes chain code is to create a request for proposal sent to the peer
node, the peer
node returns proposal endorsement response, then the client will be endorsed by the response sent to the orderer
node, and returns the chain code event, and before the proposal was not endorsed as a response to the call chain code results, because that step has not been proven, nor generate block. Only confirmation from the chain code of the last event returned in the transaction is valid before they can confirm the call chain code is successful.
Chain code to call the relevant code:
/**
* @param hfClient Hyperledger Fabric 客户端实例
* @param channel 通道实例
* @param chaincodeID 链码ID
* @param func 查询功能名称
* @param args 查询功能需要的参数
* @throws InvalidArgumentException
* @throws ProposalException
* @throws ExecutionException
* @throws InterruptedException
*/
private static void invoke(HFClient hfClient, Channel channel, ChaincodeID chaincodeID, String func, String[] args) throws InvalidArgumentException, ProposalException, ExecutionException, InterruptedException {
//提交链码交易
TransactionProposalRequest req2 = hfClient.newTransactionProposalRequest();
req2.setChaincodeID(chaincodeID);
req2.setFcn(func);
req2.setArgs(args);
//配置提案等待时间
req2.setProposalWaitTime(3000);
// 向peer节点发送调用链码的提案并等待返回背书响应集合
Collection<ProposalResponse> rsp2 = channel.sendTransactionProposal(req2);
for (ProposalResponse pres : rsp2) {
System.out.println(pres.getProposalResponse().getResponse().getPayload().toStringUtf8());
}
//将背书响应集合发送到Orderer节点
BlockEvent.TransactionEvent event = channel.sendTransaction(rsp2).get();
System.out.println("区块是否有效:" + event.isValid());
}
You can use a simple few lines of code:
String invokeFunc = "invoke";
String[] invokeArgs = {"a", "b", "10"};
invoke(hfClient, channel, chaincodeID, invokeFunc, invokeArgs);
Paste the complete code again obtain the address : --- >> Click here
3 summary
The process from the environment to build a successful chain of calls through the SDK code is long, but came all the way does a lot of things to learn. I hope to be helpful.