하이퍼레저 패브릭을 이용한 기업용 블록체인 솔루션 개발 🚀
![콘텐츠 대표 이미지 - 하이퍼레저 패브릭을 이용한 기업용 블록체인 솔루션 개발](/storage/ai/article/compressed/5f735eb1-2013-4a44-b9d2-0adfaef05b40.jpg)
안녕하세요, 블록체인 세계로의 여행을 함께 떠나볼까요? 오늘은 특별히 하이퍼레저 패브릭(Hyperledger Fabric)이라는 멋진 기술을 이용해 기업용 블록체인 솔루션을 개발하는 방법에 대해 알아보겠습니다. 마치 레고 블록을 조립하듯이, 우리도 블록체인이라는 혁신적인 기술을 조립해 나가는 재미있는 여정을 시작해볼까요? 😊
🎓 알쏭달쏭 블록체인, 이해하기 쉽게 설명해드릴게요!
블록체인은 마치 투명한 유리상자 같아요. 모든 거래 내역이 이 상자 안에 차곡차곡 쌓이죠. 그리고 이 상자는 수많은 사람들이 함께 관리해요. 누군가 거래 내역을 몰래 바꾸려고 해도, 다른 모든 사람들의 상자와 비교해보면 금방 들통나겠죠? 이게 바로 블록체인의 핵심 아이디어랍니다!
자, 이제 본격적으로 하이퍼레저 패브릭에 대해 알아볼 시간이에요. 하이퍼레저 패브릭은 기업들이 자신만의 블록체인 네트워크를 만들 수 있게 해주는 특별한 도구랍니다. 마치 맞춤 정장을 만드는 것처럼, 각 기업의 필요에 딱 맞는 블록체인을 만들 수 있어요. 😎
1. 하이퍼레저 패브릭의 특징 🌟
하이퍼레저 패브릭은 여러 가지 특별한 능력을 가지고 있어요. 마치 슈퍼히어로처럼 말이죠!
- 모듈화(Modularity): 레고 블록처럼 필요한 기능만 골라서 조립할 수 있어요.
- 허가형 네트워크(Permissioned network): 초대받은 사람들만 참여할 수 있는 VIP 파티 같아요.
- 고성능(High performance): 번개처럼 빠른 거래 처리 속도를 자랑해요.
- 프라이버시 보호(Privacy protection): 비밀 정보는 꼭꼭 숨겨주는 능력이 있어요.
이런 특징들 덕분에 하이퍼레저 패브릭은 기업들에게 인기 만점이랍니다. 재능넷 같은 플랫폼에서도 이런 기술을 활용하면 더욱 안전하고 효율적인 서비스를 제공할 수 있겠죠? 🚀
2. 하이퍼레저 패브릭의 구성요소 🧩
하이퍼레저 패브릭은 여러 가지 부품으로 이루어져 있어요. 마치 자동차의 여러 부품처럼 말이죠. 각각의 역할을 알아볼까요?
위의 그림에서 볼 수 있듯이, 하이퍼레저 패브릭은 여러 구성요소로 이루어져 있어요. 각각의 역할을 자세히 알아볼까요?
1) 피어 노드 (Peer Node) 👥
피어 노드는 블록체인 네트워크의 핵심 구성원이에요. 마치 학교에서 열심히 공부하는 학생들처럼, 피어 노드들은 블록체인의 데이터를 저장하고 관리하는 역할을 해요. 또한, 새로운 거래가 들어오면 이를 검증하고 처리하는 일도 담당하죠.
피어 노드는 크게 두 가지 유형으로 나눌 수 있어요:
- 앵커 피어 (Anchor Peer): 다른 조직과 소통하는 대표 학생 같은 존재예요. 조직 간 통신을 담당해요.
- 엔도싱 피어 (Endorsing Peer): 거래를 승인하는 권한을 가진 특별한 피어예요. 마치 선생님의 승인 도장을 찍는 것과 비슷하죠.
2) 오더링 서비스 (Ordering Service) 🔄
오더링 서비스는 거래의 순서를 정하는 중요한 역할을 해요. 학교에서 줄을 서는 것처럼, 모든 거래를 순서대로 정렬하는 거죠. 이렇게 정렬된 거래들은 블록으로 만들어져 피어 노드들에게 전달돼요.
오더링 서비스의 주요 기능:
- 거래 순서 결정
- 블록 생성
- 블록 배포
3) 채널 (Channel) 🌈
채널은 비밀 대화방 같은 거예요. 특정 참여자들끼리만 정보를 공유하고 싶을 때 사용해요. 예를 들어, A회사와 B회사가 비밀 거래를 하고 싶다면, 둘만의 채널을 만들어 사용할 수 있어요.
채널의 특징:
- 프라이버시 보호
- 데이터 격리
- 확장성 향상
4) 체인코드 (Chaincode) 🧠
체인코드는 블록체인 위에서 실행되는 스마트 계약이에요. 마치 자동판매기처럼, 특정 조건이 충족되면 자동으로 실행되는 프로그램이죠. 예를 들어, "A가 B에게 100만원을 보내면, B의 계좌에 100만원이 입금된다"와 같은 규칙을 정할 수 있어요.
체인코드로 할 수 있는 일들:
- 자산 관리
- 데이터 조회 및 수정
- 비즈니스 로직 실행
5) 멤버십 서비스 (Membership Service) 🔐
멤버십 서비스는 네트워크의 문지기 역할을 해요. 누가 네트워크에 참여할 수 있는지, 어떤 권한을 가질 수 있는지 관리하죠. 마치 클럽의 VIP 회원 관리 시스템과 비슷해요.
멤버십 서비스의 주요 기능:
- 신원 확인
- 인증서 발급
- 권한 관리
이렇게 다양한 구성요소들이 조화롭게 작동하면서 하이퍼레저 패브릭은 안전하고 효율적인 블록체인 네트워크를 만들어내요. 마치 오케스트라의 여러 악기들이 아름다운 하모니를 만들어내는 것처럼 말이죠! 🎵
3. 하이퍼레저 패브릭 개발 환경 설정 🛠️
자, 이제 본격적으로 하이퍼레저 패브릭을 이용해 개발을 시작해볼까요? 먼저 개발 환경을 설정해야 해요. 마치 요리를 시작하기 전에 주방을 정리하는 것과 같아요!
1) 필요한 도구들 준비하기
하이퍼레저 패브릭 개발을 위해 필요한 도구들이 있어요. 이것들은 마치 요리에 필요한 도구들과 같죠!
- Git: 코드 버전 관리를 위한 도구예요. 요리 레시피를 기록하는 노트와 같아요.
- cURL: 데이터를 전송하는 도구예요. 재료를 가져오는 장바구니 같은 거죠.
- Docker: 애플리케이션을 컨테이너화하는 도구예요. 요리 재료를 깔끔하게 정리해주는 밀폐용기 같아요.
- Docker Compose: 여러 Docker 컨테이너를 관리하는 도구예요. 여러 요리를 동시에 만들 때 사용하는 멀티쿠커 같은 거죠.
- Go 언어: 체인코드 개발에 주로 사용되는 프로그래밍 언어예요. 요리의 주 재료라고 할 수 있죠.
- Node.js: JavaScript 런타임 환경이에요. 요리를 더 맛있게 만드는 비밀 양념 같은 존재죠.
2) 개발 환경 설정하기
이제 이 도구들을 설치하고 설정해볼까요? 차근차근 따라해보세요!
- Git 설치:
sudo apt-get install git
- cURL 설치:
sudo apt-get install curl
- Docker 설치:
sudo apt-get install docker.io
- Docker Compose 설치:
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose
- Go 언어 설치:
wget https://golang.org/dl/go1.16.linux-amd64.tar.gz sudo tar -C /usr/local -xzf go1.16.linux-amd64.tar.gz export PATH=$PATH:/usr/local/go/bin
- Node.js 설치:
curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash - sudo apt-get install -y nodejs
와우! 이제 모든 도구가 준비되었어요. 마치 요리사가 모든 도구와 재료를 준비한 것처럼, 우리도 블록체인 개발을 위한 모든 준비를 마쳤어요. 🍳
🌟 재능넷 팁!
개발 환경 설정은 처음에는 조금 복잡해 보일 수 있어요. 하지만 걱정하지 마세요! 재능넷에서는 이런 기술적인 내용에 대해 전문가들의 도움을 받을 수 있답니다. 블록체인 개발에 관심 있는 분들은 재능넷에서 관련 전문가를 찾아 도움을 받아보는 것은 어떨까요?
4. 하이퍼레저 패브릭 네트워크 구축하기 🌐
자, 이제 본격적으로 하이퍼레저 패브릭 네트워크를 구축해볼 거예요. 마치 레고 블록으로 멋진 성을 쌓는 것처럼, 우리도 블록체인 네트워크를 만들어볼 거예요!
1) 하이퍼레저 패브릭 샘플 다운로드
먼저, 하이퍼레저 패브릭에서 제공하는 샘플 코드를 다운로드 받아볼게요. 이 샘플은 우리가 블록체인 네트워크를 쉽게 구축할 수 있도록 도와주는 가이드라인이에요.
git clone https://github.com/hyperledger/fabric-samples.git
cd fabric-samples
git checkout v2.2.0
./scripts/bootstrap.sh
이 명령어를 실행하면, 하이퍼레저 패브릭 샘플과 필요한 도커 이미지들이 다운로드돼요. 마치 레고 세트를 구매하는 것과 같죠!
2) 네트워크 시작하기
이제 샘플 네트워크를 시작해볼 거예요. 'test-network' 디렉토리로 이동해서 다음 명령어를 실행해주세요.
cd test-network
./network.sh up
이 명령어는 기본적인 하이퍼레저 패브릭 네트워크를 시작해요. 마치 레고 성의 기초를 쌓는 것과 같아요!
3) 채널 생성하기
네트워크가 시작되었다면, 이제 채널을 만들어볼 차례예요. 채널은 특정 참여자들 사이에서만 정보를 공유할 수 있게 해주는 비밀 통로 같은 거예요.
./network.sh createChannel
이 명령어를 실행하면 'mychannel'이라는 이름의 채널이 생성돼요. 마치 비밀 클럽을 만드는 것과 같죠!
4) 체인코드 배포하기
이제 체인코드를 네트워크에 배포해볼 거예요. 체인코드는 블록체인 위에서 실행되는 스마트 계약이에요. 우리의 비즈니스 로직을 담고 있죠.
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go
이 명령어는 'basic'이라는 이름의 체인코드를 배포해요. 이 체인코드는 간단한 자산 전송 기능을 가지고 있어요.
5) 네트워크 테스트하기
모든 준비가 끝났어요! 이제 우리가 만든 네트워크가 제대로 작동하는지 테스트해볼 차례예요.
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 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 query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'
이 명령어들을 실행하면, 체인코드를 호출하고 결과를 확인할 수 있어요. 마치 우리가 만든 레고 성이 제대로 서 있는지 확인하는 것과 같죠!
💡 알아두세요!
이 과정은 기본적인 하이퍼레저 패브릭 네트워크를 구축하는 방법이에요. 실제 기업 환경에서는 더 복잡하고 세밀한 설정이 필요할 수 있어요. 하지만 걱정하지 마세요! 이 기본 과정을 이해하면, 더 복잡한 네트워크도 충분히 구축할 수 있답니다.
5. 하이퍼레저 패브릭을 이용한 기업용 솔루션 개발 💼
자, 이제 우리는 하이퍼레저 패브릭 네트워크를 구축하는 방법을 배웠어요. 이제 이를 바탕으로 실제 기업용 솔루션을 개발해볼까요? 마치 레고 블록으로 멋진 성을 만든 후, 그 안에 실제로 살 수 있는 공간을 만드는 것과 같아요!
1) 비즈니스 요구사항 분석
먼저, 우리가 만들 솔루션이 어떤 문제를 해결해야 하는지 정확히 알아야 해요. 예를 들어, 공급망 관리 시스템을 만든다고 가정해볼까요?
- 제품의 생산부터 최종 소비자에게 전달되기까지의 모든 과정을 추적해야 해요.
- 각 단계마다 제품의 품질, 위치, 소유권 등의 정보를 기록해야 해요.
- 이 정보는 신뢰할 수 있고, 변조가 불가능해야 해요.
- 특정 권한을 가진 사람만 정보를 볼 수 있어야 해요.
2) 시스템 설계
비즈니스 요구사항을 바탕으로 시스템을 설계해볼게요.
이 시스템에서는:
- 생산자, 유통업체, 소매업체가 각각 하나의 조직(Organization)이 돼요.
- 각 조직은 자신만의 피어 노드를 가지고 있어요.
- 모든 거래 정보는 하이퍼레저 패브릭 네트워크에 기록돼요.
- 체인코드를 통해 제품의 이동, 소유권 변경 등을 관리해요.
3) 체인코드 개발
이제 실제로 체인코드를 개발해볼 거예요. Go 언어를 사용해서 개발해볼게요.
package main
import (
"encoding/json"
"fmt"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
type SmartContract struct {
contractapi.Contract
}
type Product struct {
ID string `json:"id"`
Name string `json:"name"`
Owner string `json:"owner"`
Location string `json:"location"`
Timestamp string `json:"timestamp"`
}
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
products := []Product{
{ID: "product1", Name: "Apple", Owner : "Producer", Location: "Farm", Timestamp: "2023-06-01 10:00:00"},
}
for _, product := range products {
productJSON, err := json.Marshal(product)
if err != nil {
return err
}
err = ctx.GetStub().PutState(product.ID, productJSON)
if err != nil {
return fmt.Errorf("failed to put to world state. %v", err)
}
}
return nil
}
func (s *SmartContract) CreateProduct(ctx contractapi.TransactionContextInterface, id string, name string, owner string, location string, timestamp string) error {
product := Product{
ID: id,
Name: name,
Owner: owner,
Location: location,
Timestamp: timestamp,
}
productJSON, err := json.Marshal(product)
if err != nil {
return err
}
return ctx.GetStub().PutState(id, productJSON)
}
func (s *SmartContract) QueryProduct(ctx contractapi.TransactionContextInterface, id string) (*Product, error) {
productJSON, err := ctx.GetStub().GetState(id)
if err != nil {
return nil, fmt.Errorf("failed to read from world state: %v", err)
}
if productJSON == nil {
return nil, fmt.Errorf("the product %s does not exist", id)
}
var product Product
err = json.Unmarshal(productJSON, &product)
if err != nil {
return nil, err
}
return &product, nil
}
func (s *SmartContract) TransferProduct(ctx contractapi.TransactionContextInterface, id string, newOwner string, newLocation string, timestamp string) error {
product, err := s.QueryProduct(ctx, id)
if err != nil {
return err
}
product.Owner = newOwner
product.Location = newLocation
product.Timestamp = timestamp
productJSON, err := json.Marshal(product)
if err != nil {
return err
}
return ctx.GetStub().PutState(id, productJSON)
}
func main() {
chaincode, err := contractapi.NewChaincode(&SmartContract{})
if err != nil {
fmt.Printf("Error creating supply chain management chaincode: %s", err.Error())
return
}
if err := chaincode.Start(); err != nil {
fmt.Printf("Error starting supply chain management chaincode: %s", err.Error())
}
}
이 체인코드는 다음과 같은 기능을 제공해요:
- InitLedger: 초기 상태를 설정해요.
- CreateProduct: 새로운 제품을 생성해요.
- QueryProduct: 특정 제품의 정보를 조회해요.
- TransferProduct: 제품의 소유권과 위치를 변경해요.
4) 애플리케이션 개발
이제 이 체인코드를 호출하는 애플리케이션을 개발해볼 거예요. Node.js를 사용해서 간단한 API 서버를 만들어볼게요.
const express = require('express');
const { Gateway, Wallets } = require('fabric-network');
const path = require('path');
const fs = require('fs');
const app = express();
app.use(express.json());
const ccpPath = path.resolve(__dirname, '..', 'connection.json');
const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
app.post('/api/product', async (req, res) => {
try {
const wallet = await Wallets.newFileSystemWallet('../wallet');
const identity = await wallet.get('appUser');
if (!identity) {
res.status(400).json({error: 'An identity for the user "appUser" does not exist in the wallet'});
return;
}
const gateway = new Gateway();
await gateway.connect(ccp, { wallet, identity: 'appUser', discovery: { enabled: true, asLocalhost: true } });
const network = await gateway.getNetwork('mychannel');
const contract = network.getContract('supplychain');
await contract.submitTransaction('CreateProduct', req.body.id, req.body.name, req.body.owner, req.body.location, req.body.timestamp);
res.json({message: 'Product created successfully'});
await gateway.disconnect();
} catch (error) {
res.status(500).json({error: `Failed to create product: ${error}`});
}
});
app.get('/api/product/:id', async (req, res) => {
try {
const wallet = await Wallets.newFileSystemWallet('../wallet');
const identity = await wallet.get('appUser');
if (!identity) {
res.status(400).json({error: 'An identity for the user "appUser" does not exist in the wallet'});
return;
}
const gateway = new Gateway();
await gateway.connect(ccp, { wallet, identity: 'appUser', discovery: { enabled: true, asLocalhost: true } });
const network = await gateway.getNetwork('mychannel');
const contract = network.getContract('supplychain');
const result = await contract.evaluateTransaction('QueryProduct', req.params.id);
res.json(JSON.parse(result.toString()));
await gateway.disconnect();
} catch (error) {
res.status(500).json({error: `Failed to get product: ${error}`});
}
});
app.put('/api/product/:id', async (req, res) => {
try {
const wallet = await Wallets.newFileSystemWallet('../wallet');
const identity = await wallet.get('appUser');
if (!identity) {
res.status(400).json({error: 'An identity for the user "appUser" does not exist in the wallet'});
return;
}
const gateway = new Gateway();
await gateway.connect(ccp, { wallet, identity: 'appUser', discovery: { enabled: true, asLocalhost: true } });
const network = await gateway.getNetwork('mychannel');
const contract = network.getContract('supplychain');
await contract.submitTransaction('TransferProduct', req.params.id, req.body.newOwner, req.body.newLocation, req.body.timestamp);
res.json({message: 'Product transferred successfully'});
await gateway.disconnect();
} catch (error) {
res.status(500).json({error: `Failed to transfer product: ${error}`});
}
});
app.listen(3000, () => console.log('Server running on port 3000'));
이 애플리케이션은 다음과 같은 API를 제공해요: