Fabric

fabric简介

Hyperledger Fabric 是一个开源的企业级许可分布式账本技术(Distributed Ledger Technology,DLT)平台,专为在企业环境中使用而设计,与其他流行的分布式账本或区块链平台相比,它有一些主要的区别。

一个主要区别是 Hyperledger 是在 Linux 基金会下建立的,该基金会本身在开放式治理的模式下培育开源项目的历史悠久且非常成功,发展了强大的可持续社区和繁荣的生态系统。Hyperledger 由多元化的技术指导委员会进行管理,Hyperledger Fabric 项目由多个组织的不同的维护人员管理。从第一次提交以来,它的开发社区已经发展到超过35个组织和近200个开发人员。

Fabric 具有高度模块化和可配置的架构,可为各行各业的业务提供创新性、多样性和优化,其中包括银行、金融、保险、医疗保健、人力资源、供应链甚至数字音乐分发。

Fabric 是第一个支持通用编程语言编写智能合约(如 Java、Go 和 Node.js)的分布式账本平台,不受限于特定领域语言(Domain-Specific Languages,DSL)。这意味着大多数企业已经拥有开发智能合约所需的技能,并且不需要额外的培训来学习新的语言或特定领域语言。

Fabric 平台也是许可的,这意味着它与公共非许可网络不同,参与者彼此了解而不是匿名的或完全不信任的。也就是说,尽管参与者可能不会完全信任彼此(例如,同行业中的竞争对手),但网络可以在一个治理模式下运行,这个治理模式是建立在参与者之间确实存在的信任之上的,如处理纠纷的法律协议或框架。

该平台最重要的区别之一是它支持可插拔的共识协议,使得平台能够更有效地进行定制,以适应特定的业务场景和信任模型。例如,当部署在单个企业内或由可信任的权威机构管理时,完全拜占庭容错的共识可能是不必要的,并且大大降低了性能和吞吐量。在这种的情况下,崩溃容错(Crash Fault-Tolerant,CFT)共识协议可能就够了,而在去中心化的场景中,可能需要更传统的拜占庭容错(Byzantine Fault Tolerant,BFT)共识协议。

Fabric 可以利用不需要原生加密货币的共识协议来激励昂贵的挖矿或推动智能合约执行。不使用加密货币会降低系统的风险,并且没有挖矿操作意味着可以使用与任何其他分布式系统大致相同的运营成本来部署平台。

这些差异化设计特性的结合使 Fabric 成为当今交易处理和交易确认延迟方面性能较好的平台之一,并且它实现了交易的隐私和保密以及智能合约(Fabric 称之为“链码”)。

fabric入门

1.安装fabric

1
2
3
4
5
mkdir -p $HOME/go/src/github.com/<your_github_userid>
cd $HOME/go/src/github.com/<your_github_userid>
# 下载安装脚本
curl -sSL https://bit.ly/2ysbOFE | bash -s -- 2.2.0 1.4.7 # -- <fabric_version> <fabric-ca_version>
export PATH=fabric-samples/bin:$PATH

2.启动fabric网路

1
2
3
4
5
6
7
cd fabric-samples/test-network
# 先清除以往启动留下的容器和产物
./network.sh down
# 此命令会创建一个由两个peer节点和一个排序节点组成的Fabric网络
./network.sh up
# 您应该看到由network.sh脚本创建的三个节点
docker ps -a

如果命令执行成功,您将看到下列结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
⠿ Network fabric_test Created                                                                                                                                                                                                                                                                                                                     0.1s
⠿ Volume "docker_orderer.example.com"     Created                                                                                                                                                                                                                                                                                                                     0.0s
⠿ Volume "docker_peer0.org1.example.com"  Created                                                                                                                                                                                                                                                                                                                     0.0s
⠿ Volume "docker_peer0.org2.example.com"  Created                                                                                                                                                                                                                                                                                                                     0.0s
⠿ Container peer0.org1.example.com        Started                                                                                                                                                                                                                                                                                                                     3.2s
⠿ Container peer0.org2.example.com        Started                                                                                                                                                                                                                                                                                                                     3.2s
⠿ Container orderer.example.com           Started                                                                                                                                                                                                                                                                                                                     2.7s
⠿ Container cli                           Started
CONTAINER ID   IMAGE                               COMMAND             CREATED          STATUS          PORTS                                                      NAMES
43bbf5e6cb12   hyperledger/fabric-tools:latest     "/bin/bash"         24 seconds ago   Up 20 seconds                                                              cli
2a6f0ff8686e   hyperledger/fabric-orderer:latest   "orderer"           24 seconds ago   Up 21 seconds   0.0.0.0:7050->7050/tcp, 0.0.0.0:9443->9443/tcp             orderer.example.com
34b1505dcea9   hyperledger/fabric-peer:latest      "peer node start"   24 seconds ago   Up 21 seconds   0.0.0.0:7051->7051/tcp, 0.0.0.0:9444->9444/tcp             peer0.org1.example.com
f050d96a62c1   hyperledger/fabric-peer:latest      "peer node start"   24 seconds ago   Up 21 seconds   0.0.0.0:9051->9051/tcp, 7051/tcp, 0.0.0.0:9445->9445/tcp   peer0.org2.example.com

