六. 智能合约

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-链码与背书策略相关推荐

  1. 区块链学习8:超级账本项目Fabric中的背书、背书节点、背书策略、背书签名

    ☞ ░ 前往老猿Python博文目录 ░ 在Hyperledger Fabric区块链中,有背书节点进行背书,Hyperledger Fabric 使用背书策略来定义哪些节点需要执行交易. Hyper ...

  2. fabric框架学习

    二.手动搭建Fabric网络 2.1 生成fabric证书 cryptogen模块主要用来生成组织结构和账号相关的文件,任何fabric系统的开发通常都是从cryptogen模板开始的. 2.1.1 ...

  3. 【Fabric】简单测试:链码单元测试+fabric-go-sdk

    纯粹记录一下,也不知道干了啥~ 链码单元测试 在Ubuntu中安装VScode 下载安装包 打开Ubuntu的火狐,访问网址:https://code.visualstudio.com/docs=&g ...

  4. Fabric背书策略

    1 用途 1.1 交易流程回顾 Hyperledger Fabric 区块链网络交易的执行分为以下几个步骤.Endorser 与 Committer 都是 Hyperledger Fabric 区块链 ...

  5. 通过 DLPack 构建跨框架深度学习编译器

    通过 DLPack 构建跨框架深度学习编译器 深度学习框架,如Tensorflow, PyTorch, and ApacheMxNet,快速原型化和部署深度学习模型提供了强大的工具箱.不幸的是,易用性 ...

  6. Java3大框架的学习都是什么

    java是互联网行业的第一编程语言,相信大家都已经有了解了,事实也确实如此,java还是世界第一编程语言,在java培训学习的过程中,框架是程序员们必学的知识点,而且是十分重要的应用,Spring.S ...

  7. 适合初学者对Yaf框架的学习(一)

    前言 最近接触到Yaf框架,从最初按照鸟哥惠新宸的写的关于Yaf手册,到自己写一个hello world 程序,对于我这个新手来说还是蛮曲折的,大家都知道yaf框架是用C写的,所以自身的效率和性能,还 ...

  8. Java的3大框架都学习什么呢?

    Java是互联网行业的第一编程语言,相信大家都已经有了解了,事实也确实如此,Java还是世界第一编程语言,在学习Java的过程中,框架是程序员们必学的知识点,而且是十分重要的应用,Spring.Str ...

  9. 定时任务框架APScheduler学习详解

    定时任务框架APScheduler学习详解 APScheduler简介 在平常的工作中几乎有一半的功能模块都需要定时任务来推动,例如项目中有一个定时统计程序,定时爬出网站的URL程序,定时检测钓鱼网站 ...

最新文章

  1. 4 RACMulticastConnection 连接类
  2. 解决问题的策略-分而治之
  3. 深度学习福利入门到精通第一讲——LeNet模型
  4. ASP.NET 无刷新上传文件
  5. c语言中extern关键字
  6. 智能锁行业安全分析报告
  7. 爬虫抓包,模拟提交、Fiddler和Postman结合Chrome的使用
  8. 如何理解base href=%=basePath%
  9. spark与hadoop对比
  10. ueditor富文本
  11. 主数据管理功能模块、实施、提供厂商
  12. java spy_Java Spy - 代码跟踪神器
  13. ZOJ 3987 Numbers(Java枚举)
  14. walsh64码 matlab,实验7 Walsh码及单用户CDMA系统直接序列扩频仿真
  15. 求滑动窗口中的最大值和最小值
  16. html中鼠标悬停图片变大,JavaScript通过mouseover()实现图片变大效果的示例
  17. 那么如何求出这个长轴和短轴呢?于是线性代数就来了
  18. 在网页中点击链接就可以和在线好友QQ聊天
  19. 八爪鱼爬取列表数据和详情页数据(国内网址)
  20. download file with c++

热门文章

  1. 算法题目-猜数字游戏
  2. MacBook pro使用入门(2)
  3. java 产生p10证书_【国密SM2算法】JAVA创建pkcs10格式的csr证书请求文件
  4. [usaco月赛]梦幻王国
  5. Linux pytorch环境搭建
  6. iOS开发中遇到的一些问题及解决方案【转载】
  7. Csgo 控制台——代码
  8. PV 操作经典例题---三个进程之间的同步
  9. 某x x x atlas汉化
  10. 魔兽争霸3中的一些数学计算