溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

fabric Transient Data與Private Data使用的示例分析

發(fā)布時間:2021-12-28 17:36:31 來源:億速云 閱讀:118 作者:小新 欄目:互聯(lián)網(wǎng)科技

這篇文章將為大家詳細講解有關(guān)fabric Transient Data與Private Data使用的示例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

1、基本概念

先讓我們重溫一下在演示程序中將要用到的一些核心概念。

賬本:在Hyperledger Fabric中,當(dāng)一個peer節(jié)點加入通道后,就會維護一個賬本的副本。賬本包含一個用于保存區(qū)塊的區(qū)塊鏈數(shù)據(jù)結(jié)構(gòu),以及一個用于保存最新狀態(tài)的世界狀態(tài)數(shù)據(jù)庫。當(dāng)peer節(jié)點從排序服務(wù)收到一個新的區(qū)塊并且驗證成功后,peer節(jié)點就將區(qū)塊提交進賬本,并根據(jù)區(qū)塊中每個交易的 RWSet來更新相應(yīng)的世界狀態(tài)。

基于共識機制,在一個通道中,不同的peer節(jié)點上的賬本的大部分都是一致的。不過有一個例外,F(xiàn)abric支持在部分通道之間存在的私有數(shù)據(jù)。

私有數(shù)據(jù):在一個通道內(nèi)有時會需要僅在部分機構(gòu)之間共享數(shù)據(jù)。Hyperledger Fabric引入私有數(shù)據(jù)的目的就是滿足這一需求。通過定義數(shù)據(jù)集,我們可以聲明私有數(shù)據(jù)實現(xiàn)的機構(gòu)子集,同時所有節(jié)點(包括在機構(gòu)子集之外的其他節(jié)點)都會保存私有數(shù)據(jù)哈希的記錄以便作為數(shù)據(jù)存在的證據(jù)或者用于審計目的。

可以利用鏈碼API來使用私有數(shù)據(jù)。我們在示例代碼中使用PutPrivateData和GetPrivateData這兩個API。作為對比,我們使用PutState和GetState完成對公共狀態(tài)的讀寫。

在Fabric 2.0中,會為每個機構(gòu)準備一個隱含的數(shù)據(jù)集。本教程將利用這個隱含的數(shù)據(jù)集,因此我們不需要單獨的數(shù)據(jù)集定義文件。

Fabric的賬本結(jié)構(gòu)以及私有數(shù)據(jù)的位置如下圖所示,在后面的演示代碼中,我們將查看交易以及世界狀態(tài)數(shù)據(jù)庫的內(nèi)容:

fabric Transient Data與Private Data使用的示例分析

暫態(tài)數(shù)據(jù):許多鏈碼函數(shù)在被調(diào)用時需要額外的輸入數(shù)據(jù)。在大多數(shù)情況下我們會在調(diào)用函數(shù)時傳入一組參數(shù),而鏈碼參數(shù),包括函數(shù)名和函數(shù)參數(shù),都會作為有效交易的一部分保存在區(qū)塊內(nèi),因此將永久性的存在于賬本中。如果出于某種原因我們不希望在鏈上永久保存參數(shù)列表,我們就可以使用暫態(tài)數(shù)據(jù)。暫態(tài)數(shù)據(jù)是一種可以向鏈碼函數(shù)傳參但不需要將其保存在交易記錄中的輸入方法。當(dāng)使用暫態(tài)數(shù)據(jù)時,需要一個特殊的鏈碼API即GetRansient方法來讀取暫態(tài)數(shù)據(jù)。我們接下來將在演示代碼中看到。

因此,鏈碼的設(shè)計需要根據(jù)業(yè)務(wù)需求設(shè)計鏈碼,決定哪些數(shù)據(jù)應(yīng)當(dāng)作為正常參數(shù)輸入并記錄在交易中,哪些數(shù)據(jù)應(yīng)當(dāng)作為暫態(tài)數(shù)據(jù)輸入而不必記錄在鏈上。

私有數(shù)據(jù)與暫態(tài)數(shù)據(jù)的關(guān)系:私有數(shù)據(jù)與暫態(tài)數(shù)據(jù)并不是直接相關(guān)的,我們可以只使用私有數(shù)據(jù)而不利用暫態(tài)數(shù)據(jù)作為輸入,也可以在非私有數(shù)據(jù)中使用暫態(tài)數(shù)據(jù)。因此我們可以得到示例中的四種應(yīng)用場景并觀察每種場景下的結(jié)果。

私有數(shù)據(jù)與暫態(tài)數(shù)據(jù)的關(guān)系如下圖所示:

fabric Transient Data與Private Data使用的示例分析

輸入方法的選擇以及是否是否私有數(shù)據(jù)依賴于具體的業(yè)務(wù)需求,因為鏈碼函數(shù)反應(yīng)了真實的業(yè)務(wù)交易。我們可以選擇普通的參數(shù)列表、暫態(tài)數(shù)據(jù)或者同時使用兩種方式的輸入,也可以向公共狀態(tài)或者私有數(shù)據(jù)集寫入數(shù)據(jù)。我們需要的是正確地選擇需要使用的鏈碼API。

2、應(yīng)用場景概述

如前所述,我們將私有數(shù)據(jù)和暫態(tài)數(shù)據(jù)進行2X2的組合,概述如下:

fabric Transient Data與Private Data使用的示例分析

場景1:不使用私有數(shù)據(jù),不輸入暫態(tài)數(shù)據(jù)

在這種場景下,數(shù)據(jù)被寫入賬本中的公開狀態(tài)部分,所有的peer節(jié)點將保存相同的賬本數(shù)據(jù)。在鏈碼中使用PutState和GetState來訪問這部分數(shù)據(jù)。當(dāng)我們調(diào)用鏈碼時,使用普通的參數(shù)列表指定輸入數(shù)據(jù)。

當(dāng)通道中的所有機構(gòu)都需要相同的數(shù)據(jù)時,適合采用這種方式。

場景2:使用私有數(shù)據(jù),不輸入暫態(tài)數(shù)據(jù)

在這種場景下,數(shù)據(jù)被寫入賬本中的私有數(shù)據(jù)部分,并且只有在私有數(shù)據(jù)集定義的機構(gòu)的peer節(jié)點上會保存數(shù)據(jù)。在鏈碼中我們使用PutPrivateData和GetPrivateData來訪問私有數(shù)據(jù)集。當(dāng)我們調(diào)用鏈碼時,使用普通的參數(shù)列表指定輸入數(shù)據(jù)。

當(dāng)應(yīng)用中存在對部分數(shù)據(jù)的隱私需求,而對于輸入數(shù)據(jù)不敏感時,可以采用這種方式。

場景3:使用私有數(shù)據(jù),輸入暫態(tài)數(shù)據(jù)

類似于場景2,數(shù)據(jù)被寫入賬本中的私有數(shù)據(jù)部分,只有在私有數(shù)據(jù)集定義中的那些peer節(jié)點會保存這部分私有數(shù)據(jù)。在鏈碼中,我們使用PutPrivateData和GetPrivateData來訪問數(shù)據(jù)集。當(dāng)我們調(diào)用鏈碼時,采用暫態(tài)數(shù)據(jù)作為輸入,因此在鏈碼中我們需要使用GetTransient來處理輸入數(shù)據(jù)。

場景4:不使用私有數(shù)據(jù),輸入暫態(tài)數(shù)據(jù)

這是一個想象的場景,只是用來表明在不使用私有數(shù)據(jù)時,也可以使用暫態(tài)數(shù)據(jù)作為輸入。我們在鏈碼中使用PutState和GetState來將數(shù)據(jù)保存到賬本的公共狀態(tài),而采用暫態(tài)數(shù)據(jù)作為鏈碼調(diào)用的輸入?yún)?shù)。和之前一樣,我們在鏈碼中使用GetTransient方法來處理輸入數(shù)據(jù)。

3、演示環(huán)境搭建

在這些演示中我們使用Fabric 2.0,使用First Network作為Fabric網(wǎng)絡(luò)。我們采用CouchDB選項啟動網(wǎng)絡(luò),以便于查看世界狀態(tài)數(shù)據(jù)庫的內(nèi)容。我們將重點關(guān)注peer0.org1.example.com (couchdb port 5984) 和 peer0.org2.example.com (couchdb port 7984) 以便查看兩個機構(gòu)中的節(jié)點的行為。

