在 m2 Mac 上搭建了基本的 fabric 环境之后,现在运行一个实际的项目。原项目是一个基于 fabric 的交易溯源系统,使用的 fabric 1.4.2 节点,移植到 mac 上遇到了很多问题,记录一下
原项目地址:https://gitee.com/real__cool/fabdeal

1 更换适合自己操作系统和架构的节点镜像以及binary工具

注意节点镜像和 binary 工具需要是统一的版本的,我选择的是 2.5.4 版本,包括 peer、orderer、fabric-tools、二进制工具包。工具包 hyperledger-fabric-linux-arm64-2.5.4 需要在官方 GitHub 中下载对应操作系统和架构的,docker 镜像只需要选择好版本,拉取镜像时会自动根据操作系统以及架构拉取正确的镜像。

image-20240131115158235

2 创建通道出现问题 – 根据版本修改configtx.yaml

出现问题的命令:

configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./config/genesis.block -channelID firstchannel 

参考这一篇博客:link,但需要根据自己所使用的 fabric 版本来修改,因为每个版本的这个文件的格式要求是不同的,可以参考对应的 fabric 官方的 fabric-samples 中的 configtx.yaml 来进行更改。在更改中遇到的错误如下(看懂 configtx.yaml 后应该就不会遇到这么多错误,其实都是因为配置有各种错误)

2.1 配置文件中的对象拥有无效的 key

2024-01-29 09:32:30.370 UTC 0002 PANI [common.tools.configtxgen.localconfig] Load -> Error loading config from config cache: Error unmarshalling config into struct: 2 error(s) decoding:
* 'Application.Organizations[0]' has invalid keys: Capabilities
* 'Orderer.Organizations[0]' has invalid keys: Capabilities

Application.Organizations[0]Orderer.Organizations[0]中找到了不应存在的Capabilities键。这通常意味着Capabilities定义可能被放置在了错误的位置,或者格式不正确。

2.2 orderer 节点意外退出

Error: failed to create deliver client for orderer: orderer client failed to connect to orderer.carunion.com:7050: failed to create new connection: context deadline exceeded

这个错误说明无法正常连接到 orderer 节点,可以查看 docker 容器的状态

image-20240129200830614

此时可以使用命令docker logs dockerName查看容器日志

image-20240129201201628

根据日志信息,orderer.carunion.com 容器退出的原因是对引导块的验证失败。错误信息指出在没有先启用orderer支持的情况下,无法启用通道功能。很有可能就是 OrdererCapabilities 相关的配置出现了问题,结果发现是 profiles 中压根就没配置 orderer 的 OrdererCapabilities

3 安装链码出现问题

出现问题的命令:

docker exec cli bash -c "$BENZPeer0Cli peer chaincode install -n fabric-realty -v 1.0.0 -l golang -p chaincode"

3.1 找不到 chaincode 包 / GOPATH 问题

image-20240129203326771

  • 检查映射:确认docker-compose.ymal中的- ./../chaincode:/opt/gopath/src/chaincode是否正确映射了宿主机上的链码目录到容器内的/opt/gopath/src/chaincode
  • 进入CLI容器:使用docker exec -it cli bash进入cli容器。
  • 检查链码路径:在cli容器内,运行ls /opt/gopath/src/chaincode来查看链码文件是否存在。
  • 验证GOPATH:在cli容器内,运行echo $GOPATH确认GOPATH是否正确设置为/opt/gopath
image-20240129205504743

发现 GOPATH 没有设置,因此在 docker-compose 中的 environment 中进行设置

image-20240129205647110

3.2 依赖包的问题(踩了很多坑,结论是直接使用 vendor 打包,尽量不要对原本的依赖包进行改动)

============== 以下是踩坑过程 ================