与Fabric网络互动的每个节点和用户都必须属于一个网络成员的组织。 Fabric网络成员的所有组织通常称为联盟(consortium)。 测试网络有两个联盟成员,Org1和Org2。 该网络还包括一个维护网络排序服务的排序组织。

Peer 节点 是任何Fabric网络的基本组件。 对等节点存储区块链账本并在进行交易之前对其进行验证。 同行运行包含业务用于管理区块链账本的智能合约上的业务逻辑。

网络中的每个对等方都必须属于该联盟的成员。 在测试网络里,每个组织各自运营一个对等节点, peer0.org1.example.compeer0.org2.example.com.

每个Fabric网络还包括一个排序服务。 虽然对等节点验证交易并将交易块添加到区块链账本,他们不决定交易顺序或包含他们进入新的区块。 在分布式网络上,对等点可能运行得很远彼此之间没有什么共同点,并且对何时创建事务没有共同的看法。 在交易顺序上达成共识是一个代价高昂的过程,为同伴增加开销。

排序服务允许对等节点专注于验证交易并将它们提交到账本。 排序节点从客户那里收到认可的交易后,他们就交易顺序达成共识,然后添加区块。 这些区块之后被分配给添加这些区块到账本的对等节点。 排序节点还可以操作定义Fabric网络的功能的系统通道,例如如何制作块以及节点可以使用的Fabric版本。 系统通道定义了哪个组织是该联盟的成员。

该示例网络使用一个单节点Raft排序服务,该服务由排序组织运行。 您可以看到在您机器上正在运行的排序节点orderer.example.com。 虽然测试网络仅使用单节点排序服务,一个真实的网络将有多个排序节点,由一个或多个多个排序者组织操作。 不同的排序节点将使用Raft共识算法达成跨交易顺序的共识网络。

3.创建通道

现在我们的机器上正在运行对等节点和排序节点, 我们可以使用脚本创建用于在Org1和Org2之间进行交易的Fabric通道。 通道是特定网络成员之间的专用通信层。通道只能由被邀请加入通道的组织使用,并且对网络的其他成员不可见。 每个通道都有一个单独的区块链账本。被邀请的组织“加入”他们的对等节点来存储其通道账本并验证交易。

您可以使用network.sh脚本在Org1和Org2之间创建通道并加入他们的对等节点。 运行以下命令以创建一个默认名称为“ mychannel”的通道:

1
./network.sh createChannel

如果命令成功执行,您将看到以下消息打印在您的日志:

1
========= Channel successfully joined ===========

4.启动链码

创建通道后,您可以开始使用智能合约与通道账本交互。 智能合约包含管理区块链账本上资产的业务逻辑。 由成员运行的应用程序网络可以在账本上调用智能合约创建,更改和转让这些资产。 应用程序还通过智能合约查询,以在分类帐上读取数据。

为确保交易有效,使用智能合约创建的交易通常需要由多个组织签名才能提交到通道账本。 多个签名是Fabric信任模型不可或缺的一部分。 一项交易需要多次背书,以防止一个通道上的单一组织使用通道不同意的业务逻辑篡改其对等节点的分类账本。 要签署交易,每个组织都需要调用并在其对等节点上执行智能合约,然后签署交易的输出。 如果输出是一致的并且已经有足够的组织签名,则可以将交易提交到账本。 该政策被称为背书政策,指定需要执行智能交易的通道上的已设置组织合同,针对每个链码设置为链码定义的一部分。

在Fabric中,智能合约作为链码以软件包的形式部署在网络上。 链码安装在组织的对等节点上,然后部署到某个通道,然后可以在该通道中用于认可交易和区块链账本交互。 在将链码部署到通道前,该频道的成员需要就链码定义达成共识,建立链码治理。 何时达到要求数量的组织同意后,链码定义可以提交给通道,并且可以使用链码了。

使用network.sh创建频道后,您可以使用以下命令在通道上启动链码:

1
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go

deployCC子命令将在peer0.org1.example.compeer0.org2.example.com上安装 asset-transfer (basic) 链码。 然后在使用通道标志(或mychannel如果未指定通道)的通道上部署指定的通道的链码。 如果您第一次部署一套链码,脚本将安装链码的依赖项。默认情况下,脚本安装Go版本的 asset-transfer (basic) 链码。 但是您可以使用语言便签 -l,用于安装 Java 或 javascript 版本的链码。 您可以在 fabric-samples 目录的 asset-transfer-basic 文件夹中找到 asset-transfer (basic) 链码。 此目录包含作为案例和用来突显 Fabric 特征的样本链码。

