fabric1.2私有数据使用

下载fabric1.2,使用bootstrap.sh下载所需镜像。

注意:fabric12.需要go的版本 为1.10.X。

1.定义私有数据集合的配置文件

// collections_config.json

[
  {
       "name": "collectionMarbles",
       "policy": "OR('Org1MSP.member', 'Org2MSP.member')",
       "requiredPeerCount": 0,
       "maxPeerCount": 3,
       "blockToLive":1000000
  },

  {
       "name": "collectionMarblePrivateDetails",
       "policy": "OR('Org1MSP.member')",
       "requiredPeerCount": 0,
       "maxPeerCount": 3,
       "blockToLive":3
  }
]

集合定义配置文件由5个属性组成:
* name:集合名称
* policy:定义组织peer节点,允许使用签名策略语法来持久化收集数据,每个成员被包含在签名策略列表中。
* requiredPeerCount:在peer节点签名背书并返回提案响应给客户端,成功传送私有数据的最小认可节点。
* maxPeerCount:为了数据冗余保存的目的,需要同步保存私有数据的被认可的最大peer节点数量。如果一个可信节点宕机后,其他的持有私有冗余数据的节点依然可以提供数据请求访问服务。
* blockToLive:私有数据在sideDB保存时长。如果要一致保存,则配置为0。

2. 使用链码API对私有数据进行读写操作

代码如下:

//marbles_private.go文件:
package main

import (
	"encoding/json"
	"fmt"
	"strconv"

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

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

// Org1 与 Org2 组织中的peer节点可以从sidedb中访问私有数据
type marble struct {
  ObjectType string `json:"docType"`
  Name       string `json:"name"`
  Color      string `json:"color"`
  Size       int    `json:"size"`
  Owner      string `json:"owner"`
}

// Org1组织中的Peer节点可以从sidedb中访问私有数据
type marblePrivateDetails struct {
  ObjectType string `json:"docType"`
  Name       string `json:"name"`
  Price      int    `json:"price"`
}

// ===================================================================================
// Main
// ===================================================================================
func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

// Init initializes chaincode
// ===========================
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
       return shim.Success(nil)	
}

// Invoke - Our entry point for Invocations
// ========================================
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
	function, args := stub.GetFunctionAndParameters()
	fmt.Println("invoke is running " + function)

	// Handle different functions
	if function == "invokeMarble" {
        	return t.invokeMarble(stub, args)
        } else if function == "readMarble" { //read a marble
		return t.readMarble(stub, args)
	} else if function == "readMarblePrivateDetails" { //find marbles for owner X using rich query
		return t.readMarblePrivateDetails(stub, args)
	}

	fmt.Println("invoke did not find func: " + function) //error
	return shim.Error("Received unknown function invocation")
}

func (t *SimpleChaincode) invokeMarble(stub shim.ChaincodeStubInterface, args []string) pb.Response {
// === Save marble to state ===
	marbles := []marble{
		   marble{ObjectType: "marble", Name: "marble2", Color: "blue", Size: 15, Owner : "tom"},
		   marble{ObjectType: "marble", Name: "marble3", Color: "blue", Size: 50, Owner : "tom"},
		   marble{ObjectType: "marble", Name: "marble4", Color: "red", Size: 35, Owner : "bob"},
		   marble{ObjectType: "marble", Name: "marble5", Color: "red", Size: 15, Owner : "bob"},
		   marble{ObjectType: "marble", Name: "marble6", Color: "red", Size: 8, Owner : "pp"},
	}
	i := 0
	for i < len(marbles){
		marbleJSONasBytes,_ := json.Marshal(marbles[i])
		err :=  stub.PutPrivateData("collectionMarbles", "marble"+strconv.Itoa(i+2), marbleJSONasBytes)
		if err != nil {
			return shim.Error(err.Error())
		}
		i = i + 1
	}

// ==== Save marble private details ====
       objectType := "marblePrivateDetails"
       marblePrivateDetails := &marblePrivateDetails{objectType, "marble1", 100}
       marblePrivateDetailsBytes, err := json.Marshal(marblePrivateDetails)
       if err != nil {
               return shim.Error(err.Error())
       }
       err = stub.PutPrivateData("collectionMarblePrivateDetails", "marble1", marblePrivateDetailsBytes)
       if err != nil {
               return shim.Error(err.Error())
       }

       return shim.Success(nil)
}
// ===============================================
// readMarble - read a marble from chaincode state
// ===============================================