这个项目原本是用的 1.4.2 版本的 fabric,由于需要在 Linux/arm 上运行换成了较新的 2.5.4 ,这可能导致依赖包出现各种问题

  1. 升级 shim/pb 两个依赖包的版本
  • image-20240129205308781

    先根据博客 linkgithub.com/hyperledger/fabric/core/chaincode/shim 换成了 github.com/hyperledger/fabric-chaincode-go/shim ,结果 go mod tidy 出现了问题,大概是说 pb 库有问题

    再根据 ChatGPT 的一些引导:

  • 将 shim 和 pb 都换成新更新的版本,注意所有的 .go 文件只要 import 了这两个包都要换掉,然后 go mod tidy,然后尝试 install ,还是出现类似的错误,表明在尝试获取链码部署规范时,依赖解析过程中遇到了问题,新版本的 github.com/hyperledger/fabric-chaincode-go/shim 包依然不完整

  • image-20240129221143621

  1. 手动使用 go get 获取校验有问题的 shim 包
  • 根据 stackoverflow 中的一个帖子 link ,执行安装之前,先手动在 cli 容器中 go get 解析出现错误的 shim 包,为了执行 go get 语句,首先还需要在容器中安装 git,这个过程可以: 1)自己在官方的 fabric-tool 镜像的基础上打包一个新的镜像一次性完成,也可以 2)使用命令行每次启动 cli 容器后,install 链码之前手动安装。为了方便选择了第二种方法:

    docker exec cli bash -c "go get github.com/hyperledger/fabric-chaincode-go/shim"
    docker exec cli bash -c "$BENZPeer0Cli peer chaincode install -n fabric-realty -v 1.0.0 -l golang -p chaincode"
    docker exec cli bash -c "$TESLAPeer0Cli peer chaincode install -n fabric-realty -v 1.0.0 -l golang -p chaincode"
    

    这样执行之后能够完整验证 shim 包,但是出现了另一个问题:

    Error: install failed with status: 500 - chaincode installed to peer but could not build chaincode: docker build failed: docker image build failed: docker build failed: Error returned from build: 1 "chaincode/input/src/google.golang.org/protobuf/reflect/protodesc/editions.go:24:12: pattern editions_defaults.binpb: no matching files found"
    

    显示 install 过程成功了,但是在 build 时出现了问题,protobuf 包中有一个文件无法找到。但实际上我通过访问给出的这个网址是可以发现 editions_defaults.binpb 文件是存在的,之后尝试了更换不同版本的 go,也都有这个问题。

    后来发现可能是因为先执行了 go get 命令,这会对项目的依赖版本造成影响……总之就是由于对 go 不是很熟悉,绕了很多弯路……

============== 回到正轨 ==============

  • 使用 vendor

综合来说目前的问题在于

a) 目前使用的 fabric 2.x 版本,但链码是原先 1.x 版本使用的依赖包

b) 只对一些依赖包进行对应的升级会导致整个依赖包环境出现问题,如远程仓库拉取、验证时的问题

因此 go mod vendor 可以解决这个问题:

当使用 Go Modules 时,项目会有一个 go.mod 文件,这个文件列出了项目所依赖的其他模块及其版本。还可能有一个 go.sum 文件,它包含了依赖的模块的特定哈希值,用于确保这些依赖的一致性和完整性。

这时候 go mod vendor 命令就发挥了作用:

  1. 创建 vendor 目录:当你在项目根目录执行 go mod vendor 命令时,Go 将会根据 go.mod 文件中定义的依赖,将这些依赖的精确版本复制到项目的 vendor 目录中。这包括依赖的所有必要文件,比如 Go 源码文件。
  2. 隔离依赖:这个 vendor 目录允许你的项目隔离其依赖,使得项目不再依赖于全局的 Go 模块缓存或者依赖的远程仓库。这对于确保项目的依赖版本一致性和构建的可复现性是非常有用的。
  3. 构建时使用 vendor 目录:当你在有 vendor 目录的项目中构建 Go 程序时,Go 构建系统会优先使用 vendor 目录中的依赖,而不是去全局的 Go 模块缓存或者远程仓库中查找这些依赖。

它可以将整个项目的依赖复制到本地,而不需要依赖远程仓库,这样就可以完美地解决我们的问题:使用老版本的一套(原先的 go.mod 完全保留),用 vendor 直接先将完整的依赖复制到本地,然后由于是将整个 chaincode 目录注入到了 cli 容器中,也就包括了 vendor 目录。也就是最后使用的还是老版本的 shim / pb 包,实际上在 fabric 2.x 的节点上也是可以运行的,可能因为 peer 节点安装链码后,实例化、执行链码都是通过在 peer 节点上创建一个新的容器来运行的,这个过程也是隔离的,因此实际上链码的版本与 peer 节点的版本无关,只要链码自己能编译通,在 policy 允许的情况下就可以放在任何 peer 节点上运行(猜测)

具体的做法,在 chaiancode 目录下:

go mod vnedor
image-20240130190637967

此时再安装链码,就可以成功安装:

但是最后不会使用这个命令安装链码,会引入链码生命周期,先打包再安装,详见下一节

4 实例化、执行链码的问题 — 新版本引入新的链码生命周期

fabric 1.x 版本中,安装、实例化链码的指令:

########### fabric 1.x ##############
# 安装链码
docker exec cli bash -c "$BENZPeer0Cli peer chaincode install -n fabric-realty -v 1.0.0 -l golang -p chaincode"
docker exec cli bash -c "$TESLAPeer0Cli peer chaincode install -n fabric-realty -v 1.0.0 -l golang -p chaincode"
# 实例化链码
docker exec cli bash -c "$BENZPeer0Cli peer chaincode instantiate -o orderer.carunion.com:7050 -C appchannel -n fabric-realty -l golang -v 1.0.0 -c '{\"Args\":[\"init\"]}' -P \"AND ('BENZMSP.member','TESLAMSP.member')\""

上一步的问题解决之后可以成功执行安装链码的指令,然后执行实例化指令时出现以下问题:

image-20240130191642609

这个错误表明尝试使用旧的链码生命周期命令(peer chaincode instantiate)在已经迁移到新的链码生命周期的通道上部署链码。从 Hyperledger Fabric 2.0 开始,引入了新的链码生命周期,旨在提供更细粒度的控制和更大的灵活性

fabric 2.0 版本中使用新的生命周期命令处理链码的安装、部署、执行应该是如下的步骤:

########### fabric 2.x ##############
# 1. cli 容器上打包链码
docker exec cli peer lifecycle chaincode package fabric-realty.tar.gz --path /opt/gopath/src/chaincode/fabric-realty --lang golang --label fabric-realty_1.0.0
# 2. 用 cli 在 peer 上安装链码
docker exec cli bash -c "$BENZPeer0Cli peer lifecycle chaincode install fabric-realty.tar.gz"
docker exec cli bash -c "$TESLAPeer0Cli peer lifecycle chaincode install fabric-realty.tar.gz"
# 3. 获取链码包的 package-id
docker exec cli bash -c "$BENZPeer0Cli peer lifecycle chaincode queryinstalled"
# 4. 每个批准链码(根据 channel policy)(填入上一步得到的 package-id)
docker exec cli bash -c "$BENZPeer0Cli peer lifecycle chaincode approveformyorg --channelID appchannel --name fabric-realty --version 1.0.0 --package-id <package-id> --sequence 1 --waitForEvent"
docker exec cli bash -c "$TESLAPeer0Cli peer lifecycle chaincode approveformyorg --channelID appchannel --name fabric-realty --version 1.0.0 --package-id <package-id> --sequence 1 --waitForEvent"
# 5. 提交链码定义
docker exec cli bash -c "$BENZPeer0Cli peer lifecycle chaincode commit -o orderer.carunion.com:7050 --channelID appchannel --name fabric-realty --version 1.0.0 --sequence 1 --waitForEvent --peerAddresses peer0.tesla.com:7051 --peerAddresses peer0.benz.com:7051"

需要注意以下三个点:

  1. 满足具体的背书策略

依照 configtx.yaml 中定义的背书策略,比如该项目Application 部分,定义了两个关键的背书策略,LifecycleEndorsementEndorsement,都设置为 "MAJORITY Endorsement"。这意味着对于链码的生命周期操作(如安装、批准、提交)以及链码的执行,需要大多数组织的背书。该项目配置中包含了三个组织:CARUNION、BENZ、TESLA,对于链码的提交操作,至少需要其中两个组织。

image-20240130193507904
  1. 提交链码的命令的形式(记得追加 --peerAddresses)

如果不追加 --peerAddresses 的话,会出现以下的错误,表明由于没有满足背书策略而导致提交链码失败

image-20240130194204889

  • 查询链码定义的准备状态:
# 查询准备状态
docker exec cli bash -c "$BENZPeer0Cli peer lifecycle chaincode checkcommitreadiness --channelID appchannel --name fabric-realty --version 1.0.0 --sequence 1 --output json"

可以得到结果,两个组织都已经批准了,按道理说是满足了背书策略的

image-20240130194523347
  • 查询 peer 节点的日志
docker logs peer0.benz.com

image-20240130194823725

还是说只有一个背书,而需要两个背书

解决这个问题需要在提交链码时加上所有的组织的节点

  1. instantiate --> invoke

注意,Fabric 2.x 中,链码的生命周期管理方式发生了变化,不再使用 peer chaincode instantiate 命令来初始化链码,instantiate 步骤被替换为 commit 步骤,链码的初始化是作为第一次调用 peer chaincode invoke 的一部分完成的。比如在 commit 成功以后使用 instantiate 命令,会出现如下的错误

image-20240130200246859

由于废弃了 peer chaincode instantiate 命令,链码的初始化需要在 Invoke 方法中自行处理。这通常通过在 Invoke 方法中检查特定的状态或标志来确定是否执行初始化逻辑,并在首次调用时执行这些逻辑。具体需要更改对应的链码逻辑

5 fabric-explorer 的问题

fabric 官方的浏览器的安装,实际上也是镜像的问题,由于早期的 docker hub 的官方版本 hyperledger/explorer 以及 hyperledger/explorer-db 都没有 arm 架构的,但是 GitHub 中官方维护的版本是有 arm 架构的镜像的

image-20240130201848453

按照官方的流程即可搭建 fabric 的浏览器

网址:https://github.com/hyperledger-labs/blockchain-explorer

参考博客:https://blog.csdn.net/weixin_62159253/article/details/131669771

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