搭建基于hyperledger fabric的联盟社区(七) --升级chaincode
上个版本的chaincode有很多功能不完备,所以要部署新版本的chaincode。Fabric支持在保留现有状态的前提对chaincode进行升级。
一.新版chaincode
新版本的chaincode增加的功能如下:
1.增加了数据追溯功能,在社区用户发起transaction时,chaincode将自动在用户证书中提取用户信息,将其存储在帖子的字段里。
2.加入了敏感词监管功能,敏感词字典和敏感词过滤功能在外部提供,chaincode通过http api(post 请求)调用服务。
3.加入了模糊查询功能。
chaincode代码:
package main import ( "bytes" "encoding/json" "fmt" "strconv" "strings" "net/http" "io/ioutil" "crypto/x509" "encoding/pem" "github.com/hyperledger/fabric/core/chaincode/shim" sc "github.com/hyperledger/fabric/protos/peer" ) type SmartContract struct { } type Post struct { Id string `json:"id"` OriginalWebsite string `json:"originalwebsite"` OriginalID string `json:"originalid"` Title string `json:"title"` Content string `json:"content"` AuthorId string `json:"authorid"` PublishTime string `json:"publishtime"` UpdateTime string `json:"updatetime"` Category string `json:"category"` SourceId string `json:"sourceid"` Labels string `json:"labels"` Follower_num int `json:"follower_num"` Browse_num int `json:"browse_num"` Star_num int `json:"star_num"` UserName string `json:"username"` } type PostLength struct { Length int `json:"length"` } func (s *SmartContract) Init(APIstub shim.ChaincodeStubInterface) sc.Response { return shim.Success(nil) } func (s *SmartContract) Invoke(APIstub shim.ChaincodeStubInterface) sc.Response { function, args := APIstub.GetFunctionAndParameters() if function == "queryPost" { return s.queryPost(APIstub, args) } else if function == "initLedger" { return s.initLedger(APIstub) } else if function == "addPost" { return s.addPost(APIstub, args) } else if function == "updatePost" { return s.updatePost(APIstub, args) } else if function == "richQueryPosts" { return s.richQueryPosts(APIstub, args) } else if function == "getPostNum" { return s.getPostNum(APIstub, args) } return shim.Error("Invalid Smart Contract function name.") } func (s *SmartContract) queryPost(APIstub shim.ChaincodeStubInterface, args []string) sc.Response { if len(args) != 1 { return shim.Error("Incorrect number of arguments. Expecting 1") } postAsBytes, _ := APIstub.GetState(args[0]) return shim.Success(postAsBytes) } func (s *SmartContract) initLedger(APIstub shim.ChaincodeStubInterface) sc.Response { creatorByte,_:= APIstub.GetCreator() certStart := bytes.IndexAny(creatorByte, "-----BEGIN") if certStart == -1 { fmt.Errorf("No certificate found") } certText := creatorByte[certStart:] bl, _ := pem.Decode(certText) if bl == nil { fmt.Errorf("Could not decode the PEM structure") } cert, err := x509.ParseCertificate(bl.Bytes) if err != nil { fmt.Errorf("ParseCertificate failed") } uname:=cert.Subject.CommonName posts := []Post{ Post{Id: "1", OriginalWebsite: "b", OriginalID: "c", Title: "如何学习人工智能呢?",Content:"好好学习",AuthorId:"f",PublishTime:"g",UpdateTime:"h",Category:"i",SourceId:"j",Labels:"k",Follower_num:100,Browse_num:200,Star_num:300,UserName:uname}, Post{Id: "2", OriginalWebsite: "bb", OriginalID: "bb", Title: "目前大数据有什么用呢?",Content:"没用",AuthorId:"ff",PublishTime:"gg",UpdateTime:"hh",Category:"ii",SourceId:"jj",Labels:"kk",Follower_num:400,Browse_num:500,Star_num:600,UserName:uname}, } length := PostLength{Length:len(posts)} lengthAsBytes,_ := json.Marshal(length) APIstub.PutState("POSTLENGTH",lengthAsBytes) i := 0 for i < len(posts) { fmt.Println("i is ", i) postAsBytes, _ := json.Marshal(posts[i]) APIstub.PutState("POST"+strconv.Itoa(i), postAsBytes) fmt.Println("Added", posts[i]) i = i + 1 } return shim.Success(nil) } func (s *SmartContract) addPost(APIstub shim.ChaincodeStubInterface, args []string) sc.Response { if len(args) != 13 { return shim.Error("Incorrect number of arguments. Expecting 13") } filteredtitle := sensitiveSupervision(args[2]) filteredcontent := sensitiveSupervision(args[3]) creatorByte,_:= APIstub.GetCreator() certStart := bytes.IndexAny(creatorByte, "-----BEGIN") if certStart == -1 { fmt.Errorf("No certificate found") } certText := creatorByte[certStart:] bl, _ := pem.Decode(certText) if bl == nil { fmt.Errorf("Could not decode the PEM structure") } cert, err := x509.ParseCertificate(bl.Bytes) if err != nil { fmt.Errorf("ParseCertificate failed") } uname:=cert.Subject.CommonName args10,error := strconv.Atoi(args[10]) args11,error := strconv.Atoi(args[11]) args12,error := strconv.Atoi(args[12]) if error != nil{ fmt.Println("String conversion integer failed!") } lengthAsBytes, _ := APIstub.GetState("POSTLENGTH") length := PostLength{} json.Unmarshal(lengthAsBytes,&length) newlength := length.Length+1 var post = Post{Id: strconv.Itoa(newlength), OriginalWebsite: args[0], OriginalID: args[1], Title: filteredtitle,Content:filteredcontent,AuthorId:args[4],PublishTime:args[5],UpdateTime:args[6],Category:args[7],SourceId:args[8],Labels:args[9],Follower_num:args10,Browse_num:args11,Star_num:args12,UserName:uname} postAsBytes, _ := json.Marshal(post) APIstub.PutState("POST"+strconv.Itoa(newlength), postAsBytes) length.Length = newlength lengthAsBytes,_ = json.Marshal(length) APIstub.PutState("POSTLENGTH",lengthAsBytes) return shim.Success(lengthAsBytes) } func (s *SmartContract) updatePost(APIstub shim.ChaincodeStubInterface, args []string) sc.Response { if len(args) != 14 { return shim.Error("Incorrect number of arguments. Expecting 14") } filteredtitle := sensitiveSupervision(args[3]) filteredcontent := sensitiveSupervision(args[4]) creatorByte,_:= APIstub.GetCreator() certStart := bytes.IndexAny(creatorByte, "-----BEGIN") if certStart == -1 { fmt.Errorf("No certificate found") } certText := creatorByte[certStart:] bl, _ := pem.Decode(certText) if bl == nil { fmt.Errorf("Could not decode the PEM structure") } cert, err := x509.ParseCertificate(bl.Bytes) if err != nil { fmt.Errorf("ParseCertificate failed") } uname:=cert.Subject.CommonName args11,error := strconv.Atoi(args[11]) args12,error := strconv.Atoi(args[12]) args13,error := strconv.Atoi(args[13]) if error != nil{ fmt.Println("String conversion integer failed!") } var post = Post{Id: args[0], OriginalWebsite: args[1], OriginalID: args[2], Title: filteredtitle,Content:filteredcontent,AuthorId:args[5],PublishTime:args[6],UpdateTime:args[7],Category:args[8],SourceId:args[9],Labels:args[10],Follower_num:args11,Browse_num:args12,Star_num:args13,UserName:uname} postAsBytes, _ := json.Marshal(post) APIstub.PutState("POST"+args[0], postAsBytes) return shim.Success(nil) } func (s *SmartContract) richQueryPosts(APIstub shim.ChaincodeStubInterface, args []string) sc.Response { if len(args) != 3 { return shim.Error("Incorrect number of arguments. Expecting 3") } var queryString string if args[1] == "0" { queryString = fmt.Sprintf("{\"selector\":{\"%s\":\"%s\"}}", args[0],args[2]) } else if args[1] == "1" { queryString = fmt.Sprintf("{\"selector\":{\"%s\":{\"$gt\":%s}}}", args[0],args[2]) } else if args[1] == "2" { queryString = fmt.Sprintf("{\"selector\":{\"%s\":{\"$gte\":%s}}}", args[0],args[2]) } else if args[1] == "3" { queryString = fmt.Sprintf("{\"selector\":{\"%s\":{\"$lt\":%s}}}", args[0],args[2]) } else if args[1] == "4" { queryString = fmt.Sprintf("{\"selector\":{\"%s\":{\"$lte\":%s}}}", args[0],args[2]) } else if args[1] == "5" { between := strings.Split(args[2], ",") queryString = fmt.Sprintf("{\"selector\":{\"$and\":[{\"%s\":{\"$gte\":%s}},{\"%s\":{\"$lte\":%s}}]}}", args[0],between[0],args[0],between[1]) } else if args[1] == "6" { queryString = fmt.Sprintf("{\"selector\":{\"%s\":{\"$regex\":\"(?i)%s\"}}}", args[0],args[2]) } else { return shim.Error("Incorrect number of arguments. Expecting 0~6") } resultsIterator, err := APIstub.GetQueryResult(queryString) if err != nil { return shim.Error(err.Error()) } defer resultsIterator.Close() var buffer bytes.Buffer buffer.WriteString("[") bArrayMemberAlreadyWritten := false for resultsIterator.HasNext() { queryResponse, err := resultsIterator.Next() if err != nil { return shim.Error(err.Error()) } if bArrayMemberAlreadyWritten == true { buffer.WriteString(",") } buffer.WriteString("{\"Key\":") buffer.WriteString("\"") buffer.WriteString(queryResponse.Key) buffer.WriteString("\"") buffer.WriteString(", \"Record\":") buffer.WriteString(string(queryResponse.Value)) buffer.WriteString("}") bArrayMemberAlreadyWritten = true } buffer.WriteString("]") fmt.Printf("- richQueryPosts:\n%s\n", buffer.String()) return shim.Success(buffer.Bytes()) } func (s *SmartContract) getPostNum(APIstub shim.ChaincodeStubInterface, args []string) sc.Response { if len(args) != 3 { return shim.Error("Incorrect number of arguments. Expecting 3") } var queryString string if args[1] == "0" { queryString = fmt.Sprintf("{\"selector\":{\"%s\":\"%s\"}}", args[0],args[2]) } else if args[1] == "1" { queryString = fmt.Sprintf("{\"selector\":{\"%s\":{\"$gt\":%s}}}", args[0],args[2]) } else if args[1] == "2" { queryString = fmt.Sprintf("{\"selector\":{\"%s\":{\"$gte\":%s}}}", args[0],args[2]) } else if args[1] == "3" { queryString = fmt.Sprintf("{\"selector\":{\"%s\":{\"$lt\":%s}}}", args[0],args[2]) } else if args[1] == "4" { queryString = fmt.Sprintf("{\"selector\":{\"%s\":{\"$lte\":%s}}}", args[0],args[2]) } else if args[1] == "5" { between := strings.Split(args[2], ",") queryString = fmt.Sprintf("{\"selector\":{\"$and\":[{\"%s\":{\"$gte\":%s}},{\"%s\":{\"$lte\":%s}}]}}", args[0],between[0],args[0],between[1]) } else if args[1] == "6" { queryString = fmt.Sprintf("{\"selector\":{\"%s\":{\"$regex\":\"(?i)%s\"}}}", args[0],args[2]) } else { return shim.Error("Incorrect number of arguments. Expecting 0~6") } resultsIterator, err := APIstub.GetQueryResult(queryString) if err != nil { return shim.Error(err.Error()) } defer resultsIterator.Close() i := 0 for resultsIterator.HasNext() { resultsIterator.Next() i = i + 1 } fmt.Printf("- getPostNum:\n%s\n", strconv.Itoa(i)) return shim.Success([]byte(strconv.Itoa(i))) } func sensitiveSupervision(arg string) string { quertString := fmt.Sprintf("{\"content\":\"%s\"}",arg) resp, err := http.Post("http://敏感监管url", "application/x-www-form-urlencoded", strings.NewReader(quertString)) if err != nil { fmt.Println(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { } return string(body) } func main() { err := shim.Start(new(SmartContract)) if err != nil { fmt.Printf("Error creating new Smart Contract: %s", err) } }
二.升级链码步骤
2.1 从宿主机将chaincode拷贝进容器
docker cp community2.0 cli:/opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/go
2.2 安装新版本chaincode,打包到peer节点
docker exec -it cli bash
peer chaincode install -n mycc -v 2.0 -p github.com/hyperledger/fabric/examples/chaincode/go/community2.0
2.3 升级chaincode
peer chaincode upgrade -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n mycc -v 2.0 -c '{"Args":["init"]}' -P "OR ('Org1MSP.member','Org2MSP.member')"
这样chaincode就升级完毕了。