教程网

您现在的位置是: 首页 > 产业

Fabric基础架构原理(4):链码的背书策略

Fabric基础架构原理(4):链码的背书策略
Fabric的智能合约 - 链码,智能合约能够部署和运行在区块链环境中,由一段代码来描述相关的业务逻辑。部署后的智能合约在区块链中无法修改,智能合约的执行完全由代码决定,不受人

Fabric的智能合约 - 链码,智能合约能够部署和运行在区块链环境中,由一段代码来描述相关的业务逻辑。部署后的智能合约在区块链中无法修改,智能合约的执行完全由代码决定,不受人为因素的干扰。一般来说,参与方通过智能合约规定各自权利和义务、触发合约的条件以及结果,一旦该智能合约在区块链环境中运行就可以得出客观、准确的结果。

在 Fabric 中,智能合约也称为链码(chaincode),分为用户链码和系统链码,通常指的是用户链码。链码是访问账本的基本方法,一般是用Go等高级语言编写的、实现规定接口的代码。上层应用可以通过调用链码来初始化和管理账本的状态。只要有适当的权限,链码之间也可以互相调用。

1. 链码的背书策略

链码实例化时可指定背书策略,当确认节点接收到交易时,节点获知相关链码信息,然后检查该链码的背书策略,判断交易是否满足背书策略,若满足则标注交易为合法。

背书策略可分为主体 principal(P )和阈值 threshold(T) 两部分,具体如下:

1)principal 指定由哪些成员进行背书。

2)threshold 接受两个输入,分别为阈值t和若干个P的集合n,只要交易中包含了 n 中 t 个成员的背书则认为交易合法。

例如:

T(1, ‘A’, ‘B’) 则需要 A,B 中任意成员背书。

T(1, ‘A’, T(2, ‘B’, ‘C’)) 则需要 A成员背书或 B,C 成员同时背书。

2. 链码开发

链码的在开发过程中需要实现链码接口,交易的类型决定了哪个接口函数将会被调用,如 instantiate 和 upgrade 类型会调用链码的Init接口,而 invoke 类型的交易则调用了链码的 Invoke 接口。链码的接口定义如下:(本文来自公众号:亨利笔记)

type Chaincode interface {

Init(stub ChaincodeStubInterface) pb.Response

Invoke(stub ChaincodeStubInterface) pb.Response

}

下面通过一个例子讲解链码的开发流程,示例链码根据交易的类型创建键值对并记录到账本中,或者根据键名到账本中查找与之相对应的值。

请先确保 Go 语言环境已经安装并且正确设置 GOPATH 环境变量。

(1)创建链码存放目录

创建keyValueStore目录以存放链码,同时进入目录

mkdir $GOPATH/src/keyValueStore

cd $GOPATH/src/keyValueStore

创建并编辑链码文件 keyValueStore.go 。

(2)链码源代码分析

1)导入头文件。

链码必须依赖 chaincode shim 包和 peer protobuf 包,它们分别用于链码的控制与数据传输,其次定义 KeyValueStore 类型,作为 chaincode shim 的载体。

package main

import (

“fmt”

“github.com/hyperledger/fabric/core/chaincode/shim”

“github.com/hyperledger/fabric/protos/peer”

)

type KeyValueStore struct {

}

2)实现Init方法。

Init 方法通过 shim.ChaincodeStubInterface 接口来获取实例化链码交易的相关信息,该接口的 GetStringArgs 方法可获取交易传给链码的参数。链码实例化时接收key 和 value 两个参数,因此先对参数个数进行验证,若验证通过,则第一个和第二个参数分别作为 key 和 value 存入到账本中。

把状态存入账本需要借助 shim.ChaincodeStubInterface 接口 PutState 方法来完成,由于账本中的数据都以键值对的形式储存,因此该方法也只接受 key,value两个参数,其中 value 为 byte 格式,里面还包含多个 json 格式的键值对。

由于执行结果需要以消息的形式返回给客户端,因此还需要把返回消息封装成 fabric/protos/peer 中 Response 格式。

值得注意的是,链码升级的时候都会调用 Init 方法,编写升级链码时应注意 Init 方法的实现,以避免重新初始化或覆盖上一版本的账本状态。

3)实现Invoke方法。

与Init方法类似,Invoke 方法通过 shim.ChaincodeStubInterface 的 GetFunctionAndParameters 方法来获取 invoke 交易的参数,其中返回的 fn 与 args 分别为交易调用的具体函数名以及相应参数,此时 Invoke 方法进一步判断fn的值以进行下一步操作(set或者get),并把操作结果存放在 result 变量中以返回操作结果。

为了完成对账本的读写,链码还需要实现以下两个方法:

set:把输入的键值对记录在账本中

get:根据键读取账本中与之对应的值

4)实现get和put方法。

正如前面所说,invoke 方法根据 fn 的值来执行相应的 get 或 put 函数,这两个函数也需要 shim.ChaincodeStubInterface 接口来访问账本数据。

5)实现主函数main():

链码需要在main函数中调用shim.Start()方法用于链码的部署。

(3)测试链码

链码的测试需要通过完整的Fabric网络,使用官方提供的例子可以快速构建测试网络,从而简化链码的开发流程。这里介绍搭建测试网络的步骤:

1)安装示例代码库。

2)进入 fabric-samples 目录。

$ cd

$GOPATH/src/github.com/hyperledger/fabric-samples

3)把新编写的链码放入fabric-samples的chaincode目录下。

$ cp -r

$GOPATH/src/keyValueStore ./chaincode

4)进入chaincode-docker-devmode目录并启动网络,命令中会创建了一个名称为myc的通道。

$ cd chaincode-docker-devmode

$ docker-compose -f docker-compose-simple.yaml up -d

5)进入chaincode容器,编译并运行链码。

$ docker exec -it chaincode

$ cd keyValueStore && go build

$ export CORE_PEER_ADDRESS=peer:7051

$ export CORE_CHAINCODE_ID_NAME=mycc:0

$./keyValueStore

$ exit

6)进入CLI容器并初始化链码,链码ID为mycc,版本号为0.部署的通道名称是myc。

$ docker exec -it cli bash

$ peer chaincode install -p chaincodedev/chaincode/keyValueStore -n mycc -v 0

$ peer chaincode instantiate -n mycc -v 0 -c ‘{“Args”:[“a”,“10”]}’ -C myc

7)Invoke和Query链码。

$ peer chaincode query -n mycc -c ‘{“Args”:[“query”,“a”]}’ -C myc

$ peer chaincode invoke -n mycc -c ‘{“Args”:[“set”, “a”, “20”]}’ -C myc

$ peer chaincode query -n mycc -c ‘{“Args”:[“query”,“a”]}’ -C myc

正常情况下,两次 query 返回的结果分别为 10 和 20.

开发链码时可以通过上述过程进行测试,但需避免使用相同的链码 ID 以免链码实例化失败。另外,对于链码升级来说,链码的 ID 应该保持不变,同时新链码的版本号需要比先前实例化的版本高,并通过 upgrade 交易来更新链码在通道中的状态。

假设对链码 keyValueStore.go 进行了更改,并把最新的链码保存在$GOPATH/src/keyValueStoreNew 下,则升级链码的操作如下:

1)进入fabric-samples目录并拷贝最新链码到chaincode目录。

$ cd $GOPATH/src/fabric-samples

$ cp -r $GOPATH/src/keyValueStoreNew ./chaincode

2)进入chaincode容器,编译并运行更新后的链码。

$ docker exec -it chaincode bash

$ cd keyValueStoreNew && go build

$ export CORE_PEER_ADDRESS=peer:7051

$ export CORE_CHAINCODE_ID_NAME=mycc:1

$ ./keyValueStoreNew

$ exit

3)进入cli容器并升级链码。

$ docker exec -it cli bash

$ peer chaincode install -p chaincodedev/chaincode/keyValueStoreNew -n mycc -v 1

$ peer chaincode upgrade -n mycc -v 1 -c ‘{“Args”:[“a”,“10”]}’ -C myc

到此升级链码完毕,可以对最新的链码mycc进行操作。

本文选自新书《区块链核心技术与应用》,略有删节。上期介绍了Fabric基础架构的共识与交易机制,本次介绍Fabric私密交易方式:通道的结构。通道是Fabric中非常重要的概念,它实质是由排序节点划分和管理的私有原子广播通道,目的是对通道的信息进行隔离,使得通道外的实体无法访问通道内的信息,从而实现交易的隐私性。

目前通道分为系统通道(System Channel)和应用通道(Application Channel)。排序节点通过系统通道来管理应用通道,用户的交易信息通过应用通道传递。对一般用户来说,通道是指应用通道。系统通道与应用通道的关系如图10-5所示:

系统通道与应用通道

通道由排序服务节点负责管理,同时该节点还负责排序通道中的交易。在通道中一般包含有若干成员(组织),若两个网络实体的身份证书能够追溯到同一个根CA,则认为这两个实体属于同一组织。此外,通道中的每个组织都会有一个或以上的“锚节点”,它负责与其他组织交换共享账本的数据。

创建通道的时候定义了成员,只有通过成员MSP验证的实体,才能够加入到通道并访问通道数据。一个验证例子如下:

Org1 是通道 mychannel 的成员之一,与 Org1 绑定的 MSP 标识为 Org1MSP,其代表的 CA 称为 CA1;若实体的 MSP 满足以下条件则认为实体有权限访问 mychannel 的数据:

实体的MSP标识(ID)为 Org1MSP;

实体身份证书的信任链源头为 CA1.

实体只要满足通道中任意成员的 MSP 校验,则认为该实体有权限访问通道中的数据。

1.通道的配置

通道的配置信息都被打包到一个区块中,并存放在通道的共享账本中。该区块除了配置信息外不包含其他交易信息,称之为通道的配置区块(Configuration Block)。通道可以使用配置区块来更新配置,因此在账本中每新添加一个配置区块,通道就按照最新配置区块的定义来修改配置。通道账本的首个区块一定是配置区块,也称为初始区块(Genesis Block)。

2.使用configtxgen工具生成通道的配置

configtxgen是Fabric提供的工具,用于生成通道所需要的配置文件。configtxgen工具以一个yaml文件作为输入,一般称为 configtx.yaml,该文件定义了将要创建通道的配置信息,该文件通常包括以下部分:

1)Profiles: 包含了通道的配置模板,通过configtxgen工具的参数 -profile 来指定使用哪个模板。

2)Organizations: 定义了组织以及与之相应的 MSP。

3)Orderer: 定义系统通道的相关配置,如排序节点地址、共识算法。

4)Application: 定义应用通道相关配置,被 profile 引用。

以下面的配置文件configtx.yml为例,解释如何通过 configtxgen 创建通道的初始区块。 configtx.yml 清单如下:

上面的 profile 定义了系统通道和应用通道两种不同类型的通道。

系统通道必须定义 Orderer 和 Consortiums 两部分,应用通道必须定义 Application 和 Consortium 两部分。 (更详细的说明请参看 哈希1024社区文章[需粘贴地址到浏览器]:https://hash1024.org/topics/50 )

定义好 yaml 文件后,需要把 configtxgen 工具以及 msp 目录都拷贝到yaml文件的所在的目录下,configtxgen 默认会读取当前目录的 configtx.yaml 作为输入:

1)创建排序节点的初始区块:

configtxgen -profile Genesis -outputBlock genesis.block

该命令通过 profile 参数来指定生成 yaml 文件中 Profile.Genesis 的配置,通过 -outputBlock 参数来将区块写入 genesis.block 文件。

2)创建应用通道 mychannel 的初始区块的交易文件 channel.tx:

configtxgen -profile Channel -outputCreateChannelTx channel.tx -channelID mychannel

该命令通过-outputCreateChannelTx参数将生成的交易写入channel.tx文件,通过-channelID来指定创建通道的名称为mychannel。

3)创建配置区块的交易文件Org1MSPanchors.tx以更新mychannel中PeerOrg1的锚节点:

configtxgen -profile Channel -outputAnchorPeersUpdate Org1MSPanchors.tx -channelID mychannel -asOrg PeerOrg1MSP

该命令通过-asOrg来指定使用PeerOrg1MSP身份创建配置区块,并且通过-outputAnchorPeersUpdate参数将配置区块写入到文件Org1MSPanchors.tx中。

类似地,创建配置区块的交易文件 Org2MSPanchors.tx 以更新 mychannel 中 PeerOrg2 的锚节点:

configtxgen -profile Channel -outputAnchorPeersUpdate Org2MSPanchors.tx -channelID mychannel -asOrg PeerOrg2MSP

3.通道相关命令

对通道的管理可通过命令行的方式,与通道相关的命令如下:

peer channel create: 用于创建通道,主要参数有-c, -f, -o分别用于指定通道ID, configtx的路径和orderer的地址。

peer channel fetch:抓取通道中的特定区块,通过-c和-f参数来指定通道ID和orderer地址。

peer channel join:加入通道,通过-b参数指定初始区块。

peer channel list:列出peer加入的通道。

peer channel update :签名并且发送configtx以升级通道配置,需要通过-c, -f, -o参数分别指定通道ID, configtx的路径以及排序节点的地址。

4.动态修改通道配置

在通道创建后,通道相关的配置以区块的形式存在于通道的账本中。如果需要修改通道的配置,可通过生成新的配置区块去更新。修改通道配置的步骤如下:

1)通过sdk或CLI获得最新的配置区块。

2)编辑配置区块。

3)计算配置更新量。

4)为配置区块添加配置更新量。

5)sdk或CLI签名并发送配置区块。

若新的配置区块通过验证,则通道配置以最新配置区块为准。具体操作流程请参考后文修改通道配置。

(未完待续)

(来源:亨利笔记)

本文选自新书《区块链核心技术与应用》,略有删节。上期介绍了超级账本的主要组件,本次介绍共识机制和交易流程。Fabric 的网络节点本质上是互相复制的状态机,节点之间需要保持相同的账本状态。为了实现这个目的,各个节点需要通过共识( consensus )过程,对账本状态的变化达成一致性的认同。

Fabric 的共识过程包括 3 个阶段:背书、排序和校验。

1. 背书

在背书( endorsement )阶段中,背书节点对客户端发来的交易预案进行合法性检验,然后模拟执行链码得到交易结果,最后根据设定的背书逻辑判断是否支持该交易预案。如果背书逻辑决定支持交易预案,它将把预案签名后发回给客户端。

 1/3    1 2 3 下一页 尾页