티스토리 뷰

반응형

해당 글은 Hyperledger Fabric 페이지의 공식 문서를 번역 및 정리한 자료입니다.

원본 사이트 : https://hyperledger-fabric.readthedocs.io/en/release-1.4/private_data_tutorial.html

Using Private Data in Fabric


이 튜토리얼에서는 권한이 부여된 조직의 블록 체인 네트워크에서 프라이빗 데이터를 저장 및 검색 할 수 있도록 컬렉션을 사용하는 방법을 보여줍니다.

이 튜토리얼의 정보는 프라이빗 데이터 저장소 및 해당 사용 사례에 대한 지식을 전제로합니다. 자세한 내용은 프라이빗 데이터를 확인하십시오.

이 자습서에서는 Fabric으로 프라이빗 데이터를 정의, 구성 및 사용하는 연습을 위해 다음 단계를 수행합니다.

  1. 컬렉션 정의 JSON 파일 만들기
  2. 체인코드 API를 사용하여 프라이빗 데이터 읽기 및 쓰기
  3. 컬렉션과 함께 체인코드 설치 및 인스턴스화
  4. 프라이빗 데이터 저장
  5. 승인된 피어로서 프라이빗 데이터 쿼리
  6. 승인되지 않은 피어로서 프라이빗 데이터 쿼리
  7. 프라이빗 데이터 삭제
  8. 프라이빗 데이터에 인덱스 사용
  9. 추가 리소스

이 튜토리얼에서는 프라이빗 데이터 컬렉션을 작성, 배포 및 사용하는 방법을 보여주기 위해 marbles 프라이빗 데이터 샘플(BYFN 튜토리얼 네트워크에서 실행)을 사용합니다. marbles 프라이빗 데이터 샘플은 Building Your First Network(BYFN) 튜토리얼 네트워크에 배포됩니다. Install Samples, Binaries and Docker Images 작업을 완료해야 합니다. 그러나 BYFN 튜토리얼을 실행하는 것이 이 튜토리얼의 전제 조건은 아닙니다. 이 튜토리얼에서는 네트워크를 사용하는 데 필요한 명령을 제공합니다. 각 단계에서 어떤 일이 일어나는지 설명하고 샘플을 실제로 실행하지 않고 튜토리얼을 이해할 수 있습니다.


Build a collection definition JSON file(컬렉션 정의 JSON 파일 만들기)

채널에서 데이터를 프라이빗화하는 첫 번째 단계는 프라이빗 데이터에 대한 액세스를 정의하는 컬렉션 정의를 작성하는 것입니다.

컬렉션 정의는 누가 데이터를 유지할 수 있는지, 얼마나 많은 피어가 데이터를 배포하는지, 프라이빗 데이터를 보급하는 데 필요한 피어 수 및 프라이빗 데이터가 프라이빗 데이터베이스에 보존되는 기간을 설정합니다. 나중에 우리는 체인코드 API인 PutPrivateDataGetPrivateData를 사용하여 컬렉션을 안전하게 보호되고 있는 프라이빗 데이터에 매핑하는 방법을 보여줍니다.

컬렉션 정의는 다음 속성으로 구성됩니다.

  • name : 컬렉션의 이름
  • policy : 컬렉션 데이터를 유지할 수 있는 조직 피어를 정의
  • requiredPeerCount : 체인코드를 보증하기 위한 조건으로 프라이빗 데이터를 보급하는 데 필요한 피어의 수
  • maxPeerCount : 데이터 중복성을 위해 현재 피어 투 피어가 데이터를 배포하려고 시도하는 다른 피어의 수. 보증하는 피어(Endorsing Peer)가 다운되면 프라이빗 데이터를 가져오는(pull) 요청이 있을 경우에 이러한 다른 피어를 커밋 시간에 사용할 수 있습니다.
  • blockToLive : 가격이나 개인 정보와 같은 매우 민감한 정보를 위해 이 값은 데이터를 블록 단위로 프라이빗 데이터베이스에 저장하는 기간을 나타냅니다. 데이터는 프라이빗 데이터베이스에서 이 지정된 수의 블록에 대해 유효하며 그 후에는 제거되어 네트워크에서 이 데이터를 더 이상 사용하지 않게 됩니다. 프라이빗 데이터를 무한정 유지하려면 즉, 프라이빗 데이터를 절대 삭제하지 않으려면 blockToLive 속성을 0으로 설정하십시오.
  • memberOnlyRead : true 값은 컬렉션 구성원 조직 중 하나에 속한 클라이언트만 프라이빗 데이터에 대한 읽기 액세스가 허용되도록 피어가 자동으로 적용함을 나타냅니다.