在私有數(shù)據(jù)部分,我們使用Org1內(nèi)置的隱含私有數(shù)據(jù)集(_implicit_org_Org1MSP)。只有Org1中的peer節(jié)點可以保存私有數(shù)據(jù),而Org1和Org2中的節(jié)點都可以保存數(shù)據(jù)哈希。

我們修改了fabric-samples中的SACC鏈碼。SACC鏈碼有兩個函數(shù)set和get。為了展示私有數(shù)據(jù)和暫態(tài)數(shù)據(jù),我們創(chuàng)建以下函數(shù):

  • setPrivate:使用相同的參數(shù)列表,數(shù)據(jù)保存在Org1隱含的私有數(shù)據(jù)集

  • setPrivateTransient:使用暫態(tài)數(shù)據(jù)輸入,數(shù)據(jù)保存在Org1隱含的私有數(shù)據(jù)集

  • setTransient:使用暫態(tài)數(shù)據(jù)輸入,數(shù)據(jù)保存在公共狀態(tài)

  • getPrivate:提取保存在Org1隱含的私有數(shù)據(jù)集中的數(shù)據(jù)

修改后的SACC鏈碼如下:

/*
 * Copyright IBM Corp All Rights Reserved
 *
 * SPDX-License-Identifier: Apache-2.0
 */

package main

import (
	"encoding/json"
	"fmt"

	"github.com/hyperledger/fabric-chaincode-go/shim"
	"github.com/hyperledger/fabric-protos-go/peer"
)

// SimpleAsset implements a simple chaincode to manage an asset
type SimpleAsset 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 *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
	// Get the args from the transaction proposal
	args := stub.GetStringArgs()
	if len(args) != 2 {
		return shim.Error("Incorrect arguments. Expecting a key and a value")
	}

	// Set up any variables or assets here by calling stub.PutState()

	// We store the key and the value on the ledger
	err := stub.PutState(args[0], []byte(args[1]))
	if err != nil {
		return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0]))
	}
	return shim.Success(nil)
}

// Invoke is called per transaction on the chaincode. Each transaction is
// either a 'get' or a 'set' on the asset created by Init function. The Set
// method may create a new asset by specifying a new key-value pair.
func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
	// Extract the function and args from the transaction proposal
	fn, args := stub.GetFunctionAndParameters()

	var result string
	var err error
	if fn == "set" {
		result, err = set(stub, args)
	} else if fn == "setPrivate" {
		result, err = setPrivate(stub, args)
	} else if fn == "setTransient" {
		result, err = setTransient(stub, args)
	} else if fn == "setPrivateTransient" {
		result, err = setPrivateTransient(stub, args)
	} else if fn == "getPrivate" {
		result, err = getPrivate(stub, args)
	} else { // assume 'get' even if fn is nil
		result, err = get(stub, args)
	}
	if err != nil {
		return shim.Error(err.Error())
	}

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

// Set stores the asset (both key and value) on the ledger. If the key exists,
// it will override the value with the new one
func set(stub shim.ChaincodeStubInterface, args []string) (string, error) {
	if len(args) != 2 {
		return "", fmt.Errorf("Incorrect arguments. Expecting a key and a value")
	}

	err := stub.PutState(args[0], []byte(args[1]))
	if err != nil {
		return "", fmt.Errorf("Failed to set asset: %s", args[0])
	}
	return args[1], nil
}

func setPrivate(stub shim.ChaincodeStubInterface, args []string) (string, error) {
	if len(args) != 2 {
		return "", fmt.Errorf("Incorrect arguments. Expecting a key and a value")
	}

	err := stub.PutPrivateData("_implicit_org_Org1MSP", args[0], []byte(args[1]))
	if err != nil {
		return "", fmt.Errorf("Failed to set asset: %s", args[0])
	}
	return args[1], nil
}

