fabric2.3链码对比1.4链码小记

article/2025/10/3 7:04:23

最近实验室的项目要部署到fabric2.0以上版本,之前写的都是1.4的链码,现在看2.0版本的链码还是有些不一样的,主要是链码api改了:

前提:如果想在fabric2.0以上环境中还是想用shim和peerAPI的话:也就是:这里记录一下我们在1.4链码中是需要初始化的,因为我们有些初始化的操作是写在Init方法中的,但是呢在2.0以上版本取消了链码的初始化操作,所以当我们在2.0以上环境中需要延续1.4的Init方法的时候,我们需要在Invoke方法中也把Init方法加进去:实例:

Init方法:

func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {// Get the args from the transaction proposal_, args := stub.GetFunctionAndParameters()if len(args) != 2 {return shim.Error("Incorrect arguments. Expecting a key and a value")}// Set up any variables or assets here by calling stub.PutState()// We store the key and the value on the ledgererr := stub.PutState(args[0], []byte(args[1]))if err != nil {return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0]))}return shim.Success([]byte("ok....."))
}

Invoke方法:

func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {// Extract the function and args from the transaction proposalfn, args := stub.GetFunctionAndParameters()var result stringvar err errorif fn == "set" {result, err = set(stub, args)} else if fn == "get"{ // assume 'get' even if fn is nilresult, err = get(stub, args)} else if fn == "Init"{ // assume 'get' even if fn is nilreturn t.Init(stub)}if err != nil {return shim.Error(err.Error())}// Return the result as success payloadreturn shim.Success([]byte(result))
}

 

这里看到,我们已经把Init方法加入了Invoke函数中了!

在fabric2.3环境运行:

注意一下,2.0链码的-c后面的格式发生了新变化:

-c '{"Args":["PutPublicInfordiy","PublicKey"]}'等价于 //这里默认第一个参数就是函数名,后面才是开始的参数列表
-c '{"function":"PutPublicInfordiy","Args":["PublicKey"]}'//这里很明显,函数名和参数已经隔开了,更加的清晰化。

这两种链格式效果是一样的!可以自己选择用哪种!

下面是fabric2.3提供的新的链码接口:contractapi

下面实例这个链码:

package chaincodeimport ("encoding/json""fmt""github.com/hyperledger/fabric-contract-api-go/contractapi"
)// SmartContract provides functions for managing an Asset
type SmartContract struct {contractapi.Contract
}// Asset describes basic details of what makes up a simple asset
type Asset struct {ID             string `json:"ID"`Color          string `json:"color"`Size           int    `json:"size"`Owner          string `json:"owner"`AppraisedValue int    `json:"appraisedValue"`
}// InitLedger adds a base set of assets to the ledger
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
}// 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)
}// ReadAsset returns the asset stored in the world state with given id.
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
}// UpdateAsset updates an existing asset in the world state with provided parameters.
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)}// overwriting original asset with new assetasset := 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)
}// DeleteAsset deletes an given asset from the world state.
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)
}// AssetExists returns true when asset with given ID exists in world state
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
}// TransferAsset updates the owner field of asset with given id in world state.
func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) error {asset, err := s.ReadAsset(ctx, id)if err != nil {return err}asset.Owner = newOwnerassetJSON, err := json.Marshal(asset)if err != nil {return err}return ctx.GetStub().PutState(id, assetJSON)
}// GetAllAssets returns all assets found in world state
func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*Asset, error) {// range query with empty string for startKey and endKey does an// open-ended query of all assets in the chaincode namespace.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
}

首先这里执行完初始化链码之后:

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":[]}'

这里记住一个模板:

就是peer chiancode invoke ....... -c '{"function":"函数名","Args":[参数]}'

function就是我们链码里的函数名!

2.0的链码是不需要初始化链码的,1.4版本的是需要的,这里2.0的就按照上面的模板就行,注意,参数这里不管链码里传入上面参数,这里都是用字符串格式,比如,int的4也要写成"4"。

注意,如果你想继续用的1.4的链码也可以,将1.4链码原来的包改成这样就可以在2.0环境中继续使用了!

如果你想使用2.0以上版本的链码,需要用的是这个api:

这里注意,2.0的链码,传参数的时候是不能使用args []string的,如果是1.4的链码是可以的。

这里注意,如果想在2.0链码环境中使用如1.4的传入多个参数 args []string的话,可以用这个api:

function, args := ctx.GetStub().GetFunctionAndParameters()

这里注意,这里的function就是Testargs,后面args直接传入4个args参数即可!

根据返回的args,就是之前在1.4环境中的args!

贴上自己写的链码方法demo:

//-c '{"function":"Testargs","Args":["01","fanwen","dayang","man"]}'
//这里注意args后面传入的参数就是args,function是不需要传入的,不然就会报错"err! number is not 4!",这里是和1.4不一样的地方
func (t *mycc) Testargs(ctx contractapi.TransactionContextInterface) string{function, args := ctx.GetStub().GetFunctionAndParameters()//这里的function就是获取了上面的函数名就是Testargsif len(args) != 4 {return "err! number is not 4!"}stu := Student{StuId:   args[0],Name:    args[1],Address: args[2],Sex:     args[3],}assetJSON, err := json.Marshal(stu)if err != nil {return err.Error()}//根据StuId存入账本err = ctx.GetStub().PutState(stu.StuId, assetJSON)if err != nil{return err.Error()}return "you use the function:" + function + " put in state ok!"}

执行效果:

如果在args输入了超过4个参数:

 

就会报错,就是我们在链码里自己写的逻辑判断的错误! 

这里注意,fabric在2.0版本以上的链码中,可以返回任何数据!比如string,int,float64,或者是自定义的结构体或者结构体指针都可以!

注意:传参数的时候,不管传什么参数,在cli端,都是传入的"内容",也就是字符串形式传入的!

如果是查询操作的话,不需要连接orderer结点,也不需要背书策略,直接用以下模板就行:

peer chaincode query -C mychannel -n fan12 -c '{"function":"GetAll","Args":["args"]}'

当然,如果用invoke也可以!看个人习惯。


http://chatgpt.dhexx.cn/article/UQofotWk.shtml

相关文章

Hyperledger Fabric 链码生命周期

目录 一、什么是链码 二、部署链码 2.1 安装和定义链码 2.1.1 打包智能合约 2.1.2 peer节点安装链码 2.1.3 组织批准链码 2.1.4 将链码提交到通道 2.2 升级链码 总结 一、什么是链码 ChainCode(链码)是一个程序,用Go、Node.js或Java编…

matlab freeman链码,对Freeman链码分析的角点检测算法

图像中的角点是图像的重要特征, 具有旋转不变性, 决定了图像形状, 可以降低图像信息的存储效率, 在目标跟踪, 目标检测, 图像匹配, 图像轮廓拟合等领域都有重要的应用价值. 近几十年来, 国内外学者提出的图像角点检测算法[, 各有各的优缺点, 大致可分为三大类: 基于灰度强度的角…

Fabric链码升级

一、修改链码,上传 二、打包链码 1、设置组织1环境变量 export PATH${PWD}/../bin:$PATH export FABRIC_CFG_PATH$PWD/../config/ # Environment variables for Org1 export CORE_PEER_TLS_ENABLEDtrue export CORE_PEER_LOCALMSPID"Org1MSP" export C…

图像特征-链码(Freeman code)

目录 引言链码编程实现轮廓提取链码计算 总结 引言 本文介绍了图像的形状特征–链码,以及通过python和opencv实现的链码提取方法。所有opencv的版本为3.4.2,已经移除了直接返回链码的选项。 链码 链码用于描述图像的形状特征,首先需要获得图像…

Java知识扫盲——向上转型(类向上转型、接口向上转型)以及向上转型的优势、灵活运用

目录 普通类示例 抽象类的向上转型, 接口向上转型: 作用:使用向上转型可以,提高代码的简洁性、灵活性、适用性。 普通类示例 父类: package 普通类向上转型;public class Father {public int age 48;public void…

java 向上转换_java的向上转型总结

在《think of java》中对向上转型有着如下的描述 看完之后很蒙圈,所以自己在网上找了一些描述,并自己做了简单的总结 简单的例子 class A{ public void A1(){ System.out.println("父类方法1"); } public void A2(){ System.out.println("…

JAVA中多态以及向上转型向下转型、重写的讲解

重写 重写(override):也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程 进行重新编写, 注意!!!返回值和形参都不能改变。 重写的好处在于子类可以根据需要&#x…

JAVA中的向上转型和向下转型

一、向上转型和向下转型 向上转型和向下转型是在JAVA继承操作中用到的东西,在讲到转型之前我们需要认识到继承过程中的对象类型转换,这种转换有两个特点: 1.这是继承过程中发生的操作 2.新类是现有类的一种类型。这种说法主要是因为现有类的方…

java转型 内存_Java向上转型及内存分析

学习设计模式的时候,发现很多模式都用到了向上转型(eg. 工厂方法)。而我对向上转型(upcasting)的机制并不十分熟悉。这篇文章将深入分析向上转型的机制、内存分析。 概念 先从几个基本概念开始: 1. Java中的引用类型(reference type) Java中的数据类型分…

java向上转型_Java向上转型和向下转型

一、向上转型 简单的说向.上转型就是:将-一个子类类型的对象赋值给- -个父类类型的变量, 基本的实现语法: 父类类型变量new 子 类类型(); DEMO:向上转型 发现了可以使用父类类型的变量调用子类覆写了父类的方法,但是为什么不调用Worker的say()方法呢?原…

C++ 向上转型

在 C 中经常会发生数据类型的转换,例如将 int 类型的数据赋值给 float 类型的变量时,编译器会先把 int 类型的数据转换为 float 类型再赋值;反过来,float 类型的数据在经过类型转换后也可以赋值给 int 类型的变量。 数据类型转换…

java 对象向上转型_JAVA对象向上转型和向下转型

今天做了一个测试的题目,发现自己还是很多问题没有静下心来做。很多问题是可以自己解决的但是自己一是没有读清题意,二是自己心里太急躁了。所以这个要自己应以为鉴! 对象的转型问题其实并不复杂,我们记住一句话:“父类…

java 向上转型_Java 转型问题(向上转型和向下转型)

Java 转型问题其实并不复杂,只要记住一句话:父类引用指向子类对象。 什么叫父类引用指向子类对象? 从 2 个名词开始说起:向上转型(upcasting) 、向下转型(downcasting)。 举个例子:有2个类,Father 是父类&a…

java向上转型_Java向上转型

向上类型转换: 1.可以通过父类引用变量调用的方法是子类覆盖或继承父类的方法。 2.父类引用变量无法调用子类新增成员变量和新增成员方法。 举个例子 public classAnimal { public voidsleep() { System.out.println("Animal sleep"); } public voidjump(…

向上转型与向下转型(超详细)

本文利用代码例子解释向上转型与向下转型,文末有举例整合原代码。 首先,我们要知道:转型发生在继承后,也就是父类子类存在的前提下。其次,我们要清楚:向下转型的前提是已经发生了向上转型,向下转…

java向上转型

我们知道按照现有类的类型来创建新类的方式为继承。 换句话说 “新类是现有类的一种类型” 因为继承可以确保父类中所有的方法在子类中也同样有效,所以能够向父类发送的所有信息也同样可以向子类发送。 这儿有一个例子: public class Test {public sta…

类中的向上转型与向下转型详解

我们的类与类之间会存在继承关系,子类继承父类,一个父类可以有多个子类,例如Animal类就可以有Cat子类,Dog子类,等等。那么我们在运用的时候根据不同的场景会出现向上转型和向下转型的情况。 一、向上转型 1、Animal a…

【基础知识】向上转型和向下转型

向上转型和向下转型的利弊 一、向上转型 好处:隐藏了子类型,提高了代码的扩展性。 坏处:只能使用父类的功能,不能使用子类特有功能,功能被限定。 使用场景:不需要面对子类型,通过提高扩展性&am…

Java向上转型的作用(有详细代码介绍)

今天看到一道Java的练习题,题目如下 当时对于主函数中 Car car (Car) new Benz(); 不是很理解,也并不知道有什么意义,因为如果仅仅写Car car new Benz(); 程序运行结果是一样的。 在经过阅读书籍和查看别的博主写的关于向上向下转型的…

MATLAB三维数组转为二维数组(时间序列分析中很有用)

在MATLAB中三维数组转二维的方法 一、写该程序的初衷 在处理时间序列遥感数据的时候,我之前的做法是: 将时间序列数据读取为三维矩阵;将该数据保存为BIP格式;在每个像元上进行循环,取出其第三维(比如有46…