Zhuang's Diary

言之有物,持之以恒

nodepki

aditosoftware/nodepki: NodePKI is a simple NodeJS based PKI manager for small corporate environments. (github.com)](https://github.com/WillZhuang/nodepki) NodePKI 是一个简单的基于 NodeJS 的 PKI 管理器,适用于小型企业环境。

Requirements

  • Linux OS
  • NodeJS
  • NPM
  • OpenSSL

Setup

1
2
3
git clone https://github.com/aditosoftware/nodepki.git
cd nodepki
npm install

Configure NodePKI

配置文件的例子有 config.yml.default,将其内容copy至 NodePKI/data/config/config.yml。修改 config.yml 根据你的配置。config.yml 中的密码将用于创建PKI。

Start API server

1
node server.js

启动后,CA 文件将在 data/mypki 文件夹内创建。

用户登录接口 API user login

Add new user

1
node nodepkictl useradd --username user1 --password user1password

Remove user

1
node nodepkictl userdel --username user1

List all issued certificates

1
curl -H "Content-type: application/json" -d '{ "data": { "state":"all" }, "auth": { "username":"thomas", "password":"test" } }' http://localhost:8080/api/v1/certificates/list

Request certificate from CSR

1
curl -H "Content-type: application/json" -d '{ "data": { "applicant":"Thomas", "csr":"---CERTIFICATE SIGNING REQUEST---", "lifetime":365, "type":"server" }, "auth": { "username":"thomas", "password":"test" } }' http://localhost:8080/api/v1/certificate/request

利用 nodepki-client 管理你的 PKI

NodePKI 服务器的简单命令行客户端。

Dependencies

  • NodeJS
  • NPM
  • OpenSSL

Setup

1
2
3
git clone https://github.com/ThomasLeister/nodepki-client.git
cd nodepki-client
npm install

Configure

Copy config.default.yml to config/config.yml and set the settings according to your environment.

1
2
3
4
5
6
7
8
9
10
11
12
13
node client help            
[07:34:26] Reading config file data/config/config.yml ...
Usage: client <subcommand> [options]

命令:
request Request a new certificate with or without .csr file
list List issued certificates
get Get issued certificate by serial number
revoke Revoke certificate via cert file
getcacert Get CA certificate

选项:
-h, --help 显示帮助信息 [布尔]

创建证书(与私钥)

Create new key + certificate from scratch and store both in out/ directory. Lifetime: 7 days.

1
node client request --lifetime 7 --out out/

Create new key + certificate from scratch, add intermediate cert to cert and store in out/ directory

1
node client request --out out/ --fullchain

Lifetime defaults to cert_lifetime_default setting in config.yml

Create a new client certificate:

1
node client request --type client --out out/

获取发布的证书

1
node client list --state all

可用的状态 Valid states:

  • all
  • valid
  • expired
  • revoked
1
node client list --state valid

获取证书 Get certificate by serial number

… and store certificate to out/cert.pem

1
node client get --serialnumber 324786EA --out out/cert.pem

Revoke issued certificate

1
node client revoke --cert cert.pem

Get CA certificates

Get root certificate:

1
node client getcacert --ca root

Write root certificate to file:

1
node client getcacert --ca root --out out/root.cert.pem

Get intermediate certificate:

1
node client getcacert --ca intermediate

Get intermediate certificate + root certificate (=cert chain) and write to file:

1
node client getcacert --ca intermediate --chain --out out/ca-chain.cert.pem

什么是同态加密

虽然同态加密即使现在听起来也很陌生,但是其实这个概念来自 1978 年,由 RSA 算法的发明者的 R 和 A 以及 Dertouzos 提出。具体的定义如下:

A way to delegate processing of your data, without giving away access to it.

翻译成人话就是传统的加密方法和数据处理方法是互斥的,比如我需要计算两个数字的和(1 和 2),如果加密了之后,就无法对密文进行计算;如果想要进行计算,就必须知道这两个数字是 1 和 2。如果数据拥有方和计算方是同一方,那么知道 1 和 2 没啥问题;但如果数据拥有方和计算方并非同一方,并且数据拥有方还不想让计算方知道这两个数字是 1 和 2,这个时候就是同态加密发挥作用的时候了。

同态加密将数据的处理和数据本身解耦了:计算方拿到的是加密之后的密文,但是依然可以相加,相加之后把结果告诉数据拥有方,最终数据拥有方解密就可以知道最终的计算结果。

同态加密的这个特点使得云服务厂商非常在意,因为这一举解决了用户担心云服务厂商窃取数据的担心(因为加密了除了计算没法做其他事情),并且因为加密计算本身耗费更多计算资源,还可以变相提高营收。

总结一下:同态加密使得数据可以在加密的状态下进行计算,至于支持什么计算,如何进行计算,我们接下来继续讲。

同态加密步骤

  1. 在本地生成用来加密数据的 Key
  2. 用 Key 和 Encrypt 算法加密本地的数据,记为 EncData = Encrypt(Key, Data)
  3. 告诉云平台/区块链平台需要如何计算数据,记为函数 F()
  4. 云平台/区块链平台进行计算 Evaluate,即 Evaluate(F(), EncData) = Encrypt(Key, F(Data)),记为 ProEncData
  5. 平台将 ProEncData 发回给到我
  6. 我用密钥进行解密 Decrypt,得到 F(Data) = Decrypt(Key, ProEncData),也就是最终结果

在以上六个步骤中,至少有四个函数是必须的:

  1. 生成密钥的函数:本地执行,生成密钥
  2. Encrypt 函数:本地执行,加密数据,加密之后的数据不会暴露源数据的信息
  3. Evaluate 函数:用来执行用户给定的计算函数 F(),是唯一由云平台运行的函数
  4. Decrypt 函数:本地执行,解密数据

根据支持的 F() 的不同,同态加密分成了两类:

  1. Fully Homomorphic Encryption, FHE:这种方式下,任何 F() 都可以,只要这个算法能够被计算机实现即可。不过这个计算开销非常大,目前暂无实际应用。
  2. Somewhat Homomorphic Encryption, SWHE:这种方式下,只支持某些特定的F() (比如只支持加法/乘法,并且只能执行有限次数)。这个方案有比较大的限制,但也因此计算开销较小,已经可以在实际中使用
    1. 乘法:RSA, Elgamal
    2. 加法:Paillier

接下来我们会详细看看 Paillier 算法和 RSA 算法,对加法同态和乘法同态有更加深入的理解。

Paillier 算法

总共有如下几个步骤:

  1. 随机选择两个质数 p 和 q 满足 |p|=|q|=τ,这个条件保证了 p 和 q 的长度相等。
  2. 计算 N=pq 和 λ=lcm(p−1,q−1),注:lcm 表示最小公倍数
  3. 随机选择 g∈Z∗,N2,满足 gcd(L(gλmodN2),N)=1gcd(L(gλmodN2),N)=1,注:gcd 表示最大公约数;Z 表示整数,下标表示该整数集合里有多少个元素;L(x)=x−1NL(x)=x−1N
  4. 公钥为 (N,g)(N,g)
  5. 私钥为 λ

参考项目:
https://github.com/apple/swift-homomorphic-encryption
苹果公司表示,它正在使用同态加密技术进行实时来电者身份验证查询,用以支持来电者识别和垃圾电话拦截服务。这项技术允许苹果通过向服务器发送加密的查询,请求获取电话号码的相关信息,而服务器无需知道或存储电话号码。
苹果公司表示,典型的同态加密工作流可能是这样的:

  • 客户端加密敏感数据,并将结果发送给服务器。
  • 服务器在不了解任何解密内容的情况下,对收到的密文进行必要的计算,可能还会结合服务器自身的明文输入。
  • 服务器将计算后的密文响应发送给客户端。
  • 客户端对收到的响应进行解密。
    Swift 实现集成了 Brakerski-Fan-Vercauteren(BFV)同态加密方案,这一方案具备抵御量子计算攻击的能力。

https://github.com/homenc/HElib
IBM 提供的 HElib目前不再进行积极的开发,尽管还有一些未解决的问题,它现在处于“维护模式”,主要的工作是修复安全漏洞。

https://github.com/microsoft/SEAL
至于微软的 SEAL 库,自 2018 年以来也都没有与发布相关的新闻,尽管其 GitHub 代码库偶尔还会有一些更新。

项目地址:data61/MP-SPDZ: Versatile framework for multi-party computation (github.com)

安装

1)在ubuntu环境中,安装依赖包。

1
apt-get install automake build-essential git libboost-dev libboost-thread-dev libntl-dev libsodium-dev libssl-dev libtool m4 python3 texinfo yasm

2)使用git下载项目源码,注意不是二进制的release文件。

3)在项目目录中,编译代码。

1
make -j 8 tldr

4)试用并执行 the tutorial 教程,他是一个双方的、对恶意安全的教程。

1
2
3
4
5
6
7
8
9
10
11
12
13
➜  MP-SPDZ git:(master) ./compile.py tutorial
Default bit length: 64
Default security parameter: 40
Compiling file /home/zhuang/Downloads/MP-SPDZ/Programs/Source/tutorial.mpc
WARNING: Order of memory instructions not preserved, errors possible
Writing to /home/zhuang/Downloads/MP-SPDZ/Programs/Schedules/tutorial.sch
Writing to /home/zhuang/Downloads/MP-SPDZ/Programs/Bytecode/tutorial-0.bc
Program requires:
4 integer inputs from player 0
4 integer inputs from player 1
5420 integer bits
2474 integer triples
238 virtual machine rounds

hyperledger fabric 2.2 kubernetes

一、本地开发环境依赖

1
2
3
4
5
6
7
8
# Minikube 安装 v1.20.0
curl -Lo minikube https://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/releases/v1.20.0/minikube-darwin-amd64
chmod +x minikube
sudo mv minikube /usr/local/bin/
# Minikube start
minikube start --image-mirror-country cn \
--iso-url=https://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/iso/minikube-v1.20.0.iso \
--registry-mirror=https://xxxxx.mirror.aliyuncs.com
  • 安装 kubectl 工具
  • 安装 git
  • 安装 docker
  • 安装 hyperledger 相关命令列工具
1
2
3
4
5
6
# 执行以下指令下载 Hyperledger 命令列工具
curl -sSL http://raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap.sh | bash -s -- 2.2.0 1.5.0
# 或者
curl -sSL https://bit.ly/2ysbOFE | bash -s
# 设定环境变数至下载下来的 bin 目录下
export PATH=<path to download location>/bin:$PATH

以上脚本会在本地下载k8s部署需要的容器和可执行文件,云上的话需要准备的镜像如下:

1
2
3
4
centos:latest
hyperledger/fabric-orderer:2.2
hyperledger/fabric-peer:2.2.0
hyperledger/fabric-tools:2.2.0

用于测试的chaincode镜像,marbles是hyperledger官方给的一个sample,但是源码没有打镜像,这里其他人打的一个镜像,我们只是用来测试部署是否成功,之后会用我们开发的存证chaincode镜像替换

1
paragones/chaincode-marbles:1.0
1
2
3
4
# 创建一个名为 hyperledger 的 namespace
kubectl create namespace hyperledger
# 切换至 hyperledger namespace
kubectl config set-context --current --namespace=hyperledger

二、系统架构规划

2.1 节点规划

下图为本范例的部署架构,所有hyperledger 所需节点皆部署于 k8s 中的 hyperledger namespace 当中。架构中包含的节点如下

  • orderer0 : 排序节点0,用于排序区块
  • orderer1 : 排序节点1,用于排序区块
  • orderer2 : 排序节点2,用于排序区块
  • peer0-org1 : 组织1的Peer节点,用于区块的实际运算、背书以及记帐。
  • cli-org1-peer : 用于操纵组织1的Peer节点
  • peer0-org2 : 组织2的Peer节点,用于区块的实际运算、背书以及记帐。
  • cli-org2-peer : 用于操纵组织2的Peer节点

2.2 存储存放规划