프라이빗 데이터의 사용을 설명하기 위해 marbles 프라이빗 데이터 예제는 collectionMarbles 및 collectionMarblePrivateDetails의 두 가지 프라이빗 데이터 컬렉션 정의가 포함되어 있습니다. collectionMarbles 정의의 policy 특성은 채널의 모든 구성원 (Org1 및 Org2)이 프라이빗 데이터베이스에 프라이빗 데이터를 가질 수 있게 합니다. collectionMarblesPrivateDetails 컬렉션을 사용하면 Org1의 구성원만 프라이빗 데이터베이스에 프라이빗 데이터를 가질 수 있습니다.

정책(policy) 정의 작성에 대한 자세한 내용은 Endorsement policies 주제를 참조하십시오.

// collections_config.json

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

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

이 정책에 의해 보안되는 데이터는 체인 코드로 매핑되며 이 튜토리얼의 뒷부분에 등장합니다.

이 컬렉션 정의 파일은 연관된 체인 코드가 peer chaincode instantiate 명령을 사용하여 채널에서 인스턴스화 될 때 채널에 배포됩니다. 이 프로세스에 대한 자세한 내용은 아래 3절에서 제공됩니다.


Read and Write private data using chaincode APIs(체인 코드 API를 사용하여 프라이빗 데이터 읽기 및 쓰기)

채널에서 데이터를 프라이빗화 하는 방법을 이해하는 다음 단계는 체인 코드에 데이터 정의를 작성하는 것입니다. marbles 프라이빗 데이터 샘플은 프라이빗 데이터를 데이터 액세스 방법에 따라 두 개의 개별 데이터 정의로 나눕니다.

// Peers in Org1 and Org2 will have this private data in a side database
type marble struct {
  ObjectType string `json:"docType"`
  Name       string `json:"name"`
  Color      string `json:"color"`
  Size       int    `json:"size"`
  Owner      string `json:"owner"`
}

// Only peers in Org1 will have this private data in a side database
type marblePrivateDetails struct {
  ObjectType string `json:"docType"`
  Name       string `json:"name"`
  Price      int    `json:"price"`
}

특히 프라이빗 데이터에 대한 액세스는 다음과 같이 제한됩니다.

  • name, color, size 및 owner가 채널의 모든 구성원에게 표시됩니다(Org1 및 Org2).
  • price는 Org1의 구성원에게만 표시됩니다.

따라서 두 개의 서로 다른 프라이빗 데이터 집합이 marbles 프라이빗 데이터 샘플에 정의됩니다. 이 데이터에 대한 접근을 제한하는 정책에 매핑하는 것은 체인 코드 API에 의해 제어됩니다. 특히, 컬렉션 정의를 사용하여 프라이빗 데이터를 읽고 쓰는 작업은 여기에서 찾을 수 있는 GetPrivateData()PutPrivateData()를 호출하여 수행합니다.

다음 다이어그램은 marbles 프라이빗 데이터 샘플에 사용되는 프라이빗 데이터 모델을 보여줍니다.


Reading collection data(컬렉션 데이터 읽기)

데이터베이스의 프라이빗 데이터를 쿼리하려면 체인 코드 API의 GetPrivateData()를 사용하십시오. GetPrivateData()컬렉션 이름데이터 키라는 두 개의 인수를 필요로 합니다. collectionMarbles을 재호출하면 Org1 및 Org2의 구성원이 Side Database에 프라이빗 데이터를 가질 수 있으며 컬렉션 collectionMarblePrivateDetails는 Org1의 구성원만 Side Database에 프라이빗 데이터를 가질 수 있습니다. 구현에 대한 자세한 내용은 두음 두 marbles 프라이빗 데이터 함수를 참조하십시오.

  • name, color, size 및 owner 속성 값을 쿼리하는 readMarble
  • price 속성 값을 쿼리하는 readMarblePrivateDetails

