티스토리 뷰
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-javascript/ -ccl javascript
시작하기 전에 필요한 거 다 설치해준다.
https://hyperledger-fabric.readthedocs.io/en/latest/prereqs.html#linux
--에러
$ sudo systemctl start docker
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down
--해결
sudo /etc/init.d/docker start
근데 이거 할 필요는 없음 도커 잘 되는지 확인하려고 하는 거니까
Go설치
sudo apt-get install golang
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
디렉토리 만들기. (여기에 Fabric sample 받을 예정)
$ mkdir -p $HOME/go/src/github.com/<your_github_userid>
$ cd $HOME/go/src/github.com/<your_github_userid>
다운로드
curl -sSL https://bit.ly/2ysbOFE | bash -s
실행하면 알아서 필요한 폴더 다 만들어 주는데 에러 나오면서 디렉토리 생성이 안됐다 ㅡㅡ;;
--에러
tar: bin: Cannot mkdir: Permission denied
--해결
권한 없다는 거 같다니까 폴더에 권한 준다.
pwd
pwd 찍어서 현재 경로 복사한 다음
sudo chmod 777 [pwd값]
그리고 다시 curl 명령 실행해준다.
이동
cd fabric-samples/test-network
./network.sh up
오더라 하나랑 피어 두개 있는 네트워크가 생성된다.
docker ps -a
로 확인한다.
종료하려면 아래 명령어를 입력하면된다. 일단은 종료하지 않고 넘어간다.
./network.sh down
채널생성
./network.sh createChannel
기본 채널명 mychannel로 생성된다.
체인코드
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-javascript/ -ccl javascript
deployCC는 채널에 체인코드를 배포하는 명령어다.
-ccn 은 체인코드의 이름
-ccp 는 체인코드의 경로
-ccl 은 체인코드 언어를 지정한다. go, java, javascript, typescript 를 지원한다.
튜토리얼 체인코드는 다음과 같다.
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
// Deterministic JSON.stringify()
const stringify = require('json-stringify-deterministic');
const sortKeysRecursive = require('sort-keys-recursive');
const { Contract } = require('fabric-contract-api');
class AssetTransfer extends Contract {
async InitLedger(ctx) {
const assets = [
{
ID: 'asset1',
Color: 'blue',
Size: 5,
Owner: 'Tomoko',
AppraisedValue: 300,
},
{
ID: 'asset2',
Color: 'red',
Size: 5,
Owner: 'Brad',
AppraisedValue: 400,
},
{
ID: 'asset3',
Color: 'green',
Size: 10,
Owner: 'Jin Soo',
AppraisedValue: 500,
},
{
ID: 'asset4',
Color: 'yellow',
Size: 10,
Owner: 'Max',
AppraisedValue: 600,
},
{
ID: 'asset5',
Color: 'black',
Size: 15,
Owner: 'Adriana',
AppraisedValue: 700,
},
{
ID: 'asset6',
Color: 'white',
Size: 15,
Owner: 'Michel',
AppraisedValue: 800,
},
];
for (const asset of assets) {
asset.docType = 'asset';
// example of how to write to world state deterministically
// use convetion of alphabetic order
// we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive'
// when retrieving data, in any lang, the order of data will be the same and consequently also the corresonding hash
await ctx.stub.putState(asset.ID, Buffer.from(stringify(sortKeysRecursive(asset))));
}
}
// CreateAsset issues a new asset to the world state with given details.
async CreateAsset(ctx, id, color, size, owner, appraisedValue) {
const exists = await this.AssetExists(ctx, id);
if (exists) {
throw new Error(`The asset ${id} already exists`);
}
const asset = {
ID: id,
Color: color,
Size: size,
Owner: owner,
AppraisedValue: appraisedValue,
};
//we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive'
await ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset))));
return JSON.stringify(asset);
}
// ReadAsset returns the asset stored in the world state with given id.
async ReadAsset(ctx, id) {
const assetJSON = await ctx.stub.getState(id); // get the asset from chaincode state
if (!assetJSON || assetJSON.length === 0) {
throw new Error(`The asset ${id} does not exist`);
}
return assetJSON.toString();
}
// UpdateAsset updates an existing asset in the world state with provided parameters.
async UpdateAsset(ctx, id, color, size, owner, appraisedValue) {
const exists = await this.AssetExists(ctx, id);
if (!exists) {
throw new Error(`The asset ${id} does not exist`);
}
// overwriting original asset with new asset
const updatedAsset = {
ID: id,
Color: color,
Size: size,
Owner: owner,
AppraisedValue: appraisedValue,
};
// we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive'
return ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(updatedAsset))));
}
// DeleteAsset deletes an given asset from the world state.
async DeleteAsset(ctx, id) {
const exists = await this.AssetExists(ctx, id);
if (!exists) {
throw new Error(`The asset ${id} does not exist`);
}
return ctx.stub.deleteState(id);
}
// AssetExists returns true when asset with given ID exists in world state.
async AssetExists(ctx, id) {
const assetJSON = await ctx.stub.getState(id);
return assetJSON && assetJSON.length > 0;
}
// TransferAsset updates the owner field of asset with given id in the world state.
async TransferAsset(ctx, id, newOwner) {
const assetString = await this.ReadAsset(ctx, id);
const asset = JSON.parse(assetString);
const oldOwner = asset.Owner;
asset.Owner = newOwner;
// we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive'
ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset))));
return oldOwner;
}
// GetAllAssets returns all assets found in the world state.
async GetAllAssets(ctx) {
const allResults = [];
// range query with empty string for startKey and endKey does an open-ended query of all assets in the chaincode namespace.
const iterator = await ctx.stub.getStateByRange('', '');
let result = await iterator.next();
while (!result.done) {
const strValue = Buffer.from(result.value.value.toString()).toString('utf8');
let record;
try {
record = JSON.parse(strValue);
} catch (err) {
console.log(err);
record = strValue;
}
allResults.push(record);
result = await iterator.next();
}
return JSON.stringify(allResults);
}
}
module.exports = AssetTransfer;
네트워크와 상호작용
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
org1의 peer를 사용하기위한 환경변수 설정인듯?
체인코드 실행.
최초 원장을 만드는 과정인듯?
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":[]}'
너무 기니까 나눠서 살펴보면
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":[]}'
peer chaincode의 내용을 살펴보면
Operate a chaincode: install|instantiate|invoke|package|query|signpackage|upgrade|list.
Usage:
peer chaincode [command]
Available Commands:
install Install a chaincode.
instantiate Deploy the specified chaincode to the network.
invoke Invoke the specified chaincode.
list Get the instantiated chaincodes on a channel or installed chaincodes on a peer.
package Package a chaincode
query Query using the specified chaincode.
signpackage Sign the specified chaincode package
upgrade Upgrade chaincode.
Flags:
--cafile string Path to file containing PEM-encoded trusted certificate(s) for the ordering endpoint
--certfile string Path to file containing PEM-encoded X509 public key to use for mutual TLS communication with the orderer endpoint
--clientauth Use mutual TLS when communicating with the orderer endpoint
--connTimeout duration Timeout for client to connect (default 3s)
-h, --help help for chaincode
--keyfile string Path to file containing PEM-encoded private key to use for mutual TLS communication with the orderer endpoint
-o, --orderer string Ordering service endpoint
--ordererTLSHostnameOverride string The hostname override to use when validating the TLS connection to the orderer
--tls Use TLS when communicating with the orderer endpoint
--tlsHandshakeTimeShift duration The amount of time to shift backwards for certificate expiration checks during TLS handshakes with the orderer endpoint
--transient string Transient map of arguments in JSON encoding
Use "peer chaincode [command] --help" for more information about a command.
원장을 한번 조회해보자.
peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'
output:
[
{"AppraisedValue":300,"Color":"blue","ID":"asset1","Owner":"Tomoko","Size":5,"docType":"asset"},
{"AppraisedValue":400,"Color":"red","ID":"asset2","Owner":"Brad","Size":5,"docType":"asset"},
{"AppraisedValue":500,"Color":"green","ID":"asset3","Owner":"Jin Soo","Size":10,"docType":"asset"},
{"AppraisedValue":600,"Color":"yellow","ID":"asset4","Owner":"Max","Size":10,"docType":"asset"},
{"AppraisedValue":700,"Color":"black","ID":"asset5","Owner":"Adriana","Size":15,"docType":"asset"},
{"AppraisedValue":800,"Color":"white","ID":"asset6","Owner":"Michel","Size":15,"docType":"asset"}
]
asset6을 크리스토퍼한테 보내주자.
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"]}'
Org2로 바꾸고,,
# Environment variables for Org2
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
Org2에 있는 원장을 조회해보자.
peer chaincode query -C mychannel -n basic -c '{"Args":["ReadAsset","asset6"]}'
output:
{"AppraisedValue":800,"Color":"white","ID":"asset6","Owner":"Christopher","Size":15,"docType":"asset"}
asset6의 소유자가 크리스토퍼로 바뀐것을 Org2의 원장에서도 확인할 수 있다.
뭐 이정도 하고,
종료하고
./network.sh down
CA를 사용하는 network를 구성
./network.sh up -ca
'블록체인' 카테고리의 다른 글
Geth) 노드 첫 실행, DAG 파일 생성 (0) | 2021.12.27 |
---|---|
Geth) Genesis Block, 계정생성 (0) | 2021.12.26 |
NFT.. 탐구 1 (0) | 2021.12.13 |
메타마스크 (0) | 2021.10.12 |
리눅스에서 C 작성 및 실행. (0) | 2021.09.10 |
- Total
- Today
- Yesterday
- MySQL
- MOD
- 로드나인
- create databases;
- 다이나믹프로그래밍
- create db
- 은둔청년체험
- 개발자면접
- 투포인터 연습
- DB 생성
- 서버점검
- 동적프로그래밍
- node.js
- 투포인터
- 면접질문
- 서버개발
- 최소공통조상
- 롱베케이션
- BFS
- 면접비
- 다이나밍프로그래밍
- 그래프
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |