Fabric:链码的部署及执行

Hyperledger Fabric:V2.5.4

写在最前

使用Fabric搭建自定义网络参考:https://blog.csdn.net/yeshang_lady/article/details/134113296
使用Fabric创建应用通道参考:https://blog.csdn.net/yeshang_lady/article/details/134668458
接下来将介绍如何在自定义的网络和通道上部署以及执行链码。

1 链码部署

Fabric中链码的部署一般包括以下步骤:编写链码->打包链码->安装链码->实例化链码->部署链码等。下面按照此步骤依次介绍。

1.1 编写链码

创建好网络和应用通道之后回到finance_network目录下创建链码目录usersChaincode。接着在链码目录usersChaincode下创建链码文件asset-transfer.go文件,其代码如下(这个文件中的代码是用test-network中的链码示例来构造的):

package mainimport ("encoding/json""fmt""log""github.com/hyperledger/fabric-contract-api-go/contractapi"
)
type SmartContract struct {contractapi.Contract
}type Asset struct {AppraisedValue int    `json:"AppraisedValue"`Color          string `json:"Color"`ID             string `json:"ID"`Owner          string `json:"Owner"`Size           int    `json:"Size"`
}
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {assets := []Asset{{ID: "asset1", Color: "blue", Size: 5, Owner: "Tomoko", AppraisedValue: 300},{ID: "asset2", Color: "red", Size: 5, Owner: "Brad", AppraisedValue: 400},{ID: "asset3", Color: "green", Size: 10, Owner: "Jin Soo", AppraisedValue: 500},{ID: "asset4", Color: "yellow", Size: 10, Owner: "Max", AppraisedValue: 600},{ID: "asset5", Color: "black", Size: 15, Owner: "Adriana", AppraisedValue: 700},{ID: "asset6", Color: "white", Size: 15, Owner: "Michel", AppraisedValue: 800},}for _, asset := range assets {assetJSON, err := json.Marshal(asset)if err != nil {return err}err = ctx.GetStub().PutState(asset.ID, assetJSON)if err != nil {return fmt.Errorf("failed to put to world state. %v", err)}}return nil
}
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)
}
func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) {assetJSON, err := ctx.GetStub().GetState(id)if err != nil {return nil, fmt.Errorf("failed to read from world state: %v", err)}if assetJSON == nil {return nil, fmt.Errorf("the asset %s does not exist", id)}var asset Asseterr = json.Unmarshal(assetJSON, &asset)if err != nil {return nil, err}return &asset, nil
}func (s *SmartContract) UpdateAsset(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 does not exist", 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)
}
func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, id string) error {exists, err := s.AssetExists(ctx, id)if err != nil {return err}if !exists {return fmt.Errorf("the asset %s does not exist", id)}return ctx.GetStub().DelState(id)
}
func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) {assetJSON, err := ctx.GetStub().GetState(id)if err != nil {return false, fmt.Errorf("failed to read from world state: %v", err)}return assetJSON != nil, nil
}
func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) (string, error) {asset, err := s.ReadAsset(ctx, id)if err != nil {return "", err}oldOwner := asset.Ownerasset.Owner = newOwnerassetJSON, err := json.Marshal(asset)if err != nil {return "", err}err = ctx.GetStub().PutState(id, assetJSON)if err != nil {return "", err}return oldOwner, nil
}
func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*Asset, error) {resultsIterator, err := ctx.GetStub().GetStateByRange("", "")if err != nil {return nil, err}defer resultsIterator.Close()var assets []*Assetfor resultsIterator.HasNext() {queryResponse, err := resultsIterator.Next()if err != nil {return nil, err}var asset Asseterr = json.Unmarshal(queryResponse.Value, &asset)if err != nil {return nil, err}assets = append(assets, &asset)}return assets, nil
}
func main() {assetChaincode, err := contractapi.NewChaincode(&SmartContract{})if err != nil {log.Panicf("Error creating asset-transfer-basic chaincode: %v", err)}if err := assetChaincode.Start(); err != nil {log.Panicf("Error starting asset-transfer-basic chaincode: %v", err)}
}

然后在该链码目录下使用go mod等命令初始化该模块。具体包括以下:

#先进入usersChaincode目录下
go mod init
sudo chmod -R 777 go.mod
#下载链码中的需要的模块信息
go get github.com/hyperledger/fabric-contract-api-go/contractapi
sudo chmod -R 777 go.sum
#将项目的依赖库复制都vendor目录中去
GO111MODULE=on go mod vendor

Tips:以下几点需要注意

  • 首先,生成go.mod文件的时候自动指定了go语言的版本为当前环境中安装的go语言版本号。比如go 1.21.3。但go.mod中的go语言版本号应该由两个数字组成,用点号分隔,例如1.13、1.14等。
  • 其次,go.mod文件中的go语言版本还要考虑此处现在的第三方包兼容的版本。
  • 再次,go.mod文件修改后要运行go mod tidy命令重新生成go.sum文件。
  • 最后,如果在安装链码时遇到以下问题invalid go version 1.21.3: must match format 1.23,则需要返回修改go.mod文件。这里要将go.mod文件中的go语言版本改为go 1.17(参考fabric-samples),然后重新生成go.sum文件,还要重新打包链码。为了方便,最好提前修改go.mod文件。在这里插入图片描述
  • 另外,如果不执行GO111MODULE=on go mod vendor命令,那么后续在安装链码会遇到超时问题:Error: chaincode install failed with status: 500 ... error sending: timeout expired while executing transaction
    在这里插入图片描述

1.2 打包链码

打包链码是指将链码文件打包成一个tar格式的文件。可以使peer lifecycle chaincode package命令。其具体执行命令如下:

#先使用cd命令跳转到finance_network目录下
export FABRIC_CFG_PATH=$PWD/config
#basic即为链码的名字
peer lifecycle chaincode package basic.tar.gz --path usersChaincode --lang "golang" --label basic_1.0.1

其中basic为链码名称。代码执行结束将会在finance_network目录下看到basic.tar.gz文件。
Tips:peer lifecycle chaincode package命令只是将链码打包成一个tar格式的文件,这个过程不需要与具体的peer节点交互,因此这个命令的执行不需要事先绑定节点。

1.3 安装链码

安装链码主要负责将将链码部署到每个需要执行链码的Peer节点上。通过调用Peer节点的peer lifecycle chaincode install命令将链码安装到Peer节点的本地文件系统。下面仅以peer0.org1.finance.com节点说明链码安装过程。具体如下:

#先设置环境变量将peer CLI绑定到peer0.org1.finance.com节点上
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=$PWD/organizations/peerOrganizations/org1.finance.com/peers/peer0.org1.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=$PWD/organizations/peerOrganizations/org1.finance.com/users/Admin@org1.finance.com/msp
export CORE_PEER_ADDRESS=localhost:7051
export FABRIC_CFG_PATH=$PWD/config
# 安装链码
peer lifecycle chaincode install basic.tar.gz

结果如下:
在这里插入图片描述
可以使用peer lifecycle chaincode queryinstalled查看peer节点已经安装的链码。具体如下:
在这里插入图片描述
另外,也将该链码安装在peer0.org2.finance.com上,安装步骤这里省略。Tips: 虽然在fabric_test网络中创建了3个peer节点,但链码不一定需要在所有peer节点上都安装。

1.4 实例化链码

  • 使用peer lifecycle chaincode approveformyorg命令完成组织对链码部署的批准。假设这里需要两个组织都同意链码的部署。这里以Org1为例进行说明,其具体代码如下:
export ORDERER_CA=$PWD/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/msp/tlscacerts/tlsca.finance.com-cert.pem
export PACKAGE_ID=$(peer lifecycle chaincode calculatepackageid basic.tar.gz)
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.finance.com --tls --cafile "$ORDERER_CA" --channelID channel1 --name basic --version 1.0 --sequence 1 --package-id ${PACKAGE_ID} 

其结果如下:
在这里插入图片描述

  • 使用peer lifecycle chaincode checkcommitreadiness命令检查链码定义的提交准备情况。其具体命令如下:
peer lifecycle chaincode checkcommitreadiness --channelID channel1 --name basic --version 1.0 --sequence 1 

其执行结果如下:
在这里插入图片描述

  • 使用peer lifecycle chaincode commit命令提交链码定义的交易。其命令如下:
peer lifecycle chaincode commit -o localhost:7050 --orderdeTLSHostnameOverride orderer.finance.com --tls --cafile "$ORDERER_CA" --channelID channel1 --name basic --version 1.0 --sequence 1  --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.finance.com/peers/peer0.org1.finance.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.finance.com/peers/peer0.org2.finance.com/tls/ca.crt"

其代码执行结果如下:
在这里插入图片描述
可以使用下述代码判断提交是否成功。具体如下:

peer lifecycly chaincode querycommitted -C channel1 -n basic

其执行结果如下:
在这里插入图片描述
至此链码的实例化已经完成。可以使用docker ps -a看到链码的容器信息。具体如下:
在这里插入图片描述

2 链码执行

关于链码的执行,这里只介绍两个命令。

  • peer chaincode invoke:可以使链码执行自定义的业务逻辑,并且可以改变区块链账本中的状态。举例如下:
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.finance.com --tls --cafile "${PWD}/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/msp/tlscacerts/tlsca.finance.com-cert.pem" -C channel1 -n basic --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.finance.com/peers/peer0.org1.finance.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.finance.com/peers/peer0.org2.finance.com/tls/ca.crt" -c '{"Args":["InitLedger"]}'

其执行结果如下:
在这里插入图片描述

  • peer chaincode query: 可以从区块链账本中获取数据,而不会对账本进行任何的状态更新。
peer chaincode query -C channel -n basic -c '{"Args":["GetAllAssets

其执行结果如下:
在这里插入图片描述
为了说明peer chaincode query没有对账本进行修改, 执行以下两条命令,具体如下:

#删除id为asset6的记录
peer chaincode query -C channel1 -n basic -c '{"Args":["DeleteAsset","asset6"]}'
#读取id为asset6的记录
peer chaincode query -C channel1 -n basic -c '{"Args":["ReadAsset","asset6"]}'

其结果如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/202336.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ELK的日志解决方案

1. 安装和配置ELK 确保你已经安装了Elasticsearch、Logstash和Kibana。你可以按照官方文档或使用包管理工具进行安装。 Elasticsearch官方配置文档 Kibana官方配置文档 2. Logstash配置 拉取logstash 创建容器 docker run -it \ --name logstash \ --privileged \ -p 5044:5…

Ubuntu-Sim2Real环境配置(下)

cd ICRA-RM-Sim2Real/docker_client/ ./exec_client.sh cd ~ roslaunch rtab_navigation rtab_navigation.launch 执行上面代码的时候后台一直刷新 cd ICRA-RM-Sim2Real/docker_client/ ./exec_client.sh cd ~ roslaunch carto_navigation navigation.launch 1.Usage 执行该…

【微服务】spring循环依赖深度解析

目录 一、循环依赖概述 1.2 spring中的循环依赖 二、循环依赖问题模拟 2.1 循环依赖代码演示 2.2 问题分析与解决 2.2.1 使用反射中间容器 三、spring循环依赖问题解析 3.1 spring中的依赖注入 3.1.1 field属性注入 3.1.2 setter方法注入 3.1.3 构造器注入 3.2 spri…

树莓派学习:wiringPi+硬件pwm+舵机

目录 目的 代码 只有io口1是支持pwm,其他要软件pwm 编译 运行 目的 黄色pwm,红色正极,棕色负极 让sg90舵机转动,就需要一个20ms的周期pwm,其中高电平在0.5-2.5ms之间 转动角度 高电平在一个周期内的时间0 …

ElasticSearch篇---第四篇

系列文章目录 文章目录 系列文章目录前言一、elasticsearch 是如何实现 master 选举的?二、elasticsearch 索引数据多了怎么办,如何调优,部署?三、说说你们公司 es 的集群架构,索引数据大小,分片有多少?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽…

集成开发环境 PyCharm 的安装【侯小啾python基础领航计划 系列(二)】

集成开发环境PyCharm的安装【侯小啾python基础领航计划 系列(二)】 大家好,我是博主侯小啾, 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔…

LeetCode Hot100 207.课程表

题目: 你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。 在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习…

掌握大型语言模型(LLM)技术:推理优化

原文链接:Mastering LLM Techniques: Inference Optimization | NVIDIA Technical Blog 大模型相关技术文章已整理到Github仓库,欢迎start! 堆叠Transformer层以创建大型模型可以获得更好的准确性、few-shot学习能力,甚至在各种语言任务中具有…

关键活动——拓扑排序

假定一个工程项目由一组子任务构成,子任务之间有的可以并行执行,有的必须在完成了其它一些子任务后才能执行。“任务调度”包括一组子任务、以及每个子任务可以执行所依赖的子任务集。 比如完成一个专业的所有课程学习和毕业设计可以看成一个本科生要完成…

Kafka 的特点和优势

Apache Kafka 作为一款分布式流处理平台,以其独特的特点和卓越的优势成为实时数据处理领域的瑰宝。本文将深入研究 Kafka 的各项特点和优势,并通过详实的示例代码展示其在不同场景下的强大应用。 高吞吐量和水平扩展 Kafka 的设计注重高吞吐量和水平扩…

Python-炸弹人【附完整源码】

炸弹人 炸弹人是童年的一款经典电子游戏,玩家控制一个类似"炸弹人"的角色,这个角色可以放置炸弹,并在指定的时间内引爆它们消灭敌人以达到目标,此游戏共设有两节关卡,代码如下: 运行效果&#x…

python将时间戳转换为时间

python将时间戳转换为时间 import datetime timestamp 1701862813779 # 将时间戳转换为秒(因为Python的timestamp通常是以秒为单位的) timestamp_seconds timestamp / 1000 # 将时间戳转换为UTC时间 utc_time datetime.datetime.utcfromti…

[原创][5]探究C#多线程开发细节-利用AutoResetEvent类解决多线程循环轮询假同步的问题.

[简介] 常用网名: 猪头三 出生日期: 1981.XX.XX QQ联系: 643439947 个人网站: 80x86汇编小站 https://www.x86asm.org 编程生涯: 2001年~至今[共22年] 职业生涯: 20年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、D…

【昇腾CANN技术月刊】2023.11-Ascend C在线课程上新;CANN 7.0大模型推理部署技术解密;特邀名校老师面对面分享Ascend C开发经验

【Ascend C】昇腾Ascend C算子开发入门课程,新手零基础入门 摘要:本课程是Ascend C算子开发的初级教程,通过课程讲解及样例实操,帮助你学习如何使用Ascend C开发矢量算子。 1、了解并行计算架构、并行计算方法等基本概念 2、理解…

空间金字塔池化(SPP,Spatial Pyramid Pooling)系列

空间金字塔池化的作用是解决输入图片大小不一造成的缺陷,同时在目标识别中增加了精度。空间金字塔池化可以使得任意大小的特征图都能够转换成固定大小的特征向量,下面针对一些典型的空间金字塔进行盘点。 部分图片来自blog:空间金字塔池化改进 SPP / SP…

优雅处理MyBatis与Apollo集成中的配置加载

⭐️前言 MyBatis作为一种优秀的持久层框架,在使用MyBatis的过程中,我们经常需要从配置文件中读取一些参数,以便在mapper文件中使用。本文将介绍在不使用传参的情况下,如何从Apollo配置中读取这些参数,以及在mapper文…

SD-WAN异地组网提升多元企业网络体验

SD-WAN(软件定义广域网)异地组网方案是一种灵活、可靠且高效的解决方案,能够满足许多企业的组网需求。在这个全球化和数字化快速发展的时代,越来越多的企业开始关注网络连接的稳定性,而SD-WAN因其卓越的网络连接体验&a…

每天一点python——day88

#每天一点Python——88 #编程两大思想【面向过程与面向对象】 #如图: 面向过程的线性思维: 类似于做菜一步步的来,先怎么样怎么样,再怎么样 如果不一步步的来,例如先炒菜再点火,这样是做不好的 面向对象&a…

IntelliJ IDE 插件开发 | (二)UI 界面与数据持久化

系列文章 IntelliJ IDE 插件开发 |(一)快速入门 前言 在上一篇文章中介绍了在IDEA下开发、运行和安装插件的基本步骤,因此创建项目等基础步骤不再赘述,本文则开始介绍如何进行 UI 界面的开发以及相关数据的持久化存储&#xff…

安全测试工具,自动发现网站所有URL!

作为一个安全测试人员来说,首先要拿到网站所有url,然后根据拿到的url进行渗透测试进行漏洞挖掘。本文给大家介绍的是如何拿到一个网站所有的url。 深度爬取层级控制 现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很…