Fabric1.4 编写链码下
Posted 杰西啊杰西
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Fabric1.4 编写链码下相关的知识,希望对你有一定的参考价值。
五、在开发者环境中加入couchdb
1、关闭网络
docker-compose -f docker-compose-simple.yaml down
2、编辑docker-compose-simple.yaml
首先在文件中添加couchdb段的配置:
couchdb:
container_name: couchdb
image: hyperledger/fabric-couchdb
environment:
- COUCHDB_USER=
- COUCHDB_PASSWORD=
ports:
- 5984:5984
networks:
- default
在peer的environment部分添加:
environment:
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=
在peer的depends_on部分添加:
depends_on:
- couchdb
3、访问页面并查看区块数据
(这里的数据是最开始的链码代码那里的,新的我忘了截图orz)
小插曲:发现退出之后再启动无法进入cli,配置couchdb之后再也没办法进入cli
解决方法:
① 查看cli日志
docker logs cli
发现报错,说是连接被拒绝
Error: error getting endorser client for channel: endorser client failed to connect to peer:7051: failed to create new connection: connection error: desc = "transport: error while dialing: dial tcp 172.30.0.4:7051: connect: connection refused"
② 修改docker-compose-simple.yaml文件,等待一段时间使得couchdb完全启动
在cli的command部分,修改命名
command: /bin/bash -c 'sleep 20; ./script.sh'
③ 重新启动网络、chaincode容器和cli ,均成功
六、 使用链码使用富查询语句
因为普通查询只能根据主键查询,如果要使用根据其他字段查询就只能依靠搜索json字符串进行查询,这也是为什么使用couchdb 的原因
1、在链码文件夹下新建文件夹
2、编写索引文件
在该文件夹下新建 indexIDCard.json 文件,其中IDCard是要进行查询的字段
{
"index":{
"fields":["IDCard"]
},
"ddoc":"indexIDCard",
"name":"indexIDCard",
"type":"json"
}
3、修改链码,增加基于身份证IDCard的富查询、查看历史数据修改功能
package main
import (
"bytes"
"encoding/json"
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/protos/peer"
"time"
)
type BasicInfo struct{
//个人基本信息ID
UserID string `json:"UserID"`
//身份证
IDCard string `json:"IDCard"`
//姓名
Name string `json:"Name"`
//性别
Sex string `json:"Sex"`
//民族
Nation string `json:"Nation"`
//籍贯
Native string `json:"Native"`
//生日
Birthday string `json:"Birthday"`
//手机
Phone string `json:"Phone"`
//邮箱
Email string `json:"Email"`
//政治面貌
PoliticalLook string `json:"PoliticalLook"`
//家庭住址
HomeAddress string `json:"HomeAddress"`
//信息上传账号
LoginUserID string `json:"LoginUserID"`
//个人信息文件hash
UserInfoFileHash string `json:"UserInfoFileHash"`
//插入该数据的时间
Time string `json:"Time"`
Histories []HistoryItem //当前BasicInfo的历史记录
}
type HistoryItem struct {
TxId string //交易hash,也是标志ID
BasicInfo BasicInfo
}
type SmartContract struct{ //合约即链码
}
func (b *SmartContract) Init(stub shim.ChaincodeStubInterface) peer.Response{
return shim.Success(nil)
}
//提供函数入口
func (b *SmartContract) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
function, args := stub.GetFunctionAndParameters()
if function == "addBasicInfo" { //添加个人基本信息
stub.SetEvent("addBasicInfo", []byte{})
return b.addBasicInfo(stub, args)
}else if function == "queryBasicByUserID" { //根据UserID查询个人基本信息
stub.SetEvent("queryBasicByUserID", []byte{})
return b.queryBasicByUserID(stub,args)
}else if function == "delBasicInfoByUserID"{ // 根据UserID删除个人基础信息
stub.SetEvent("delBasicInfoByUserID", []byte{})
return b.delBasicInfoByUserID(stub, args)
}else if function == "updateBasicInfoByUserID"{ // 根据UserID更新个人基础信息
stub.SetEvent("updateBasicInfoByUserID", []byte{})
return b.updateBasicInfoByUserID(stub, args)
} else if function == "queryBasicByIDCard" { //根据IDCard查询个人基本信息
stub.SetEvent("queryBasicByIDCard", []byte{})
return b.queryBasicByIDCard(stub,args)
}else if function == "queryHistoryBasic"{ // 查询历史变更数据
stub.SetEvent("queryHistoryBasic", []byte{})
return b.queryHistoryBasic(stub, args)
}
return shim.Error("Invalid BasicInfo Chaincode Smart Contract function name.")
}
//添加个人基本信息(链码函数)
/*
**args:
[0]:基本信息ID
[1]:身份证
[2]:姓名
[3]:性别
[4]:民族
[5]:籍贯
[6]:生日
[7]:手机
[8]:邮箱
[9]:政治面貌
[10]:家庭住址
[11]:信息上传账号
[12]:个人信息文件hash
*/
func (b *SmartContract) addBasicInfo(stub shim.ChaincodeStubInterface, args []string) peer.Response {
insert_time :=time.Now().Format("2006-01-02 15:04:05")
basicInfo := BasicInfo{
//个人基本信息id
UserID:args[0],
//身份证
IDCard:args[1],
//姓名
Name:args[2],
//性别
Sex:args[3],
//民族
Nation:args[4],
//籍贯
Native:args[5],
//生日
Birthday:args[6],
//手机
Phone:args[7],
//邮箱
Email:args[8],
//政治面貌
PoliticalLook:args[9],
//家庭住址
HomeAddress:args[10],
//信息上传账号
LoginUserID:args[11],
//个人信息文件hash
UserInfoFileHash:args[12],
//插入该数据的时间
Time:insert_time, //time.Now().Format("2006-01-02 15:04:05")
}
basicInfoAsBytes, _ := json.Marshal(basicInfo)
stub.PutState(basicInfo.UserID, basicInfoAsBytes)
fmt.Println("Added", basicInfo)
txid:=stub.GetTxID() //获取当前交易的tx_id,每一笔交易和每一个客户端是唯一的
return shim.Success([]byte(txid)) //返回区块txid
}
//根据用户ID进行查找人的基本信息(链码函数)
// args: UserID
func (b *SmartContract) queryBasicByUserID(stub shim.ChaincodeStubInterface, args []string) peer.Response {
//args传入函数多个参数,这里如果只传入UserID也可以不使用args []string 只用user_id string
if len(args) < 1 {
return shim.Error("Incorrect number of arguments. Expecting 1")
}
basic_info, _ := stub.GetState(args[0])
return shim.Success(basic_info)
}
// 根据UserID删除个人信息
// args: UserID
func (b *SmartContract) delBasicInfoByUserID(stub shim.ChaincodeStubInterface, args []string) peer.Response {
if len(args) != 1 {
return shim.Error("给定的参数个数不符合要求")
}
err := stub.DelState(args[0])
if err != nil {
return shim.Error("删除信息时发生错误")
}
return shim.Success([]byte("信息删除成功"))
}
// 根据UserID修改个人信息
// args: UserID
func (b *SmartContract) updateBasicInfoByUserID(stub shim.ChaincodeStubInterface, args []string) peer.Response {
//反序列化传入参数
insert_time :=time.Now().Format("2006-01-02 15:04:05")
info := BasicInfo{
//个人基本信息id
UserID:args[0],
//身份证
IDCard:args[1],
//姓名
Name:args[2],
//性别
Sex:args[3],
//民族
Nation:args[4],
//籍贯
Native:args[5],
//生日
Birthday:args[6],
//手机
Phone:args[7],
//邮箱
Email:args[8],
//政治面貌
PoliticalLook:args[9],
//家庭住址
HomeAddress:args[10],
//信息上传账号
LoginUserID:args[11],
//个人信息文件hash
UserInfoFileHash:args[12],
//插入该数据的时间
Time:insert_time, //time.Now().Format("2006-01-02 15:04:05")
}
//根据userid查询信息
basic, err:=stub.GetState(args[0])
if err!=nil{
return shim.Error("未找到要修改的信息")
}
var basic_info BasicInfo
err = json.Unmarshal(basic,&basic_info)
if err!=nil{
return shim.Error("反序列化basic_info失败")
}
basic_info.IDCard=info.IDCard
basic_info.Name=info.Name
basic_info.Sex=info.Sex
basic_info.Nation=info.Nation
basic_info.Native=info.Native
basic_info.Birthday=info.Birthday
basic_info.Phone=info.Phone
basic_info.Email=info.Email
basic_info.PoliticalLook=info.PoliticalLook
basic_info.HomeAddress=info.HomeAddress
basic_info.LoginUserID=info.LoginUserID
basic_info.UserInfoFileHash=info.UserInfoFileHash
basic_info.Time=info.Time
basic, err = json.Marshal(basic_info)
if err != nil {
return shim.Error("序列化basic_info失败")
}
// 保存basic_info状态
err = stub.PutState(basic_info.UserID, basic)
if err != nil {
return shim.Error("更新basic_info失败")
}
return shim.Success([]byte("修改信息成功")) //返回区块txid
}
//根据身份证号查询人的基本信息(链码函数)
// args: IDCard
func (b *SmartContract) queryBasicByIDCard(stub shim.ChaincodeStubInterface, args []string) peer.Response {
if len(args) != 1 {
return shim.Error("给定的参数个数不符合要求")
}
idCard := args[0]
// 使用富查询进行查询数据
// 拼装CouchDB所需要的查询字符串(是标准的一个JSON串)
queryString := fmt.Sprintf("{\\"selector\\":{\\"IDCard\\":\\"%s\\"}}", idCard)
resultsIterator, err := stub.GetQueryResult(queryString)
if err != nil {
return shim.Error(err.Error())
}
defer resultsIterator.Close()
// buffer is a JSON array containing QueryRecords
var buffer bytes.Buffer
bArrayMemberAlreadyWritten := false
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
if err != nil {
return shim.Error(err.Error())
}
// Add a comma before array members, suppress it for the first array member
if bArrayMemberAlreadyWritten == true {
buffer.WriteString(",")
}
// Record is a JSON object, so we write as-is
buffer.WriteString(string(queryResponse.Value))
bArrayMemberAlreadyWritten = true
}
fmt.Printf("- queryAllBasicInfo:\\n%s\\n", buffer.String())
return shim.Success(result)
}
//根据UserID查询历史变更数据
// args: UserID
func (b *SmartContract) queryHistoryBasic(stub shim.ChaincodeStubInterface, args []string) peer.Response {
if len(args) != 1 {
return shim.Error("给定的参数个数不符合要求")
}
// 根据UserID查询basic-info状态
basic, err := stub.GetState(args[0])
if err != nil {
return shim.Error("根据UserID查询信息失败")
}
if basic == nil {
return shim.Error("根据UserID没有查询到相关的信息")
}
// 对查询到的状态进行反序列化
var basic_info BasicInfo
err = json.Unmarshal(basic, &basic_info)
if err != nil {
return shim.Error("反序列化basic_info信息失败")
}
// 获取历史变更数据
iterator, err := stub.GetHistoryForKey(basic_info.UserID)
if err != nil {
return shim.Error("根据指定的UserID查询对应的历史变更数据失败")
}
defer iterator.Close()
// 迭代处理
var histories []HistoryItem
var hisBasicInfo BasicInfo
for iterator.HasNext(){
hisData, err :=iterator.Next()
if err !=nil{
return shim.Error("获取basic_info的历史变更数据失败")
}
var historyItem HistoryItem
historyItem.TxId = hisData.TxId
json.Unmarshal(hisData.Value, &hisBasicInfo)
if hisData.Value == nil{
var empty BasicInfo
historyItem.BasicInfo = empty
}else {
historyItem.BasicInfo = hisBasicInfo
}
histories = append(histories,historyItem)
}
basic_info.Histories=histories
//返回
res, err := json.Marshal(basic_info)
if err != nil{
return shim.Error("序列化sco信息时发生错误")
}
return shim.Success(res)
}
func main(){
err := shim.Start(new(SmartContract))
if err != nil{
fmt.Printf("启动SmartContract时发生错误: %s\\n", err)
}
}
4、按照之前的方法,先开启网络,然后使用运行的chaincode镜像编译链码,通过后部署到区块链测试网络fabric-samples上。
以上是关于Fabric1.4 编写链码下的主要内容,如果未能解决你的问题,请参考以下文章