5.**与网络交互**

在您启用测试网络后,可以使用peer CLI与您的网络进行交互。 peer CLI允许您调用已部署的智能合约,更新通道,或安装和部署新的智能合约。

确保您正在从test-network目录进行操作。 如果你按照说明安装示例,二进制文件和Docker映像, 您可以在fabric-samples代码库的bin文件夹中找到peer二进制文件。 使用以下命令将这些二进制文件添加到您的CLI路径:

1
export PATH=${PWD}/../bin:$PATH

您还需要将fabric-samples代码库中的FABRIC_CFG_PATH设置为指向其中的core.yaml文件:

1
export FABRIC_CFG_PATH=$PWD/../config/

现在,您可以设置环境变量,以允许您作为Org1操作peer CLI:

1
2
3
4
5
6
7
# Environment variables for Org1

export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051

CORE_PEER_TLS_ROOTCERT_FILECORE_PEER_MSPCONFIGPATH环境变量指向Org1的organizations文件夹中的的加密材料。 如果您使用 ./network.sh deployCC -ccl go 安装和启动 asset-transfer (basic) 链码,您可以调用链码(Go)的 InitLedger 方法来赋予一些账本上的初始资产(如果使用 typescript 或者 javascript,例如 ./network.sh deployCC -l javascript,你会调用相关链码的 initLedger 功能)。 运行以下命令用一些资产来初始化账本:

1
2
3
4
5
6
7
8
9
10
11
peer chaincode invoke -o localhost:7050 \
	--ordererTLSHostnameOverride orderer.example.com \
	--tls \
	--cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
	-C mychannel \
	-n basic \
	--peerAddresses localhost:7051 \
	--tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
	--peerAddresses localhost:9051 \
	--tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
	-c '{"function":"InitLedger","Args":[]}'

如果命令成功,您将观察到类似以下的输出:

1
-> INFO 001 Chaincode invoke successful. result: status:200

现在你可以用你的 CLI 工具来查询账本。运行以下指令来获取添加到通道账本的资产列表:

1
peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'

如果成功,您将看到以下输出:

1
2
3
4
5
6
7
8
[
  {"ID": "asset1", "color": "blue", "size": 5, "owner": "Tomoko", "appraisedValue": 300},
  {"ID": "asset2", "color": "red", "size": 5, "owner": "Brad", "appraisedValue": 400},
  {"ID": "asset3", "color": "green", "size": 10, "owner": "Jin Soo", "appraisedValue": 500},
  {"ID": "asset4", "color": "yellow", "size": 10, "owner": "Max", "appraisedValue": 600},
  {"ID": "asset5", "color": "black", "size": 15, "owner": "Adriana", "appraisedValue": 700},
  {"ID": "asset6", "color": "white", "size": 15, "owner": "Michel", "appraisedValue": 800}
]

当一个网络成员希望在账本上转一些或者改变一些资产,链码会被调用。使用以下的指令来通过调用 asset-transfer (basic) 链码改变账本上的资产所有者:

1
2
3
4
5
6
7
8
9
10
11
12
peer chaincode invoke \
	-o localhost:7050 \
	--ordererTLSHostnameOverride orderer.example.com \
	--tls \
	--cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
	-C mychannel \
	-n basic \
	--peerAddresses localhost:7051 \
	--tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
	--peerAddresses localhost:9051 \
	--tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
	-c '{"function":"TransferAsset","Args":["asset6","Christopher"]}'

如果命令成功,您应该看到以下响应:

1
[chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200

因为 asset-transfer (basic) 链码的背书策略需要交易同时被 Org1 和 Org2 签名,链码调用指令需要使用 --peerAddresses 标签来指向 peer0.org1.example.com 和 peer0.org2.example.com。因为网络的 TLS 被开启,指令也需要用 --tlsRootCertFiles 标签指向每个 peer 节点的 TLS 证书。

调用链码之后,我们可以使用另一个查询来查看调用如何改变了区块链账本的资产。因为我们已经查询了 Org1 的 peer,我们可以把这个查询链码的机会通过 Org2 的 peer 来运行。设置以下的环境变量来操作 Org2:

1
2
3
4
5
6
7
# Environment variables for Org2

export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051

你可以查询运行在 peer0.org2.example.com asset-transfer (basic) 链码:

1
peer chaincode query -C mychannel -n basic -c '{"Args":["ReadAsset","asset6"]}'

结果显示 "asset6" 转给了 Christopher:

1
{"ID":"asset6","color":"white","size":15,"owner":"Christopher","appraisedValue":800}