整个架构如下图所示。
包括三大组件:区块链服务(Blockchain)、链码服务(Chaincode)、成员权限管理(Membership)。
{chaincodeID, ckey}
代表键;区块链服务提供一个分布式账本平台。一般地,多个交易被打包进区块中,多个区块构成一条区块链。
交易意味着围绕着某个链码进行操作。
交易可以改变世界状态。
交易中包括的内容主要有:
交易的数据结构(Protobuf 格式)定义为
message Transaction {
enum Type {
UNDEFINED = 0;
// deploy a chaincode to the network and call `Init` function
CHAINCODE_DEPLOY = 1;
// call a chaincode `Invoke` function as a transaction
CHAINCODE_INVOKE = 2;
// call a chaincode `query` function
CHAINCODE_QUERY = 3;
// terminate a chaincode; not implemented yet
CHAINCODE_TERMINATE = 4;
}
Type type = 1;
//store ChaincodeID as bytes so its encrypted value can be stored
bytes chaincodeID = 2;
bytes payload = 3;
bytes metadata = 4;
string uuid = 5;
google.protobuf.Timestamp timestamp = 6;
ConfidentialityLevel confidentialityLevel = 7;
string confidentialityProtocolVersion = 8;
bytes nonce = 9;
bytes toValidators = 10;
bytes cert = 11;
bytes signature = 12;}
区块打包交易,确认交易后的世界状态。
一个区块中包括的内容主要有:
注意具体的交易信息并不存放在区块中。
交易的数据结构(Protobuf 格式)定义为
message Block {
uint32 version = 1;
google.protobuf.Timestamp timestamp = 2;
repeated Transaction transactions = 3;
bytes stateHash = 4;
bytes previousBlockHash = 5;
bytes consensusMetadata = 6;
NonHashData nonHashData = 7;}
一个真实的区块内容示例:
{
"nonHashData": {
"localLedgerCommitTimestamp": {
"nanos": 975295157,
"seconds": 1466057539
},
"transactionResults": [
{
"uuid": "7be1529ee16969baf9f3156247a0ee8e7eee99a6a0a816776acff65e6e1def71249f4cb1cad5e0f0b60b25dd2a6975efb282741c0e1ecc53fa8c10a9aaa31137"
}
]
},
"previousBlockHash": "RrndKwuojRMjOz/rdD7rJD/NUupiuBuCtQwnZG7Vdi/XXcTd2MDyAMsFAZ1ntZL2/IIcSUeatIZAKS6ss7fEvg==",
"stateHash": "TiIwROg48Z4xXFFIPEunNpavMxnvmZKg+yFxKK3VBY0zqiK3L0QQ5ILIV85iy7U+EiVhwEbkBb1Kb7w1ddqU5g==",
"transactions": [
{
"chaincodeID": "CkdnaXRodWIuY29tL2h5cGVybGVkZ2VyL2ZhYnJpYy9leGFtcGxlcy9jaGFpbmNvZGUvZ28vY2hhaW5jb2RlX2V4YW1wbGUwMhKAATdiZTE1MjllZTE2OTY5YmFmOWYzMTU2MjQ3YTBlZThlN2VlZTk5YTZhMGE4MTY3NzZhY2ZmNjVlNmUxZGVmNzEyNDlmNGNiMWNhZDVlMGYwYjYwYjI1ZGQyYTY5NzVlZmIyODI3NDFjMGUxZWNjNTNmYThjMTBhOWFhYTMxMTM3",
"payload": "Cu0BCAESzAEKR2dpdGh1Yi5jb20vaHlwZXJsZWRnZXIvZmFicmljL2V4YW1wbGVzL2NoYWluY29kZS9nby9jaGFpbmNvZGVfZXhhbXBsZTAyEoABN2JlMTUyOWVlMTY5NjliYWY5ZjMxNTYyNDdhMGVlOGU3ZWVlOTlhNmEwYTgxNjc3NmFjZmY2NWU2ZTFkZWY3MTI0OWY0Y2IxY2FkNWUwZjBiNjBiMjVkZDJhNjk3NWVmYjI4Mjc0MWMwZTFlY2M1M2ZhOGMxMGE5YWFhMzExMzcaGgoEaW5pdBIBYRIFMTAwMDASAWISBTIwMDAw",
"timestamp": {
"nanos": 298275779,
"seconds": 1466057529
},
"type": 1,
"uuid": "7be1529ee16969baf9f3156247a0ee8e7eee99a6a0a816776acff65e6e1def71249f4cb1cad5e0f0b60b25dd2a6975efb282741c0e1ecc53fa8c10a9aaa31137"
}
]}
链码包含所有的处理逻辑,并对外提供接口,外部通过调用链码接口来改变世界观。
链码目前支持的交易类型包括:部署(Deploy)、调用(Invoke)和查询(Query)。
不同链码之间可能互相调用和查询。
通过基于 PKI 的成员权限管理,平台可以对接入的节点和客户端的能力进行限制。
证书有三种,Enrollment,Transaction,以及确保安全通信的 TLS 证书。
节点之间通过消息来进行交互,所有消息都由下面的数据结构来实现。
message Message {
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;}
消息分为四大类:Discovery(探测)、Transaction(交易)、Synchronization(同步)、Consensus(一致性)。
不同消息类型,payload 中数据不同。
包括 DISC_HELLO、DISC_GET_PEERS、DISC_PEERS。
包括 Deploy、Invoke、Query。
SYNC_GET_BLOCKS 和对应的 SYNC_BLOCKS。
SYNC_STATE_GET_SNAPSHOT 和对应的 SYNC_STATE_SNAPSHOT。
SYNC_STATE_GET_DELTAS 和对应的 SYNC_STATE_DELTAS。
CONSENSUS 消息。
目前,VP 节点执行了所有的操作,包括接收交易,进行交易验证,进行一致性达成,进行账本维护等。这些功能的耦合导致节点性能很难进行扩展。
新的思路就是对这些功能进行解耦,让每个功能都相对单一,容易进行扩展。社区内已经有了一些讨论。
一种可能的设计是根据功能将节点角色解耦开。
chaincode(链码)是部署在 Hyperledger fabric 网络节点上,可被调用与分布式账本进行交互的一段程序代码,也即狭义范畴上的“智能合约”。链码在 VP 节点上的隔离沙盒(目前为 Docker 容器)中执行,并通过 gRPC 协议来被相应的 VP 节点调用和查询。
Hyperledger 支持多种计算机语言实现的 chaincode,包括 Golang、JavaScript、Java 等。
下面以 golang 为例来实现 chaincode 的 shim 接口。在这之中三个核心的函数是 Init, Invoke, 和Query。三个函数都以函数名和字符串结构作为输入,主要的区别在于三个函数被调用的时机。
chaincode 需要引入如下的软件包。
fmt
:包含了 Println
等标准函数.errors
:标准 errors 类型包;github.com/hyperledger/fabric/core/chaincode/shim
:与 chaincode 节点交互的接口代码。shim 包 提供了 stub.PutState
与 stub.GetState
来写入和查询链上键值对的状态。当首次部署 chaincode 代码时,init 函数被调用。如同名字所描述的,该函数用来做一些初始化的工作。
当通过调用 chaincode 代码来做一些实际性的工作时,可以使用 invoke 函数。发起的交易将会被链上的区块获取并记录。
它以被调用的函数名作为参数,并基于该参数去调用 chaincode 中匹配的的 go 函数。
顾名思义,当需要查询 chaincode 的状态时,可以调用 Quer()
函数。
最后,需要创建一个 main
函数,当每个节点部署 chaincode 的实例时,该函数会被调用。
它仅仅在 chaincode 在某节点上注册时会被调用。
与 chaincode 交互的主要方法有 cli 命令行与 rest api,关于 rest api 的使用请查看该目录下的例子。