Fabric v2.0 智能合约新生命周期模型的常用操作指南

文章目录

  • 1. 打包智能合约
  • 2. 安装智能合约
  • 3. 组织认可智能合约定义
  • 4. 检查智能合约是否就绪
  • 5. 提交智能合约定义
  • 6. 调用智能合约
  • 7. 升级智能合约
    • 7.1 打包智能合约
    • 7.2 安装合约包
    • 7.3 组织认可新的合约定义
    • 7.4 提交新的合约定义
  • 8. 合约级别的背书策略指定
    • 8.1 组织认可新的合约定义
    • 8.2 提交新的合约定义
  • 9. 键级别的背书策略指定
    • 9.1 chaincode代码实现
    • 9.2 升级智能合约
    • 9.3 调用智能合约修改背书策略
  • 附录:环境变量

推荐阅读Fabric v1.x 智能合约的生命周期,了解Fabric v1.x的chaincode生命周期模型。
推荐阅读Hyperledger Fabric v2.0发行版的新增功能介绍,了解Fabric v2.0的新增功能。

Fabric v2.0引入了智能合约的去中心化治理,升级到了新的chaincode生命周期管理模式。下面将进行实际的生命周期管理操作演练。

1. 打包智能合约

Fabric生命周期将chaincode打包在易于阅读的tar文件中,方便协调跨多个组织的安装。
执行docker exec -it cli命令进入cli容器,使用下面命令打包chaincode:

peer lifecycle chaincode package mycc2.tar.gz --path github.com/hyperledger/fabric-samples/chaincode/abstore/go/ --lang golang --label mycc_1
  • mycc1.tar.gz为包文件名
  • path:智能合约路径
  • lang:智能合约语言,支持golang、node、java
  • label:智能合约标签,可以标记chaincode源代码的版本

打包后文件mycc1.tar.gz解压后,可以看到里面包含Metadata.json文件和code.tar.gz文件,Metadata.json文件的内容就是我们刚刚打包时指定的参数,为合约的代码路径path、语言lang以及标签label,code.tar.gz中则是合约源代码以及依赖包。

2. 安装智能合约

在cli中执行下面命令安装chaincode,mycc1.tar.gz为智能合约合约压缩包路径:

peer lifecycle chaincode install mycc1.tar.gz

查询已安装的chaincode:

peer lifecycle chaincode queryinstalled

3. 组织认可智能合约定义

Fabric v1.x的生命周期使用安装chaincode包时指定的名称和版本定义channel上的每个chaincode。现在,您可以使用单个chaincode程序包,并在channel上以不同的名称多次部署它。

channel成员需要认可合约定义,该认可将作为组织接受合约参数定义的投票。对合约定义的认可,保证了在使用chaincode之前,channel成员达成了对chaincode定义的共识。chaincode定义包括以下参数,这些参数需要在组织之间保持一致:

  • 名称:智能合约名称;
  • 版本:与给定的合约包相关联的版本号或值。如果您升级了合约源代码,那么您也需要更改合约版本;
  • 序列:chaincode定义的次数。该值为整数,用于跟踪合约升级。第一次安装并同意一个chaincode定义时,序列号将是1,下次升级合约时,序列号将增加到2;
  • 背书策略:哪些组织需要执行和验证事务输出。背书策略可以表示为传递给CLI或SDK的字符串;channel配置中默认要求channel中的大多数组织对交易进行背书;
  • 集合配置:指向与您的chaincode关联的私有数据集合定义文件的路径;
  • 初始化:所有chaincode需要包含一个初始化函数来初始化chaincode。默认情况下,这个函数永远不会执行。但是,您可以使用chaincode定义来请求Init函数是可调用的。如果请求执行Init,则fabric将确保在调用任何其他函数之前调用Init,并且只调用一次;
  • ESCC/VSCC插件: 自定义背书或验证插件的名称。

在cli中使用下面命令认可智能合约定义:

peer lifecycle chaincode approveformyorg --tls true --cafile $ORDERER_CA --channelID mychannel --name mycc --version 1 --init-required --package-id mycc_1:33c137ade1dcc3dd383174a451549a1eda509336cf957dfb472854686d565b9e --sequence 1 --waitForEvent
  • tls 是否启动tls
  • cafile orderer的ca证书路径
  • channelID 智能合约安装的channel
  • name 合约名
  • version 合约版本
  • init-required 合约是否必须执行init
  • package-id queryinstalled查询的合约ID
  • sequence 序列号
  • waitForEvent 等待peer提交交易返回

4. 检查智能合约是否就绪

合约的生命周期背书策略在channel配置中定义,见下面配置中的LifecycleEndorsement,需要大多数组织同意:

Application: &ApplicationDefaults

    # Organizations is the list of orgs which are defined as participants on
    # the application side of the network
    Organizations:

    # Policies defines the set of policies at this level of the config tree
    # For Application policies, their canonical path is
    #   /Channel/Application/
    Policies:
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"
        LifecycleEndorsement:
            Type: ImplicitMeta
            Rule: "MAJORITY Endorsement"
        Endorsement:
            Type: ImplicitMeta
            Rule: "MAJORITY Endorsement"

    Capabilities:
        <<: *ApplicationCapabilities

在cli中使用下面命令查询是否满足提交智能合约生命周期背书策略:

peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name mycc --version 1 --sequence 1 --output json --init-required

可以查看到channel中各个组织是否已同意该合约定义,如果已同意会显示true,否则为false。在不满足合约定义策略的情况下提交合约定义,将会报错Error: transaction invalidated with status (ENDORSEMENT_POLICY_FAILURE),表示不满足合约定义策略。

我们需要切换环境变量到其他组织(切换方法见文章末尾),重复安装、认可的步骤,使过半数的组织同意该合约定义。

5. 提交智能合约定义

在满足合约定义的策略后,可以在cli中进行提交合约的操作了:

peer lifecycle chaincode commit -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA --channelID mychannel --name mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles $PEER0_ORG1_CA --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles $PEER0_ORG2_CA --version 1 --sequence 1 --init-required
  • peerAddresses 节点地址
  • tlsRootCertFiles 节点ca根证书路径(–peerAddresses --tlsRootCertFiles 可使用多个节点,将合约部署到这些节点上)

我们使用了两对peerAddresses和tlsRootCertFiles,将向peer0.org1.example.com和peer0.org2.example.com两个节点发送提交交易,操作完成后这两个节点都会提交该智能合约定义,使用docker ps可查看到合约容器都启动成功了。

cli中使用下面命令可查看已提交的智能合约:

peer lifecycle chaincode querycommitted --channelID mychannel --name mycc

6. 调用智能合约

调用chaincode的Init方法,设置初始值:

peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles $PEER0_ORG1_CA --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles $PEER0_ORG2_CA --isInit -c '{"Args":["Init","a","100","b","100"]}'  --waitForEvent

查询a的余额:

peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'

a转账给b:

peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles $PEER0_ORG1_CA --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles $PEER0_ORG2_CA -c '{"Args":["invoke","a","b","10"]}'  --waitForEvent

再次查询a的余额,变成了90。

7. 升级智能合约

在先前的chaincode生命周期中,升级事务可能由单个组织发出,这给尚未安装新链码的channel成员带来了风险。新模型仅在足够数量的组织认可升级后才允许升级chaincode。

7.1 打包智能合约

从peer节点上获取chaincode压缩包:

peer lifecycle chaincode getinstalledpackage --package-id  mycc_1:33c137ade1dcc3dd383174a451549a1eda509336cf957dfb472854686d565b9e

packge_id为peer lifecycle chaincode querycommitted查询到的packge_id。

修改完代码后打包智能合约:

peer lifecycle chaincode package mycc_2.tar.gz --path github.com/hyperledger/fabric-samples/chaincode/myabstore/go/ --lang golang --label mycc_2

然后在不同节点(切换方法见文章末尾)执行安装合约包、认可合约定义的操作。

7.2 安装合约包

安装合约包:

peer lifecycle chaincode install mycc_2.tar.gz

查询已安装的合约包,可以看到新安装的合约包package_id信息:

peer lifecycle chaincode queryinstalled

7.3 组织认可新的合约定义

认可新的合约定义,package_id改为新安装的合约包package_id,因为第二次定义,sequence改为2:

peer lifecycle chaincode approveformyorg --tls true --cafile $ORDERER_CA --channelID mychannel --name mycc --version 1 --init-required --sequence 2 --package-id  mycc_2:a455444dd2f0cd9b07117260422a2ac0f3e25a28fcc329c7e054545ea0271e1a --waitForEvent

查看是否满足生命周期背书策略:

peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name mycc --version 1 --init-required --sequence 2 --output json

7.4 提交新的合约定义

提交新的智能合约定义:

peer lifecycle chaincode commit -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA --channelID mychannel --name mycc --version 1 --sequence 2 --init-required --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles $PEER0_ORG1_CA --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles $PEER0_ORG2_CA

提交完成后,智能合约的升级也就成功了。

8. 合约级别的背书策略指定

关于背书策略的详细介绍,推荐阅读Fabric v1.x 背书策略。
Fabric v2.0 生命周期允许您更改认可策略,而无需重新打包或重新安装链码。用户还可以利用新的默认策略,该策略需要频道中大多数成员的认可。在从channel中添加或删除组织时,该策略会自动更新。
默认情况下,合约的背书策略需要过半数的channel成员,见下面配置中的Endorsement:

Application: &ApplicationDefaults

    # Organizations is the list of orgs which are defined as participants on
    # the application side of the network
    Organizations:

    # Policies defines the set of policies at this level of the config tree
    # For Application policies, their canonical path is
    #   /Channel/Application/
    Policies:
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"
        LifecycleEndorsement:
            Type: ImplicitMeta
            Rule: "MAJORITY Endorsement"
        Endorsement:
            Type: ImplicitMeta
            Rule: "MAJORITY Endorsement"

    Capabilities:
        <<: *ApplicationCapabilities

8.1 组织认可新的合约定义

在cli中设置合约级别的背书策略为OR('Org1.member', 'Org2.member')

peer lifecycle chaincode approveformyorg  --signature-policy "OR('Org1MSP.member','Org2MSP.member')" --tls true --cafile $ORDERER_CA --channelID mychannel --name mycc --version 1 --init-required --package-id mycc_2:0d395e922a99405e12fdd51b3e1c392808cb1c4031a684e9a61354f095ba40aa --sequence 3 --waitForEvent
  • signature-policy:指定背书策略

切换不同节点(切换方法见文章末尾)执行认可新背书策略的合约定义。
查询是否已满足生命周期背书策略:

peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name mycc --version 1 --sequence 3 --output json --init-required

8.2 提交新的合约定义

提交新的合约定义:

peer lifecycle chaincode commit -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA --channelID mychannel --name mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles $PEER0_ORG1_CA --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles $PEER0_ORG2_CA --version 1 --sequence 3 --init-required --signature-policy "OR('Org1MSP.member', 'Org2MSP.member')"

提交完成后,合约级别的背书策略也就更新成功了。

9. 键级别的背书策略指定

有了key级别的背书策略,不需要升级chaincoe,只需要对某一些特定的key做背书策略配置。

9.1 chaincode代码实现

shim包提供了获取和设置背书策略的API:

GetStateValidationParameter(key string) ([]byte, error)
SetStateValidationParameter(key string, ep []byte) error

statebased包提供了接口KeyEndorsementPolicy,用于表示背书策略:

type KeyEndorsementPolicy interface {
	Policy() ([]byte, error)
	AddOrgs(roleType RoleType, organizations ...string) error
	DelOrgs(organizations ...string)
	ListOrgs() []string
}

调用statebased包的NewStateEP函数可获得KeyEndorsementPolicy接口类型的值,调用AddOrgs方法增加组织,调用DelOrgs方法删除组织,调用Policy方法获得策略的字节数组。由于只能增加或删除,支持“AND”类型的背书策略。

下面是chaincode中修改背书策略的实现:

func (t *ABstore) changeEP(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 3 {
		return shim.Error("Incorrect number of arguments.")
	}
	key := args[0]
	role := args[1]
	op := args[2]

	newEP, err := statebased.NewStateEP(nil)
	if err != nil {
		return shim.Error(err.Error())
	}
	if op == "del" {
		newEP.DelOrgs(role)
	} else if op == "add" {
		err = newEP.AddOrgs(statebased.RoleTypeMember, role)
	}
	if err != nil {
		return shim.Error(err.Error())
	}

	policyByte, err := newEP.Policy()
	if err != nil {
		return shim.Error(err.Error())
	}

	err = stub.SetStateValidationParameter(key, policyByte)
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(nil)
}

9.2 升级智能合约

升级合约的操作参照本文第7章节。

9.3 调用智能合约修改背书策略

修改背书策略为AND("Org1MSP.member", "Org2MSP.member")

peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles $PEER0_ORG1_CA --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles $PEER0_ORG2_CA -c  '{"Args":["changeEP","a","Org1MSP","add"]}'
peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles $PEER0_ORG1_CA --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles $PEER0_ORG2_CA -c  '{"Args":["changeEP","a","Org2MSP","add"]}'

只向peer0.org1.example.com请求背书,交易将会验证失败:

peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n mycc2 --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles $PEER0_ORG1_CA  -c '{"Args":["invoke","a","b","10"]}' --waitForEvent

再次修改背书策略,删除Org2MSP:

peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles $PEER0_ORG1_CA --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles $PEER0_ORG2_CA  -c  '{"Args":["changeEP","a","Org2MSP","del"]}'

再次只向peer0.org1.example.com请求背书,将会交易满足背书策略,执行成功:

peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n mycc2 --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles $PEER0_ORG1_CA  -c '{"Args":["invoke","a","b","10"]}' --waitForEvent

附录:环境变量

本文命令中使用的环境变量配置:

ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
PEER0_ORG1_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
PEER0_ORG2_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt

cli中设置连接不同的节点,需要设置相应的环境变量:

  • peer0.org1.example.com
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
  • peer0.org2.example.com
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=peer0.org2.example.com:9051

感谢富强的博客:
https://blog.csdn.net/qq_28540443/article/details/104379132

参考资料:
github.com/hyperledger/fabric-samples/first-network/scripts/script.sh
github.com/hyperledger/fabric-samples/first-network/scripts/utils.sh

你可能感兴趣的:(#,Fabric,v2.x,Hyperledger,Fabric)