Fabric系列 - 链码- 外部链码(v2.0)
创始人
2024-05-30 15:53:16
0

Fabric2.0的重大变化之一就是支持外部构建智能合约,在1.x版本的Fabric中,合约是由Peer以容器的方式进行启动和维护,依赖于Docker。这在一定程度上违反了安全准则,并且在管理运维中带来了麻烦。Fabric 2.0支持用户自行启动合约容器。

1.修改Peer节点配置

(1)准备构建器与启动器脚本

外部构建器(externalBuilder)和启动器由四个程序或脚本组成:

  • bin/detect:确定是否应使用此buildpack来构建chaincode程序包并启动它。
    • 它用于检测当前install的合约是否适用外部构建器构建,假如exit 0就会继续执行构建发布外部合约的操作,exit 1就会按照原本适用节点安装部署合约的方式。
  • bin/build:将chaincode包转换为可执行的chaincode。
    • 将我们提交的合约配置文件按照构建规则放到它指定的目录
  • bin/release (可选):向peer提供有关链码的元数据。
    • 在完成合约基础构建之后,剩下只需要发布
  • bin/run (可选):运行链码。

(2)准备core.yaml

 externalBuilders:# 填写节点容器内存放 externalBuilder 脚本的目录- path: /opt/gopath/src/github.com/hyperledger/fabric/peer/externalBuildername: builder			# 外部构建器名称#   environmentWhitelist:	#环境变量白名单#      - ENVVAR_NAME_TO_PROPAGATE_FROM_PEER#      - GOPROXY

(3)增加 dockerfile / docker-compose 的挂载参数

之后把externalBuilder目录映射到externalBuilders.path 以及 将core.yaml挂载到容器的/etc/hyperledger/fabric目录

volumes:# 挂载目录- ./external:/opt/gopath/src/github.com/hyperledger/fabric/peer/externalBuilder- ./core.yaml:/etc/hyperledger/fabric/core.yaml

2.部署合约到网络

(1)准备json文件

要实现外部部署合约,对于要install到fabric的合约包跟之前的包是不一样的,这个包里面不需要合约的源代码。

按照定义来说,这个合约包含有:

  • metadata.json : 合约的属性,与原本的合约属性不一致的是他的path可以为空,他的type可以自定义。

    {"path":"","type":"external","label":"mycc_1"}
    
  • connection.json :这个文件是用于节点去连接合约的相关配置信息,双方交互基于grpc服务。

    {"address": "192.168.2.103:7052","dial_timeout": "10s","tls_required": false,"client_auth_required": false,"client_key": "-----BEGIN EC PRIVATE KEY----- ... -----END EC PRIVATE KEY-----","client_cert": "-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----","root_cert": "-----BEGIN CERTIFICATE---- ... -----END CERTIFICATE-----"
    }
    
  • metadata文件夹:应该是跟couchdb存放私有数据相关的,本实践不做详细说明。


以下通过cli容器操作

(2)打包合约

tar cfz code.tar.gz connection.json  
tar cfz mycc2.tgz metadata.json code.tar.gz

(3)安装部署合约

# 每个背书节点都要install
peer lifecycle chaincode install mycc2.tgz# 批准合约定义,必须符合lifecycle策略
peer lifecycle chaincode approveformyorg --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name mycc2 --version 1 --init-required --package-id mycc_1:84b3aaf583a6632e806a0ff46ad804539797d84ff7826c88a6d6009a9930cfee --sequence 1 --waitForEvent# 提交合约定义到网络peer lifecycle chaincode commit -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --version 1 --sequence 1  --init-required

(4)构建发布成功

完全部署成功之后,我们可以看到跟往常部署不一样的是,合约容器并没有启动,在节点容器 /var/hyperledger/production/externalbuilder/builds/出现构建发布后的合约文件目录:

$ ls /var/hyperledger/production/externalbuilder/builds/
mycc_1-1334f6ae3dc48da53113bd1d3f430976757181ccd2b6162dab1efc72295e1e4f

3.启动合约

在宿主机操作

编写合约main函数