이 튜토리얼의 뒷부분에 있는 peer 명령을 사용하여 데이터베이스 쿼리를 실행할 때 이 두 함수를 호출할 것입니다.


Writing private data(프라이빗 데이터 쓰기)

프라이빗 데이터를 프라이빗 데이터베이스에 저장하려면 체인 코드 API의 PutPrivateData()를 사용하십시오. API에는 또한 컬렉션의 이름이 필요합니다. marbles 프라이빗 데이터 샘플에는 두 개의 다른 컬렉션이 포함되어 있으므로 체인 코드에서 두 번 호출됩니다.

  1. collectionMarbles 컬렉션을 사용하여 프라이빗 데이터 name, color, size 및 owner를 저장합니다.
  2. collectionMarblePrivateDetails 컬렉션을 사용하여 프라이빗 데이터 price를 저장합니다.

예를 들어 initMarble 함수의 다음 코드에서 PutPrivateData()는 각 프라이빗 데이터 집합에 대해 한 번씩 두 번 호출됩니다.

// ==== Create marble object, marshal to JSON, and save to state ====
      marble := &marble{
              ObjectType: "marble",
              Name:       marbleInput.Name,
              Color:      marbleInput.Color,
              Size:       marbleInput.Size,
              Owner:      marbleInput.Owner,
      }
      marbleJSONasBytes, err := json.Marshal(marble)
      if err != nil {
              return shim.Error(err.Error())
      }

      // === Save marble to state ===
      err = stub.PutPrivateData("collectionMarbles", marbleInput.Name, marbleJSONasBytes)
      if err != nil {
              return shim.Error(err.Error())
      }

      // ==== Create marble private details object with price, marshal to JSON, and save to state ====
      marblePrivateDetails := &marblePrivateDetails{
              ObjectType: "marblePrivateDetails",
              Name:       marbleInput.Name,
              Price:      marbleInput.Price,
      }
      marblePrivateDetailsBytes, err := json.Marshal(marblePrivateDetails)
      if err != nil {
              return shim.Error(err.Error())
      }
      err = stub.PutPrivateData("collectionMarblePrivateDetails", marbleInput.Name, marblePrivateDetailsBytes)
      if err != nil {
              return shim.Error(err.Error())
      }

요약하면, collection.json에 대한 위의 정책 정의는 Org1 및 Org2의 모든 피어가 프라이빗 데이터베이스에 marbles 프라이빗 데이터 name, color, size, owner를 저장하고 거래할 수 있게 합니다. 그러나 Org1의 피어만 프라이빗 데이터베이스의 price 프라이빗 데이터를 저장하고 거래할 수 있습니다.

추가된 데이터 프라이버시 장점으로서, 컬렉션이 사용 중이기 때문에 프라이빗 데이터 자체가 아닌 프라이빗 데이터의 해시 값만 오더러를 통해 전달되므로 프라이빗 데이터를 오더러로부터 비밀로 유지합니다.


Start the network(네트워크 시작)

이제 프라이빗 데이터를 사용하는 방법을 설명하는 몇 가지 명령을 단계별로 실행할 준비가 되었습니다.

아래의 marbles 프라이빗 데이터 체인 코드를 설치하고 인스턴스화하기 전에 BYFN 네트워크를 시작해야 합니다. 이 튜토리얼에서는 알려진 초기 상태에서 작동하려고 합니다. 다음 명령은 활성 또는 비활성 Docker 컨테이너를 제거하고 이전에 생성된 아티팩트를 제거합니다. 따라서 다음 명령을 실행하여 이전 환경을 정리하십시오. :

cd fabric-samples/first-network
./byfn.sh down

이 튜토리얼을 이미 실행한 경우 marbles 프라이빗 데이터 체인 코드에 대한 기본 고정 컨테이너를 삭제해야 합니다. 이전 환경을 정리하기 위해 다음 명령을 실행합니다. :

docker rm -f $(docker ps -a | awk '($2 ~ /dev-peer.*.marblesp.*/) {print $1}')
docker rmi -f $(docker images | awk '($1 ~ /dev-peer.*.marblesp.*/) {print $3}')