func setTransient(stub shim.ChaincodeStubInterface, args []string) (string, error) {

	type keyValueTransientInput struct {
		Key   string `json:"key"`
		Value string `json:"value"`
	}

	if len(args) != 0 {
		return "", fmt.Errorf("Incorrect arguments. Expecting no data when using transient")
	}

	transMap, err := stub.GetTransient()
	if err != nil {
		return "", fmt.Errorf("Failed to get transient")
	}

	// assuming only "name" is processed
	keyValueAsBytes, ok := transMap["keyvalue"]
	if !ok {
		return "", fmt.Errorf("key must be keyvalue")
	}

	var keyValueInput keyValueTransientInput
	err = json.Unmarshal(keyValueAsBytes, &keyValueInput)
	if err != nil {
		return "", fmt.Errorf("Failed to decode JSON")
	}

	err = stub.PutState(keyValueInput.Key, []byte(keyValueInput.Value))
	if err != nil {
		return "", fmt.Errorf("Failed to set asset")
	}
	return keyValueInput.Value, nil
}

func setPrivateTransient(stub shim.ChaincodeStubInterface, args []string) (string, error) {

	type keyValueTransientInput struct {
		Key   string `json:"key"`
		Value string `json:"value"`
	}

	if len(args) != 0 {
		return "", fmt.Errorf("Incorrect arguments. Expecting no data when using transient")
	}

	transMap, err := stub.GetTransient()
	if err != nil {
		return "", fmt.Errorf("Failed to get transient")
	}

	// assuming only "name" is processed
	keyValueAsBytes, ok := transMap["keyvalue"]
	if !ok {
		return "", fmt.Errorf("key must be keyvalue")
	}

	var keyValueInput keyValueTransientInput
	err = json.Unmarshal(keyValueAsBytes, &keyValueInput)
	if err != nil {
		return "", fmt.Errorf("Failed to decode JSON")
	}

	err = stub.PutPrivateData("_implicit_org_Org1MSP", keyValueInput.Key, []byte(keyValueInput.Value))
	if err != nil {
		return "", fmt.Errorf("Failed to set asset")
	}
	return keyValueInput.Value, nil
}

// Get returns the value of the specified asset key
func get(stub shim.ChaincodeStubInterface, args []string) (string, error) {
	if len(args) != 1 {
		return "", fmt.Errorf("Incorrect arguments. Expecting a key")
	}

	value, err := stub.GetState(args[0])
	if err != nil {
		return "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err)
	}
	if value == nil {
		return "", fmt.Errorf("Asset not found: %s", args[0])
	}
	return string(value), nil
}

// Get returns the value of the specified asset key
func getPrivate(stub shim.ChaincodeStubInterface, args []string) (string, error) {
	if len(args) != 1 {
		return "", fmt.Errorf("Incorrect arguments. Expecting a key")
	}

	value, err := stub.GetPrivateData("_implicit_org_Org1MSP", args[0])
	if err != nil {
		return "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err)
	}
	if value == nil {
		return "", fmt.Errorf("Asset not found: %s", args[0])
	}
	return string(value), nil
}

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

4、Fabric私有數(shù)據(jù)和暫態(tài)數(shù)據(jù)演示

首先啟動First Network,不要部署默認鏈碼,啟用CouchDB選項:

cd fabric-samples/first-network
./byfn.sh up -n -s couchdb

當(dāng)看到所有容器(5個排序節(jié)點,4個peer節(jié)點,4個couchdb,一個CLI)啟動后:

fabric Transient Data與Private Data使用的示例分析

創(chuàng)建一個新的鏈碼目錄:

cd fabric-samples/chaincode
cp -r sacc sacc_privatetransientdemo
cd sacc_privatetransientdemo

然后使用上面的鏈碼替換sacc.go。

在第一次運行之前我們需要先加載依賴的模塊:

GO111MODULE=on go mod vendor

最后我們使用lifecycle chaincode命令部署這個鏈碼。

5、場景1演示:不使用Fabric私有數(shù)據(jù)和暫態(tài)數(shù)據(jù)輸入

場景1時最常用的一種:使用普通的參數(shù)列表作為鏈碼方法的輸入,然后將其保存在公共狀態(tài)中,所有peer節(jié)點持有完全相同的數(shù)據(jù)。我們調(diào)用鏈碼的set和get方法。

