超级账本chaincode编写与升级

一、 编写chaincode
    本文以fabric-samples工程为例,在该示例的基础上编译chaincode,该工程可以从github上下载。Fabric-samples的启动参考“chaincode开发手册”,fabric-samples会启动4个docker容器,名称如下:peer、chaincode、cli、orderer。
编写chaincode需要实现hyperledger/fabric/core/chaincode/shim/interfaces_stable.go文件中的Init和Invoke方法(接口Chaincode中),在init和invoke方法中,传递的参数为ChaincodeStubInterface接口,该接口也定义在interfaces_stable.go文件中。通过invoke方法为入口,实现调用自定义chaincode中的其他业务方法。

    下面的gbivcc.go的chaincode,分别实现了方法:Init,Invoke,verify,storeResult,getResult方法。通过invoke方法,可以分别调用verify,storeResult,getResult方法。Gbivcc的代码见文章最后,下面按照启动fabric-samples的终端个数来说明如何安装chaincode。

1号终端

    启动fabric-samples示例

docker-compose -f docker-compose-simple.yaml up
2号终端

    docker exec –it chaincode bash

root@d2629980e76b:/opt/gopath/src/chaincode#
mkdir gbivcc && cd gbivcc
touch gbivcc.go (拷贝文件末尾的chaincode到该文件中)
go build gbivcc.go
运行chaincode
CORE_PEER_ADDRESS=peer:7052 CORE_CHAINCODE_ID_NAME=gbivcc:0 ./gbivcc
3号终端
    进入cli,安装chaincode

    docker exec –it cli bash

安装chaincode
peer chaincode install -p chaincodedev/chaincode/gb_chaincode/ -n gbivcc -v 0 
peer chaincode instantiate -n gbivcc -v 0 -c '{"Args":[]}' -C myc 
调用getResult方法
peer chaincode invoke -n gbivcc -c '{"Args":["getResult", "request_id"]}' -C myc
二、 升级chaincode
升级chaincode时,不能修改chaincode的name,只能修改chaincode的版本号。通过以下三个步骤即可完成gbivcc的版本升级:
     1) 替换gbivcc.go的源码为新的chaincode代码

在2号终端中,修改gbivcc.go的源码为新版本的chaincode代码,或者新添加一个文件也可以。修改完执行如下操作编译chaincode代码,如意命令行中的红色字体,代表版本号的变化(0→1)。

vim gbivcc.go 
go build gbivcc.go 
CORE_PEER_ADDRESS=peer:7052 CORE_CHAINCODE_ID_NAME=gbivcc:1 ./gbivcc
    2) 安装和更新新版本的chaincode

在3号终端中,安装并升级新的chaincode,注意命令中的红色字体部分,代表版本号的变化(0→1)。

peer chaincode install -p chaincodedev/chaincode/gb_chaincode/ -n gbivcc -v 1 
peer chaincode upgrade -n gbivcc -v 1 -c '{"Args":[]}' -C myc 
    3) 调用方法,验证结果

在3号终端中,调用chaincode中的方法,验证方法是否运行正常。调用方法时没有版本号的修改。

peer chaincode invoke -n gbivcc -c '{"Args":["getResult", "request_id"]}' -C myc 
peer chaincode invoke -n gbivcc -c '{"Args":["storeResult", "request_id", "verify_result"]}' -C myc 

三、 gbivcc.go的chaincode完整代码

    下载地址gbivcc.go

package main

import (
	"encoding/json"
	"encoding/hex"
	"crypto/md5"
	"strings"
    "fmt"
    "math/rand"
    "time"
    "net/http"
    "io/ioutil"

    "github.com/hyperledger/fabric/core/chaincode/shim"
    "github.com/hyperledger/fabric/protos/peer"
    "log"
)


const (
    //LVWANCenterURL = "http://127.0.0.1:8080"
    LVWANCenterURL = "http://www.baidu.com"
    REQUEST_PARAMS_HASH = "params_hash"
    REQUEST_VERIFY_RESULT = "verify_result"
    SUCCESS = "success"
    FAILURE = "failure"
)