다음 명령을 실행하여 CouchDB로 BYFN 네트워크를 시작하십시오. :

./byfn.sh up -c mychannel -s couchdb

이렇게 하면 두 개의 조직(두 개의 피어 노드를 유지관리하는)과 CouchDB를 상태 데이터베이스로 사용하는 ordering 서비스로 구성된 mychannel이라는 단일 채널로 구성된 간단한 패브릭 네트워크가 생성됩니다. LevelDB 또는 CouchDB는 컬렉션과 함께 사용될 수 있습니다. CouchDB는 프라이빗 데이터베이스에 인덱스를 사용하는 방법을 보여주기 위해 선택되었습니다.

컬렉션이 작동하려면 크로스 조직 가십을 올바르게 구성해야 합니다. "앵커 피어(anchor peers)" 섹션에 특히 주의를 기울여 Gossip data dissemination protocol(가십 데이터 보급 프로토콜)에 대한 문서를 참조하십시오. 우리의 튜토리얼은 BYFN 샘플에서 이미 구성되어 있기 때문에 가십에 초점을 맞추지 않지만, 채널을 구성할 때 가십 앵커 피어는 컬렉션이 제대로 작동하도록 구성하는 데 중요합니다.


Install and instantiate chaincode with a collection(컬렉션과 함께 체인 코드 설치 및 인스턴스화)

클라이언트 애플리케이션은 체인 코드를 통해 블록 체인 원장과 상호 작용합니다. 따라서 우리는 트랜잭션을 실행하고 보증할 모든 피어에 체인 코드를 설치하고 인스턴스화 해야 합니다. 체인 코드는 피어에 설치되고 peer-commands를 사용하여 채널에 인스턴스화 됩니다.


Install chaincode on all peers(모든 피어에 체인 코드 설치)

위에서 논의된 바와 같이, BYFN 네트워크에는 Org1 및 Org2라는 두 개의 조직이 있으며 각각 두 개의 피어가 있습니다. 따라서 체인 코드는 4 개의 피어에 설치되어야 합니다.

  • peer0.org1.example.com
  • peer1.org1.example.com
  • peer0.org2.example.com
  • peer1.org2.example.com

peer chaincode install 명령을 사용하여 각 피어에 Marbles 체인 코드를 설치하십시오.

BYFN 네트워크를 시작했다고 가정하면 CLI 컨테이너에 들어갑니다.

docker exec -it cli bash

명령 프롬프트가 다음과 같이 바뀝니다.

root@81eac8493633:/opt/gopath/src/github.com/hyperledger/fabric/peer#

  1. 다음 명령을 사용하여 git 저장소에서 BYFN 네트워크의 피어 peer0.org1.example.com으로 Marbles 체인 코드를 설치하십시오. (기본적으로 BYFN 네트워크를 시작한 후 활성 피어는 다음과 같이 설정됩니다. CORE_PEER_ADDRESS=peer0.org1.example.com:7051) :
    peer chaincode install -n marblesp -v 1.0 -p github.com/chaincode/marbles02_private/go/
    
    완료되면 다음과 유사한 내용이 표시됩니다.
    install -> INFO 003 Installed remotely response:<status:200 payload:"OK" >
    
  2. CLI를 사용하여 활성 피어를 Org1의 두 번째 피어로 전환하고 체인 코드를 설치하십시오. 다음 전체 명령 블록을 복사하여 CLI 컨테이너에 붙여넣고 실행하십시오.
    export CORE_PEER_ADDRESS=peer1.org1.example.com:7051
    peer chaincode install -n marblesp -v 1.0 -p github.com/chaincode/marbles02_private/go/
    
  3. CLI를 사용하여 Org2로 전환하십시오. 다음 명령 블록을 그룹으로 복사하여 피어 컨테이너에 붙여넣고 한꺼번에 실행하십시오.
    export CORE_PEER_LOCALMSPID=Org2MSP
    export PEER0_ORG2_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
    export CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG2_CA
    export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
    
  4. Org2에서 활성 피어를 첫 번째 피어로 전환하고 체인 코드를 설치하십시오.
    export CORE_PEER_ADDRESS=peer0.org2.example.com:7051
    peer chaincode install -n marblesp -v 1.0 -p github.com/chaincode/marbles02_private/go/
    
  5. 활성 피어를 Org2의 두 번째 피어로 전환하고 체인 코드를 설치하십시오.
    export CORE_PEER_ADDRESS=peer1.org2.example.com:7051
    peer chaincode install -n marblesp -v 1.0 -p github.com/chaincode/marbles02_private/go/
    