docker exec cli peer chaincode invoke -o orderer.example.com:7050 --tls \
  --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
  --peerAddresses peer0.org1.example.com:7051 \
  --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
  --peerAddresses peer0.org2.example.com:9051 \
  --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
  -C mychannel -n mycc -c '{"Args":["set","name","alice"]}'

docker exec cli peer chaincode query -C mychannel -n mycc -c '{"Args":["get","name"]}'

結(jié)果如下:

fabric Transient Data與Private Data使用的示例分析

我們首先查看世界狀態(tài)。這個數(shù)據(jù)同時保存在peer0.org1.example.com 和peer0.org2.example.com的公共狀態(tài)中(mychannel_mycc)。

fabric Transient Data與Private Data使用的示例分析

當(dāng)查看區(qū)塊鏈中的交易記錄時,我么看到WriteSet中的鍵/值對是:name/alice,采用base64編碼。

我們也可以看到調(diào)用鏈碼時的參數(shù)列表,3個base64編碼的參數(shù)分別是:set、name和alice。

fabric Transient Data與Private Data使用的示例分析

和預(yù)期一樣,RWSet更新了公開狀態(tài),輸入?yún)?shù)被記錄在交易中。

6、場景2演示:使用私有數(shù)據(jù),不適用暫態(tài)數(shù)據(jù)輸入

在場景2中,鏈碼調(diào)用還是采用普通的參數(shù)列表,數(shù)據(jù)則保存在Org1的私有數(shù)據(jù)集。我們使用setPrivate和getPrivate訪問鏈碼

docker exec cli peer chaincode invoke -o orderer.example.com:7050 --tls \
  --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
  --peerAddresses peer0.org1.example.com:7051 \
  --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
  --peerAddresses peer0.org2.example.com:9051 \
  --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
  -C mychannel -n mycc -c '{"Args":["setPrivate","name","bob"]}'
  
docker exec cli peer chaincode query -C mychannel -n mycc -c '{"Args":["getPrivate","name"]}'

fabric Transient Data與Private Data使用的示例分析

我們首先查看世界狀態(tài)。在peer0.org1.example.com中我們可以看到數(shù)據(jù)保存為私有數(shù)據(jù), 創(chuàng)建了兩個數(shù)據(jù)庫:一個用于實際數(shù)據(jù),一個用于數(shù)據(jù)哈希。在peer0.org2.example.com 上,我們看到只有哈希文件。

fabric Transient Data與Private Data使用的示例分析 內(nèi)容的哈希在兩個機構(gòu)的節(jié)點上都是一樣的。此外,在peer0.org1.example.com中我們可以 看到調(diào)用鏈碼時輸入的數(shù)據(jù)。

fabric Transient Data與Private Data使用的示例分析

當(dāng)查看區(qū)塊鏈中的交易記錄時,我們看到?jīng)]有RWSet。相反我們看到數(shù)據(jù)被應(yīng)用于 Org1隱含的數(shù)據(jù)集,它指向已經(jīng)保存在peer中的數(shù)據(jù),通過hash得以保護這部分數(shù)據(jù)的隱私。

fabric Transient Data與Private Data使用的示例分析

我們可以看到調(diào)用鏈碼時的參數(shù)列表。3個base64編碼的參數(shù)分別是:setPrivate、name、bob。

fabric Transient Data與Private Data使用的示例分析

如果我們關(guān)系數(shù)據(jù)隱私,這可能存在問題。一方面數(shù)據(jù)保存在私有數(shù)據(jù)集中,這樣只有限定的機構(gòu)節(jié)點可以保存。另一方面,這部分隱私數(shù)據(jù)的鏈碼輸入?yún)s還是公開可見的,并且永久保存在所有peer節(jié)點的區(qū)塊鏈中。如果這不是你期望的,那么我們還需要將輸入數(shù)據(jù)隱藏掉。這就是使用暫態(tài)數(shù)據(jù)輸入的原因。

6、場景3演示:使用私有數(shù)據(jù)和暫態(tài)數(shù)據(jù)輸入

