Fabric框架的学习-4-链码与背书策略
六. 智能合约
6.1 Golang版本的ChainCode的代码结构
链代码的包名的指定
// xxx.go package main // main不能改
必须要引入的包
// go get github.com/hyperledger/fabric/core/chaincode/shim import {// 客户端需要和Fabric框架通信"github.com/hyperledger/fabric/core/chaincode/shim" //通信的接口就需要shimpb "github.com/hyperledger/fabric/protos/peer" //pb 起别名 peer=>客户端请求响应结果需要的包 }
链码的书写要求
//自定义一个结构体 -类, 实现一些接口函数 type Test struct { //名字自定义// 空着即可 } func (t *Test) Init(stub ChaincodeStubInterface) pb.Response {} func (t *Test) Invoke(stub ChaincodeStubInterface) pb.Response {}
链码API查询
https://pkg.go.dev/github.com/hyperledger/fabric/core/chaincode/shim // 其中必须实现的接口 type Chaincode interface {// Init is called during Instantiate transaction after the chaincode container// has been established for the first time, allowing the chaincode to// initialize its internal dataInit(stub ChaincodeStubInterface) pb.Response// Invoke is called to update or query the ledger in a proposal transaction.// Updated state variables are not committed to the ledger until the// transaction is committed.Invoke(stub ChaincodeStubInterface) pb.Response }
6.2 shim包的核心方法
6.2.1 Response结构
type Response struct {// A status code that should follow the HTTP status codes. 状态Status int32 `protobuf:"varint,1,opt,name=status,proto3" json:"status,omitempty"`// A message associated with the response code.Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`// A payload that can be used to include metadata with this response.// 状态描述Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"`XXX_NoUnkeyedLiteral struct{} `json:"-"`XXX_unrecognized []byte `json:"-"`XXX_sizecache int32 `json:"-"`
}
交易最后要结束时调用的函数:
6.2.2 Success
func Success(payload []byte) pb.Response // 返回值是pb.Response函数 payload是成功提示信息
//示例代码
func (t *TestStudy) Invoke(stub shim.ChaincodeStubInterface) pb.Response{return shim.Success([]byte("Success invoke!"))
}
6.2.3 Error
func Error(msg string) pb.Response //同理
//示例代码
func (t *TestStudy) Invoke(stub shim.ChaincodeStubInterface) pb.Response{return shim.Error("Error invoke!")
}
对链码做调试的时候调整链码中运行日志的级别(一般下调)方便调试, 调试结束后要发布了一般就调高:
6.2.4 LogLevel 设置日志级别
func LogLevel(levelString string) (LoggingLevel, error) //string => LoggingLevelfunc SetLoggingLevel(level LoggingLevel) //LoggingLevel作为参数//示例
func (t *TestStudy) Invoke(stub shim.ChaincodeStubInterface) pb.Response{lv,_ := shim.LogLevel("DEBUG")shim.SetLoggingLevel(lv)return shim.Success([]byte("Success invoke!"))
}
6.2.5 ChaincodeStubInterface接口中的核心方法
不管是Init还是Invoke参数都是这个接口实例
在shim包中有一个接口ChaincodeStubinterface,该接口提供了一组方法,可以非常方便的操作Fabric中的账本数据,其核心的方法大概分为四大类:系统管理、存储管理、交易管理、调动外部chaincode
1. 系统管理常用方法
GetFunctionAndParameters
// 赋值接收调用chaincode的客户端传递过来的参数
func GetFunctionAndParameters() (function string, params []string);
//示例
func (t *TestStudy) Invoke(stub shim.ChaincodeStubInterface) pb.Response{_, args := stub.GetFunctionAndParameters()var a_param = args[0]var a_param = args[1]var a_param = args[2]return shim.Success([]byte("Success invoke!"))
}
2. 存储管理相关的方法
PutState
//把客户端传递过来的数据保存到Fabric中,数据格式为键值对
func PutState(key string, value []byte) error;
//实例代码
func (t *TestStudy) Invoke(stub shim.ChaincodeStubInterface) pb.Response{//数据写入stub.PutState("user1", []byte("putvalue"))return shim.Success([]byte("Success invoke user1!"))
};
GetState
//从Fabric中取出数据
func GetState(key string) ([]byte, error);
//实例代码
func (t *TestStudy) Invoke(stub shim.ChaincodeStubInterface) pb.Response{//数据读取keyvalue, err := stub.GetState("user1")return shim.Success(keyvalue)
};
GetStateByRange
//根据key的访问查询相关的数据 根据key的范围取查询数据
func GetStateByRange(startKey, endKey string)(StateQueryIteratorInterface, error);
//示例代码
func (t *TestStudy) Invoke(stub shim.ChaincodeStubInterface) pb.Response{startKey := "startKey"endKey := "endKey"//范围查询,得到一个StateQueryIteratorInterface迭代器接口keysIter, err := stub.GetStateByRange(startKey, endKey)//关闭迭代器接口defer keysIter.Close()var keys []stringfor keysIter.HasNext(){//得到下一个键值对response, iterErr := keysIter.Next()if iterErr != nil{return shim.Error("iterErr")}keys = append(keys, response.Key) //储存到数组中}//编码keys数组成json格式jsonKeys, err := json.Marshal(keys)if err != nil{return shim.Error("toJsonErr")}//完成后向客户端传递return shim.Success(jsonkeys)
};
GetHistoryForKey
//根据key查询其历史记录
func (stub *ChaincodeStub) GetHistoryForKey(key string) (HistoryQueryIteratorInterface, error)
DelState
CreateCompositeKey
GetStateByPartialCompositeKey/SplitCompositeKey
3. 交易管理相关的方法
GetTxTimestamp
4. 调用其他chaincode的方法
InvokeChaincode
6.3 chaincode交易的背书策略(endorse)
6.3.1背书策略的指定/设置
背书策略在链码初始化的时候就需要指定:
peer chaincode instantiate -o orderer.xwj.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/xwj.com/orderers/orderer.xwj.com/msp/tlscacerts/tlsca.xwj.com-cert.pem -C xwjchannel -n testcc -l golang -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "AND ('OrgGoMSP.member', 'OrgCppMSP.member')"
# -P "AND ('OrgGoMASP.member', 'OrgCppMSP.member')"
# AND表示这两个组织中的成员都需要参与,member表示组织中任一节点均可。如果是“OR”则表示任何一个组织成员都可以
背书规则只对chaincode中写入数据的操作进行校验,对于查询类操作不进行背书
Fabric的背书是发生在客户端的,需要进行相关的代码的编写才能完成整个背书的操作
6.3.2 背书策略的调用
上面显示的invoke函数调用指定了两个peer背书节点(可以指定任意数量的节点),那么执行时就会先给这个两个节点执行,返回结果后再由orderer节点写进区块中。
七、链码
//chaincode/go/test1/test.go -》 对应链码名testcc
package main
import {}
type Test struct{}
func (t *Test)Init();
func (t *Test)Invoke(); //业务逻辑1
func main(){}//chaincode/go/test2/test1.go -》 对应链码名testcc1
package main
import {}
type Test struct{}
func (t *Test)Init();
func (t *Test)Invoke(); //业务逻辑2
func main(){}
不同的链码名称对应这不同的Go文件
示例链码解析
调用的json:
- 初始化json:’{“Args”:[“init”,“a”,“100”,“b”,“200”]}’
- 调用的json:’{“Args”:[“invoke”,“a”,“b”,“10”]}’
官方示例fabric-samples/chaincode/chaincode_example02/go/chaincode_example02.go
文件:
package main//WARNING - this chaincode's ID is hard-coded in chaincode_example04 to illustrate one way of
//calling chaincode from a chaincode. If this example is modified, chaincode_example04.go has
//to be modified as well with the new ID of chaincode_example02.
//chaincode_example05 show's how chaincode ID can be passed in as a parameter instead of
//hard-coding.import ("fmt""strconv""github.com/hyperledger/fabric/core/chaincode/shim"pb "github.com/hyperledger/fabric/protos/peer"
)// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {}func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {fmt.Println("ex02 Init")_, args := stub.GetFunctionAndParameters() // 获取调用的函数参数, 返回值_就是Init,args是后接的参数var A, B string // Entitiesvar Aval, Bval int // Asset holdingsvar err errorif len(args) != 4 { //判断参数个数return shim.Error("Incorrect number of arguments. Expecting 4")}// Initialize the chaincodeA = args[0]Aval, err = strconv.Atoi(args[1])if err != nil {return shim.Error("Expecting integer value for asset holding")}B = args[2]Bval, err = strconv.Atoi(args[3])if err != nil {return shim.Error("Expecting integer value for asset holding")}fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)// Write the state to the ledger 把数据写入账本中err = stub.PutState(A, []byte(strconv.Itoa(Aval))) if err != nil {return shim.Error(err.Error())}err = stub.PutState(B, []byte(strconv.Itoa(Bval)))if err != nil {return shim.Error(err.Error())}return shim.Success(nil)
}func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { //交易函数fmt.Println("ex02 Invoke")function, args := stub.GetFunctionAndParameters() //获取参数,function是第一个参数代表保存的函数名,这里是invoke//“路由设置”if function == "invoke" {// Make payment of X units from A to Breturn t.invoke(stub, args)} else if function == "delete" {// Deletes an entity from its statereturn t.delete(stub, args)} else if function == "query" {// the old "Query" is now implemtned in invokereturn t.query(stub, args)}return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"")
}
// Transaction makes payment of X units from A to B
func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {var A, B string // Entitiesvar Aval, Bval int // Asset holdingsvar X int // Transaction valuevar err errorif len(args) != 3 {return shim.Error("Incorrect number of arguments. Expecting 3")}A = args[0]B = args[1]// Get the state from the ledger// TODO: will be nice to have a GetAllState call to ledgerAvalbytes, err := stub.GetState(A) //获取A的资产if err != nil {return shim.Error("Failed to get state")}if Avalbytes == nil {return shim.Error("Entity not found")}Aval, _ = strconv.Atoi(string(Avalbytes))Bvalbytes, err := stub.GetState(B) //获取B的资产if err != nil {return shim.Error("Failed to get state")}if Bvalbytes == nil {return shim.Error("Entity not found")}Bval, _ = strconv.Atoi(string(Bvalbytes))// Perform the executionX, err = strconv.Atoi(args[2]) //获取转账金额if err != nil {return shim.Error("Invalid transaction amount, expecting a integer value")}Aval = Aval - X // 转账Bval = Bval + X fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)// Write the state back to the ledgererr = stub.PutState(A, []byte(strconv.Itoa(Aval))) //重新写入if err != nil {return shim.Error(err.Error())}err = stub.PutState(B, []byte(strconv.Itoa(Bval))) //重新写入if err != nil {return shim.Error(err.Error())}return shim.Success(nil)
}// Deletes an entity from state
func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {if len(args) != 1 {return shim.Error("Incorrect number of arguments. Expecting 1")}A := args[0]// Delete the key from the state in ledgererr := stub.DelState(A) //删除账本中的key,假删除,这个操作是被记录的if err != nil {return shim.Error("Failed to delete state")}return shim.Success(nil)
}// query callback representing the query of a chaincode
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response { //查询函数var A string // Entitiesvar err errorif len(args) != 1 {return shim.Error("Incorrect number of arguments. Expecting name of the person to query")}A = args[0]// Get the state from the ledgerAvalbytes, err := stub.GetState(A) //取出值if err != nil {jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"return shim.Error(jsonResp)}if Avalbytes == nil {jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"return shim.Error(jsonResp)}jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}" //拼接成字符串给客户端fmt.Printf("Query Response:%s\n", jsonResp)return shim.Success(Avalbytes)
}func main() {err := shim.Start(new(SimpleChaincode)) //写法固定 SimpleChaincode就是定义的空结构体if err != nil {fmt.Printf("Error starting Simple chaincode: %s", err)}
}
如果要自定义函数,函数的格式:(自定义函数一般都是在Invoke函数中被调用的)
func (t *自定义结构体)functionName (stub shim.ChaincodeStubInterface, args []string) pb.Response { xxxxx}
Fabric框架的学习-4-链码与背书策略相关推荐
- 区块链学习8:超级账本项目Fabric中的背书、背书节点、背书策略、背书签名
☞ ░ 前往老猿Python博文目录 ░ 在Hyperledger Fabric区块链中,有背书节点进行背书,Hyperledger Fabric 使用背书策略来定义哪些节点需要执行交易. Hyper ...
- fabric框架学习
二.手动搭建Fabric网络 2.1 生成fabric证书 cryptogen模块主要用来生成组织结构和账号相关的文件,任何fabric系统的开发通常都是从cryptogen模板开始的. 2.1.1 ...
- 【Fabric】简单测试:链码单元测试+fabric-go-sdk
纯粹记录一下,也不知道干了啥~ 链码单元测试 在Ubuntu中安装VScode 下载安装包 打开Ubuntu的火狐,访问网址:https://code.visualstudio.com/docs=&g ...
- Fabric背书策略
1 用途 1.1 交易流程回顾 Hyperledger Fabric 区块链网络交易的执行分为以下几个步骤.Endorser 与 Committer 都是 Hyperledger Fabric 区块链 ...
- 通过 DLPack 构建跨框架深度学习编译器
通过 DLPack 构建跨框架深度学习编译器 深度学习框架,如Tensorflow, PyTorch, and ApacheMxNet,快速原型化和部署深度学习模型提供了强大的工具箱.不幸的是,易用性 ...
- Java3大框架的学习都是什么
java是互联网行业的第一编程语言,相信大家都已经有了解了,事实也确实如此,java还是世界第一编程语言,在java培训学习的过程中,框架是程序员们必学的知识点,而且是十分重要的应用,Spring.S ...
- 适合初学者对Yaf框架的学习(一)
前言 最近接触到Yaf框架,从最初按照鸟哥惠新宸的写的关于Yaf手册,到自己写一个hello world 程序,对于我这个新手来说还是蛮曲折的,大家都知道yaf框架是用C写的,所以自身的效率和性能,还 ...
- Java的3大框架都学习什么呢?
Java是互联网行业的第一编程语言,相信大家都已经有了解了,事实也确实如此,Java还是世界第一编程语言,在学习Java的过程中,框架是程序员们必学的知识点,而且是十分重要的应用,Spring.Str ...
- 定时任务框架APScheduler学习详解
定时任务框架APScheduler学习详解 APScheduler简介 在平常的工作中几乎有一半的功能模块都需要定时任务来推动,例如项目中有一个定时统计程序,定时爬出网站的URL程序,定时检测钓鱼网站 ...
最新文章
- 4 RACMulticastConnection 连接类
- 解决问题的策略-分而治之
- 深度学习福利入门到精通第一讲——LeNet模型
- ASP.NET 无刷新上传文件
- c语言中extern关键字
- 智能锁行业安全分析报告
- 爬虫抓包,模拟提交、Fiddler和Postman结合Chrome的使用
- 如何理解base href=%=basePath%
- spark与hadoop对比
- ueditor富文本
- 主数据管理功能模块、实施、提供厂商
- java spy_Java Spy - 代码跟踪神器
- ZOJ 3987 Numbers(Java枚举)
- walsh64码 matlab,实验7 Walsh码及单用户CDMA系统直接序列扩频仿真
- 求滑动窗口中的最大值和最小值
- html中鼠标悬停图片变大,JavaScript通过mouseover()实现图片变大效果的示例
- 那么如何求出这个长轴和短轴呢?于是线性代数就来了
- 在网页中点击链接就可以和在线好友QQ聊天
- 八爪鱼爬取列表数据和详情页数据(国内网址)
- download file with c++