//GBIdcardVerify implements a simple chaincode to manage an idcard verify
type GBIdcardVerify struct{
}

// Init is called during chaincode instantiation to initialize any
// data. Note that chaincode upgrade also calls this function to reset
// or to migrate data.

func (t *GBIdcardVerify) Init(stub shim.ChaincodeStubInterface) peer.Response{
    // Get the args from the transaction proposal
    args := stub.GetStringArgs()
    log.SetFlags(log.Lshortfile | log.LstdFlags)
    log.Printf("Init receive args: %s\n", args)
    return shim.Success(nil)
}

// Invoke is called per transaction on the chaincode. Each transaction is
// either a query or verify  on a varify idcard created by Init function.
func(t * GBIdcardVerify) Invoke(stub shim.ChaincodeStubInterface) peer.Response{
    fn, args := stub.GetFunctionAndParameters()
    var result string
    var err error
    log.Printf("fn: %s, args: %s", fn, args)
    //1.validate right

    //2.execute function
    if fn == "verify"{
        result, err = verify(stub, args)
    }else if fn =="storeResult"{
        result, err = storeResult(stub, args)
    }else if fn=="getResult"{
        result, err = getResult(stub,args)
    }else{
        desc :=[]string{"没有实现函数:", fn}
        shim.Error(strings.Join(desc, ""))
    }

    //3.judge error
    if err !=nil{
        return shim.Error(fmt.Sprintf("function executer error. %s , err: %s", fn, err))
    }

    // Return the result as success payload
    return shim.Success([]byte(result))
}

//Post parameters to lvwan data center.
//return request_id,error
func verify(stub shim.ChaincodeStubInterface, args []string) (string, error){
    request_id := stub.GetTxID()
    args = append(args,"request_id", request_id)
    log.Println("verify receive args: %s", args)

    //1.hypteledger
    var stateMap map[string]interface{}
    stateMap = make(map[string]interface{})
    stateMap["REQUEST_PARAMS_HASH"] = getHash(args)
    marshaledData, err := json.Marshal(stateMap)
    if err !=nil{
        return request_id,fmt.Errorf("json marshal failed.request_id: %s, err: %s", request_id, err)
    }
    err = stub.PutState(request_id, marshaledData)
    if err !=nil{
        return request_id, fmt.Errorf("put state failed. request_id: %s, err: %s", request_id, err)
    }

    //2.do request
    verifyUrl := getVerifyUrl()
    log.Printf("verifyUrl: %s", verifyUrl)
    paramsMap :=converArrayToMap(args)
    _, err = postData2LvwanCenter(verifyUrl, paramsMap)
    if err !=nil{
        return request_id, fmt.Errorf("post data to lvwan center failed. request_id: %s, err: %s", request_id, err)
    }
    return request_id, nil
}

//store task result to state
//return store_result, error
func storeResult(stub shim.ChaincodeStubInterface, args []string) (string,error){
    //1.get request_id
    if len(args)<2{
        return FAILURE,fmt.Errorf("require request_id param.")
    }
    request_id := args[0]
    byteValue, err := stub.GetState(request_id)
    log.Printf("store result, receive request_id: %s, byteValue: %s, new result: %s", request_id, byteValue, args[1])
    if err !=nil{
        return FAILURE, fmt.Errorf("get state failed. request_id: %s, err: %s", request_id, err)
    }
    var r map[string]interface{}
    r = make(map[string]interface{})
    json.Unmarshal(byteValue, &r)
    r[REQUEST_VERIFY_RESULT] = args[1]

    //store result
    marshaledData, err := json.Marshal(r)
    if err !=nil{
        return request_id,fmt.Errorf("store result,json marshal failed.request_id: %s, err: %s", request_id, err)
    }
    err = stub.PutState(request_id, marshaledData)
    if err !=nil{
        return request_id, fmt.Errorf("store result,put state failed. request_id: %s, err: %s", request_id, err)
    }

    return SUCCESS, nil
}

//get task result by request_id,return result, error
func getResult(stub shim.ChaincodeStubInterface, args []string)(string, error){
    //1.get request_id
    log.Printf("getResult receive args: %s\n", args)
    log.Printf("stub.GetTxID is %s\n", stub.GetTxID())
    if len(args)<1{
        return "",fmt.Errorf("require request_id param.")
    }
    request_id := args[0]
    byteValue, err := stub.GetState(request_id)
    log.Printf("receive request_id: %s", request_id)
    log.Printf("getSate result, byteValue: %s", byteValue)
    log.Printf("getSate result, err: %s", err)
    if err !=nil{
        return "", fmt.Errorf("get state failed. request_id: %s, err: %s", request_id, err)
    }
    if byteValue == nil{
        return "",nil
    }
    var r map[string]interface{}
    json.Unmarshal(byteValue, &r)
    fmt.Printf("result map: %s\n", r)
    if r[REQUEST_VERIFY_RESULT] ==nil{
        return "",nil
    }
    return (r[REQUEST_VERIFY_RESULT]).(string), nil
}

//conver string[] to map
func converArrayToMap(params []string) map[string]string{
	if params ==nil || len(params) <=0{
		return nil
	}

	if len(params)%2 !=0{
		log.Fatalf("length of params is invalid. length: %d", len(params))
	}
	var paramMap map[string]string
	paramMap = make(map[string]string)
	for i:=0; i<len(params); i+=2{
		paramMap[params[i]]=params[i+1]
	}

	return paramMap
}

//Post data to lvwan center
//return str_response_body, error
func postData2LvwanCenter(url string, paramsMap map[string]string) (string,error){
    //post的body内容,当前为json格式
// 	reqbody := `
//     {
//    "touser":"OPENID",
//     "msgtype":"text",
//     "text":
//       {
//           "content":"THECONTENT"
//       }
//     }
//     `
    reqbody,err := json.Marshal(paramsMap)
	if err!=nil{
		log.Println("paramsMap marshal failed", err)
		return "",fmt.Errorf("paramsMap marshal failed,err: %s", err)
	}

    //创建请求
    postReq, err := http.NewRequest("POST",url,strings.NewReader(string(reqbody)))
    if err !=nil{
        log.Println("Post请求:创建请求失败", err)
        return "",fmt.Errorf("创建请求失败,err: %s", err)
    }

    //增加header
    postReq.Header.Set("Content-type","application/json; encoding=utf-8")

    //执行请求
    client := &http.Client{}
    resp, err := client.Do(postReq)
    if err!=nil{
        log.Println("Post请求:创建请求失败", err)
        return "",fmt.Errorf("创建请求失败,err: %s", err)
    }

    //读取响应
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err!=nil{
        log.Println("Post请求:读取body失败", err)
        return "",fmt.Errorf("读取body失败,err: %s", err)
    }

    log.Println("Post请求: 创建成功", string(body))
    return string(body), nil
}

//get lvwan center full url
func getVerifyUrl() string{
    fullUrl :=fmt.Sprintf("%s/idcard/verify",LVWANCenterURL)
    return fullUrl
}

//generate uuid
func getUUID() string{
    r := rand.New(rand.NewSource(time.Now().UnixNano()))
    return string(r.Intn(10000000))
}

//calculate hash
func getHash(args []string) string{
    if len(args) == 0{
        return ""
    }
    var joinStr = strings.Join(args,"")
    var signByte = []byte(joinStr)
    hash :=md5.New()
    hash.Write(signByte)
    return hex.EncodeToString(hash.Sum(nil))
}


// main function starts up the chaincode in the container during instantiate
func main() {
    log.SetFlags(log.Lshortfile | log.LstdFlags)
    if err := shim.Start(new(GBIdcardVerify)); err != nil{
        fmt.Printf("Error starting GBIdcardVerify chaincode: %s", err)
    }
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值