HyperLedger Fabric的协议规范
时间:2023-04-24 20:37:00
协议规范
前言
本文件是区块链行业的协议规范。它不会详细解释实现细节,而是描述系统与应用程序之间的界面和关系。
目标读者
本规范的目标读者包括:
- 符合这一标准的区块链制造商希望实现
- 想扩展 fabric 工具开发者的功能
- 利用区块链技术丰富其应用开发者
作者
以下作者编写了这个分类: Binh Q Nguyen,Elli Androulaki, Angelo De Caro, Sheehan Anderson, Manish Sethi, ThorstenKramp, Alessandro Sorniotti, Marko Vukolic, Florian Simon Schubert, Jason KYellick, Konstantinos Christidis, Srinivasan Muralidharan, Anna D Derbakova,Dulce Ponceleon, David Kravitz, Diego Masini.
评审
以下评审员对本文档进行了评审: Frank Lu, JohnWolpert, Bishop Brock, Nitin Gaur, Sharon Weed, Konrad Pabjan.
致谢
下面这些贡献者对这份规范提供了技术支持: Gennaro Cuomo,Joseph A Latone, Christian Cachin
目录
1. 介绍
- 1.1 什么是 fabric ?
- 1.2 为什么是 fabric ?
- 1.3 术语
2. Fabric
- 2.1 架构
- 2.1.1 Membership 服务
- 2.1.2 Blockchain 服务
- 2.1.3 Chaincode 服务
- 2.1.4 事件
- 2.1.5 应用程序接口
- 2.1.6 命令行界面
- 2.2 拓扑
- 2.2.1 单验证 Peer
- 2.2.2 多验证 Peers
- 2.2.3 多链
3. 协议
- 3.1 消息
- 3.1.1 发现消息
- 3.1.2 交易消息
- 3.1.2.1 交易数据结构
- 3.1.2.2 交易规范
- 3.1.2.3 交易部署
- 3.1.2.4 交易调用
- 3.1.2.5 交易查询
- 3.1.3 同步消息
- 3.1.4 共识消息
- 3.2 总账
- 3.2.1 区块链
- 3.2.1.1 块
- 3.2.1.2 块 Hashing
- 3.2.1.3 非散列数据(NonHashData)
- 3.2.1.4 交易
- 3.2.2 世界状态(World State)
- 3.2.2.1 世界状态的 Hashing
- 3.2.2.1.1 Bucket-tree
- 3.3 Chaincode
- 3.3.1 Virtual Machine 实例化
- 3.3.2 Chaincode 协议
- 3.3.2.1 Chaincode 部署
- 3.3.2.2 Chaincode 调用
- 3.3.2.3 Chaincode 查询
- 3.3.2.4 Chaincode 状态
- 3.4 可插拔的共识框架
- 3.4.1 共识者接口
- 3.4.2 共识程序接口
- 3.4.3 Inquirer 接口
- 3.4.4 Communicator 接口
- 3.4.5 SecurityUtils 接口
- 3.4.6 LedgerStack 接口
- 3.4.7 Executor 接口
- 3.4.7.1 开始批量交易
- 3.4.7.2 执行交易
- 3.4.7.3 提交回滚交易
- 3.4.8 Ledger 接口
- 3.4.8.1 ReadOnlyLedger 接口 3.4.8.2 UtilLedger 接口
- 3.4.8.3 WritableLedger 接口
- 3.4.9 RemoteLedgers 接口
- 3.4.10 Controller 包
- 3.4.11 Helper 包
- 3.5 事件
- 3.5.1 事件流
- 3.5.2 事件结构
- 3.5.3 事件适配器
4. 安全
-
- 安全
- 4.1 商业安全需求
- 4.2 使用成员管理的用户隐私
- 4.2.1 用户/客户端注册过程
- 4.2.2 过期和废止证书
- 4.3 基础设施层面提供的交易安全
- 4.3.1 交易的安全生命周期
- 4.3.2 交易保密性
- 4.3.2.1 针对用户的保密
- 4.3.2.2 针对验证器的保密
- 4.3.3 防重放攻击
- 4.4 应用的访问控制功能
- 4.4.1 调用访问控制
- 4.4.2 读访问控制
- 4.5 在线钱包服务
- 4.6 网络安全(TLS)
- 4.7 当前版本的限制
- 4.7.1 简化客户端
- 4.7.2 简化交易保密
5. 拜占庭共识
- 5.1 概览
- 5.2 Core PBFT
6. 应用编程接口
- 6.1 REST 服务
- 6.2 REST API
- 6.3 CLI
7. 应用模型
- 7.1 应用组成
- 7.2 应用样例
8. 未来发展方向
- 8.1 企业集成
- 8.2 性能与可扩展性
- 8.3 附加的共识插件
- 8.4 附加的语言
9. References
1. 介绍
这份文档规范了适用于工业界的区块链的概念,架构和协议。
1.1 什么是 fabric?
fabric 是在系统中数字事件,交易调用,不同参与者共享的总账。总账只能通过共识的参与者来更新,而且一旦被记录,信息永远不能被修改。每一个记录的事件都可以根据参与者的协议进行加密验证。
交易是安全的,私有的并且可信的。每个参与者通过向网络membership服务证明自己的身份来访问系统。交易是通过发放给各个的参与者,不可连接的,提供在网络上完全匿名的证书来生成的。交易内容通过复杂的密钥加密来保证只有参与者才能看到,确保业务交易私密性。
总账可以按照规定规则来审计全部或部分总账分录。在与参与者合作中,审计员可以通过基于时间的证书来获得总账的查看,连接交易来提供实际的资产操作。
fabric 是区块链技术的一种实现,比特币是可以在fabric上构建的一种简单应用。它通过模块化的架构来允许组件的“插入-运行”来实现这份协议规范。它具有强大的容器技术来支持任何主流的语言来开发智能合约。利用熟悉的和被证明的技术是fabric的座右铭。
1.2 为什么是 fabric?
早期的区块链技术提供一个目的集合,但是通常对具体的工业应用支持的不是很好。为了满足现代市场的需求,fabric 是基于工业关注点针对特定行业的多种多样的需求来设计的,并引入了这个领域内的开拓者的经验,如扩展性。fabric 为权限网络,隐私,和多个区块链网络的私密信息提供一种新的方法。
1.3 术语
以下术语在此规范的有限范围内定义,以帮助读者清楚准确的了解这里所描述的概念。
交易(Transaction) 是区块链上执行功能的一个请求。功能是使用**链码(Chaincode)**来实现的。
交易者(Transactor) 是向客户端应用这样发出交易的实体。
总账(Ledger) 是一系列包含交易和当前**世界状态(World State)**的加密的链接块。
世界状态(World State) 是包含交易执行结果的变量集合。
链码(Chaincode) 是作为交易的一部分保存在总账上的应用级的代码(如智能合约)。链码运行的交易可能会改变世界状态。
验证Peer(ValidatingPeer) 是网络中负责达成共识,验证交易并维护总账的一个计算节点。
非验证Peer(Non-validatingPeer) 是网络上作为代理把交易员连接到附近验证节点的计算节点。非验证Peer只验证交易但不执行它们。它还承载事件流服务和REST服务。
带有权限的总账(PermissionedLedger) 是一个由每个实体或节点都是网络成员所组成的区块链网络。匿名节点是不允许连接的。
隐私(Privacy) 是链上的交易者需要隐瞒自己在网络上身份。虽然网络的成员可以查看交易,但是交易在没有得到特殊的权限前不能连接到交易者。
保密(Confidentiality) 是交易的内容不能被非利益相关者访问到的功能。
可审计性(Auditability) 作为商业用途的区块链需要遵守法规,很容易让监管机构审计交易记录。所以区块链是必须的。
2. Fabric
fabric是由下面这个小节所描述的核心组件所组成的。
2.1 架构
这个架构参考关注在三个类别中:会员(Membership),区块链(Blockchan)和链码(chaincode)。这些类别是逻辑结构,而不是物理上的把不同的组件分割到独立的进程,地址空间,(虚拟)机器中。
2.1.1 成员服务
成员服务为网络提供身份管理,隐私,保密和可审计性的服务。在一个不带权限的区块链中,参与者是不需要被授权的,且所有的节点都可以同样的提交交易并把它们汇集到可接受的块中,既:它们没有角色的区分。成员服务通过公钥基础设施(Public KeyInfrastructure (PKI))和去中心化的/共识技术使得不带权限的区块链变成带权限的区块链。在后者中,通过实体注册来获得长时间的,可能根据实体类型生成的身份凭证(登记证书enrollmentcertificates)。在用户使用过程中,这样的证书允许交易证书颁发机构(TransactionCertificate Authority (TCA))颁发匿名证书。这样的证书,如交易证书,被用来对提交交易授权。交易证书存储在区块链中,并对审计集群授权,否则交易是不可链接的。
2.1.2 区块链服务
区块链服务通过 HTTP/2 上的点对点(peer-to-peer)协议来管理分布式总账。为了提供最高效的哈希算法来维护世界状态的复制,数据结构进行了高度的优化。每个部署中可以插入和配置不同的共识算法(PBFT, Raft, PoW,PoS)。
2.1.3 链码服务
链码服务提供一个安全的,轻量的沙箱在验证节点上执行链码。环境是一个“锁定的”且安全的包含签过名的安全操作系统镜像和链码语言,Go,Java 和 Node.js 的运行时和 SDK 层。可以根据需要来启用其他语言。
2.1.4 事件
验证 peers 和链码可以向在网络上监听并采取行动的应用发送事件。这是一些预定义好的事件集合,链码可以生成客户化的事件。事件会被一个或多个事件适配器消费。之后适配器可能会把事件投递到其他设备,如 Web hooks 或 Kafka。
2.1.5 应用编程接口(API)
fabric的主要接口是 REST API,并通过 Swagger 2.0 来改变。API 允许注册用户,区块链查询和发布交易。链码与执行交易的堆间的交互和交易的结果查询会由 API 集合来规范。
2.1.6 命令行界面(CLI)
CLI包含REST API的一个子集使得开发者能更快的测试链码或查询交易状态。CLI 是通过 Go 语言来实现,并可在多种操作系统上操作。
2.2 拓扑
fabric 的一个部署是由成员服务,多个验证 peers、非验证 peers 和一个或多个应用所组成一个链。也可以有多个链,各个链具有不同的操作参数和安全要求。
2.2.1 单验证Peer
功能上讲,一个非验证 peer 是验证 peer 的子集;非验证 peer 上的功能都可以在验证 peer 上启用,所以在最简单的网络上只有一个验证peer组成。这个配置通常使用在开发环境:单个验证 peer 在编辑-编译-调试周期中被启动。
单个验证 peer 不需要共识,默认情况下使用noops插件来处理接收到的交易。这使得在开发中,开发人员能立即收到返回。
2.2.2 多验证 Peer
生产或测试网络需要有多个验证和非验证 peers 组成。非验证 peer 可以为验证 peer 分担像 API 请求处理或事件处理这样的压力。
网状网络(每个验证peer需要和其它验证peer都相连)中的验证 peer 来传播信息。一个非验证 peer 连接到附近的,允许它连接的验证 peer。当应用可能直接连接到验证 peer 时,非验证 peer 是可选的。
2.2.3 多链
验证和非验证 peer 的各个网络组成一个链。可以根据不同的需求创建不同的链,就像根据不同的目的创建不同的 Web 站点。
3. 协议
fabric的点对点(peer-to-peer)通信是建立在允许双向的基于流的消息gRPC上的。它使用Protocol Buffers来序列化peer之间传输的数据结构。Protocol buffers是语言无关,平台无关并具有可扩展机制来序列化结构化的数据的技术。数据结构,消息和服务是使用 proto3 language注释来描述的。
3.1 消息
消息在节点之间通过Messageproto 结构封装来传递的,可以分为 4 种类型:发现(Discovery), 交易(Transaction), 同步(Synchronization)和共识(Consensus)。每种类型在payload中定义了多种子类型。
messageMessage {
enum Type {
UNDEFINED = 0;
DISC_HELLO = 1;
DISC_DISCONNECT = 2;
DISC_GET_PEERS = 3;
DISC_PEERS = 4;
DISC_NEWMSG = 5;
CHAIN_STATUS = 6;
CHAIN_TRANSACTION = 7;
CHAIN_GET_TRANSACTIONS = 8;
CHAIN_QUERY = 9;
SYNC_GET_BLOCKS = 11;
SYNC_BLOCKS = 12;
SYNC_BLOCK_ADDED = 13;
SYNC_STATE_GET_SNAPSHOT = 14;
SYNC_STATE_SNAPSHOT = 15;
SYNC_STATE_GET_DELTAS = 16;
SYNC_STATE_DELTAS = 17;
RESPONSE = 20;
CONSENSUS = 21;
}
Type type = 1;
bytes payload = 2;
google.protobuf.Timestamp timestamp = 3;
}
payload是由不同的消息类型所包含的不同的像Transaction或Response这样的对象的不透明的字节数组。例如:type为CHAIN_TRANSACTION那么payload就是一个Transaction对象。
3.1.1 发现消息
在启动时,如果CORE_PEER_DISCOVERY_ROOTNODE被指定,那么 peer 就会运行发现协议。CORE_PEER_DISCOVERY_ROOTNODE是网络(任意peer)中扮演用来发现所有 peer 的起点角色的另一个 peer 的 IP 地址。协议序列以payload是一个包含:
messageHelloMessage {
PeerEndpoint peerEndpoint = 1;
uint64 blockNumber = 2;
}
messagePeerEndpoint {
PeerID ID = 1;
string address = 2;
enum Type {
UNDEFINED = 0;
VALIDATOR = 1;
NON_VALIDATOR = 2;
}
Type type = 3;
bytes pkiID = 4;
}
messagePeerID {
string name = 1;
}
这样的端点的HelloMessage对象的DISC_HELLO消息开始的。
域的定义:
- PeerID 是在启动时或配置文件中定义的 peer 的任意名字
- PeerEndpoint 描述了端点和它是验证还是非验证 peer
- pkiID 是 peer 的加密ID
- address 以ip:port这样的格式表示的 peer 的主机名或IP和端口
- blockNumber 是 peer 的区块链的当前的高度
如果收到的DISC_HELLO 消息的块的高度比当前 peer 的块的高度高,那么它马上初始化同步协议来追上当前的网络。
DISC_HELLO之后,peer 会周期性的发送DISC_GET_PEERS来发现任意想要加入网络的 peer。收到DISC_GET_PEERS后,peer 会发送payload 包含PeerEndpoint的数组的DISC_PEERS作为响应。这是不会使用其它的发现消息类型。
3.1.2 交易消息
有三种不同的交易类型:部署(Deploy),调用(Invoke)和查询(Query)。部署交易向链上安装指定的链码,调用和查询交易会调用部署号的链码。另一种需要考虑的类型是创建(Create)交易,其中部署好的链码是可以在链上实例化并寻址的。这种类型在写这份文档时还没有被实现。
3.1.2.1 交易的数据结构
CHAIN_TRANSACTION和CHAIN_QUERY类型的消息会在payload带有Transaction对象:
messageTransaction {
enum Type {
UNDEFINED = 0;
CHAINCODE_DEPLOY = 1;
CHAINCODE_INVOKE = 2;
CHAINCODE_QUERY = 3;
CHAINCODE_TERMINATE = 4;
}
Type type = 1;
string uuid = 5;
bytes chaincodeID = 2;
bytes payloadHash = 3;
ConfidentialityLevel confidentialityLevel =7;
bytes nonce = 8;
bytes cert = 9;
bytes signature = 10;
bytes metadata = 4;
google.protobuf.Timestamp timestamp = 6;
}
messageTransactionPayload {
bytes payload = 1;
}
enumConfidentialityLevel {
PUBLIC = 0;
CONFIDENTIAL = 1;
}
域的定义:
- type - 交易的类型, 为1时表示:
- UNDEFINED - 为未来的使用所保留.
- CHAINCODE_DEPLOY - 代表部署新的链码.
- CHAINCODE_INVOKE - 代表一个链码函数被执行并修改了世界状态
- CHAINCODE_QUERY - 代表一个链码函数被执行并可能只读取了世界状态
- CHAINCODE_TERMINATE - 标记的链码不可用,所以链码中的函数将不能被调用
- chaincodeID - 链码源码,路径,构造函数和参数哈希所得到的ID
- payloadHash - TransactionPayload.payload所定义的哈希字节.
- metadata - 应用可能使用的,由自己定义的任意交易相关的元数据
- uuid - 交易的唯一ID
- timestamp - peer 收到交易时的时间戳
- confidentialityLevel - 数据保密的级别。当前有两个级别。未来可能会有多个级别。
- nonce - 为安全而使用
- cert - 交易者的证书
- signature - 交易者的签名
- TransactionPayload.payload - 交易的payload所定义的字节。由于payload可以很大,所以交易消息只包含payload的哈希
交易安全的详细信息可以在第四节找到
3.1.2.2 交易规范
一个交易通常会关联链码定义及其执行环境(像语言和安全上下文)的链码规范。现在,有一个使用Go语言来编写链码的实现。将来可能会添加新的语言。
messageChaincodeSpec {
enum Type {
UNDEFINED = 0;
GOLANG = 1;
NODE = 2;
}
Type type = 1;
ChaincodeID chaincodeID = 2;
ChaincodeInput ctorMsg = 3;
int32 timeout = 4;
string secureContext = 5;
ConfidentialityLevel confidentialityLevel =6;
bytes metadata = 7;
}
messageChaincodeID {
string path = 1;
string name = 2;
}
messageChaincodeInput {
string function = 1;
repeated string args = 2;
}
域的定义:
- chaincodeID - 链码源码的路径和名字
- ctorMsg - 调用的函数名及参数
- timeout - 执行交易所需的时间(以毫秒表示)
- confidentialityLevel - 这个交易的保密级别
- secureContext - 交易者的安全上下文
- metadata - 应用想要传递下去的任何数据
当 peer 收到chaincodeSpec后以合适的交易消息包装它并广播到网络
3.1.2.3 部署交易
部署交易的类型是CHAINCODE_DEPLOY,且它的payload包含ChaincodeDeploymentSpec对象。
messageChaincodeDeploymentSpec {
ChaincodeSpec chaincodeSpec = 1;
google.protobuf.Timestamp effectiveDate =2;
bytes codePackage = 3;
}
域的定义:
- chaincodeSpec - 参看上面的3.1.2.2节.
- effectiveDate - 链码准备好可被调用的时间
- codePackage - 链码源码的gzip
当验证 peer 部署链码时,它通常会校验codePackage的哈希来保证交易被部署到网络后没有被篡改。
3.1.2.4 调用交易
调用交易的类型是CHAINCODE_DEPLOY,且它的payload包含ChaincodeInvocationSpec对象。
messageChaincodeInvocationSpec {
ChaincodeSpec chaincodeSpec = 1;
}
3.1.2.5 查询交易
查询交易除了消息类型是CHAINCODE_QUERY其它和调用交易一样
3.1.3 同步消息
同步协议以3.1.1节描述的,当 peer 知道它自己的区块落后于其它 peer 或和它们不一样后所发起的。peer 广播SYNC_GET_BLOCKS,SYNC_STATE_GET_SNAPSHOT或SYNC_STATE_GET_DELTAS并分别接收SYNC_BLOCKS,SYNC_STATE_SNAPSHOT或 SYNC_STATE_DELTAS。
安装的共识插件(如:pbft)决定同步协议是如何被应用的。每个消息是针对具体的状态来设计的:
SYNC_GET_BLOCKS 是一个SyncBlockRange对象,包含一个连续区块的范围的payload的请求。
messageSyncBlockRange {
uint64 correlationId = 1;
uint64 start = 2;
uint64 end = 3;
}
接收peer使用包含 SyncBlocks对象的payload的SYNC_BLOCKS信息来响应
messageSyncBlocks {
SyncBlockRange range = 1;
repeated Block blocks = 2;
}
start和end标识包含的区块的开始和结束,返回区块的顺序由start和end的值定义。如:当start=3,end=5时区块的顺序将会是3,4,5。当start=5,end=3时区块的顺序将会是5,4,3。
SYNC_STATE_GET_SNAPSHOT 请求当前世界状态的快照。 payload是一个SyncStateSnapshotRequest对象
messageSyncStateSnapshotRequest {
uint64 correlationId = 1;
}
correlationId是请求 peer 用来追踪响应消息的。接受 peer 回复payload为SyncStateSnapshot实例的SYNC_STATE_SNAPSHOT信息
messageSyncStateSnapshot {
bytes delta = 1;
uint64 sequence = 2;
uint64 blockNumber = 3;
SyncStateSnapshotRequest request = 4;
}
这条消息包含快照或以0开始的快照流序列中的一块。终止消息是len(delta) == 0的块
SYNC_STATE_GET_DELTAS 请求连续区块的状态变化。默认情况下总账维护500笔交易变化。 delta(j)是block(i)和block(j)之间的状态转变,其中i=j-1。 payload包含SyncStateDeltasRequest实例
messageSyncStateDeltasRequest {
SyncBlockRange range = 1;
}
接收 peer 使用包含 SyncStateDeltas实例的payload的SYNC_STATE_DELTAS信息来响应
messageSyncStateDeltas {
SyncBlockRange