func main() {server := &shim.ChaincodeServer{CCID:    os.Getenv("CHAINCODE_CCID"),    //读取环境变量Address: os.Getenv("CHAINCODE_SERVER_ADDRESS"),CC:      new(ABstore),TLSProps: shim.TLSProperties{Disabled: true,},}// Start the chaincode external servererr := server.Start()if err != nil {fmt.Printf("Error starting Marbles02 chaincode: %s", err)}
}

(1)二进制启动

配置环境变量文件 chaincode.env

# CHAINCODE_SERVER_ADDRESS must be set to the host and port where the peer can
# connect to the chaincode server
# grpc服务IP端口
CHAINCODE_SERVER_ADDRESS=0.0.0.0:9999#mycc.org1.example.com:9999# CHAINCODE_CCID must be set to the Package ID that is assigned to the chaincode
# on install. The `peer lifecycle chaincode queryinstalled` command can be
# used to get the ID after install if required
# 部署完成后生产的合约ID
CHAINCODE_CCID=mycc_1:1334f6ae3dc48da53113bd1d3f430976757181ccd2b6162dab1efc72295e1e4f

启动

cd到合约所在目录
go build
source chaincode.env; ./sacc_external  #光这样跑会报缺参数

(2) [推荐]docker启动

构建 docker image

编写Dockerfile

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0# ********************
# 构建合约可执行文件,启动容器运行合约可执行文件
# ********************#This image is a microservice in golang for the Degree chaincode
FROM golang:1.14.4-alpine3.12 AS buildCOPY ./ /go/src/github.com/sacc_external
WORKDIR /go/src/github.com/sacc_external# Build application
RUN GO111MODULE=on go build -o chaincode -v .
# RUN  GOPROXY="https://goproxy.cn" GO111MODULE=on   go build -mod vendor -o chaincode -v .# Production ready image
# Pass the binary to the prod image
FROM alpine:3.11 as prodCOPY --from=build /go/src/github.com/sacc_external/chaincode /app/chaincodeUSER 1000WORKDIR /app
CMD ./chaincode

构建image

#构建合约可执行文件的image
docker build -t chaincode/mycc2:1.0 .

注意 CHAINCODE_CCID一定要对应我们之前安装好的合约id

启动外部合约容器

配置 docker-compose-mycc.yaml

version: '2'networks:basic:services:#合约容器mycc2:#定义主机名container_name: mycc.org1.example.com#使用的镜像image: chaincode/mycc2:1.0#容器的映射端口ports:- 9999:9999#环境变量# privileged: trueenvironment:- CHAINCODE_CCID=mycc_1:594f63870f497feb7d3c8d28ceaa35aa1607aad39b28fc3296161f2389069e90- CHAINCODE_ADDRESS=0.0.0.0:9999networks:- basic

启动容器

#启动合约容器
docker-compose -f docker-compose-mycc.yaml up -d

4.合约初始化(如果需要)

peer chaincode invoke -n ${CHAINCODE_NAME} -C ${CHANNEL_NAME} -o orderer.example.com:7050 --tls --cafile $ORDERER_CA --isInit -c '{\"Args\":[\"a\",\"10\"]}'

5.共享外部的合约容器

(1)同组织内其它Peer

需要先安装链码包==(注意: 链码包不要重新打包,会导致package id不一致)==

#install
docker exec cli1.org1.example.com /bin/sh -c "cd ./script; ./cc_install_external.sh 1 mychannel mycc 1 1 true 1 ./chaincode/sacc_external mycc2"#query
docker exec cli1.org1.example.com peer chaincode query -n mycc -c '{"Args":["query","a"]}' -C mychannel

(2)不同组织间的Peer

  1. 需要先安装链码包==(注意: 链码包不要重新打包,会导致package id不一致)==
  2. 每个组织都还需要做 approve

总结

1)使用链码生命周期打包和部署链码(Peer节点无须再安装链码)。

2)运行可执行链码文件作为外部链码服务启动。

3)提交链码定义到通道。

4)Peer通过connection.json中指定信息连接到外部链码服务。

最后,用户可以调用链码,而无须关注该链码如何管理。