Instantiate the chaincode on the channel(채널에서 체인 코드를 인스턴스화)

peer chaincode instantiate 명령을 사용하여 채널에서 marbles 체인 코드를 인스턴스화합니다. 채널에서 체인 코드 컬렉션을 구성하려면 이 예제에서 컬렉션 JSON 파일의 이름인 collections_config.json과 함께 --collections-config 플래그를 지정하십시오.

다음 명령을 실행하여 BYFN의 채널인 mychannel에서 marbles 프라이빗 데이터 체인 코드를 인스턴스화합니다.

export ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C mychannel -n marblesp -v 1.0 -c '{"Args":["init"]}' -P "OR('Org1MSP.member','Org2MSP.member')" --collections-config  $GOPATH/src/github.com/chaincode/marbles02_private/collections_config.json
--collections-config 플래그의 값을 지정할 때 collections_config.json 파일에 대한 완전한 경로를 지정해야합니다. 예를 들면 다음과 같습니다.: --collections-config  $GOPATH/src/github.com/chaincode/marbles02_private/collections_config.json

인스턴스화가 성공적으로 완료되면 다음과 비슷한 내용이 표시됩니다.

[chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
[chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc


Store private data(프라이빗 데이터 저장)

marbles 프라이빗 데이터 샘플의 프라이빗 데이터를 모두 처리할 권한이 있는 Org1의 구성원으로 활동하면서 Org1의 피어로 다시 전환하여 marbles 추가 요청(request)을 제출(submit)합니다.

다음 명령 세트를 복사하여 CLI 명령 행에 붙여 넣으십시오.

export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
export CORE_PEER_LOCALMSPID=Org1MSP
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export PEER0_ORG1_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt

구슬(marble)을 생성하는 marbles의 initMarble 함수를 호출하면, 프라이빗 데이터가 있는 구슬(marble)을 생성합니다. 이름은 marble1이고 소유자는 tom, 색상은 blue, 크기는 35, 가격은 99입니다. 프라이빗 데이터를 재호출해 가격(price)을 프라이빗 데이터 이름(name), 소유자(owner), 색상(color), 크기(size)와 별도로 저장합니다. 이러한 이유로 initMarble 함수는 PutPrivateData() API를 두 번 호출하여 프라이빗 데이터를 각 컬렉션에 대해 한 번씩 유지합니다. 또한 프라이빗 데이터는 --transient 플래그를 사용하여 전달됩니다. 일시적인 데이터(transient data)로 전달된 입력은 데이터를 비공개로 유지하기 위해 트랜잭션에 유지되지 않습니다. 일시적인 데이터(transient data)는 2진 데이터로 전달되므로 CLI를 사용할 때 base64로 인코딩되어야합니다. 우리는 환경변수를 사용하여 base64로 인코딩 된 값을 캡쳐하고, tr 명령을 사용하여 linux base64 명령이 추가하는 데에 문제가 있는 개행 문자를 제거합니다.

export MARBLE=$(echo -n "{\"name\":\"marble1\",\"color\":\"blue\",\"size\":35,\"owner\":\"tom\",\"price\":99}" | base64 | tr -d \\n)
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 -C mychannel -n marblesp -c '{"Args":["initMarble"]}'  --transient "{\"marble\":\"$MARBLE\"}"

결과는 다음과 유사해야 합니다.:

[chaincodeCmd] chaincodeInvokeOrQuery->INFO 001 Chaincode invoke successful. result: status: 200


Query the private data as an authorized peer(승인된 피어로서 프라이빗 데이터 쿼리)

우리의 컬렉션 정의를 사용하면 Org1 및 Org2의 모든 구성원(member)이 name, color, size, owner 프라이빗 데이터를 Side database에 저장할 수 있지만 Org1의 피어만 Sida database에 price 프라이빗 데이터를 저장할 수 있습니다. Org1의 승인된 피어로서 우리는 프라이빗 데이터의 두 세트를 쿼리할 것입니다.

첫 번째 query 명령은 collectionMarbles를 인수로 전달하는 readMarble 함수를 호출합니다.

// ===============================================
// 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)
}

두 번째 query 명령은 collectionMarblePrivateDetails를 인수로 전달하는 readMarblePrivateDetails 함수를 호출합니다.

// ===============================================
// readMarblePrivateDetails - 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)
}

이제 Org1의 구성원으로 marble1name, color, size 및 owner 프라이빗 데이터를 쿼리합니다. 쿼리는 원장에 기록되지 않으므로 marble 이름을 일시적인 입력(transient input)으로 전달할 필요가 없습니다.

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

다음 결과가 표시됩니다. :

{"color":"blue","docType":"marble","name":"marble1","owner":"tom","size":35}

Org1의 구성원으로 marble1price 프라이빗 데이터를 쿼리합니다.

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

다음 결과가 표시됩니다. :

{"docType":"marblePrivateDetails","name":"marble1","price":99}


Query the private data as an unauthorized peer(승인되지 않은 피어로서 프라이빗 데이터 쿼리)

이제 Side database에 marbles의 name, color, size, owner 프라이빗 데이터는 가지고 있지만 marbles의 price 프라이빗 데이터가 없는 Org2의 구성원으로 전환합니다. 우리는 프라이빗 데이터의 두 세트를 모두 쿼리합니다.


Switch to a peer in Org2(Org2의 피어로 전환)

Docker 컨테이너 내부에서 다음 명령을 실행하며 marbles price 프라이빗 데이터에 액세스 할 수 있는 권한이 없는 피어로 전환합니다.

export CORE_PEER_ADDRESS=peer0.org2.example.com:7051
export CORE_PEER_LOCALMSPID=Org2MSP
export PEER0_ORG2_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG2_CA
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp


Query private data Org2 is authorized to(Org2가 승인된 프라이빗 데이터 쿼리)

Org2의 피어는 Side database에 marbles 프라이빗 데이터의 첫 번째 세트(name, color, size and owner)가 있어야 하며 collectionMarbles 인수로 호출되는 readMarble() 함수를 사용하여 액세스 할 수 있습니다.

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

다음과 비슷한 결과가 출력됩니다. :