如果你希望確保數(shù)據(jù)輸入不會保存在鏈上,那么場景3是推薦的方式。在這種場景下,采用暫態(tài)數(shù)據(jù)輸入,并且數(shù)據(jù)保存在Org1的私有數(shù)據(jù)集。我們使用setPrivateTransient和getPrivate方法訪問鏈碼:

在我們的鏈碼中,我們實現(xiàn)函數(shù)時將暫態(tài)數(shù)據(jù)編碼為特定的JSON格式 {“key”:”some key”, “value”: “some value”} (鏈碼134–137行)。我們也要求暫態(tài)數(shù)據(jù)包含一個keyvalue鍵(鏈碼149行)。為了在命令行調(diào)用 中使用暫態(tài)數(shù)據(jù),我們需要首先將其進行base64編碼。

export KEYVALUE=$(echo -n "{\"key\":\"name\",\"value\":\"charlie\"}" | base64 | tr -d \\n)

docker exec cli peer chaincode invoke -o orderer.example.com:7050 --tls \
  --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
  --peerAddresses peer0.org1.example.com:7051 \
  --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
  --peerAddresses peer0.org2.example.com:9051 \
  --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
  -C mychannel -n mycc -c '{"Args":["setPrivateTransient"]}' \
  --transient "{\"keyvalue\":\"$KEYVALUE\"}"
  
docker exec cli peer chaincode query -C mychannel -n mycc -c '{"Args":["getPrivate","name"]}'

結(jié)果如下:

fabric Transient Data與Private Data使用的示例分析

同樣,我們首先查看世界狀態(tài)。這類似于我們在場景2中看到的內(nèi)容。實際的數(shù)據(jù)僅在peer0.org1.example.com保存,而哈希則在兩個peer節(jié)點中都有保存。注意修訂版本的值目前是2,而在場景2中的第一次修訂的值是1。是鏈碼調(diào)用促成了對數(shù)據(jù)的修訂。

fabric Transient Data與Private Data使用的示例分析

類似于場景2,在區(qū)塊鏈上的交易記錄中,我們可以看到?jīng)]有Write Set。

fabric Transient Data與Private Data使用的示例分析

我們也可以看到?jīng)]有調(diào)用鏈碼的參數(shù)列表。唯一的參數(shù)是鏈碼函數(shù)名,setPrivateTransient。 具體的調(diào)用數(shù)據(jù){“key”:”name”, “value”:”charlie”}沒有出現(xiàn)在區(qū)塊鏈上。

fabric Transient Data與Private Data使用的示例分析

我們看到私有數(shù)據(jù)和隱私數(shù)據(jù)的組合提供了某種程度的數(shù)據(jù)隱私。

7、場景4演示:不適用私有數(shù)據(jù),使用暫態(tài)數(shù)據(jù)輸入

最后我們看一下想象的這個場景的演示。在場景3中,采用暫態(tài)數(shù)據(jù)作為數(shù)據(jù), 然后保存在賬本的公開狀態(tài)。我們使用setTransient和get訪問鏈碼:

export KEYVALUE=$(echo -n "{\"key\":\"name\",\"value\":\"david\"}" | base64 | tr -d \\n)

docker exec cli peer chaincode invoke -o orderer.example.com:7050 --tls \
  --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
  --peerAddresses peer0.org1.example.com:7051 \
  --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
  --peerAddresses peer0.org2.example.com:9051 \
  --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
  -C mychannel -n mycc -c '{"Args":["setTransient"]}' \
  --transient "{\"keyvalue\":\"$KEYVALUE\"}"
  
docker exec cli peer chaincode query -C mychannel -n mycc -c '{"Args":["get","name"]}'

結(jié)果如下:

fabric Transient Data與Private Data使用的示例分析 可以看到公開狀態(tài)被更新,兩個節(jié)點目前有同樣的數(shù)據(jù)。注意修訂版本更新為2.

fabric Transient Data與Private Data使用的示例分析

我們看到Write Set中的鍵/值對是name和david,base64編碼。

fabric Transient Data與Private Data使用的示例分析

我們沒有看到參數(shù)中的輸入數(shù)據(jù),只看到調(diào)用的方法名setTransient。

fabric Transient Data與Private Data使用的示例分析

關(guān)于“fabric Transient Data與Private Data使用的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI