알고리즘 문제풀이

간단한 블록체인 네트워크 ( seller ↔ customer ) 본문

블록체인/2020 겨울학기

간단한 블록체인 네트워크 ( seller ↔ customer )

JoonDev 2021. 1. 12. 17:40

1. 프로젝트 생성

프로젝트를 만들기 위해 먼저, 프로젝트가 저장될 directory를 생성해주자 .

cd $GOPATH/src
mkdir stream-music && cd stream-music
mkdir basic-network && cd basic-network

 

하이퍼레저 패브릭을 구동하기 위한 바이너리 파일은 fabric-samples 내부의 bin 파일에 있다.

cp -r $GOPATH/src/fabric-samples/bin ./

자 이제 인증서 발급과 채널 생성, 오더링 서비스 노드의 제네시스 블록을 생성해주기 위한 설정 파일과 블록체인 네트워크가 구동되기 위한 docker-compose 파일까지 생성해주자.

또한 인증서들이 보관될 디렉토리 crypto-config 를 만들어주자.

touch crypto-config.yaml
touch configtx.yaml
touch docker-compose.yaml
export FABRIC_CFG_PATH=$PWD
mkdir crypto-config

 

2. 설정 파일 작성

2-1 인증서 구성 파일 작성

Hyperledger Fabric Network 내부에 있는 모든 노드들은 인증서를 발급받는다.

또한, Hyperledger Fabric Network에 접근하는 관리자 및 사용자도 인증서를 발급받아야 접근할 수 있다.

네트워크를 구성하는 기본적인 노드( Ordering Service Node의 제네시스 블록 등.. ) 은 네트워크를 구성할 때 생성.

관리자, 판매자, 구매자에 대한 인증서는 네트워크가 실행한 후 생성할 수 있다.

Hyperledger Fabric Network는 Private한 특성을 가지기 때문에 개발자, 운영자, 사용자 모두 회원 가입과 같은 인증서 등록 절차를 밟아야한다.

 

앞으로 우리가 구성해야하는 도메인 주소에 따른 호스트와 조직 구성은 다음과 같다.

 

 

도메인 주소에 따른 조직 구성

*Diagram 설명 : 도메인 주소인 acornpub.com 에서 각 노드를 관리하는 조직인 Orderer, Sales1, Customer 을 구성

각 조직마다 인증서가 1개씩 발급되는데, 그것은 각 조직 위에 있는 Sales1Org, CustomerOrg, OrdererOrg 이다.

 

그림의 구성대로 crypto-config.yaml을 설정해보자.

# 오더링 서비스 노드 조직을 정의
OrdererOrgs:
  #이름
  - Name : Orderer 
  # 도메인 네임
    Domain : acornpub.com
    # 호스트 네임을 orderer로 정하자
    Specs :
    - Hostname : orderer
    
# 피어 노드 조직을 정의
PeerOrgs:
  - Name : Sales1
    Domain : sales1.acornpub.com
    # 피어의 수
    Template :
      Count : 2
    # 사용자의 수
    Users :
      Count : 1
  
  - Name : Customer1
    Domain : customer.acornpub.com
    Template :
      Count : 2
    Users :
      Count : 1

 자 이제 이것을 토대로 cryptogen을 실행하여 인증서를 발급해 보자.

cryptogen을 실행하여 새로운 인증서를 발급받는 과정은 다음과 같다.

./bin/cryptogen generate --config=./crypto-config.yaml

cryptogen generate 의 config옵션을 사용하여 인증서 설정파일을 지정해주었다.

 

 

2-2 오더링 서비스의 제네시스 블록 및 트랜잭션 생성

 

인증서를 발급한 다음 해주어야하는 일은 

오더링 서비스 노드의 제네시스 블록과 채널에 대한 정보, 조직에 대한 정보를 담을 파일을 작성해주는 것이다.

[ 채널, 조직, 오더링 서비스 노드 제네시스 블록 등의 설정은 configtx.yaml 에서 한다 ]

# 조직들에 대한 설정! ( 조직의 이름, ID, 인증서 저장 위치 )
Organizations:
  - &OrdererOrg
    Name : OrdererOrg
    ID: OrdererOrg
    MSPDir: crypto-config/ordererOrganizations/acornpub.com/msp


  - &Sales1Org
    Name : Sales1Org
    ID: Sales1Org
    MSPDir: crypto-config/peerOrganizations/sales1.acornpub.com/msp
    AnchorPeers: 
      - Host : peer0.sales1.acornpub.com
        Port : 7051
    

  - &CustomerOrg
    Name : CustomerOrg
    ID : CustomerOrg
    MSPDir : crypto-config/peerOrganizations/customer.acornpub.com/msp
    AnchorPeers :
      - Host : peer0.customer.acornpub.com
        Port : 7051
# 오더링 서비스 노드 정보를 입력  
Orderer : &OrdererDefaults
  # 오더링 서비스의 타입
  OrdererType: solo
  # 도메인 주소 : 포트주소(docker 컨테이너 기반)
  Addresses: 
  - orderer.acornpub.com:7050
  # 일괄 처리 시간 및 크기 설정
  BatchTimeOut: 2s
  BatchSize:
    MaxMessageCount : 10
    AbsoluteMaxBytes : 99 MB
    preferredMaxBytes : 512 KB
  
  Kafka: 
    Brokers:
      - 127.0.0.1:9092
  Organizations:

Application : &ApplicationDefaults
  Organizations:

# 오더링 서비스 노드의 제네시스 블록 및 채널에 대한 profile 정보를 정의한다.
# OrdererGenesis 등은 여기서 정의할 프로파일의 이름을 나타낸다.
# 해당 스펙들에 맞게 configtxgen 은 블록을 생성하거나, 채널 트랜잭션 파일을 생성한다.
profiles:

  OrdererGenesis:
    Orderer:
      <<: *OrdererDefaults
      Organizations:
        - *OrdererOrg
    Consortiums:
      SampleConsortium:
        Organizations:
          - *Sales1Org
          - *CustomerOrg

  Channel1:
    Consortium: SampleConsortium
    Application:
      <<: *ApplicationDefaults
      Organizations:
        - *Sales1Org
        - *CustomerOrg

  

자 이제, configtxgen 을 이용하여 오더링 서비스 제네시스 블록을 추가해보자.

mkdir config
./bin/configtxgen -profile OrdererGenesis -outputBlock ./config/genesis.block

* 제네시스 블록을 추가해주기 위해 Profile 에 정의되어 있는 OrdererGenesis의 내용을 가지고 block을 생성한다.

- 아마도, 정의되어 있는 OrdererOrg와 같이 *로 정의되어 있는 멤버들의 개념은 Organizations 에서 구체적으로 정의한 것 같다.

 

 

2-3 채널 트랜잭션 파일 생성

 

configtx.yaml 파일의 profile 에 정의 된 Channel1 의 형식으로 채널을 만들고 싶을 경우 다음과 같이 입력한다.

./bin/configtxgen -profile Channel1 -outputCreateChannelTx ./config/channel1.tx -channelID channelsales1

위와 같은 명령어를 실행시켜 주면, 채널 생성과 관련한 transaction 파일(channel1.tx)이 생성되게 된다.

여기서 주의해야할 점은 channelID 와 transaction 파일의 이름을 다르게 설정해주어야한다는 것이다.

 

 

2-4 각 조직에 대한 앵커피어 설정

 

1) configtx.yaml파일의 Channel1에 정의 된 내용을 바탕으로 앵커피어를 업데이트한다. 결과는 Sales1Organchors.tx 로 배출, 채널 아이디는 앞에서 정의한 채널 안에 포함될 것이므로 channelsales1 으로 지정한다.

해당 피어는 이제 채널 안에서 Sales1Org 의 역할을 수행한다.

./bin/configtxgen -profile Channel1 -outputAnchorPeersUpdate ./config/Sales1Organchors.tx -channelID channelsales1 -asOrg Sales1Org

 

2) configtx.yaml파일의 Channel1에 정의 된 내용을 바탕으로 앵커피어를 업데이트한다. 결과는 Sales1organchors.tx 로 배출되고, 채널은 channelsales1으로 지정하고 이 채널안에서 해당 피어는 CustomerOrg 의 역할을 수행한다.

./bin/configtxgen -profile Channel1 -outputAnchorPeersUpdate ./config/CustomerOrganchors.tx -channelID channelsales1 -asOrg CustomerOrg

현재 생성된 트랜잭션 파일들이 네트워크 상에서 체인코드 형식으로 실행된다면 다음과 같은 구성을 이룰 것이다.

이제, 도커 컨테이너로 동작하는 도메인에 따른 전체 구성도를 살펴보자.

 

 

도메인 주소에 따른 전체 구상도

2-5. Docker상에 올라갈 컨테이너들에 대한 정의

위의 구성과 동일하게 docker-compose 에서 5개의 컨테이너로 동작하도록 docker-compose.yaml 파일을 작성해보자.

 

version: '2' # 버전 정보 입력

networks: 	# 도커에서 사용할 네트워크 이름을 지정한다.
acorn:		# ""

services:
	orderer.example.com:
    	container_name: orderer.acornpub.com
        image: hyperledger/fabric-orderer:1.4.3
        enviroment:
        	- ORDERER_GENERAL_LOGLEVEL=debug
            - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
            - ORDERER_GENERAL_GENESISMETHOD=file
            - ORDERER_GENERAL_GENESISFILE=/etc/hyperledger/configtx/genesis.block
            - ORDERER_GENERAL_LOCALMSPID=Ordererorg #모든 피어들은 반드시 인증서 필요
            - ORDERER_GENERAL_LOCALMSPDIR=/etc/hyperledger/msp/orderer/msp
        
        working_dir: /opt/gopath/src/github.com/hyperledger/fabric/orderer
        command: orderer
        ports:
        	- 7070:7050 # (external port, internal port)
        
        volumes:
        	- ./config/:/etc/hyperledger/configtx
            - ./crypto-config/ordererOrganizations/acornpub.com/orderers/orderer.acornpub.com/:/etc/hyperledger/msp/orderer
        
        networks:
        	- acorn
    
    
	peer0.sales1.acornpub.com:
    	container_name: peer0.sales1.acornpub.com
        image: hyperledger/fabric-peer:1.4.3
        enviroment:
        	- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
            - CORE_PEER_ID=peer0.sales1.acornpub.com
            - CORE_LOGGING_PEER=debug
            - CORE_CHAINCODE_LOGGING_LEVEL=DEBUG
            - CORE_PEER_LOCALMSPID=Sales1Org
            - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer/
            - CORE_PEER_ADDRESS=peer0.sales1.acornpub.com:7051 # 다른 피어들과 통신을 하기 위한 주소
            - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.sales1.acornpub.com:7051
            - CORE_PEER_GOSSIP_ENDPOINT=peer0.sales1.acornpub.com:7051
            - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.sales1.acornpub.com:7051
            - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=net_acorn
        
        working_dir: /opt/gopath/src/github.com/hyperledger/fabric
        command: peer node start #Starts a node that interacts with the network
        ports:
        	- 7051:7051
            - 7053:7053
        volumes:
        	- /var/run/:/host/var/run/
            - ./crypto-config/peerOrganizations/sales1.acornpub.com/peers/peer0.sales1.acornpub.com/msp:/etc/hyperledger/msp/peer
            - ./config:/etc/hyperledger/configtx
        depends_on:
        	- orderer.acornpub.com
            
        networks:
        	- acorn
   	
    peer1.sales1.acornpub.com:
    	container_name: peer1.sales1.acornpub.com
        image: hyperleder/fabric-peer:1.4.3
        
        enviroment:
        	- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
            - CORE_PEER_ID=peer1.sales1.acornpub.com
            - CORE_LOGGING_PEER=debug
            - CORE_CHAINCODE_LOGGING_LEVEL=DEBUG
            - CORE_PEER_LOCALMSPID=Sales1Org
            - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer/
            - CORE_PEER_ADDRESS=peer0.sales1.acornpub.com:7051 # 다른 피어들과 통신을 하기 위한 주소
            - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.sales1.acornpub.com:7051
            - CORE_PEER_GOSSIP_ENDPOINT=peer0.sales1.acornpub.com:7051
            - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.sales1.acornpub.com:7051
            - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=net_acorn
       
       working_dir: /opt/gopath/src/github.com/hyperledger/fabric
       command: peer node start
       ports:
       		- 8051:7051
            - 8053:7053
       volumes:
       		- /var/run/:/host/var/run/
            - ./crypto-config/peerOrganizations/sales1.acornpub.com/peers/peer1.sales1.acornpub.com/msp:/etc/hyperledger/msp/peer
            - ./crypto-config/peerOrganizations/sales1.acornpub.com/users:/etc/hyperledger/msp/users
            - ./config:/etc/hyperledger/configtx
       
       depends_on:
       		- orderer.acornpub.com
       networks:
       		- acorn
           
           
 	peer0.cutomer.acornpub.com:
    	container_name: peer0.customer.acornpub.com
        image: hyperledger/fabric-peer:1.4.3
        	- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
            - CORE_PEER_ID=peer0.customer.acornpub.com
            - CORE_LOGGING_PEER=debug
            - CORE_CHAINCODE_LOGGING_LEVEL=DEBUG
            - CORE_PEER_LOCALMSPID=CustomerOrg
            - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer/
            - CORE_PEER_ADDRESS=peer0.customer.acornpub.com:7051
            - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=net_acorn
            
        working_dir: /opt/gopath/src/github.com/hyperledger/fabric
        command: peer node start
        ports:
        	- 9051:7051
            - 9053:7053
        volumes:
        	- /var/run/:/host/var/run/
            - ./crypto-config/peerOrganizations/customer.acornpub.com/peers/peer0.customer.acornpub.com/msp:/etc/hyperledger/msp/peer
            - ./crypto-config/peerOrganizations/customer.acornpub.com/users:/etc/hyperledger/msp/users
            - ./config:/etc/hyperledger/configtx
            
       	depends_on:
        	- orderer.acornpub.com 
        networks:
        	- acorn
       
 	peer1.cutomer.acornpub.com:
    	container_name: peer1.customer.acornpub.com
        image: hyperledger/fabric-peer:1.4.3
        	- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
            - CORE_PEER_ID=peer1.customer.acornpub.com
            - CORE_LOGGING_PEER=debug
            - CORE_CHAINCODE_LOGGING_LEVEL=DEBUG
            - CORE_PEER_LOCALMSPID=CustomerOrg
            - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer/
            - CORE_PEER_ADDRESS=peer1.customer.acornpub.com:7051
            - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=net_acorn
            
        working_dir: /opt/gopath/src/github.com/hyperledger/fabric
        command: peer node start
        ports:
        	- 10051:7051
            - 10053:7053
        volumes:
        	- /var/run/:/host/var/run/
            - ./crypto-config/peerOrganizations/customer.acornpub.com/peers/peer1.customer.acornpub.com/msp:/etc/hyperledger/msp/peer
            - ./crypto-config/peerOrganizations/customer.acornpub.com/users:/etc/hyperledger/msp/users
            - ./config:/etc/hyperledger/configtx
            
       	depends_on:
        	- orderer.acornpub.com 
        networks:
        	- acorn
     
     cli:
     	container_name: cli
        image: hyperledger/fabric-tools
        tty: true
        enviroment:
        	- GOPATH=/opt/gopath
            - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
            - FABRIC_LOGGING_SPEC=INFO
            - CORE_PEER_ID=cli
            - CORE_PEER_ADDRESS=peer0.sales1.acornpub.com:7051 #기본값으로 설정된 변수는 Sales1조직의 peer0이다.
            - CORE_PEER_LOCALMSPID=Sales1Org
            - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/sales1.acornpub.com/users/Admin@sales1.acornpub.com/msp
            - CORE_CHAINCODE_KEEPALIVE=10
            
      	working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
        command: /bin/bash
        volumes:
        	- /var/run/:/host/var/run/
            - ./../chaincode/:/opt/gopath/src/chaincode/
            - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
            - ./config:/etc/hyperledger/configtx
            
        networks:
        	- acorn
        	
            

다음과 같이 docker-compose.yaml 설정 파일을 설정해준다.

각 컨테이너의 enviroment 값이 중요한데, 이 중에서도 제일 중요한 것은 다음과 같다. 

< Orderer Node 컨테이너를 만들 때 사용 되는 enviroment 값 >

- ORDERER_GENERAL_GENESISMETHOD          # 제네시스 블록의 형식 
- ORDERER_GENERAL_GENESISFILE                 # 제네시스 파일의 경로
- ORDERER_GENERAL_LOCALMSPID                # 인증서의 ID
- ORDERER_GENERAL_LOCALMSPDIR               # 인증서가 위치한 디렉토리
< Peer Node 컨테이너를 만들 때 사용 되는 enviroment 값 >
- CORE_PEER_ID 
- CORE_PEER_LOCALMSPID
- CORE_PEER_MSPCONFIGPATH
- CORE_PEER_ADDRESS                             # 다른 peer node와 통신하기 위해 필요한 주소

그 외의 멤버들은, 필요할 때 마다 찾아봐도 무방할 듯 하다.

 


3. 컨테이너 실행 및 채널 생성, 채널에 가입 및 앵커 피어 노드 지정

 

3-1 컨테이너 실행 

자 이제 우리는 2-3, 2-4 과정에서 생성하였던 Transaction 파일을 통해서 채널을 생성하고, 특정 노드를 조직의 앵커피어노드로 설정하는 작업을 할 것이다.

 