节点 挂载路径 路径说明 PVC PV hostPath
orderer0 /var/hyperledger/orderer/ 存放凭证 orderer0-pvc ./fabric/orderer0
orderer0 /var/hyperledger/production 持久化资料 orderer0-persist-pvc ./fabric/orderer0persist
orderer1 /var/hyperledger/orderer/ 存放凭证 orderer1-pvc ./fabric/orderer1
orderer1 /var/hyperledger/production 持久化资料 orderer1-persist-pvc ./fabric/orderer1persist
orderer2 /var/hyperledger/orderer/ 存放凭证 orderer2-pvc ./fabric/orderer2
orderer2 /var/hyperledger/production 持久化资料 orderer2-persist-pvc ./fabric/orderer2persist
Org1-Peer /etc/hyperledger/fabric/ 存放凭证 peer0-org1-pvc ./fabric/peer0org1
Org1-Peer /var/hyperledger/production 持久化资料 peer0-org1-persist-pvc ./fabric/peer0org1persist
Org1-Peer-CLI /opt/gopath/src/github.com/ hyperledger/fabric/peer/crypto/ 存放凭证 peer0-org1-pvc ./fabric/peer0org1
Org2-Peer /etc/hyperledger/fabric/ 存放凭证 peer0-org2-pvc ./fabric/peer0org2
Org2-Peer /var/hyperledger/production 持久化资料 peer0-org2-persist-pvc ./fabric/peer0org2persist
Org2-Peer-CLI /opt/gopath/src/github.com/ hyperledger/fabric/peer/crypto/ 存放凭证 peer0-org1-pvc ./fabric/peer0org2

三、准备凭证

Hyperledger Fabric 于节点沟通时必须依赖凭证进行沟通,因此必须先签发凭证。在凭证的签发过程中可以使用两种方式签发凭证

  • cryptogen 命令
    cryptogen 为 Hyperledger Fabric 生成凭证的命令列工具,于 crypto-config.yaml 定义 Orderer 以及各组织的Peer的数量。
  • fabric-ca 服务
    Fabric CA 是一个为 Hyperledger Fabric 签发凭证的工具,通常每个组织会有自己的 Fabric CA,通過fabric-ca client 获得凭证后,就可以用这些凭证访问Peer。

在此范例中将以 cryptogen 命令列生成各节点所需凭证,以下为签发凭证的指令。可以查看 git repo 中的 crypto-config.yaml 为签发凭证设定文件,crypto-config则为签发结果

1
cryptogen generate --config=crypto-config.yaml --output ./crypto-config

(notice:练习中,需要再次生成新的凭证设定文件时,需要将./crypto-config文件夹删除后,再行运行上述命令。否则凭证设定文件不会被更新覆盖!)

四、准备创世区块

1
configtxgen -profile TwoOrgsOrdererGenesis -channelID devchan -outputBlock ./channel-artifacts/genesis.block

五、产生Channel 所需档案

1
2
3
4
5
6
# 产生Channel 所需档案
configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID "mychannel"
# 产生 Org1 使用的 channel 设定文件
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/org1Anchors.tx -channelID "mychannel" -asOrg org1MSP
# 产生 Org2 使用的 channel 设定文件
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/org2Anchors.tx -channelID "mychannel" -asOrg org2MSP

六、同步档案至PV中

在前述三、四、五章节中我们已经准备了以下内容

  • 各节点所需凭证
  • 创世区块
  • Channel 设定档

由于 Hyperledger 之 container 必须先将以上档案放置至正确位置后 container 才能正常启动。但本次安装不使用NFS 预先将档案填入,而是先启临时的 container 同步档案。
在本步骤我们将启动两个用于填充档案的 container

container 名称 说明
orderer-bastion 填充 orderer0-pvc,orderer1-pvc,orderer2-pvc 所需要的文档
peer-bastion 填充 peer0-org1-pvc,peer0-org2-pvc 所需要的文档

以下为同步文档的步骤

6.1 启动临时 container

1
kubectl create -f /deploy-hyperledger-fabric-on-k8s/file-populate-bastion/

这个指令将会产生 pv/pvc/orderer-bastion/peer-bastion 这些资源

6.2 同步 Orderer 所需文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 登录进入 orderer-bastion
kubectl exec -it ${orderer-bastion-pod-name} bash

# 安装 git 并 clone deploy-hyperledger-fabric-on-k8s repo
yum install git -y
git clone https://github.com/willzhuang/deploy-hyperledger-fabric-on-k8s.git