func (t *SimpleChaincode) readMarble(stub shim.ChaincodeStubInterface, args []string) pb.Response {
        var name, jsonResp string
    	var err error
   	if len(args) != 1 {
                return shim.Error("Incorrect number of arguments. Expecting name of the marble to query")
        }

	name = args[0]
	valAsbytes, err := stub.GetPrivateData("collectionMarbles", name) //get the marble from chaincode state

        if err != nil {
    		jsonResp = "{\"Error\":\"Failed to get state for " + name + "\"}"
    		return shim.Error(jsonResp)
	} else if valAsbytes == nil {
   		jsonResp = "{\"Error\":\"Marble does not exist: " + name + "\"}"
    		return shim.Error(jsonResp)
	}
       
	return shim.Success(valAsbytes)
}

// ===============================================
// readMarblereadMarblePrivateDetails - read a marble private details from chaincode state
// ===============================================

func (t *SimpleChaincode) readMarblePrivateDetails(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	var name, jsonResp string
	var err error

	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting name of the marble to query")
	}

	name = args[0]
	valAsbytes, err := stub.GetPrivateData("collectionMarblePrivateDetails", name) //get the marble private details from chaincode state

	if err != nil {
		jsonResp = "{\"Error\":\"Failed to get private details for " + name + ": " + err.Error() + "\"}"
		return shim.Error(jsonResp)
	} else if valAsbytes == nil {
		jsonResp = "{\"Error\":\"Marble private details does not exist: " + name + "\"}"
		return shim.Error(jsonResp)
	}
	return shim.Success(valAsbytes)
}

定义的规则如下:
- "name,color,size,and owner" 可以被Org1和Org2组织下的所有成员访问
- "price" 仅仅被Org1组织下的成员访问

其中,链码的shim APIs接口提供常用私有数据操作方法:

  • PutPrivateData(collection,key,value)
  • GetPrivateData(collection,key)
  • GetPrivateDataByRange(collection, startKey, endKey string)
  • GetPrivateDataByPartialCompositeKey(collection, objectType string, keys []string)
  • GetPrivateDataQueryResult(collection, query string) (*只有使用couchdb才能使用富查询语句

注意:fabric1.2的e2e默认背书策略为AND,invoke等操作都需要在两个组织的背书节点上进行背书。

3.安装链码 (script.sh)

peer chaincode install -n mycc5 -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/marbles_private

4.初始化链码 (script.sh)

peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc5 -v 1.0 -c '{"Args":["init"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" --collections-config /opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/go/marbles_private/collections_config.json

注意在链码初始化的时候使用命令加载该配置文件

peer chaincode instantiate ... --collections-config

5.插入弹珠(script.sh)

peer chaincode invoke -o orderer.example.com:7050  --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc4 $PEER_CONN_PARMS -c '{"Args":["invokeMarble"]}'

6.查询私有数据

peer chaincode query -C mychannel -n mycc -c '{"Args":["readMarble","marble1"]}'
peer chaincode query -C mychannel -n mycc -c '{"Args":["readMarblePrivateDetails","marble1"]}'

 注意:若查询未被授权的私有数据,则会返回Error:nil

7. 清理私有数据

在私有数据集合中配置的属性blockToLive,可以设置在多少个区块后清理私有数据,只留下数据的哈希值,作为交易的不可改变的证据。

比如我们在创建上面的样例链码的时候,设置私有数据集合属性blockToLive=4。

在上面的样例中,我们已经初始化了一个marble1,其中price=99,使用如下命令查询:

扫描二维码关注公众号,回复: 3116747 查看本文章

详见https://blog.csdn.net/songbin830/article/details/81224203

参考https://hyperledger-fabric.readthedocs.io/en/release-1.2/private_data_tutorial.html#

猜你喜欢

转载自blog.csdn.net/mx1222/article/details/82460052