往期精彩回顾:
区块链知识系列
密码学系列
零知识证明系列
共识系列
公链调研系列
BTC系列
以太坊系列
EOS系列
Filecoin系列
联盟链系列
Fabric系列
智能合约系列
Token系列

相关内容

热门资讯

我好想再坐一次过山车小学作文... 我好想再坐一次过山车小学作文 篇一过山车是我最喜欢的游乐设施之一。每当我看到它高高地耸立在游乐园中时...
一年级作文生日作文【优选6篇... 一年级作文生日作文 篇一我的生日今天是我的生日,我已经等待这一天很长时间了。一大早,我就迫不及待地跳...
多彩的活动六年级作文700字... 多彩的活动六年级作文700字 篇一奇妙的春游春天是一个充满活力和希望的季节,我们班级决定组织一次奇妙...
远山者,宅之东,落凤山是也(... 远山者,宅之东,落凤山是也 篇一远山者,宅之东,落凤山是也落日余晖洒在窗前,映照着远山的轮廓,宛如一...
小学作文极速风车【优质3篇】 小学作文极速风车 篇一极速风车是一款非常受小学生欢迎的游乐设备。它由一个巨大的圆盘和一根中央轴组成,...
看图写话铲雪作文(推荐6篇) 看图写话铲雪作文 篇一冬天的早晨,大雪纷飞,整个小区都被染上了一片银白色的颜色。小明推开窗户,看着窗...
小松树小学作文(优秀6篇) 小松树小学作文 篇一:我的暑假生活暑假终于来了,我迫不及待地计划着如何度过这个美好的假期。首先,我决...
走进新时代小学作文【优选4篇... 走进新时代小学作文 篇一随着时代的发展,我们迎来了新时代小学。新时代小学是一座现代化的学校,拥有先进...
我的心儿怦怦跳小学生作文【优... 我的心儿怦怦跳小学生作文 篇一我的心儿怦怦跳今天,我要给大家讲一个有关我的心情的故事。故事的主人公是...
走进医院小学作文【优秀3篇】 走进医院小学作文 篇一医院小学是一所特殊的学校,它位于医院内,为住院的患儿提供教育服务。我有幸参观了...
父母的爱小学作文700字【实... 父母的爱小学作文700字 篇一父母的爱父母是孩子一生中最重要的人,他们的爱无处不在。我有一个特别疼爱...
美丽的秋天树叶小学作文【精彩... 美丽的秋天树叶小学作文 篇一秋天来了,大地变得金黄了起来。走在树林里,你会看到树叶一个个像小精灵一样...
买菜小学作文【优质6篇】 买菜小学作文 篇一我喜欢去菜市场买菜我家离菜市场很近,所以每次我都会去买菜。我喜欢去菜市场买菜的原因...
逛书店的作文(最新3篇) 逛书店的作文 篇一逛书店的作文近年来,随着电子书的兴起,逛书店的人似乎越来越少了。然而,对我来说,逛...
心儿怦怦跳小学作文(最新6篇... 心儿怦怦跳小学作文 篇一心儿怦怦跳我是一颗小小的心儿,每天都在孩子们的胸腔中怦怦跳动。当孩子们快乐时...
大力士小学作文(优选6篇) 大力士小学作文 篇一我的偶像我有一个偶像,他就是大力士先生。大力士先生是我们学校的保安,他不仅身手敏...
我的伙伴小学作文【精彩6篇】 我的伙伴小学作文 篇一 我的伙伴小学作文 篇二我的伙伴小学作文 篇三   一天,我在院子里玩耍,无意...
春节联欢晚会小学作文(通用6... 春节联欢晚会小学作文 篇一喜迎新春,迎接春节联欢晚会今年的春节联欢晚会真是精彩纷呈!我和家人一起坐在...
同一个屋檐下作文600字【精... 同一个屋檐下作文600字 篇一家是一个温暖的港湾,是每个人一生中最重要的地方。在同一个屋檐下生活,意...
养兔真让我着迷小学作文(实用... 养兔真让我着迷小学作文 篇一 我家养了一只可爱的小兔子,从那时起,我就对养兔子产生了浓厚的兴趣...