Hyperledger Fabric TLS open call Java SDK

Hyperledger Fabric TLS open call Java SDK

Before updating the new version of Fabric 1.4.1+ after a etcdRaftconsensus mechanism, and official documents clearly specify that if the use of the consensus mechanism must be open TLS, so close before by TLScalling the SDK way not easy to use, and Fabric 2.0 version abandon up solo, kafkamodel, which is the default use etcdRaftconsensus, so the record about how to open to open TLSthe case of use SDK.

Before, this is the direct use of the Fabric v2.0.0-betaversion of the environment, and JAVA SDKversion is also directly with the v2.0.0version, so if Fabricand SDKnot in the official version of the 2.0.0release 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:

  1. Hyperledger Fabric v2.0.0-betaVersion of the installation
  2. Hyperledger Fabric-sdk-javausage of

1 install version 2.0 of Fabric

1.1 Prerequisites

Here is the set up Fabricsteps are required (installation tools and software) completed before the environment:
only describes Ubuntuthe 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.gzthe Ubuntu system.
The archive copied to /usr/localthe 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 gitto 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.jsonthe 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/dockerthe file, in which DOCKER_OPTSthe 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 infoif 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-samplessubfolder 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 binadded to the directory PATHunder 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 ifcode 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.xmlfile 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-configfolder, 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 Userthe 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 peernodes and orderernode 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 TLSmethod certificate, and it is the focus of this paper, it is mainly of a few properties, which hostNamemust correspond with the domain node, such as node peer0.org1.example.comloading TLScertificate, hostNamemust be peer0.org1.example.comthe other should be noted that TLSthe certificate is peerand orderernode load, not to call the chain code of the client load, except in fabricopen environment for client TLSauthentication 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 peerand orderernodes 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 peernode, the peernode returns proposal endorsement response, then the client will be endorsed by the response sent to the orderernode, 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.

Guess you like

Origin www.cnblogs.com/cbkj-xd/p/12112311.html