2. Prerequisites on this practice
• Install Ubuntu 22.04 LTS
• For this exercise only, all libraries will be installed under a root account.
-----------------------------------------------------------------------------------------------------
• apt-get -y install docker-compose
docker --version
docker-compose –version
• systemctl start docker
• systemctl enable docker
https://hyperledger-fabric.readthedocs.io/en/release-2.5/prereqs.html
6. 첫 번째 튜토리얼
Using the Fabric test network
목표
- 전반적인 아키텍처의 이해(DOCKER)
- 체인코드 배포과정 체험
7. Using the Fabric test network
• It includes two peer organizations and an ordering organization.
• For simplicity, a single node Raft ordering service is configured.
• To reduce complexity, a TLS Certificate Authority (CA) is not deployed. All
certificates are issued by the root CAs.
• The sample network deploys a Fabric network with Docker Compose. Because the
nodes are isolated within a Docker Compose network, the test network is not
configured to connect to other running Fabric nodes.
https://hyperledger-fabric.readthedocs.io/en/release-2.5/test_network.html
8. Using the Fabric test network
• at fabric-samples/test-network
• ./network.sh up
• docker ps –a
2 peer, 1 orderer will be listed
9. - Peer
• Peers store the blockchain ledger and validate transactions before they are
committed to the ledger.
• Peers run the smart contracts.
• Every peer in the network needs to belong to an organization
- peer0.org1.example.com
- peer0.org2.example.com
https://hyperledger-fabric.readthedocs.io/en/release-2.5/test_network.html
Using the Fabric test network
10. - Orderer
• After ordering nodes receive endorsed transactions from clients, they come to
consensus on the order of transactions and then add them to blocks. The blocks are
then distributed to peer nodes, which add the blocks to the blockchain ledger.
- orderer.example.com
• It would use the Raft consensus algorithm to come to agreement on the order of
transactions across the network
https://hyperledger-fabric.readthedocs.io/en/release-2.5/test_network.html
Using the Fabric test network
11. - creating a channel
• Channels are a private layer of communication between specific network
members.
• ./network.sh createChannel
Using the Fabric test network
channel ledger
https://hyperledger-fabric.readthedocs.io/en/release-2.5/test_network.html
12. Generating channel genesis block 'mychannel.block'
+ configtxgen -profile TwoOrgsApplicationGenesis -outputBlock ./channel-artifacts/mychannel.block -channelID mychannel
Creating channel mychannel
Using organization 1
+ osnadmin channel join --channelID mychannel --config-block ./channel-artifacts/mychannel.block -o localhost:7053 --ca-file
/root/fabric-samples/test-network/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem
--client-cert /root/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt
--client-key /root/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.key
+ res=0
Status: 201
{
"name": "mychannel",
"url": "/participation/v1/channels/mychannel",
"consensusRelation": "consenter",
"status": "active",
"height": 1
}
Channel 'mychannel' created
Joining org1 peer to the channel...
Using organization 1
+ peer channel join -b ./channel-artifacts/mychannel.block
+ res=0
2023-03-19 10:55:44.556 UTC 0001 INFO [channelCmd] InitCmdFactory -> Endorser and orderer connections initialized
2023-03-19 10:55:45.007 UTC 0002 INFO [channelCmd] executeJoin -> Successfully submitted proposal to join channel
Joining org2 peer to the channel...
Using organization 2
+ peer channel join -b ./channel-artifacts/mychannel.block
+ res=0
2023-03-19 10:55:48.116 UTC 0001 INFO [channelCmd] InitCmdFactory -> Endorser and orderer connections initialized
2023-03-19 10:55:48.188 UTC 0002 INFO [channelCmd] executeJoin -> Successfully submitted proposal to join channel
- creating a channel
Using the Fabric test network
13. Setting anchor peer for org1...
Using organization 1
Fetching channel config for channel mychannel
Using organization 1
Fetching the most recent configuration block for the channel
Generating anchor peer update transaction for Org1 on channel mychannel
Anchor peer set for org 'Org1MSP' on channel 'mychannel'
Setting anchor peer for org2...
Using organization 2
Fetching channel config for channel mychannel
Using organization 2
Fetching the most recent configuration block for the channel
Generating anchor peer update transaction for Org2 on channel mychannel
Anchor peer set for org 'Org2MSP' on channel 'mychannel'
Channel 'mychannel' joined
- Creating a channel
Using the Fabric test network
14. - Starting a chaincode on the channel
• apt install jq
• apt-get install openjdk-11-jdk
• ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-java -ccl java
export JAVA_HOME=$(dirname $(dirname $(readlink -f $(which java))))
export PATH=$PATH:$JAVA_HOME/bin
vi ~/.bashrc
source ~/.bashrc
Using the Fabric test network
https://hyperledger-fabric.readthedocs.io/en/release-2.5/test_network.html
15. - Interacting with the network
Using the Fabric test network
vi ~/.bashrc
source ~/.bashrc
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
16. - Interacting with the network
Using the Fabric test network
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C
mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles
"${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --
tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -c
'{"function":"InitLedger","Args":[]}'
Because the endorsement policy for the asset-transfer (basic) chaincode requires the transaction to be signed by Org1 and Org2, the chaincode invoke command needs
to target both peer0.org1.example.com and peer0.org2.example.com using the --peerAddresses flag. Because TLS is enabled for the network, the command also
needs to reference the TLS certificate for each peer using the --tlsRootCertFiles flag.
17. - Interacting with the network
Using the Fabric test network
peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C
mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles
"${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --
tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -c
'{"function":"TransferAsset","Args":["asset6","Christopher"]}'
18. - Interacting with the network
Using the Fabric test network
Ledger check by Org2, it should be same as Org1
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051
peer chaincode query -C mychannel -n basic -c '{"Args":["ReadAsset","asset6"]}'
19. Fabric CA를 사용하여 구동
• ./network.sh up –ca
• 노드와 사용자ID를 등록
• MSP 폴더를 생성
https://hyperledger-fabric.readthedocs.io/en/release-2.5/membership/membership.html
https://hyperledger-fabric-ca.readthedocs.io/en/latest/operations_guide.html
24. 두 번째 튜토리얼
Deploying a smart contract to a channel
이번 튜토리얼은
첫 번째 튜토리얼에서 아래의 명령을 통해 체인코드를 패키징~배포~커밋한 내용을 하나씩 단계별로
체인코드를 배포하는 튜토리얼
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-java/ -ccl java
25. 준비
• cd fabric-samples/test-network
• ./network.sh down
• ./network.sh up createChannel
https://hyperledger-fabric.readthedocs.io/en/release-2.5/deploy_chaincode.html
26. Docker 모니터링
• 별도 터미널 쉘에서 실행
• cd fabric-samples/test-network
• ./monitordocker.sh fabric_test
https://hyperledger-fabric.readthedocs.io/en/release-2.5/deploy_chaincode.html
27. Install and define a chaincode
https://hyperledger-fabric.readthedocs.io/en/release-2.5/chaincode_lifecycle.html
28. Package the smart contract
• 패키지 명령 형식
peer lifecycle chaincode package ${CC_NAME}.tar.gz --path ${CC_SRC_PATH} --lang
${CC_RUNTIME_LANGUAGE} --label ${CC_NAME}_${CC_VERSION} >&log.txt
• 자바 체인코드 패키지 생성
peer lifecycle chaincode package basic.tar.gz --path ../asset-transfer-basic/chaincode-java/ --lang
java --label basic_1.0
tar는 해당 자바 디렉토리를 target 디렉토리만 빼고 단순 압축한 형태임
https://hyperledger-fabric.readthedocs.io/en/release-2.5/deploy_chaincode.html
29. Install the chaincode package
• Org1과 Org2 모두에 설치
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
root@koposvr:~/fabric-samples/test-network# peer lifecycle chaincode install basic.tar.gz
2023-03-21 07:02:07.236 UTC 0001 INFO [cli.lifecycle.chaincode] submitInstallProposal -> Installed remotely: response:<status:200
payload:"nJbasic_1.0:7ac9411f0ac3d33a79007b3d3307ee7b246e2ea95bd29467a0331e5997378b6e022tbasic_1.0" >
2023-03-21 07:02:07.270 UTC 0002 INFO [cli.lifecycle.chaincode] submitInstallProposal -> Chaincode code package identifier:
basic_1.0:7ac9411f0ac3d33a79007b3d3307ee7b246e2ea95bd29467a0331e5997378b6e
root@koposvr:~/fabric-samples/test-network# export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051
root@koposvr:~/fabric-samples/test-network# peer lifecycle chaincode install basic.tar.gz
2023-03-21 07:06:08.573 UTC 0001 INFO [cli.lifecycle.chaincode] submitInstallProposal -> Installed remotely: response:<status:200
payload:"nJbasic_1.0:7ac9411f0ac3d33a79007b3d3307ee7b246e2ea95bd29467a0331e5997378b6e022tbasic_1.0" >
2023-03-21 07:06:08.573 UTC 0002 INFO [cli.lifecycle.chaincode] submitInstallProposal -> Chaincode code package identifier:
basic_1.0:7ac9411f0ac3d33a79007b3d3307ee7b246e2ea95bd29467a0331e5997378b6e
Org1
Org2
두 개의 조직이 같은 식별자를 리턴함
https://hyperledger-fabric.readthedocs.io/en/release-2.5/deploy_chaincode.html
53. 트랜잭션 기능을 호출하여 갱신
• This time the transaction is invoked using submitAsync(), which returns after successfully submitting the endorsed transaction to the ordering
service instead of waiting until the transaction is committed to the ledger.
56. [참고] 전체 수행 로그
oot@koposvr:~/fabric-samples/asset-transfer-basic/application-gateway-java# ./gradlew
run
> Task :run
--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger
*** Transaction committed successfully
--> Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger
*** Result: [
{
"appraisedValue": 300,
"assetID": "asset1",
"color": "blue",
"owner": "Tomoko",
"size": 5
},
{
"appraisedValue": 400,
"assetID": "asset2",
"color": "red",
"owner": "Brad",
"size": 5
},
{
"appraisedValue": 500,
"assetID": "asset3",
"color": "green",
"owner": "Jin Soo",
"size": 10
},
{
"appraisedValue": 600,
"assetID": "asset4",
"color": "yellow",
"owner": "Max",
"size": 10
},
{
"appraisedValue": 700,
"assetID": "asset5",
"color": "black",
"owner": "Adrian",
"size": 15
},
{
"appraisedValue": 700,
"assetID": "asset6",
"color": "white",
"owner": "Michel",
"size": 15
}
]
--> Submit Transaction: CreateAsset, creates new asset with ID, Color, Size, Owner and AppraisedValue arguments
*** Transaction committed successfully
--> Async Submit Transaction: TransferAsset, updates existing asset owner
*** Successfully submitted transaction to transfer ownership from Tom to Saptha
*** Waiting for transaction commit
*** Transaction committed successfully
--> Evaluate Transaction: ReadAsset, function returns asset attributes
*** Result:{
"owner": "Saptha",
"color": "yellow",
"size": 5,
"appraisedValue": 1300,
"assetID": "asset1679492916126"
}
--> Submit Transaction: UpdateAsset asset70, asset70 does not exist and should return an error
*** Successfully caught the error:
org.hyperledger.fabric.client.EndorseException: io.grpc.StatusRuntimeException: ABORTED: failed to endorse transaction, see attached details for more
info
at org.hyperledger.fabric.client.GatewayClient.endorse(GatewayClient.java:73)
at org.hyperledger.fabric.client.ProposalImpl.endorse(ProposalImpl.java:74)
at org.hyperledger.fabric.client.Proposal.endorse(Proposal.java:65)
at org.hyperledger.fabric.client.ContractImpl.submitTransaction(ContractImpl.java:47)
at App.updateNonExistentAsset(App.java:225)
at App.run(App.java:132)
at App.main(App.java:71)
Caused by: io.grpc.StatusRuntimeException: ABORTED: failed to endorse transaction, see attached details for more info
at io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:271)
at io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:252)
at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:165)
at org.hyperledger.fabric.protos.gateway.GatewayGrpc$GatewayBlockingStub.endorse(GatewayGrpc.java:472)
at org.hyperledger.fabric.client.GatewayClient.endorse(GatewayClient.java:71)
... 6 more
Transaction ID: 0c4d10e9dd4b2573f9a06f9a8ac594f1c2098d3e65f3561dc05a8494761cf2ea
Error Details:
- address: peer0.org1.example.com:7051, mspId: Org1MSP, message: chaincode response 500, Asset asset70 does not exist
BUILD SUCCESSFUL in 20s
2 actionable tasks: 1 executed, 1 up-to-date
root@koposvr:~/fabric-samples/asset-transfer-basic/application-gateway-java#
57. 네 번째 튜토리얼
Running External Chaincode Builders
- chaincode as a service
58. 개요
• 기존
the peer to orchestrate the complete lifecycle of the chaincode
체인코드 빌드와 시작을 어떻게 할지, 체인코드 언어도 Peer에 전달해야 함
쿠버네티스 등 가상화된 환경이나 체인코드 재빌드를 위해 외부망 접속이 필요한
경우 등 복잡한 이슈가 있을 수 있음
• 따라서, Separation of Concern 관점에서 이를 서비스化 하자.
• 무엇으로? 도커로!
• 이미 ccaasbuiler라는 도커 이미지가 준비되어 있음
https://hyperledger-fabric.readthedocs.io/en/release-2.4/cc_basic.html
59. 준비
• cd test-network
• ./network.sh up createChannel
• 새로운 터미널에서 도커 모니터링을 위하여
./test-network/monitordocker.sh
https://hyperledger-fabric.readthedocs.io/en/release-2.4/cc_basic.html
60. 실행
• ./network.sh deployCCAAS -ccn basicj -ccp ../asset-transfer-basic/chaincode-java
• 빌드 오류 발생시, 하단 슬라이드 노트 참고
• 순서
① 체인코드 컨테이너를 빌드(Dockerfile)
② 체인코드 설치~커밋을 Peer에 실행
(이때, peer는 체인코드의 위치(host, port, tls인증서 정보를 획득하고 rpc로
peer <-> peer0org1_basicj_ccaas 또는 peer0org2_basicj_ccaas 와 통신하게 됨)
③ 도커 컨테이너 실행
https://hyperledger-fabric.readthedocs.io/en/release-2.4/cc_basic.html
61. 결과 확인
• 도커 프로세스 확인 → 두 개의 컨테이너를 확인
컨테이너 이름에 조직, 피어 및 체인코드 이름이 포함됨
☞ docker 모니터링 로그는 하단 슬라이드 노트 참조
https://hyperledger-fabric.readthedocs.io/en/release-2.4/cc_basic.html
62. 테스트
• export CORE_PEER_TLS_ENABLED=true
• export CORE_PEER_LOCALMSPID="Org1MSP"
• export
CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/tl
sca/tlsca.org1.example.com-cert.pem
• export
CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users
/Admin@org1.example.com/msp
• export CORE_PEER_ADDRESS=localhost:7051
• export PATH=${PWD}/../bin:$PATH
• export FABRIC_CFG_PATH=${PWD}/../config
• peer chaincode query -C mychannel -n basicj -c '{"Args":["org.hyperledger.fabric:GetMetadata"]}' | jq
쉘에서 peer로 요청한 내용이 by rpc로 체인코드 컨테이너(peer0org1_basicj_ccaas 또는 peer0org2_basicj_ccaas)
로 전달되어 그 결과를 정상 수신하는지 확인하기 위한 테스트
https://hyperledger-fabric.readthedocs.io/en/release-2.4/cc_basic.html
65. 시나리오
fabric_samples/asset-transfer-private-data/chaincode-java/collections_config.json
① Org1의 소유자가 데이터 생성
- (assetID, color, size, appraisedValue) = asset1, green, 20, 100
그런데 100에 해당하는 appraisedValue 속성은 비공개 데이터로 assetID, closer, size와
별도 저장됨
② Org1, Org2 모두 assetID, color, size에 대해서는 조회 가능
③ Org1의 구성원(소유자限)는 appraisedValue 조회 가능
④ Org2의 구성원은 appraisedValue 조회 : Org1으로 조회시 접근 불가, Org2로 조회시 Null
⑤ Org2의 구성원은 (assetID, color, size) 조회 가능
⑥ 이후, Org1의 소유자가 asset 을 이관하게 되면 기존 소유자는 appraisedValue조회가 안됨
69. AssetTransfer.java - ① CreateAsset
Public State 저장
Private State 저장
스마트 컨트랙트 함수 호출 주체가 해당 조직의 MSP ID와 같은지 검사
ex> clientMSPID == peerMSPID
다음 장…
../asset-transfer-private-data/chaincode-java/ 체인코드 리뷰
70. AssetTransfer.java - ② AgreeToTransfer
export ASSET_VALUE=$(echo -n "{"assetID":"asset1","appraisedValue":100}" | base64 | tr -d n)
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n private -c
'{"function":"AgreeToTransfer","Args":[]}' --transient "{"asset_value":"$ASSET_VALUE"}"
Org2MSPPrivateCollection에
구매하려는 assetID와 가격을 저장
-> 뒤의 TransferAsset에서 이 저장된 값을 검증에 사용(p72)
TransferAsset에서 aggKey로 조회하여 거래 종료후,
해당 키로 거래데이터 삭제
../asset-transfer-private-data/chaincode-java/ 체인코드 리뷰
implicit private data collection에 저장된다.
71. AssetTransfer.java – ③ ReadTransferAgreement ../asset-transfer-private-data/chaincode-java/ 체인코드 리뷰
72. AssetTransfer.java - ④ TransferAsset
다음 장…
조건이 충족되면 양도 계약에서 구매자의 클라이언트 ID를
가져와 구매자를 자산의 새로운 소유자로 만듭니다.
그리고, 이전 소유자의 컬렉션에서 Asset을 삭제하고 이전
계약을 제거합니다
AgreeToTransfer에서 aggKey형태로 저장했음
../asset-transfer-private-data/chaincode-java/ 체인코드 리뷰
73. AssetTransfer.java - ⑤ VerifyAgreement
이 함수 호출 이전에
agreeToTransfer함수 호출을 통해
구매자가 특정가격에 구매를 하겠다고 등록한 상황
스마트 컨트랙트는 GetPrivateDataHash()를 사용하여
Org1MSPPrivateCollection감정가의 해시와 Org2MSPPrivateCollection이
일치하는지 확인합니다. 해시가 같으면 소유자와 관심있는 구매자가 동일한
자산 가치에 동의했음을 확인합니다.
../asset-transfer-private-data/chaincode-java/ 체인코드 리뷰
74. 프라이빗 데이터 스마트 계약을 채널에 배포
./network.sh deployCC -ccn private -ccp ../asset-transfer-private-data/chaincode-java/ -ccl java -
ccep "OR('Org1MSP.peer','Org2MSP.peer')" -cccg ../asset-transfer-private-data/chaincode-
java/collections_config.json
위 명령 수행 결과 출력되는 로그중,
체인코드 승인, 커밋에 –collections-config 에 private data collection 파일의 경로가 같이 포함됨
75. go 체인코드는 잘 되는데, 자바 체인코드는 TLS 에러 발생
- openJDK 11.0.4 관련 이슈로 추정
• Go 설치
https://go.dev/doc/install
76. • 체인코드 배포를 Java에서 Go로 변경
• ./network.sh down
• ./network.sh deployCC -ccn private -ccp ../asset-transfer-private-
data/chaincode-go/ -ccl go -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -
cccg ../asset-transfer-private-data/chaincode-go/collections_config.json
77. 신원 등록 (Org1의 owner)
• Org1 CA를 사용하여 ID 자산 소유자를 생성
• Fabric CA 클라이언트 홈을 Org1 CA 관리자의 MSP로 설정합니다
• fabric-ca-client 도구를 사용하여 새 소유자 클라이언트 ID를 등록
fabric-ca-client register --caname ca-org1 --id.name owner --id.secret ownerpw --id.type client --
tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem"
• enroll명령에 등록 이름과 pw을 제공하여 ID 인증서 및 MSP 폴더를 생성
fabric-ca-client enroll -u https://owner:ownerpw@localhost:7054 --caname ca-org1 -M
"${PWD}/organizations/peerOrganizations/org1.example.com/users/owner@org1.example.com/msp"
--tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem"
• Node OU 구성 파일을 소유자 ID MSP 폴더에 복사
cp "${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml"
"${PWD}/organizations/peerOrganizations/org1.example.com/users/owner@org1.example.com/msp/config.yaml"
org1 -> users -> owner
78. 신원 등록 (Org2의 buyer)
• Org2 CA를 사용하여 구매자 ID를 생성
• Fabric CA 클라이언트 홈을 Org2 CA 관리자로 설정
• fabric-ca-client 도구를 사용하여 새 소유자 클라이언트 ID를 등록
fabric-ca-client register --caname ca-org2 --id.name buyer --id.secret buyerpw --id.type client --tls.certfiles
"${PWD}/organizations/fabric-ca/org2/tls-cert.pem“
• ID MSP 폴더를 생성
fabric-ca-client enroll -u https://buyer:buyerpw@localhost:8054 --caname ca-org2 -M
"${PWD}/organizations/peerOrganizations/org2.example.com/users/buyer@org2.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-
ca/org2/tls-cert.pem"
• Node OU 구성 파일을 구매자 ID MSP 폴더에 복사
cp "${PWD}/organizations/peerOrganizations/org2.example.com/msp/config.yaml"
"${PWD}/organizations/peerOrganizations/org2.example.com/users/buyer@org2.example.com/msp/config.yaml"
80. Query the private data as an authorized peer
query the assetCollection collection as Org1
peer chaincode query -C mychannel -n private -c '{"function":"ReadAsset","Args":["asset1"]}'
결과 : {"objectType":"asset","assetID":"asset1","color":"green","size":20,"owner":"x509::CN=appUser1,OU=admin,O=Hyperledger,ST=North Carolina,C=US::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US"}
Query for the appraisedValue private data of asset1 as a member of Org1.
peer chaincode query -C mychannel -n private -c '{"function":"ReadAssetPrivateDetails","Args":["Org1MSPPrivateCollection","asset1"]}'
결과 : {"assetID":"asset1","appraisedValue":100}
81. Query the private data as an unauthorized peer (1/3)
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/buyer@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051
Org2의 buyer 클라이언트로 설정
Query private data Org2 is authorized to
peer chaincode query -C mychannel -n private -c '{"function":"ReadAsset","Args":["asset1"]}'
결과 : {"objectType":"asset","assetID":"asset1","color":"green","size":20,
"owner":"x509::CN=appUser1,OU=admin,O=Hyperledger,ST=North Carolina,C=US::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" }
82. Query private data Org2 is not authorized to
peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-
cert.pem" -C mychannel -n private -c '{"function":"ReadAssetPrivateDetails","Args":["Org2MSPPrivateCollection","asset1"]}'
결과 : empty response
Query the private data as an unauthorized peer (2/3)
83. Query private data Org2 is not authorized to
peer chaincode query -C mychannel -n private -c
'{"function":"ReadAssetPrivateDetails","Args":["Org1MSPPrivateCollection","asset1"]}'
결과 :
Query the private data as an unauthorized peer (3/3)
84. Transfer the Asset
agree to the appraised value of 100 as Org2
export ASSET_VALUE=$(echo -n "{"assetID":"asset1","appraisedValue":100}" | base64 | tr -d n)
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-
cert.pem" -C mychannel -n private -c '{"function":"AgreeToTransfer","Args":[]}' --transient "{"asset_value":"$ASSET_VALUE"}"
query the value they agreed to in the Org2 private data collection
peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-
cert.pem" -C mychannel -n private -c '{"function":"ReadAssetPrivateDetails","Args":["Org2MSPPrivateCollection","asset1"]}'
상기와 같이 구매자가 구매 동의를 완료하였으니, 이제는 원 소유자가 이를 확인하여 Asset를 이관하는 시나리오
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/owner@org1.example.com/msp
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_ADDRESS=localhost:7051
The owner from Org1 can read the data added by the AgreeToTransfer transaction to view the buyer identity:
peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-
cert.pem" -C mychannel -n private -c '{"function":"ReadTransferAgreement","Args":["asset1"]}'
85. Transfer the Asset
체인코드의 GetPrivateDataHash()를 통해Org1MSPPrivateCollection 감정가의 해시와 Org2MSPPrivateCollection의 해시가 일치하는지 확인
조건이 충족되면 구매자의 클라이언트 ID를 가져와 구매자를 자산의 새로운 소유자로 설정
Run the following commands to transfer the asset
export ASSET_OWNER=$(echo -n "{"assetID":"asset1","buyerMSP":"Org2MSP"}" | base64 | tr -d n)
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n
private -c '{"function":"TransferAsset","Args":[]}' --transient "{"asset_owner":"$ASSET_OWNER"}" --peerAddresses localhost:7051 --tlsRootCertFiles
"${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt"
query asset1 to see the results of the transfer
peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n
private -c '{"function":"ReadAsset","Args":["asset1"]}'
confirm that transfer removed the private details from the Org1 collection
peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n
private -c '{"function":"ReadAssetPrivateDetails","Args":["Org1MSPPrivateCollection","asset1"]}'
결과 : empty
86. Purge Private Data
• 3개의 블록이 생성되면 데이터가 자동으로
삭제되는 것을 테스트하는 섹션
• CreateAsset 함수를 3번 호출하여 3개의
블록이 생성되도록 환경을 조성한 수,
데이터를 조회해 보면,
기존에 asset1의 appraisedValue가 100으로 출력되던 데이터가
조회되지 않음을 확인할 수 있음
88. 시나리오
• 자산 발행(Org1)
• 자산 식별자는 자산의 불변 속성의 해시이며 현재 소유자와 함께 모든 채널 구성원이 볼 수 있는 공개
채널 데이터로 저장
• 그러나 자산 불변 속성은 자산 소유자(및 이전 소유자)에게만 알려진 Private Information
• 관심 있는 구매자는 구매하기 전에 해시된 자산 ID에 대해 자산의 사유 재산을 확인하기를 원할
것입니다. 이는 구매자가 올바른 자산 설명을 가지고 있음을 확인
• 자산 양도 위한 구매자와 판매자가 먼저 자산의 속성과 판매 가격 합의
• 현재 소유자만 자산을 다른 조직으로 이전 가능
• 구매자와 판매자 모두 양도를 승인
89. 준비
• ./network.sh up createChannel -c mychannel
• ./network.sh deployCC -ccn secured -ccp ../asset-transfer-secured-
agreement/chaincode-go/ -ccl go -ccep "OR('Org1MSP.peer','Org2MSP.peer')"
• 2개의 터미널창 준비
91. Create an asset
• 모든 채널 구성원은 스마트 계약을 사용하여 조직이 소유한 자산을 생성할 수 있습니다. 자산의 세부
정보는 개인 데이터 컬렉션에 저장되며 자산을 소유한 조직에서만 액세스할 수 있습니다. 자산, 소유자 및
공개 설명의 공개 기록은 채널 원장에 저장됩니다. 모든 채널 구성원은 자산 소유자를 확인하기 위해 공공
소유권 기록에 액세스할 수 있으며 자산이 판매용인지 확인하기 위해 설명을 읽을 수 있습니다.
at Terminal #1
export ASSET_PROPERTIES=$(echo -n "{"object_type":"asset_properties","color":"blue","size":35,"salt":"a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"}" | base64 | tr -d n)
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n secured -c
'{"function":"CreateAsset","Args":["A new asset for Org1MSP"]}' --transient "{"asset_properties":"$ASSET_PROPERTIES"}"
peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n secured -c
"{"function":"GetAssetPrivateProperties","Args":["$ASSET_ID"]}"
peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n secured -c
"{"function":"ReadAsset","Args":["$ASSET_ID"]}"
생성후 리턴되는 해시값이 자산 ID가 됨
93. Agree to sell as Org1
자산을 판매하려면 구매자와 판매자 모두 자산 가격에 동의하고 각자의 개인 데이터 컬렉션에 동일한 자산
속성이 있는지 확인해야 합니다. 각 당사자는 자신의 개인 데이터 컬렉션에 동의한 가격을 저장합니다.
개인 자산 전송 스마트 계약은 자산을 전송하기 전에 양 당사자가 동일한 가격과 자산 속성에 동의해야 한
다고 강제합니다.
at Terminal #1
export ASSET_PRICE=$(echo -n "{"asset_id":"$ASSET_ID","trade_id":"109f4b3c50d7b0df729d299bc6f8e9ef9066971f","price":110}" | base64 | tr -d n)
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n secured -c
"{"function":"AgreeToSell","Args":["$ASSET_ID"]}" --transient "{"asset_price":"$ASSET_PRICE"}"
peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n secured -c
"{"function":"GetAssetSalesPrice","Args":["$ASSET_ID"]}"
구매자나 판매자가 아닌 채널 구성원이 가격을 추측하는 것을 방지하기 위해 사용
94. Agree to buy as Org2
구매에 동의하기 전에 다음 명령을 실행하여 자산 속성을 확인하십시오. 자산 속성과 salt는 구매자와
판매자 사이에서 이메일 또는 기타 통신을 통해 대역외로 전달됩니다.
at Terminal #2
export ASSET_PROPERTIES=$(echo -n "{"object_type":"asset_properties","color":"blue","size":35,"salt":"a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"}" | base64 | tr -d n)
peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n secured -c
"{"function":"VerifyAssetProperties","Args":["$ASSET_ID"]}" --transient "{"asset_properties":"$ASSET_PROPERTIES"}"
다음 명령을 실행하여 100달러에 asset1 구매에 동의합니다. 현재 Org2는 Org1과 다른 가격에 동의합니다.
걱정하지 마십시오. 두 조직은 향후 단계에서 동일한 가격에 동의할 것입니다. 그러나 우리는 구매자와 판
매자가 다른 가격에 동의할 경우 어떤 일이 발생하는지 테스트하기 위해 이 일시적인 불일치를 사용할 수
있습니다. Org2는 Org1과 동일하게 사용해야 합니다
export ASSET_PRICE=$(echo -n "{"asset_id":"$ASSET_ID","trade_id":"109f4b3c50d7b0df729d299bc6f8e9ef9066971f","price":100}" | base64 | tr -d n)
export ASSET_PROPERTIES=$(echo -n "{"object_type":"asset_properties","color":"blue","size":35,"salt":"a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"}" | base64 | tr -d n)
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n secured -c
"{"function":"AgreeToBuy","Args":["$ASSET_ID"]}" --transient "{"asset_price":"$ASSET_PRICE", "asset_properties":"$ASSET_PROPERTIES"}"
peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n secured -c
"{"function":"GetAssetBidPrice","Args":["$ASSET_ID"]}"
95. Org1과 Org2가 자산 이전에 동의한 후 각 조직에서 동의한 가격이 Private data collection에 저장됩니다. 자산내역과 자산소유기록이 충돌
하는 것을 방지하기 위해 판매자와 구매자를 위한 복합키를 사용합니다. 합의된 가격은 각 조직의 피어에만 저장됩니다. 그러나 두 계약의
해시는 채널에 가입한 모든 피어의 Channel World State저장됩니다.
96. Transfer the asset from Org1 to Org2
두 조직이 가격 및 자산 속성에 동의한 후 Org1은 자산을 Org2로 이전하려고 시도할 수 있습니다. 스마트
계약의 개인 자산 이전 기능은 원장의 해시를 사용하여 두 조직이 동일한 가격에 동의했는지 확인합니다.
이 기능은 또한 판매자 및 구매자 개인 컬렉션의 자산 속성 해시를 확인하여 전송된 자산이 Org1이 소유한
자산과 동일한지 확인합니다.
at Terminal #1
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n secured -c
"{"function":"TransferAsset","Args":["$ASSET_ID","Org2MSP"]}" --transient "{"asset_price":"$ASSET_PRICE"}" --peerAddresses localhost:7051 --tlsRootCertFiles
"${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles
"${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt"
결과적으로 Org1과 Org2는 자산을 구매할 가격에 대해 새로운 합의에 도달합니다. Org1은 자산 가격을 100으로 떨어뜨립니다.
export ASSET_PRICE=$(echo -n "{"asset_id":"$ASSET_ID","trade_id":"109f4b3c50d7b0df729d299bc6f8e9ef9066971f","price":100}" | base64 | tr -d n)
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n secured -c
"{"function":"AgreeToSell","Args":["$ASSET_ID","Org2MSP"]}" --transient "{"asset_price":"$ASSET_PRICE"}"
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n secured -c
"{"function":"TransferAsset","Args":["$ASSET_ID","Org2MSP"]}" --transient "{"asset_price":"$ASSET_PRICE"}" --peerAddresses localhost:7051 --tlsRootCertFiles
"${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles
"${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt"
peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n secured -c
"{"function":"ReadAsset","Args":["$ASSET_ID"]}"
97. 자산이 전송된 후 자산 세부 정보는 Org2 암시적 데이터 컬렉션에 배치되고 Org1 암시적 데이터 컬렉션에서 삭제됩니다. 결과적으로 자산
세부 정보는 이제 Org2 피어에만 저장됩니다. 원장의 자산 소유권 레코드는 Org2가 자산을 소유하고 있음을 반영하도록 업데이트됩니다.
98. Update the asset description as Org2
Org2 터미널에서 작동합니다. 이제 Org2가 자산을 소유하고 있으므로 Org2 암시적 데이터 컬렉션에서 자
산 세부 정보를 읽을 수 있습니다.
peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n secured -c
"{"function":"GetAssetPrivateProperties","Args":["$ASSET_ID"]}"
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n secured -c
"{"function":"ChangePublicDescription","Args":["$ASSET_ID","This asset is not for sale"]}"
peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n secured -c
"{"function":"ReadAsset","Args":["$ASSET_ID"]}"
100. 개요
• A Docker image of CouchDB is available and we recommend that it be run on
the same server as the peer.
• If a rich query includes a sort specification, then an index on that field is
required
• When using CouchDB, each chaincode is represented as its own CouchDB
database, that is, each chaincode has its own namespace for keys.
101. 개요
docType is used to identify that this JSON document represents an asset. Potentially there could be
other JSON document types in the chaincode namespace
102. Create an index
When defining an index for use in chaincode queries
- each one must be defined in its own text file with the extension *.json
- the index definition must be formatted in the CouchDB index JSON format.
ddoc선택적으로 색인 정의에 디자인 문서 속성을 지정할 수 있습니다. 디자
인 문서는 인덱스를 포함하도록 설계된 CouchDB 구조입니다. 색인은 효율
성을 위해 설계 문서로 그룹화할 수 있지만 CouchDB는 설계 문서당 하나의
색인을 권장합니다.
109. Query the CouchDB State Database With Pagination
peer chaincode query -C $CHANNEL_NAME -n ledger -c '{"Args":["QueryAssetsWithPagination", "{"selector":{"docType":"asset","owner":"tom"},
"use_index":["_design/indexOwnerDoc",
"indexOwner"]}","3","g1AAAABJeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqzJRYXp5YYg2Q5YLI5IPUgSVawJIjFXJKfm5UFANozE8s"]}'
peer chaincode query -C $CHANNEL_NAME -n ledger -c '{"Args":["QueryAssetsWithPagination", "{"selector":{"docType":"asset","owner":"tom"},
"use_index":["_design/indexOwnerDoc",
"indexOwner"]}","3","g1AAAABJeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqzJRYXp5aYgmQ5YLI5IPUgSVawJIjFXJKfm5UFANqBE80"]}'
앞 장에 이어서, 다음 페이지 조회
조회결과를 북마크 인덱스를 리턴하는데, 이 값을 이용하여 다음 페이지 조회에 사용함
Range Query Pagination 기능도 지원함
- GetStateByRangeWithPagination
115. • 어플리케이션 채널 생성하고 오더링 노드에 조인하는 튜토리얼
• In this tutorial,
① we use the configtxgen tool to create a channel genesis block
② and then use the osnadmin channel command to create the channel.(application channel)
116. 준비
• ./network.sh up
By default, when you start the test network, it does not contain any channels.
채널을 생성하기 위해서, 다음 장의 configtxgen 사용
117. Set up the configtxgen tool
• 채널은 제네시스 블록에 채널 생성 정보를 오더링 서비스에 전달함으로써 생성된다.
• configex.yaml에 채널 명세를 해야 한다.
• configtxgen은 fabric-sample/bin 디렉토리에 있다.
• export PATH=${PWD}/../bin:$PATH
• export FABRIC_CFG_PATH=${PWD}/configtx
• configtxgen --help
118. The configtx.yaml file
• Organizations
• Ordering service : 합의 방식/프로토콜
• Channel policies
• Channel profiles
119. Step one: Generate the genesis block of the channel
• configtxgen -profile TwoOrgsApplicationGenesis -outputBlock ./channel-
artifacts/channel1.block -channelID channel1
121. Join peers to the channel
• view the channels
• Join peers to the channel
osnadmin channel list -o localhost:7053 --ca-file "$ORDERER_CA" --client-cert "$ORDERER_ADMIN_TLS_SIGN_CERT" --client-key
"$ORDERER_ADMIN_TLS_PRIVATE_KEY"
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
export FABRIC_CFG_PATH=$PWD/../config/
peer channel join -b ./channel-artifacts/channel1.block
peer CLI를 사용하기 위해 환경변수 재설정
acting as the Org1 admin and targeting the Org1 peer
122. Join peers to the channel
• Join peers to the channel
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051
export FABRIC_CFG_PATH=$PWD/../config/
peer channel join -b ./channel-artifacts/channel1.block
acting as the Org2 admin and targeting the Org2 peer
→ Joined their peers to the channel
123. Set anchor peer
• We will use the configtxlator tool to update the channel configuration and
select an anchor peer for Org1 and Org2.
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
acting as the Org1 admin
peer channel fetch config channel-artifacts/config_block.pb -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com -c channel1 --tls --cafile
"$ORDERER_CA"
fetch the channel configuration
cd channel-artifacts
configtxlator proto_decode --input config_block.pb --type common.Block --output config_block.json
jq '.data.data[0].payload.data.config' config_block.json > config.json
cp config.json config_copy.json
jq '.channel_group.groups.Application.groups.Org1MSP.values += {"AnchorPeers":{"mod_policy": "Admins","value":{"anchor_peers": [{"host":
"peer0.org1.example.com","port": 7051}]},"version": "0"}}' config_copy.json > modified_config.json
decode the block from protobuf into a JSON objec
124. Set anchor peer
configtxlator proto_encode --input config.json --type common.Config --output config.pb
configtxlator proto_encode --input modified_config.json --type common.Config --output modified_config.pb
configtxlator compute_update --channel_id channel1 --original config.pb --updated modified_config.pb --output config_update.pb
채널 구성 파일(원본, 수정본)을 protobuf 형식으로 변경하고 변경분을 계산
configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate --output config_update.json
echo '{"payload":{"header":{"channel_header":{"channel_id":"channel1", "type":2}},"data":{"config_update":'$(cat config_update.json)'}}}' | jq . > config_update_in_envelope.json
configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope --output config_update_in_envelope.pb
cd ..
peer channel update -f channel-artifacts/config_update_in_envelope.pb -c channel1 -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"
채널 헤더와 타입의 정보(K:V)를 앞에 추가(JSON 형태)하고, 이를 pb형식으로 다시 변환
128. Bring Org3 into the Channel with the Script
• 채널 생성후 Org3 조직을 Join
• ./network.sh down
• ./network.sh up createChannel -c channel1
• cd addOrg3
• ./addOrg3.sh up -c channel1 인증서 등 생성 이후, 채널에 조인함
129. Bring Org3 into the Channel Manually
• ./network.sh down
• ./network.sh up createChannel -c channel1
• cd addOrg3
• 기 구성된 채널(channel1)에 업데이트를 하기 때문에, CA를 사용하지 않고
cryptogen 도구를 사용한다.
• ../../bin/cryptogen generate --config=org3-crypto.yaml --
output="../organizations"
앞 장에서 했던 내용을
하나씩 수행하면서, 원리를 알아보자.
기존 조직 Org1, Org2에
Org3 조직 추가됨
130. • configtxgen 도구를 사용하여 Org3 조직를 출력
• export FABRIC_CFG_PATH=$PWD
• ../../bin/configtxgen -printOrg
Org3MSP > ../organizations/peerOrganizations/org3.example.com/org3.json
Bring Org3 into the Channel Manually
configtxgen로 하여금 현재 디렉토리의 configtx.yaml을 참조하게 함
위 수행의 결과로 org3.json 파일이 생성되고, 이 파일에는 조직의 정책 정의 내용과
CA 루트 인증서, TLS 루트 인증서가 포함된다. 이후, 이 파일을 채널에 추가하게 된다.
131. Bring up Org3 components
• From the addOrg3 directory,
• docker-compose -f compose/compose-org3.yaml -f compose/docker/docker-
compose-org3.yaml up -d
볼륨 마운트 대상 디렉토리 표기시 뒤에 슬래쉬 기호를 추가해야 아래와 같은 오류가 발생하지 않는다.
132. Fetch the Configuration
• 현재 채널의 설정 블록을 불러온다.
• From the test-network directory
• Org3가 아직 채널 멤버가 아니기 때문에, Org1의 Admin으로 환경변수를 설정하여
작업을 진행한다.
• 현재 채널(channel1)의 구성 정보를 불러와서, config_block.pb 파일로 저장
export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=${PWD}/../config/
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
peer channel fetch config channel-artifacts/config_block.pb -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com -c channel1 --tls
--cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"
133. Convert the Configuration to JSON and Trim It Down
• cd channel-artifacts
• 앞장에서 생성한 config_block.pb파일을 json으로 형식을 변경하고 불필요한 정보를
제외하여 config.json파일로 출력
• configtxlator proto_decode --input config_block.pb --type common.Block --
output config_block.json
• jq ".data.data[0].payload.data.config" config_block.json > config.json
134. Add the Org3 Crypto Material
• 이전에 생성한 org3.json(organization/peer~/org3.peer~) 파일 내용을 앞장에서 생성한 json파일에
추가하여 modified_config.json으로 생성
• jq -s '.[0] * {"channel_group":{"groups":{"Application":{"groups": {"Org3MSP":.[1]}}}}}'
config.json ../organizations/peerOrganizations/org3.example.com/org3.json > modified_config.json
• 작업 순서
① Org1/2 만 있는 기존의 config.json을 protobuf형식으로 변경
② Org3까지 포함하고 있는 modified_config.json을 protobuf형식으로 변경
③ 상기 2개의 pb 파일을 configtxlator 도구를 이용하여 변경분을 계산(org3_update.pb)
④ 상기 변경분을 json 형식으로 변환(org3_update.json)
⑤ org3 정보 + header 추가한 json 파일을 생성(org3_update_in_envelope.json)
(☞ 앞장에서 config.json을 생성할때 채널 설정을 읽어서 헤더를 제거했었음)
⑥ configtxlator 도구를 이용 상기 json파일을 pb로 포맷 변경(org3_update_in_envelope.pb)
헤더
org3_update.json
org3_update_in_envelope.json
jq -s '.[0] * {"channel_group":{"groups":{"Application":{"groups": {"Org3MSP":.[1]}}}}}' config.json ../organizations/peerOrganizations/org3.example.com/org3.json > modified_config.json
configtxlator proto_encode --input config.json --type common.Config --output config.pb
configtxlator proto_encode --input modified_config.json --type common.Config --output modified_config.pb
configtxlator compute_update --channel_id channel1 --original config.pb --updated modified_config.pb --output org3_update.pb
configtxlator proto_decode --input org3_update.pb --type common.ConfigUpdate --output org3_update.json
echo '{"payload":{"header":{"channel_header":{"channel_id":"'channel1'", "type":2}},"data":{"config_update":'$(cat org3_update.json)'}}}' | jq . > org3_update_in_envelope.json
configtxlator proto_encode --input org3_update_in_envelope.json --type common.Envelope --output org3_update_in_envelope.pb
135. Sign and Submit the Config Update
• 수정 정책(mod_policy)는 과반 이상 동의해야 하기 때문에, Org1/Org2 두 조직의
signature가 필요한 상황
• Org1으로 사인하고, 환경설정 변수를 Org2로 변경하고 peer channel update로
렛져에 반영(Org2는 peer channel update시 자동으로 사인이 추가되기 때문에
별도로 사인할 필요 없음)
• From the test-network directory
• peer channel signconfigtx -f channel-artifacts/org3_update_in_envelope.pb
• peer channel update -f channel-artifacts/org3_update_in_envelope.pb -c
channel1 -o localhost:7050 --ordererTLSHostnameOverride
orderer.example.com --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.e
xample.com/msp/tlscacerts/tlsca.example.com-cert.pem"
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051
136. Join Org3 to the Channel
• 환경변수를 Org3 Admin으로 설정하고, 제네시스 블록을 요청한다.
(신규 조직이 채널에 참가하는 방법: 제네시스 블록 또는 스냅샷으로 생성)
• 제네시스 블록을 기반으로 peer channel join 명령으로 채널에 참가한다.
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org3MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp
export CORE_PEER_ADDRESS=localhost:11051
peer channel fetch 0 channel-artifacts/channel1.block -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com -c channel1 --tls --cafile
"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"
peer channel join -b channel-artifacts/channel1.block
145. Go 설치
• rm -rf /usr/local/go && tar -C /usr/local -xzf go1.20.2.linux-amd64.tar.gz
• vi /etc/profile
• 상기 파일에 환경변수 추가 export PATH=$PATH:/usr/local/go/bin
• source /etc/profile
• go version
147. [참조] 기본 아이디어 (1/2)
https://kctheservant.medium.com/multi-host-setup-with-raft-based-ordering-service-29730788b171
https://kctheservant.medium.com/multi-host-deployment-for-first-network-hyperledger-fabric-v2-273b794ff3d
docker swarm을 이용한 멀티 호스트 예제
- 인증서는 cryptogen을 이용해 생성
- v2.2 기준
다음과 같이 재구성 해보자.
- Hyperledger fabric CA 서버로 인증서 생성
- 최신 예제와 환경으로 프로젝트 재구성(v2.5)
v1.4기준 멀티호스트 예제
v2.2 기준 멀티호스트 예제
148. [참조] 기본 아이디어 (2/2)
1. 앞 장의 2개의 가이드를 수행 테스트
https://github.com/wonyongHwang/4host-swarm
https://kctheservant.medium.com/a-companion-guide-to-fabric-ca-
operation-guide-c81591ef0321
https://kctheservant.medium.com/add-a-peer-to-an-organization-in-
test-network-hyperledger-fabric-v2-2-4a08cb901c98
CA 서버 가이드 참조
peer 추가 가이드 참조
150. 준비작업 - 인증서 발급
1번 서버 :
cd fabric-samples/kopo-network
./network.sh up -ca
인증서(organizations) 디렉토리 복사 및 2~4번 서버 폴더에 복사(kopo-network/organizations)
./network down
인증서(organizations) 디렉토리 복사 및 1번 서버 폴더에 복사(kopo-network/organizations)
151. 기동
1,4번 서버 :
cd fabric-samples/kopo-network
./kopo-network.sh up
2,3번 서버 :
cd fabric-samples/kopo-network
./kopo-network.sh up -s couchdb
[참고] 1번 서버에서 차후에 별도로 CA서버 기동할 시
docker-compose -f compose/compose-ca.yaml -f compose/docker/docker-compose-ca.yaml up -d
152. 채널 생성
1번 서버 :
export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=${PWD}/configtx
configtxgen -profile TwoOrgsApplicationGenesis -outputBlock ./channel-artifacts/channel1.block -channelID channel1
# 여기서 생성된 channel-artifacts 디렉토리를 2~4번 서버의 kopo-network/ 에 복사한다.
(다른 오더러들도 채널에 조인하기 위함)
export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-
cert.pem
export ORDERER_ADMIN_TLS_SIGN_CERT=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt
export ORDERER_ADMIN_TLS_PRIVATE_KEY=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.key
osnadmin channel join --channelID channel1 --config-block ./channel-artifacts/channel1.block -o localhost:7053 --ca-file "$ORDERER_CA" --client-cert
"$ORDERER_ADMIN_TLS_SIGN_CERT" --client-key "$ORDERER_ADMIN_TLS_PRIVATE_KEY"
2번 서버 :
export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=${PWD}/configtx
export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer2.example.com/msp/tlscacerts/tlsca.example.com-
cert.pem
export ORDERER_ADMIN_TLS_SIGN_CERT=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/server.crt
export ORDERER_ADMIN_TLS_PRIVATE_KEY=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/server.key
osnadmin channel join --channelID channel1 --config-block ./channel-artifacts/channel1.block -o localhost:8053 --ca-file "$ORDERER_CA" --client-cert
"$ORDERER_ADMIN_TLS_SIGN_CERT" --client-key "$ORDERER_ADMIN_TLS_PRIVATE_KEY"