티스토리 뷰
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-javascript/ -ccl javascript
시작하기 전에 필요한 거 다 설치해준다.
https://hyperledger-fabric.readthedocs.io/en/latest/prereqs.html#linux
Prerequisites — hyperledger-fabricdocs main documentation
Git Install the latest version of git if it is not already installed. To use Fabric binaries, you will need to have the uname command available. You can get it as part of Git but beware that only the 64bit version is supported. Update the following git con
hyperledger-fabric.readthedocs.io
--에러
$ 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, 계정생성 (1) | 2021.12.26 |
NFT.. 탐구 1 (0) | 2021.12.13 |
메타마스크 (0) | 2021.10.12 |
리눅스에서 C 작성 및 실행. (0) | 2021.09.10 |
- Total
- Today
- Yesterday
- BFS
- 롱베케이션
- KMP
- create databases;
- MySQL
- 면접질문
- 동적프로그래밍
- DB 생성
- 투포인터 연습
- MOD
- 최소공통조상
- node.js
- 다이나밍프로그래밍
- create db
- 면접비
- 그래프
- 투포인터
- 서버개발
- 로드나인
- 서버점검
- 개발자면접
- 은둔청년체험
- 다이나믹프로그래밍
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |