十一、ブロックチェーン学習-Hyperledger Fabric(release-1.0に基づく)チェーンコード開発-marbles管理


チェーンコード開発-marbles管理
  • 1.概要
  • 2.marbleビーズ管理
  • 2.1実装機能
  • 2.2 chaincodeチェーンコード
  • 2.3試験類
  • を作成する
  • 2.4走試験類
  • 3ローカルテスト環境を構築し、チェーンコード
  • をテストする.
  • 3.1マウントチェーンコード
  • 3.2ネットワーク環境を起動する
  • 3.3 chaincodeコンテナコンパイルチェーンコード提供チェーンコードサービス
  • に入る.
  • 3.4 cli容器取付チェーンコードインスタンス化チェーンコード
  • に入る.
  • 3.5テストチェーンコード
  • 4ネットワークを閉じる
  • 1.概要
    前の10の文章の紹介によると、fabricのネットワーク環境とチェーンコード開発の導入デバッグの過程は基本的に理解されている.この記事では、チェーンコードの開発と呼び出しデバッグの導入を再強化します.
    2.marbleビーズ管理
    marble
    //        
    type Marble struct {
    	//     
    	ObjectType string `json:"objectType"`
    	//     
    	Name string `json:"name"`
    	//     
    	Color string `json:"color"`
    	//     
    	Size int `json:"size"`
    	//      
    	Owner string `json:"owner"`
    }
    

    2.1実装機能
  • ビーズ作成
  • 弾珠照会
  • 弾珠削除
  • 弾珠取引
  • 弾珠操作履歴照会
  • ユーザーのビーズリスト
  • を問い合わせる
    2.2 chaincodeチェーンコード
    markbels.go
    package main
    
    //      
    import (
    	"fmt"
    	"github.com/hyperledger/fabric/core/chaincode/shim"
    	"github.com/hyperledger/fabric/protos/peer"
    
    	"time"
    	"bytes"
    	"strconv"
    	"encoding/json"
    )
    
    //      
    type MarblesChaincode struct{
    
    }
    
    //        
    type Marble struct {
    	//     
    	ObjectType string `json:"objectType"`
    	//     
    	Name string `json:"name"`
    	//     
    	Color string `json:"color"`
    	//     
    	Size int `json:"size"`
    	//      
    	Owner string `json:"owner"`
    }
    
    //        
    func (t *MarblesChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response {
    
    	//          
    	fmt.Println("MarblesChaincode      ")
    	return shim.Success(nil)
    }
    
    // invoke   
    func (t *MarblesChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
    
    	//           
    	fn, args := stub.GetFunctionAndParameters()
    
    	//          
    	if fn == "initMarble" {
    		//         
    		return t.initMarble(stub,args)
    	}else if fn == "readMarble" {
    		//            
    		return t.readMarble(stub,args)
    	}else if fn == "deleteMarble" {
    		//         
    		return t.deleteMarble(stub,args)
    	}else if fn == "transferMarble" {
    		//          
    		return t.transferMarble(stub,args)
    	}else if fn == "getMarbleByRange" {
    		//       
    		return t.getMarbleByRange(stub,args)
    	}else if fn == "queryMarblesByOwner" {
    		//              
    		return t.queryMarblesByOwner(stub,args)
    	}else if fn == "queryHistoryForMarble" {
    		//            
    		return t.queryHistoryForMarble(stub,args)
    	}
    
    	//               
    	return shim.Error(fn +"      !")
    
    }
    
    
    //   marble args: name color size owner
    func (t *MarblesChaincode) initMarble(stub shim.ChaincodeStubInterface,args []string) peer.Response {
    
    	//       marble      
    	name := args[0]
    
    	//             name  marble
    	marbleBytes, err := stub.GetState(name)
    
    	//     
    	if err != nil {
    		return shim.Error(err.Error())
    	}
    
    	//   marbleBytes      
    	if marbleBytes != nil {
    		return shim.Error("  "+ name + "       ");
    	}
    
    	//              
    	color := args[1]
    	size,err := strconv.Atoi(args[2])
    	owner := args[3]
    
    	//       
    	marble := &Marble{"marble",name,color,size,owner}
    
    	//  marble   json         
    	marbleJsonStr, err := json.Marshal(marble)
    	if err != nil {
    		return shim.Error(err.Error())
    	}
    
    	// PutState json      
    	err = stub.PutState(name,marbleJsonStr)
    	if err != nil {
    		return shim.Error(err.Error())
    	}
    
    	fmt.Println("      !!")
    	//            
    	indexName := "owner~record"
    	indexKey, err := stub.CreateCompositeKey(indexName,[]string{ owner,string(marbleJsonStr)})
    	if err != nil{
    		return shim.Error(err.Error())
    	}
    	err = stub.PutState(indexKey,[]byte{0x00})
    	if err != nil{
    		return shim.Error(err.Error())
    	}
    	fmt.Println(indexKey)
    	return shim.Success(nil)
    }
    
    //   marble args:  marbleName
    func (t *MarblesChaincode) readMarble(stub shim.ChaincodeStubInterface,args []string) peer.Response {
    	//         marble name
    	name := args[0]
    
    	//   name   marble   
    	marbleBytes, err := stub.GetState(name)
    
    	if err != nil {
    		return shim.Error(err.Error())
    	}
    
    	if marbleBytes == nil {
    		return shim.Error(name + "         ")
    	}
    
    	//      
    	return shim.Success(marbleBytes)
    
    }
    
    //   marble args: marbleName
    func (t *MarblesChaincode) deleteMarble(stub shim.ChaincodeStubInterface,args []string) peer.Response {
    	//        markble name
    	name := args[0]
    
    	//         
    	marbleBytes, err := stub.GetState(name)
    	if err != nil {
    		return shim.Error(err.Error())
    	}
    
    	if marbleBytes == nil {
    		return shim.Error(name + "        ")
    	}
    
    	//     
    	err = stub.DelState(name)
    
    	if err != nil {
    		return shim.Error(err.Error())
    	}
    
    	fmt.Println(name + "       !")
    	return shim.Success(nil)
    }
    
    //   marble args: marbleName newOwner
    func (t *MarblesChaincode) transferMarble(stub shim.ChaincodeStubInterface,args []string) peer.Response {
    
    	//      
    	marbleName := args[0]
    
    	newOwner := args[1]
    
    	//         
    	marbleBytes, err := stub.GetState(marbleName)
    	if err != nil{
    		return shim.Error(err.Error())
    	}
    	if marbleBytes == nil {
    		return shim.Error(marbleName + "         ")
    	}
    
    	//           Marble    
    	marbleInfo := Marble{}
    	err = json.Unmarshal(marbleBytes,&marbleInfo)
    	if err != nil {
    		return shim.Error(err.Error())
    	}
    
    	//      
    	marbleInfo.Owner = newOwner
    
    	//   json   
    	newMarbleBytes,err := json.Marshal(marbleInfo)
    	if err != nil {
    		return shim.Error(err.Error())
    	}
    
    	//     
    	err = stub.PutState(marbleName,newMarbleBytes)
    	if err != nil {
    		return shim.Error(err.Error())
    	}
    
    	fmt.Println(marbleName +"  "+ newOwner+ "       ")
    	return shim.Success(nil)
    
    }
    
    //         marble args:startMarble endMarble
    func (t *MarblesChaincode) getMarbleByRange(stub shim.ChaincodeStubInterface, args []string) peer.Response {
    	//     
    	startMarble := args[0]
    	endMarble := args[1]
    
    	//       
    	resultIterator, err := stub.GetStateByRange(startMarble,endMarble)
    	if err!=nil {
    		return shim.Error(err.Error())
    	}
    	defer resultIterator.Close();
    	
    	var buffer bytes.Buffer
    	buffer.WriteString("[")
    
    	isWriteSplit := false
    	//   resultIterator
    	for resultIterator.HasNext() {
    		item,err := resultIterator.Next()
    		if err!= nil {
    			return shim.Error(err.Error())
    		}
    		if isWriteSplit==true {
    			buffer.WriteString(",")
    		}
    		buffer.WriteString("{\"key\":")
    		buffer.WriteString("\""+item.Key+"\"")
    		buffer.WriteString(",\"record\":")
    		buffer.WriteString(string(item.Value))
    		buffer.WriteString("}")
    		isWriteSplit = true
    	}
    	buffer.WriteString("]")
    
    	//     
    	return shim.Success(buffer.Bytes())
    
    }
    
    //            
    func (t *MarblesChaincode) queryMarblesByOwner(stub shim.ChaincodeStubInterface,args []string) peer.Response {
    	//           couchdb               
    	//       couchdb           cli      couchdb 
    	//      couchdb          cli       。
    	//  chaincode-docker-devmode    script.sh  cli      channel   channel   
    	//        sleep 10s        couchdb    
    	owner := args[0]
    	fmt.Println("      "+owner+"       ")
    
    	queryString := fmt.Sprintf("{\"selector\":{\"owner\": \"%s\" }}",owner)
    
    	resultIterator,err := stub.GetQueryResult(queryString)
    	if err != nil {
    		return shim.Error(err.Error())
    	}
    	defer resultIterator.Close();
    
    	var buffer bytes.Buffer
    	buffer.WriteString("[")
    
    	isWriteSplit := false
    	//   resultIterator
    	for resultIterator.HasNext() {
    		item,err := resultIterator.Next()
    		if err!= nil {
    			return shim.Error(err.Error())
    		}
    		if isWriteSplit==true {
    			buffer.WriteString(",")
    		}
    		buffer.WriteString("{\"key\":")
    		buffer.WriteString("\""+item.Key+"\"")
    		buffer.WriteString(",\"record\":")
    		buffer.WriteString(string(item.Value))
    		buffer.WriteString("}")
    		isWriteSplit = true
    	}
    	buffer.WriteString("]")
    
    	//     
    	return shim.Success(buffer.Bytes())
    
    }
    
    //     
    func (t *MarblesChaincode) queryHistoryForMarble(stub shim.ChaincodeStubInterface,args []string) peer.Response {
    	//     
    	marbleName := args[0]
    	//       
    	resultIterator,err := stub.GetHistoryForKey(marbleName)
    	if err != nil {
    		return shim.Error(err.Error())
    	}
    	defer resultIterator.Close()
    
    
    	var buffer bytes.Buffer
    	buffer.WriteString("[")
    
    	isWriteSplit := false
    	//   resultIterator
    	for resultIterator.HasNext() {
    		item,err := resultIterator.Next()
    		if err!= nil {
    			return shim.Error(err.Error())
    		}
    
    		if isWriteSplit==true {
    			buffer.WriteString(",")
    		}
    		buffer.WriteString("{\"TxId\":")
    		buffer.WriteString("\""+item.TxId+"\"")
    		buffer.WriteString(",\"Timestamp\":")
    		buffer.WriteString(time.Unix(item.Timestamp.Seconds,int64(item.Timestamp.Nanos)).String())
    		buffer.WriteString(",\"Value\":")
    		buffer.WriteString(string(item.Value))
    		buffer.WriteString(",\"IsDelete\":")
    		buffer.WriteString(strconv.FormatBool(item.IsDelete))
    		buffer.WriteString("}")
    		isWriteSplit = true
    	}
    	buffer.WriteString("]")
    
    	//               
    	return shim.Success(buffer.Bytes())
    
    }
    
    // main   
    func main (){
    	err := shim.Start(new (MarblesChaincode))
    	if err != nil {
    		fmt.Printf("Error start MarblesChaincode")
    	}
    }
    
    

    2.3試験クラスの作成
    markbels_test.go
    package main
    
     import(
     	"fmt"
     	"testing"
     	"github.com/hyperledger/fabric/core/chaincode/shim"
     )
    
     func checkInit(t *testing.T,stub *shim.MockStub,args [][]byte) {
     	res := stub.MockInit("1",args)
     	if (res.Status != shim.OK){
     		fmt.Println(string(res.Message))
     		t.FailNow()
     	}
     }
    
     func checkInvoke(t *testing.T,stub *shim.MockStub,args [][]byte) {
     	res := stub.MockInvoke("1",args)
     	if (res.Status != shim.OK){
     		fmt.Println(string(res.Message))
     		t.FailNow()
     	}
     }
    
     func checkReadMarble(t *testing.T,stub *shim.MockStub, name string) {
     	res := stub.MockInvoke("1",[][]byte{[]byte("readMarble"),[]byte(name)})
     	if(res.Status != shim.OK){
    		fmt.Println(string(res.Message))
    		t.FailNow()
     	}
    
     	if(res.Payload == nil){
     		fmt.Println("checkReadMarble",name,"failed to get value")
     		t.FailNow()
     	}
    
     	fmt.Println(string(res.Payload))
     }
    
     func checkReadMarbleByRange(t *testing.T,stub *shim.MockStub, startKey string,endKey string) {
     	res := stub.MockInvoke("1",[][]byte{[]byte("getMarbleByRange"),[]byte(startKey),[]byte(endKey)})
     	if(res.Status != shim.OK){
    		fmt.Println(string(res.Message))
    		t.FailNow()
     	}
    
     	if(res.Payload == nil){
     		fmt.Println("checkReadMarbleByRange",startKey,endKey,"failed to get value")
     		t.FailNow()
     	}
    
     	fmt.Println(string(res.Payload))
     }
    
     func checkQueryMarblesByOwner(t *testing.T,stub *shim.MockStub, owner string) {
     	res := stub.MockInvoke("1",[][]byte{[]byte("queryMarblesByOwner"),[]byte(owner)})
     	if(res.Status != shim.OK){
    		fmt.Println(string(res.Message))
    		t.FailNow()
     	}
    
     	if(res.Payload == nil){
     		fmt.Println("checkQueryMarblesByOwner",owner,"failed to get value")
     		t.FailNow()
     	}
    
     	fmt.Println(string(res.Payload))
     }
    
     func checkQueryMarblesHistoryByKey(t *testing.T,stub *shim.MockStub, marbleName string) {
     	res := stub.MockInvoke("1",[][]byte{[]byte("queryHistoryForMarble"),[]byte(marbleName)})
     	if(res.Status != shim.OK){
    		fmt.Println(string(res.Message))
    		t.FailNow()
     	}
    
     	if(res.Payload == nil){
     		fmt.Println("checkReadMarbleByRange",marbleName,"failed to get value")
     		t.FailNow()
     	}
    
     	fmt.Println(string(res.Payload))
     }
    
     func Test_MarblesChaincode(t *testing.T) {
     	hello := new(MarblesChaincode)
     	stub := shim.NewMockStub("marble",hello)
    
     	checkInit(t,stub,nil)
     	// name color size owner
     	checkInvoke(t,stub,[][]byte{[]byte("initMarble"),[]byte("marble-1"),[]byte("red"),[]byte("10"),[]byte("LH")})
     	checkInvoke(t,stub,[][]byte{[]byte("initMarble"),[]byte("marble-2"),[]byte("yellow"),[]byte("11"),[]byte("LH")})
     	checkInvoke(t,stub,[][]byte{[]byte("initMarble"),[]byte("marble-3"),[]byte("blue"),[]byte("12"),[]byte("WX")})
    	checkQueryMarblesByOwner(t,stub,"WX")
    
     	// checkReadMarble(t,stub,"marble-1")
     	// checkInvoke(t,stub,[][]byte{[]byte("transferMarble"),[]byte("marble-1"),[]byte("WX")})
     	// checkInvoke(t,stub,[][]byte{[]byte("transferMarble"),[]byte("marble-1"),[]byte("LH")})
     	// checkInvoke(t,stub,[][]byte{[]byte("deleteMarble"),[]byte("marble-1")})
     	// checkQueryMarblesHistoryByKey(t,stub,"marble-1")
     	// checkInvoke(t,stub,[][]byte{[]byte("initMarble"),[]byte("marble-4"),[]byte("green"),[]byte("12"),[]byte("WX")})
     	// checkReadMarbleByRange(t,stub,"marble-1","marble-4")
    	// checkReadMarble(t,stub,"marble-1") 	
     	// checkInvoke(t,stub,[][]byte{[]byte("initMarble"),[]byte("marble-1"),[]byte("red"),[]byte("10"),[]byte("LH")})
     	// checkReadMarble(t,stub,"marble-2")
     	
     }
    

    2.4ランニングテストクラス
    marbles.goとmarblesに入ります.test.goのディレクトリは$GOPATH/myに入れましたchaincode/marblesディレクトリの下
    cd $GOPATH/my_chaincode/marbles 
    go test marbles_test.go -v marbles.go --tags=nopkcs11
    

    marblesを変更してみてください.test.goは他の方法をテストします
    3ローカルテスト環境を構築し、チェーンコードをテストする
    fabric-samplesプロジェクトのchaincode-docker-devmode環境テストの使用
    3.1マウントチェーンコード
    作成されたmarbles.goとmarbles_test.goファイルの移動先
    $GOAPTH/src/github.com/hyperledger/fabric-samples/chaincode
    

    コンテナへのマウントが容易
    3.2ネットワーク環境の起動
    chaincode-docker-devmodeディレクトリに移動
    cd $GOPATH/src/github.com/hyperledger/fabric-samples/chaincode-docker-devmode
    

    docker-composeによるネットワーク環境の起動
    docker-compose -f docker-compose-simple.yaml up
    

    起動完了後のコンテナリスト
    CONTAINER ID        IMAGE                        COMMAND                  CREATED             STATUS              PORTS                                            NAMES
    a7b22f7351fa        hyperledger/fabric-tools     "/bin/bash -c ./scri…"   7 seconds ago       Up 5 seconds                                                         cli
    d761b06a034a        hyperledger/fabric-ccenv     "/bin/bash -c 'sleep…"   7 seconds ago       Up 5 seconds                                                         chaincode
    7b329ef1311f        hyperledger/fabric-peer      "peer node start --p…"   8 seconds ago       Up 6 seconds        0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp   peer
    6302ffa111e2        hyperledger/fabric-orderer   "orderer"                9 seconds ago       Up 7 seconds        0.0.0.0:7050->7050/tcp                           orderer
    

    3.3 chaincode容器に入ってチェーンコードをコンパイルしてチェーンコードサービスを提供する
    新しい端末を起動
    容器に入る
    docker exec -it chaincode /bin/bash
    

    マウントgoファイルディレクトリに移動
    cd marbles/
    

    コンパイラ
    go build
    

    コンパイル完了後にチェーンコードサービスを開始
    CORE_PEER_ADDRESS=peer:7051 CORE_CHAINCODE_ID_NAME=mycc:0 ./marbles
    

    3.4 cli容器に入ってチェーンコードを実例化する
    新しい端末を起動してcliコンテナに入ります
    docker exec -it cli /bin/bash
    

    チェーンコードのインストール
    peer chaincode install -p chaincodedev/chaincode/marbles -n mycc -v 0 
    

    イニシャルチェーンコード
    peer chaincode instantiate -n mycc -v 0 -c '{"Args":[]}' -C myc
    

    3.5テストチェーンコード
    3つのビーズを作成
    peer chaincode invoke -n mycc -c '{"Args":["initMarble","marble-1","red","10","LH"]}' -C myc
    peer chaincode invoke -n mycc -c '{"Args":["initMarble","marble-2","yellow","11","LH"]}' -C myc
    peer chaincode invoke -n mycc -c '{"Args":["initMarble","marble-3","blue","12","WX"]}' -C myc
    

    玉を調べる
    peer chaincode query -n mycc -c '{"Args":["readMarble","marble-1"]}' -C myc
    

    範囲クエリー
    peer chaincode query -n mycc -c '{"Args":["getMarbleByRange","marble-1","marble-3"]}' -C myc
    

    玉を譲り渡す
    peer chaincode invoke -n mycc -c '{"Args":["transferMarble","marble-1","WX"]}' -C myc
    

    再照会marble-1:ownerがWXになるかどうか
    peer chaincode query -n mycc -c '{"Args":["readMarble","marble-1"]}' -C myc
    

    ownerのすべてのビーズを検索
    peer chaincode query -n mycc -c '{"Args":["queryMarblesByOwner","WX"]}' -C myc
    

    ビーズ修正履歴の表示:結果として、初期化されたトランザクションと譲渡されたトランザクションを問い合わせることができます.
    peer chaincode query -n mycc -c '{"Args":["queryHistoryForMarble","marble-1"]}' -C myc 
    

    4ネットワークのシャットダウン
    ネットワークを最初に起動した端末で2回control+cを押した後に実行
     docker-compose -f docker-compose-simple.yaml down
    

    すべてのコンテナを停止して閉じる