docker docker-compose
Single Container를 관리할 때 용이 yaml file 기반으로 multi container를 관리 가능,
yaml파일에 명령어를 적어서 컨테이너를 정의하고 관리

우리는 docker-compose 를 통해서 컨테이너를 올릴 것이다.

 

먼저, 깔끔하게 docker-compose 상에 올라와 있는 컨테이너들을 전부 비워주자.

# Docker-compose 에 정의되어 있는 모든 서비스 컨테이너들을 정지시키고 삭제한다.
docker-compose down   

 

그리고 다음 명령어를 실행시켜주자.

docker-compose -f docker-compose.yaml up -d orderer.acornpub.com peer0.sales1.acornpub.com peer1.sales1.acornpub.com peer0.customer.acornpub.com peer1.customer.acornpub.com cli

docker-compose.yaml 파일을 참조하여, detached 모드로 orderer.acornpub.com ~~ 와 같은 서비스 컨테이너들을 

올려주는 역할을 한다. 

 

이 후 모든 컨테이너들이 잘 올라 갔는지 확인해보자.

docker-compose ps

앞 서, 우리가 docker-compose.yaml 에서 정의한 customer 조직의 peer0,peer1 과 sales 조직의 peer0,1 그리고 cli 컨테이너 까지 올라 왔다면 성공이다.

3-2 채널 생성, 가입 및 앵커피어노드 업데이트

이 상태로 터미널을 2개 켜서 작업을 진행한다.

 

1번 터미널은 Sales1Org의 Peer0의 노드에서 channelsales1 이라는 채널을 생성하고 가입시키기 위한 용도이고

나머지 2번 터미널은 CustomerOrg의 peer0의 노드를 channelsales1 이라는 채널에 가입시키기 위한 용도이다.

이하, 터미널1 터미널2 로 호칭하겠다.

 

[터미널 1] 

터미널 1은 이미 cli 컨테이너가 실행 되었을 때 기본 address 가 peer0.sales1.acornpub.com:7051 로 되어 있으므로

환경 변수 재 설정의 필요가 없다.

 

1. Sales1 조직의 Peer0 노드 Cli 실행

docker exec -it cli bash

2. Sales1 조직의 peer0 노드에서 channelsales1 채널 생성

peer channel create -o orderer.acornpub.com:7050 -c channelsales1 -f /etc/hyperledger/configtx/channel1.tx

3. Sales1 조직의 peer0 노드를 channelsales1 채널에 가입 및 앵커 피어 지정 업데이트

peer channel update -o orderer.acornpub.com:7050 -c channelsales1 -f /etc/hyperledger/configtx/Sales1Organchors.tx

4. Sales1 조직의 peer1 노드를 channelsales1 채널에 가입

CORE_PEER_ADDRESS=peer1.sales1.acornpub.com:7051
peer channel join -b channelsales1.block

 

[터미널 2]

터미널2에서는 Customer조직의 peer0노드에서 cli를 실행한다.

그것을 위해 환경변수들을 재설정해주는 과정이 필요하다.

docker exec -e "CORE_PEER_LOCALMSPID=CustomerOrg" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/customer.acornpub.com/users/Admin@customer.acornpub.com/msp" -e "CORE_PEER_ADDRESS=peer0.customer.acornpub.com:7051" -it cli bash

자 이제, Customer조직의 peer0노드에서 cli 가 실행되었다.

이제 Customer조직의 peer0노드를 channelsales1 채널에 가입 및 앵커 피어 지정을 해주자

peer channel join -b channelsales1.block
peer channel update -o orderer.acornpub.com:7050 -c channelsales1 -f /etc/hyperledger/configtx/CustomerOrganchors.tx

ㅊ이 후 터미널1의 과정과 마찬가지로 peer1노드를 channelsales1 채널에 가입 시킨다.

CORE_PEER_ADDRESS=peer1.customer.acornpub.com:7051
peer channel join -b channelsales1.block

 

여기까지, CLI환경에서 각 피어 노드를 channelsales1에 참여시키고 앵커피어노드를 업데이트 하는 과정을 완료했다.

블록체인 네트워크 구축은 여기서 끝이 난다.

 

4. 체인코드 작성 및 설치

이제 실제로 스마트 컨트랙트를 위한 체인코드를 작성해서 물건을 등록하고 구매할 수 있는 체인코드를 작성해보자.

 

Comments