{"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"tom"}


Query private data Org2 is not authorized to(Org2가 승인되지 않은 프라이빗 데이터 쿼리)

Org2의 피어는 Side database에 marbles price 프라이빗 데이터가 없습니다. 이 데이터를 쿼리하려고 하면 퍼블릭 상태와 일치하는 키의 해시 값이 반환되지만 프라이빗 상태는 갖지 않습니다.

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

다음과 비슷한 결과가 출력됩니다. :

{"Error":"Failed to get private details for marble1: GET_STATE failed:
transaction ID: b04adebbf165ddc90b4ab897171e1daa7d360079ac18e65fa15d84ddfebfae90:
Private data matching public hash version is not available. Public hash
version = &version.Height{BlockNum:0x6, TxNum:0x0}, Private data version =
(*version.Height)(nil)"}

Org2의 구성원은 프라이빗 데이터의 공개 해시 값만 볼 수 있습니다.


Purge Private Data(프라이빗 데이터 삭제)

프라이빗 데이터가 off-chain 데이터베이스로 복제될 때까지 원장에 있어야 하는 경우에는 특정 수의 블록 이후에 데이터를 "제거(purge)"할 수 있으며 데이터의 해시 값만 남겨둡니다. 거래의 불변 증거로 사용됩니다.

이 예제에서는 개인 정보 또는 기밀 정보(예: 가격 데이터)를 비롯한 프라이빗 데이터가 있을 수 있으며 거래 당사자는 채널의 다른 조직에 공개하기를 원하지 않습니다. 따라서 제한된 수명을 가지며 컬렉션 정의에서 blockToLive 속성을 사용하여 지정된 블록 수만큼 블록 체인에서 변경되지 않은 상태로 제거될 수 있습니다.

우리의 collectionMarblePrivateDetailsblockToLive 속성 값을 3으로 정의했는데, 이는 해당 데이터를 세 블록 동안만 Side database에 저장하고 그 이후에는 제거됨을 의미합니다. 모든 컬렉션을 묶어서 이 컬렉션 정의인 collectionMarblePrivateDetails를 호출하는데, 이는 PutPrivateData() API를 호출하고 collectionMarblePrivateDetails를 인수로 전달할 때 initMarble() 함수의 price 프라이빗 데이터와 연관됩니다.

체인에 블록을 추가한 다음 체인에 4 개의 새로운 블록을 추가하도록 4 개의 새 트랜잭션(새로운 marble 생성 후 이동)을 발행하여 price 정보가 제거되는 것을 확인합니다. 네 번째 거래(세 번째 marble 이동)가 끝나면 가격(price) 프라이빗 데이터가 삭제되었는지 확인합니다.

다음 명령을 사용하여 Org1의 peer0으로 다시 전환하십시오. 다음 코드 블록을 복사하여 붙여넣고 피어 컨테이너 내부에서 실행합니다.

export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
export CORE_PEER_LOCALMSPID=Org1MSP
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export PEER0_ORG1_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt

새 터미널 창을 열고 다음 명령을 실행하여 이 피어에 대한 프라이빗 데이터 로그를 확인합니다.

docker logs peer0.org1.example.com 2>&1 | grep -i -a -E 'private|pvt|privdata'

결과는 다음과 유사해야합니다. 목록에서 가장 높은 블록 번호를 기록하십시오. 아래 예제에서 가장 높은 블록 높이는 4입니다.

[pvtdatastorage] func1 -> INFO 023 Purger started: Purging expired private data till block number [0]
[pvtdatastorage] func1 -> INFO 024 Purger finished
[kvledger] CommitWithPvtData -> INFO 022 Channel [mychannel]: Committed block [0] with 1 transaction(s)
[kvledger] CommitWithPvtData -> INFO 02e Channel [mychannel]: Committed block [1] with 1 transaction(s)
[kvledger] CommitWithPvtData -> INFO 030 Channel [mychannel]: Committed block [2] with 1 transaction(s)
[kvledger] CommitWithPvtData -> INFO 036 Channel [mychannel]: Committed block [3] with 1 transaction(s)
[kvledger] CommitWithPvtData -> INFO 03e Channel [mychannel]: Committed block [4] with 1 transaction(s)

피어 컨테이너로 돌아가서 다음 명령을 실행하여 marble1의 price 데이터를 쿼리합니다. (쿼리는 거래되는 데이터가 없으므로 원장에 새 트랜잭션을 생성하지 않습니다.)

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

결과는 다음과 유사해야 합니다.

{"docType":"marblePrivateDetails","name":"marble1","price":99}

price 데이터는 여전히 프라이빗 데이터 원장에 남아있습니다.

다음 명령을 실행하여 새로운 marble2를 만듭니다. 이 트랜잭션은 체인에 새로운 블록을 생성합니다.

export MARBLE=$(echo -n "{\"name\":\"marble2\",\"color\":\"blue\",\"size\":35,\"owner\":\"tom\",\"price\":99}" | base64 | tr -d \\n)
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 -C mychannel -n marblesp -c '{"Args":["initMarble"]}' --transient "{\"marble\":\"$MARBLE\"}"

터미널 창으로 다시 전환하고 이 피어의 프라이빗 데이터 로그를 다시 확인합니다. 블록 높이가 1씩 증가해야 합니다.

docker logs peer0.org1.example.com 2>&1 | grep -i -a -E 'private|pvt|privdata'

피어 컨테이너로 돌아가서 다음 명령을 실행하여 marble1의 price 데이터를 다시 쿼리합니다.

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

프라이빗 데이터가 삭제되지 않았으므로 결과는 이전 쿼리와 동일합니다.

{"docType":"marblePrivateDetails","name":"marble1","price":99}

다음 명령을 실행하여 marble2를 "joe"에게로 이동합니다. 이 트랜잭션은 체인에 두 번째 새로운 블록을 추가합니다.

export MARBLE_OWNER=$(echo -n "{\"name\":\"marble2\",\"owner\":\"joe\"}" | base64 | tr -d \\n)
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 -C mychannel -n marblesp -c '{"Args":["transferMarble"]}' --transient "{\"marble_owner\":\"$MARBLE_OWNER\"}"

터미널 창으로 다시 전환하고 이 피어의 프라이빗 데이터 로그를 다시 확인합니다. 블록 높이가 1씩 증가해야 합니다.

docker logs peer0.org1.example.com 2>&1 | grep -i -a -E 'private|pvt|privdata'

피어 컨테이너로 돌아가서 다음 명령을 실행하여 marble1의 price 데이터를 다시 쿼리합니다.

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

price 브라이빗 데이터는 여전히 볼 수 있습니다.

{"docType":"marblePrivateDetails","name":"marble1","price":99}

다음 명령을 실행하여 marble2를 "tom"에게로 이동합니다. 이 트랜잭션은 체인에 세 번째 새로운 블록을 추가합니다.

export MARBLE_OWNER=$(echo -n "{\"name\":\"marble2\",\"owner\":\"tom\"}" | base64 | tr -d \\n)
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 -C mychannel -n marblesp -c '{"Args":["transferMarble"]}' --transient "{\"marble_owner\":\"$MARBLE_OWNER\"}"

터미널 창으로 다시 전환하고 이 피어의 프라이빗 데이터 로그를 다시 확인합니다. 블록 높이가 1씩 증가해야 합니다.

docker logs peer0.org1.example.com 2>&1 | grep -i -a -E 'private|pvt|privdata'

피어 컨테이너로 돌아가서 다음 명령을 실행하여 marble1의 price 데이터를 다시 쿼리합니다.

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

price 브라이빗 데이터는 여전히 볼 수 있습니다.

{"docType":"marblePrivateDetails","name":"marble1","price":99}

마지막으로 다음 명령을 실행하여 marble2를 "jerry"에게로 이동합니다. 이 트랜잭션은 체인에 네 번째 새로운 블록을 추가합니다. price 프라이빗 데이터는 이 거래 후 제거되어야 합니다.

export MARBLE_OWNER=$(echo -n "{\"name\":\"marble2\",\"owner\":\"jerry\"}" | base64 | tr -d \\n)
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 -C mychannel -n marblesp -c '{"Args":["transferMarble"]}' --transient "{\"marble_owner\":\"$MARBLE_OWNER\"}"

터미널 창으로 다시 전환하고 이 피어의 프라이빗 데이터 로그를 다시 확인합니다. 블록 높이가 1씩 증가해야 합니다.

docker logs peer0.org1.example.com 2>&1 | grep -i -a -E 'private|pvt|privdata'

피어 컨테이너로 돌아가서 다음 명령을 실행하여 marble1의 price 데이터를 다시 쿼리합니다.

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

price 데이터가 제거되었으므로 더 이상 볼 수 없습니다. 다음과 비슷한 결과가 출력되어야 합니다. :

Error: endorsement failure during query. response: status:500
message:"{\"Error\":\"Marble private details does not exist: marble1\"}"


Using indexes with private data(프라이빗 데이터에 인덱스 사용)

체인 코드와 함께 META-INF/statedb/couchdb/collections/<collection_name>/indexes 디렉토리에 인덱스를 패키징하여 프라이빗 데이터 컬렉션에 적용할 수도 있습니다. 여기에 인덱스에 대한 예제가 있습니다.

프로덕션 환경에 체인 코드를 배포할 경우, 체인 코드가 피어에 설치되고 채널에 인스턴스화 된 후에 체인 코드와 지원 인덱스가 하나의 단위로 자동 배포되도록 체인 코드와 함께 인덱스를 정의하는 것이 좋습니다. 연관된 인덱스는 컬렉션 JSON 파일의 위치를 가리치는 --collections-config 플래그가 지정될 때 채널의 체인 코드 인스턴스화 시 자동으로 배포됩니다.


Additional resources(추가 리소스)

추가적인 프라이빗 데이터 교육을 위해, 비디오 튜토리얼이 만들어졌습니다.

https://youtu.be/qyjDi93URJE

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함