• 【Hyperledger Fabric 学习】部署智能合约到通道上


    HyperLedger Fabric官方文档

    中文网址:https://hyperledger-fabric.readthedocs.io/zh_CN/latest
    英文网址:https://hyperledger-fabric.readthedocs.io/en/latest
    一般情况英文网址的内容更全面,版本也比中文新。

    前言

    终端用户通过调用智能合约与区块链账本进行交互。在 Hyperledger Fabric 中,智能合约部署在称为链码的包中。想要验证交易或查询账本的组织需要在其Peer节点上安装链码。在加入通道的节点上安装链码后,通道成员可以将链码部署到通道并使用链码中的智能合约在通道账本上创建或更新资产。

    链码部署到通道使用称为 Fabric 链码生命周期的过程。Fabric 链码生命周期允许多个组织在链码用于创建交易之前就如何操作链码达成一致。例如,虽然背书策略指定了哪些组织需要执行链码来验证交易,但通道成员需要使用 Fabric 链码生命周期来就链码背书策略达成一致。有关如何在通道上部署和管理链代码的更深入概述,请参阅Fabric 链代码生命周期

    使用Peer CLI部署asset-transfer-basic链码的四个步骤:

    • 第一步:打包智能合约
    • 第二步:安装链码包
    • 第三步:批准链码定义
    • 第四步:将链码定义提交到通道

    设置Logspout(可选)
    此步骤不是必需的,但对于排查链代码非常有用。要监控智能合约的日志,管理员可以使用该logspout工具查看一组 Docker 容器的聚合输出。该工具将来自不同 Docker 容器的输出流收集到一个位置,从而可以轻松地从单个窗口查看正在发生的事情。这可以帮助管理员在安装智能合约或开发人员调用智能合约时调试问题。由于某些容器纯粹是为了启动智能合约而创建的,并且只存在很短的时间,因此从您的网络收集所有日志会很有帮助。

    Fabric 示例的目录中monitordocker.sh已经包含一个用于安装和配置 Logspout 的脚本,位于test-network目录中。Logspout 工具会不断地将日志流式传输到您的终端,因此您需要使用新的终端窗口。打开一个新终端并导航到该test-network目录。
    cd fabric-samples/test-network

    然后,您可以通过运行以下命令来启动 Logspout:
    ./monitordocker.sh fabric_test

    打包智能合约

    这里只介绍GO语言
    在打包链码之前,我们需要安装链码依赖项。导航到包含资产转移(基本)链码的 Go 版本的文件夹。
    cd fabric-samples/asset-transfer-basic/chaincode-go

    该示例使用 Go 模块来安装链码依赖项。依赖项列在asset-transfer-basic/chaincode-go目录中的go.mod文件。

    go.mod文件将 Fabric 合约 API 导入到智能合约包中。您可以打开asset-transfer-basic/chaincode-go/chaincode/smartcontract.go以查看如何使用合约 API 来定义SmartContract智能合约开头的类型:

    // SmartContract provides functions for managing an Asset
    type SmartContract struct {
        contractapi.Contract
    }
    
    • 1
    • 2
    • 3
    • 4

    然后,使用Smartcontract类型为在智能合约中定义的功能创建事务上下文,这些功能将数据读写到区块链账本。

    // CreateAsset issues a new asset to the world state with given details.
    func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error {
        exists, err := s.AssetExists(ctx, id)
        if err != nil {
            return err
        }
        if exists {
            return fmt.Errorf("the asset %s already exists", id)
        }
    
        asset := Asset{
            ID:             id,
            Color:          color,
            Size:           size,
            Owner:          owner,
            AppraisedValue: appraisedValue,
        }
        assetJSON, err := json.Marshal(asset)
        if err != nil {
            return err
        }
    
        return ctx.GetStub().PutState(id, assetJSON)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    API文档
    智能合约过程

    安装智能合约依赖,在asset-transfer-basic/chaincode-go目录下运行:
    GO111MODULE=on go mod vendor
    然后可以回到test-network目录

    使用Peer CLI创建链码包。二进制文件位于fabric-samples/bin。添加二进制文件到当前路径:
    export PATH=${PWD}/../bin:$PATH

    同时要设置环境变量FABRIC_CFG_PATH指向core.yaml
    export FABRIC_CFG_PATH=$PWD/../config/

    创建链码包:
    peer lifecycle chaincode package basic.tar.gz --path ../asset-transfer-basic/chaincode-go/ --lang golang --label basic_1.0

    安装链码包

    在我们打包完asset-transfer-basic智能合约后,我们可以在我们的Peer节点上安装链码。链码需要安装在每个将支持交易的对等方上。因为我们要将背书策略设置为需要来自 Org1 和 Org2 的背书,所以我们需要在两个组织运营的对等节点上安装链码:

    • peer0.org1.example.com
    • peer0.org2.example.com

    让我们先在 Org1 peer 上安装链码。设置以下环境变量,以peer Org1 管理员用户身份操作 CLI。将CORE_PEER_ADDRESS指向 Org1 Peer,peer0.org1.example.com

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5

    安装链码:
    peer lifecycle chaincode install basic.tar.gz

    使用Peer Org2进行同样的操作:

    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
    
    peer lifecycle chaincode install basic.tar.gz
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    批准链码定义

    安装链码包后,您需要为您的组织批准链码定义。该定义包括链码治理的重要参数,例如名称、版本和链码背书策略。

    在部署链码之前需要批准链码的通道成员集由该/Channel/Application/LifecycleEndorsement策略管理。默认情况下,此策略要求大多数通道成员需要批准链码才能在通道上使用。因为我们在通道上只有两个组织,并且2的大多数是 2,所以我们需要作为 Org1 和 Org2批准asset-transfer-basic的链码定义。

    如果组织已在其对等节点上安装了链码,则他们需要在其组织批准的链码定义中包含 packageID。packageID 用于将安装在Peer节点上的链码与批准的链码定义相关联,并允许组织使用链码来背书交易。您可以使用peer lifecycle chaincode queryinstalled命令查询您的对等点来查找链代码的包 ID。
    peer lifecycle chaincode queryinstalled

    命令行会显示已经安装的链码packageID。

    当我们批准链码时,我们将使用packageID,将其保存为环境变量。将返回的包 ID 粘贴到下面的命令的“=”后面。
    注意:并非所有用户的 packageID 都相同,因此您需要使用上一步命令窗口返回的包 ID 完成此步骤。
    export CC_PACKAGE_ID=+复制的packageID

    当前是以Peer Org2 管理员身份运行 CLI,因此我们可以作为Org2批准asset-transfer-basic的链代码定义。链码在组织级别获得批准,因此该命令只需要针对一个节点。使用Gossip将批准消息分发给组织内的其他Peer。使用命令 peer lifecycle chaincode approveformyorg批准链代码定义:
    peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name basic --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"

    上面的命令使用--package-id标志在l链码定义中包含pakageID。--sequence参数是一个整数,用于跟踪链码被定义或更新的次数。由于链码是第一次部署到通道中,因此序列号为1。当asset-transfer-basic链码升级时,序列号将增加到2。如果你正在使用Fabric Chaincode Shim API提供的低级别APIl,你可以将--Init-required标志传递给上面的命令,以请求执行Init函数来初始化Chaincode。链代码的第一次调用需要以Init函数为目标,并包含--isInit标志,然后才能使用链代码中的其他函数与账本交互。

    我们可以为approveformyorg命令提供--signature-policy--channel-config-policy参数来指定链码背书策略。背书策略指定了针对给定的链码交易需要多少属于不同通道成员的Peer来验证。因为我们没有设置策略,所以asset-transfer-basic的定义将使用默认的背书策略,该策略要求在提交交易时,交易必须得到大多数在场的通道成员的背书。这意味着,如果在通道中添加或删除新的组织,背书政策将自动更新,以要求更多或更少的背书。在本教程中,默认策略将需要2 / 2的大多数,事务将需要由来自Org1和Org2的Peer批准。如果需要指定自定义的背书策略,可以通过背书策略操作指南了解该策略的语法。

    您需要批准具有管理员角色的标识的链码定义。因此,CORE_PEER_MSPCONFIGPATH变量需要指向包含管理标识的MSP文件夹。您不能通过客户端用户来批准链码定义。批准消息需要提交给排序服务,它将验证管理员签名,然后将批准分发给您的对等点。

    作为Org1批准链码定义也是一样:

    export CORE_PEER_LOCALMSPID="Org1MSP"
    export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
    export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
    export CORE_PEER_ADDRESS=localhost:7051
    
    peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name basic --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    提交链码定义到通道

    在足够数量的组织批准链码定义后,一个组织可以将链码定义提交给通道。如果大多数通道成员都批准了定义,则提交事务将成功,链码定义中约定的参数将在通道上实现。

    您可以使用 peer lifecycle chaincode checkcommitreadiness命令检查通道成员是否批准了相同的链码定义。用于该checkcommitreadiness命令的标志与用于批准您的组织的链代码的标志相同。但是,您不需要包含--package-id标志。
    peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name basic --version 1.0 --sequence 1 --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --output json
    该命令将生成一个JSON映射,显示通道成员是否批准。

    由于作为通道成员的两个组织都批准了相同的参数,因此链码定义可以提交给通道。可以使用peer lifecycle chaincode commit命令将链码定义提交给该通道。提交命令也需要由组织管理员提交。
    peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name basic --version 1.0 --sequence 1 --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --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"
    使用--peerAddresses标志来定位peer0.org1.example.comOrg1 peer0.org2.example.comcommit交易被提交给加入通道的对等点,以查询操作Peer的组织批准的链码定义。该命令需要定位来自足够数量的组织的Peer,以满足部署链代码的策略。由于批准分布在每个组织内,因此您可以针对属于通道成员的任何Peer。

    通道成员对链码定义的背书提交给排序服务,以添加到块中并分发到通道。然后通道上的Peer验证是否有足够数量的组织批准了链码定义。命令peer lifecycle chaincode commit将在返回响应之前等待Peer的验证。

    使用peer lifecycle chaincode querycommitted命令来确认链码定义是否被提交到通道。
    peer lifecycle chaincode querycommitted --channelID mychannel --name basic --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"

    调用链码

    将链码定义提交到通道后,链码将在加入安装链码的通道的Peer点上启动。asset-transfer-basic链码现在已准备好由客户端应用程序调用。使用以下命令在分类帐上创建一组初始资产。请注意,invoke 命令需要针对足够数量的Peer以满足链码背书策略。(注意 CLI 不访问 Fabric Gateway 对等体,因此必须指定每个背书对等体。)
    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":[]}'

    查询链码创建的car集合
    peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'

    更新智能合约

    您可以使用相同的 Fabric 链码生命周期流程来升级已部署到通道的链码。通道成员可以通过安装新的链码包,然后批准具有新包 ID、新链码版本和序列号加一的链码定义来升级链码。在将链码定义提交到通道后,可以使用新的链码。此过程允许通道成员在升级链代码时进行协调,并确保有足够数量的通道成员准备好使用新的链代码,然后再将其部署到通道。

    通道成员还可以使用升级过程来更改链码背书策略。通过使用新的背书策略批准链码定义并将链码定义提交给通道,通道成员可以更改管理链码的背书策略,而无需安装新的链码包。

    为了提供升级我们刚刚部署的asset-transfer-basic链码的场景,我们假设 Org1 和 Org2 想要安装用另一种语言编写的链代码版本。他们将使用 Fabric 链码生命周期来更新链码版本,并确保两个组织在新链码在通道上激活之前都已安装它。

    我们将假设 Org1 和 Org2 最初安装了asset-transfer-basic链码的 GO 版本,但使用 JavaScript 编写的链码会更舒服。第一步是打包资产转移(基本)链码的 JavaScript 版本。如果您在学习本教程时使用 JavaScript 说明打包链代码,则可以按照打包用Go或TypeScript编写的链代码的步骤安装新的链代码二进制文件。

    安装依赖:

    cd ../asset-transfer-basic/chaincode-javascript
    npm install
    cd ../../test-network
    
    • 1
    • 2
    • 3

    打包JavaScript链码:

    export PATH=${PWD}/../bin:$PATH
    export FABRIC_CFG_PATH=$PWD/../config/
    export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
    peer lifecycle chaincode package basic_2.tar.gz --path ../asset-transfer-basic/chaincode-javascript/ --lang node --label basic_2.0
    
    • 1
    • 2
    • 3
    • 4

    作为Org安装链码:

    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
    
    peer lifecycle chaincode install basic_2.tar.gz
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    查询packageID:
    peer lifecycle chaincode queryinstalled

    将新版本的ID复制到环境变量:
    export NEW_CC_PACKAGE_ID=+新packageID

    同意链码定义:
    peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name basic --version 2.0 --package-id $NEW_CC_PACKAGE_ID --sequence 2 --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"

    Org2一样:

    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
    
    peer lifecycle chaincode install basic_2.tar.gz
    
    peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name basic --version 2.0 --package-id $NEW_CC_PACKAGE_ID --sequence 2 --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    检查sequence2是否可以提交到通道:
    peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name basic --version 2.0 --sequence 2 --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --output json

    升级:
    peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name basic --version 2.0 --sequence 2 --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --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"

    可以使用docker ps查看是否更新

    在更新前使用--init-required需要调用初始化函数初始化账本:
    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":"CreateAsset","Args":["asset8","blue","16","Kelley","750"]}'

  • 相关阅读:
    华为od100问持续分享-1
    海思3559开发常识储备:相关名词全解
    Java字符集/编码集
    python 时间加法 输出t分钟后的时间
    Misc入门干货
    Android studio将一个项目作为module导入另一个项目
    动手学深度学习——数据操作笔记
    深度学习 | Transformer 基本原理
    Linux0.11——操作系统怎么把自己从硬盘搬到内存
    IDEA版SSM入门到实战(Maven+MyBatis+Spring+SpringMVC) -Maven核心概念
  • 原文地址:https://blog.csdn.net/qq_39681297/article/details/126158457