# 同步 orderer0 创世区块
cp deploy-hyperledger-fabric-on-k8s/channel-artifacts/genesis.block /orderer0-pvc/
# 同步 orderer0 凭证
cp -r deploy-hyperledger-fabric-on-k8s/crypto-config/ordererOrganizations/consortium/orderers/orderer0/* /orderer0-pvc/

# 同步 orderer1 创世区块
cp deploy-hyperledger-fabric-on-k8s/channel-artifacts/genesis.block /orderer1-pvc/
# 同步 orderer1 凭证
cp -r deploy-hyperledger-fabric-on-k8s/crypto-config/ordererOrganizations/consortium/orderers/orderer1/* /orderer1-pvc/

# 同步 orderer2 创世区块
cp deploy-hyperledger-fabric-on-k8s/channel-artifacts/genesis.block /orderer2-pvc/
# 同步 orderer2 凭证
cp -r deploy-hyperledger-fabric-on-k8s/crypto-config/ordererOrganizations/consortium/orderers/orderer2/* /orderer2-pvc/

6.3 同步 Peer 所需要的文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 登录进入 peer-bastion
kubectl exec -it ${peer-bastion-pod-name} bash

# 安装 git 並 clone deploy-hyperledger-fabric-on-k8s repo
yum install git -y
git clone https://github.com/willzhuang/deploy-hyperledger-fabric-on-k8s.git

# 同步 org1 peer0 所需之凭证
cp -r /deploy-hyperledger-fabric-on-k8s/crypto-config/peerOrganizations/org1/peers/peer0-org1/* peer0-org1-pvc/
# 同步 org1 peer0 cli 所需之凭证
cp -r /deploy-hyperledger-fabric-on-k8s/crypto-config/* /peer0-org1-pvc/
# 同步 org1 peer0 所需之 channel设定文档
cp /deploy-hyperledger-fabric-on-k8s/channel-artifacts/* peer0-org1-pvc/

# 同步 org2 peer0 所需之凭证
cp -r /deploy-hyperledger-fabric-on-k8s/crypto-config/peerOrganizations/org2/peers/peer0-org2/* peer0-org2-pvc/
# 同步 org2 peer0 cli 所需之凭证
cp -r /deploy-hyperledger-fabric-on-k8s/crypto-config/* /peer0-org2-pvc/
# 同步 org2 peer0 所需之 channel设定文档
cp /deploy-hyperledger-fabric-on-k8s/channel-artifacts/* peer0-org2-pvc/

七、启动 Orderer

1
2
# 启动 orderer cluster
kubectl create -f /deploy-hyperledger-fabric-on-k8s/orderer/

內含 orderer0,orderer1,orderer2 所需的 deployment 与 service 资源

八、启动 Peer

1
2
3
4
5
6
7
# 启动 org1 peer0 
kubectl create -f /deploy-hyperledger-fabric-on-k8s/org1/
# 內含 org1 peer0/cli 所需的 deployment,configmap,service 资源

# 启动 org2 peer0
kubectl create -f /deploy-hyperledger-fabric-on-k8s/org2/
# 內含 org2 peer0/cli 所需的 deployment,configmap,service 资源

九、创建channel

9.1 将 org1 peer0 加入 channel

1
2
# 登录进入 cli pod 
kubectl exec -it ${org1-peer0-cli-pod-name} sh
1
2
# 产生 channel 区块
peer channel create -o orderer0:7050 -c mychannel -f ./scripts/channel-artifacts/channel.tx --tls true --cafile $ORDERER_CA

运行成功后,log信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/opt/gopath/src/github.com/hyperledger/fabric/peer # peer channel create -o orderer0:7050 -c mychannel -f ./scripts/channel-artifacts/channel.tx -
-tls true --cafile $ORDERER_CA
2021-08-10 05:41:03.212 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-08-10 05:41:03.242 UTC [cli.common] readBlock -> INFO 002 Expect block, but got status: &{NOT_FOUND}
2021-08-10 05:41:03.246 UTC [channelCmd] InitCmdFactory -> INFO 003 Endorser and orderer connections initialized
2021-08-10 05:41:03.447 UTC [cli.common] readBlock -> INFO 004 Expect block, but got status: &{SERVICE_UNAVAILABLE}
2021-08-10 05:41:03.450 UTC [channelCmd] InitCmdFactory -> INFO 005 Endorser and orderer connections initialized
2021-08-10 05:41:03.651 UTC [cli.common] readBlock -> INFO 006 Expect block, but got status: &{SERVICE_UNAVAILABLE}
2021-08-10 05:41:03.654 UTC [channelCmd] InitCmdFactory -> INFO 007 Endorser and orderer connections initialized
2021-08-10 05:41:03.857 UTC [cli.common] readBlock -> INFO 008 Expect block, but got status: &{SERVICE_UNAVAILABLE}
2021-08-10 05:41:03.866 UTC [channelCmd] InitCmdFactory -> INFO 009 Endorser and orderer connections initialized
2021-08-10 05:41:04.068 UTC [cli.common] readBlock -> INFO 00a Expect block, but got status: &{SERVICE_UNAVAILABLE}
2021-08-10 05:41:04.070 UTC [channelCmd] InitCmdFactory -> INFO 00b Endorser and orderer connections initialized
2021-08-10 05:41:04.273 UTC [cli.common] readBlock -> INFO 00c Expect block, but got status: &{SERVICE_UNAVAILABLE}
2021-08-10 05:41:04.277 UTC [channelCmd] InitCmdFactory -> INFO 00d Endorser and orderer connections initialized
2021-08-10 05:41:04.480 UTC [cli.common] readBlock -> INFO 00e Received block: 0

1
2
# 加入 channel
peer channel join -b mychannel.block

运行成功后,log信息如下:

1
2
3
/opt/gopath/src/github.com/hyperledger/fabric/peer # peer channel join -b mychannel.block
2021-08-10 05:48:59.716 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-08-10 05:48:59.736 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel

1
2
# 查看是否在 channel 当中
peer channel list

9.2 將 org2 peer0 加入 channel

1
2
3
4
5
6
7
8
9
10
11
# 登录进入 cli pod 
kubectl exec -it pod ${org2-peer0-cli-pod-name} sh

# 取得 channel 区块
peer channel fetch 0 mychannel.block -c mychannel -o orderer0:7050 --tls --cafile $ORDERER_CA

# 加入 channel
peer channel join -b mychannel.block

# 查看是否在 channel 当中
peer channel list

运行成功后,log信息如下:

1
2
3
4
5
6
7
8
9
10
/opt/gopath/src/github.com/hyperledger/fabric/peer # peer channel fetch 0 mychannel.block -c mychannel -o orderer0:7050 --tls --cafile $ORDERER_CA
2021-08-10 06:05:04.550 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-08-10 06:05:04.553 UTC [cli.common] readBlock -> INFO 002 Received block: 0
/opt/gopath/src/github.com/hyperledger/fabric/peer # peer channel join -b mychannel.block
2021-08-10 06:05:16.493 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-08-10 06:05:16.513 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
/opt/gopath/src/github.com/hyperledger/fabric/peer # peer channel list
2021-08-10 06:05:24.222 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
Channels peers has joined:
mychannel

十、Fabric节点上安装外的Chaincode

10.1 安装chaincode
‘marbles’ 链码作为范例

打包org1

1
2
3
4
5
6
# 进入github的chaincode/packaging
# 将connection.json 打包成为 code.tar.gz
$ tar cfz code.tar.gz connection.json

#再將code.tar.gz metadata.json包成marbles-org1.tgz
$ tar cfz marbles-org1.tgz code.tar.gz metadata.json

将org1 tar文档安装到peer cli pod中

1
2
3
4
5
6
7
8
9
10
11
# 将marbles-org1.tgz放入peer pod
kubectl cp marbles-org1.tgz hyperledger/${cli-org1-name}:/opt/gopath/src/github.com/hyperledger/fabric/peer

# 登录进入${cli-org1-name} pod
kubectl exec -it ${cli-org1-name} -- /bin/bash

# 在peer-cli上安装chaincode
$ peer lifecycle chaincode install marbles-org1.tgz

# 查询链码,识别字符串
$ peer lifecycle chaincode queryinstalled

打包org2,如打包or1一样的步骤,请修改connection.json中的address

1
"address": "chaincode-marbles-org2.hyperledger:7052"

依照下列打包步骤

1
2
3
4
5
6
7
$ rm -f code.tar.gz
$ tar cfz code.tar.gz connection.json
$ tar cfz marbles-org2.tgz code.tar.gz metadata.json
$ peer lifecycle chaincode install marbles-org2.tgz

# 查询链码,识别字符串
$ peer lifecycle chaincode queryinstalled

至此,已完成外部链码设置。


10.2 部署”智能合约”

制作golang的alpine镜像文件

1
2
3
4
5
$ docker build -t chaincode/marbles:1.0 .

# 将文件推送至dockerhub
$ docker login
$ docker push chaincode/marbles:1.0

进入github中 chaincode\k8s ,找到org1-chaincode-deployment.yaml和org2-chaincode-deployment.yaml中的CHAINCODE_CCID

将yaml文件中的CHAINCODE_CCID更换成为对应的 chaincode 识别码

1
2
# 部署 chaincode 到aks上
$ kubectl create -f chaincode/k8s

完成部署。


10.3审核链码的安装

请在peer-cli-org1/peer-cli-org2 这2个pod中允许链码的安装,记得修改CHAINCODE_CCID
※peer-cli-org1 及 peer-cli-org2的CHAINCODE_CCID 需要对应到各自的chaincode识别码

1
2
$ peer lifecycle chaincode approveformyorg --channelID mychannel --name marbles --version 1.0 --init-required --package-id marbles:e001937433673b11673d660d142c722fc372905db87f88d2448eee42c9c63064 --sequence 1 -o orderer0:7050 --tls --cafile $ORDERER_CA --signature-policy "AND ('org1MSP.peer','org2MSP.peer')

检查所有org允许状态

1
2
$peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name marbles --version 1.0 --init-require
d --sequence 1 -o -orderer0:7050 --tls --cafile $ORDERER_CA --signature-policy "AND ('org1MSP.peer','org2MSP.peer')"

至此,2个peer-cli都审核完毕。

之后提交到channel 中

1
2
peer lifecycle chaincode commit -o orderer0:7050 --channelID mychannel --name marbles --version 1.0 --sequence 1 --init-required --tls true --cafile $ORDERER_CA --peerAddresses peer0-org1:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1/peers/peer0-org1/tls/ca.crt --peerAddresses peer0-org2:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2/peers/peer0-org2/tls/ca.crt --signature-policy "AND ('org1MSP.peer','org2MSP.peer')"


10.4测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 查询安装的链码
peer lifecycle chaincode queryinstalled
# 查询审核通过的链码
peer lifecycle chaincode queryapproved --channelID mychannel --name marbles
# 查询提交完成的链码
peer lifecycle chaincode querycommitted --channelID mychannel --name marbles
# 塞弹珠(第一次)
peer chaincode invoke -o orderer0:7050 --isInit --tls true --cafile $ORDERER_CA -C mychannel -n marbles \
--peerAddresses peer0-org1:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1/peers/peer0-org1/tls/ca.crt \
--peerAddresses peer0-org2:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2/peers/peer0-org2/tls/ca.crt \
-c '{"Args":["initMarble","marble1","blue","35","tom"]}' --waitForEvent
# 塞弹珠
peer chaincode invoke -o orderer0:7050 --tls true --cafile $ORDERER_CA -C mychannel -n marbles \
--peerAddresses peer0-org1:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1/peers/peer0-org1/tls/ca.crt \
--peerAddresses peer0-org2:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2/peers/peer0-org2/tls/ca.crt \
-c '{"Args":["initMarble","marble5","red","50","tom"]}' --waitForEvent
# 查询弹珠
peer chaincode query -C mychannel -n marbles -c '{"Args":["readMarble","marble5"]}'


开发Client Application

目前hyperledger不对外,请使用kubectl port-forward的方式连进去。
指令:

1
kubectl port-forward ${pord-id} 7050:7050

参考 fabric-samples 中typescript所撰写的范例 ※另有java, go 语言的范例!!

以下为typerscript 范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

async function main() {
try {
const ccpPath = path.resolve(__dirname, '..', 'connection.json');

const fileExists = fs.existsSync(ccpPath);
if (!fileExists) {
throw new Error('no such file or directory: ${ccpPath}');
}
const contents = fs.readFileSync(ccpPath, 'utf8');
console.log(contents);

const connectionProfile = JSON.parse(contents);
const gateway = new Gateway();
const wallet = await buildWallet(walletPath);

const identity: X509Identity = {
credentials: {
//crypto-config\peerOrganizations\org1\users\Admin@org1\msp\signcerts\Admin@org1-cert.pem
certificate: '-----BEGIN CERTIFICATE-----\nMIICBjCCAaygAwIBAgIRAKeXh5QGRlhFCf31amakNiowCgYIKoZIzj0EAwIwWzEL
//crypto-config\peerOrganizations\org1\users\Admin@org1\msp\keystore
privateKey: '-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg9tkGBGl8aIWYbN/i\nqKjl5dK3D3qXx6ltn3YrlH4NFPehRANCAATMJIf0mY3FQDysZOevzbsBwqttfVuW\nwoIFV9Z0TwBEXXAQ0HPd9u77zV4my0onty3rJnWKF2kuhIn5PUzz61zk\n-----END PRIVATE KEY-----\n',
},
mspId: org1UserId,
type: 'X.509',
};
await wallet.put(org1UserId, identity);


const gatewayOpts: GatewayOptions = {
wallet,
identity: org1UserId,
discovery: { enabled: false, asLocalhost: false }, // using asLocalhost as this gateway is using a fabric network deployed locally
};

await gateway.connect(connectionProfile, gatewayOpts);

const network = await gateway.getNetwork('mychannel');

const contract = network.getContract('marbles');
let result = await contract.evaluateTransaction('readMarble', 'marble2');
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
} catch (error) {
console.error(`******** FAILED to run the application: ${error}`);
}
}

main();

上述为app.ts,此app.ts会读取connection.json档,此档用于定义peer url以及peer的tls凭证路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{
"name": "Network",
"version": "1.1",
"channels": {
"mychannel": {
"peers": [
"peer0-org1",
"peer0-org2"
]
}
},
"organizations": {
"Org1": {
"mspid": "org1MSP",
"peers": [
"peer0-org1"
]
},
"Org2": {
"mspid": "org2MSP",
"peers": [
"peer0-org2"
]
}
},
"peers": {
"peer0-org1": {
"url": "grpcs://peer0-org1:7051",
"grpcOptions": {
"ssl-target-name-override": "peer0-org1"
},
"tlsCACerts": {
"path": "crypto-config\peerOrganizations\org1\tlsca\tlsca.org1-cert.pem"
}
},
"peer0-org2": {
"url": "grpcs://peer0-org2:7051",
"grpcOptions": {
"ssl-target-name-override": "peer0-org2"
},
"tlsCACerts": {
"path": "crypto-config\peerOrganizations\org2\tlsca\tlsca.org2-cert.pem"
}
}
}
}

  • application连到peer的时候必须要有tls 凭证去验证peer service是否安全及正确。
  • 当交易的时候需要提供该使用者(user or admin)的交易凭证(x509 cert +private key)

路径对应如下:
tls CA Cert: crypto-config\peerOrganizations\org1\tlsca\tlsca.org1-cert.pem
X509 certificate: crypto-config\peerOrganizations\org1\users\Admin@org1\msp\signcerts\Admin@org1-cert.pem
X509 privateKey: crypto-config\peerOrganizations\org1\users\Admin@org1\msp\keystore\priv_sk
[color=#d85887]

成功收到资料如图


附录、参考连结

  1. Hyperledger 参考链接
  1. Kubenetes 参考链接
  1. NFS 架构参考链接
  1. 部署 fabric 和 CA 与 Kubenetes 之上

    Deploy Hyperledger Fabric network on Kubernetes

EYBlockchain/starlight: solidity –> zApp transpiler (github.com)

​ zApps 是零知识应用程序。 它们就像 dApp(去中心化应用程序),但具有隐私性。 zApp 编写起来很棘手,但 Solidity 合约编写起来很可爱。 那么为什么不尝试用 Solidity 编写一个 zApp 呢?

starlight帮助开发人员做到这一点:

  • 编写 Solidity 合约
  • 在合约中添加一些新的隐私装饰器(以获得“Zolidity”合约)
  • 运行 zappify
  • 作为回报,获得一个完全可用的 zApp
  • Solidity 合约 –> Zolidity 合约 –> zappify –> zApp

此转译器的主要目标是使开发人员能够快速为 zApps 起草框架。