Firefly와 Fabric 스마트 컨트랙트 배포,실행 비교
Fabric 스마트 컨트랙트 배포
간단하게 설치
cd fabric-samples/test-network
# org1, org2 모두 설치됨
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go/ -ccl go
구체적인 설치 과정
cd fabric-samples/test-network
# peer 명령은 패키징을 수행하기 위해 core.yaml파일이 필요함
touch core.yaml
# package chaincode
peer lifecycle chaincode package basic.tar.gz --path ../asset-transfer-basic/chaincode-go/ --lang golang --label basic_1.0
#org1 환경변수 설정
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 lifecycle chaincode install basic.tar.gz
#org2 환경변수 설정
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 lifecycle chaincode install basic.tar.gz
# 설치 되었는지 확인
peer lifecycle chaincode queryinstalled
# package ID 환경 변수 설정
export CC_PACKAGE_ID=basic_1.0:2816b63cdcdad810756db9066a2dfc3d8230750422d2fbcd918ab62c7e0f445c
#org2로부터 체인코드 정의를 승인받음
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name basic --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"
#org1 환경변수 설정
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@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
#org1로부터 체인코드 정의를 승인받음
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name basic --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"
#승인 받았는 지 확인
peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name basic --version 1.0 --sequence 1 --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --output json
# 커밋
peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name basic --version 1.0 --sequence 1 --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --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 lifecycle chaincode querycommitted --channelID mychannel --name basic --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"
# 체인코드 실행
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"]}'
과정 및 결과
// 기존 코드
//return ctx.GetStub().PutState(id, assetJSON)
// 이벤트가 발생되도록 수정한 코드
err = ctx.GetStub().PutState(id, assetJSON)
if err != nil {
return err
}
return ctx.GetStub().SetEvent("AssetCreated", assetJSON)
}
Firefly 스마트 컨트랙트 배포
간단하게 설치
cd fabric-samples/asset-transfer-basic/chaincode-go
# peer 명령은 패키징을 수행하기 위해 core.yaml파일이 필요함
touch core.yaml
# package chaincode
peer lifecycle chaincode package -p . --label basic ./basic.zip
# deploy chaincode(+ install, query, approve,commit chaincode)
ff deploy fabric jeho basic.zip firefly basic 1.0
# FFI define request
POST <http://localhost:5000/api/v1/namespaces/default/contracts/interfaces>
{
"namespace": "default",
"name": "basic",
"description": "Spec interface for the asset-transfer-basic golang chaincode",
"version": "1.0",
"methods": [
{
"name": "GetAllAssets",
"pathname": "",
"description": "",
"params": [],
"returns": [
{
"name": "",
"schema": {
"type": "array",
"details": {
"type": "object",
"properties": {
"type": "string"
}
}
}
}
]
},
{
"name": "CreateAsset",
"pathname": "",
"description": "",
"params": [
{
"name": "id",
"schema": {
"type": "string"
}
},
{
"name": "color",
"schema": {
"type": "string"
}
},
{
"name": "size",
"schema": {
"type": "string"
}
},
{
"name": "owner",
"schema": {
"type": "string"
}
},
{
"name": "value",
"schema": {
"type": "string"
}
}
],
"returns": []
}
],
"events": [
{
"name": "AssetCreated"
}
]
}
#Broadcast the contract interface
POST <http://localhost:5000/api/v1/namespaces/default/apis>
{
"name": "basic",
"interface": {
"id": "b7247cfe-79ee-4a1f-a323-c2e6b4bf07c4"
},
"location": {
"channel": "firefly",
"chaincode": "basic"
}
}
#Invoke Chaincode
POST <http://localhost:5000/api/v1/namespaces/default/apis/basic/invoke/CreateAsset>
{
"input": {
"color": "blue",
"id": "asset-01",
"owner": "Harry",
"size": "30",
"value": "23400"
}
}
#Query Chaincode
POST <http://localhost:5000/api/v1/namespaces/default/apis/basic/query/GetAllAssets>
{}
#Create blockchain event listener
POST <http://localhost:5000/api/v1/namespaces/default/contracts/listeners>
{
"interface": {
"id": "f1e5522c-59a5-4787-bbfd-89975e5b0954"
},
"location": {
"channel": "firefly",
"chaincode": "basic"
},
"event": {
"name": "AssetCreated"
},
"options": {
"firstEvent": "oldest"
},
"topic": "assets"
}
#Subscribe to events from my contract
POST <http://localhost:5000/api/v1/namespaces/default/subscriptions>
{
"namespace": "default",
"name": "basic",
"transport": "websockets",
"filter": {
"events": "blockchain_event_received",
"blockchainevent": {
"listener": "76b9c322-176e-4ddf-bb0b-5127b8e4d98b"
}
},
"options": {
"firstEvent": "oldest"
}
}
#Receive custom smart contract events
ws://localhost:5000/ws
{
"type": "start",
"name": "basic",
"namespace": "default",
"autoack": true
}
# FFI define response
POST <http://localhost:5000/api/v1/namespaces/default/contracts/interfaces>
{
"id": "b7247cfe-79ee-4a1f-a323-c2e6b4bf07c4",
"message": "4ba2c202-723f-4a52-86fc-f6e356aa45b5",
"namespace": "default",
"name": "basic",
"description": "Spec interface for the asset-transfer-basic golang chaincode",
"version": "1.0",
"methods": [
{
"id": "5686a72e-2893-4090-838d-0dab9f71ed4e",
"interface": "b7247cfe-79ee-4a1f-a323-c2e6b4bf07c4",
"name": "GetAllAssets",
"namespace": "default",
"pathname": "GetAllAssets",
"description": "",
"params": [],
"returns": [
{
"name": "",
"schema": {
"type": "array",
"details": {
"type": "object",
"properties": {
"type": "string"
}
}
}
}
]
},
{
"id": "d83a1c5f-9243-4549-a11e-cb7dac947f01",
"interface": "b7247cfe-79ee-4a1f-a323-c2e6b4bf07c4",
"name": "CreateAsset",
"namespace": "default",
"pathname": "CreateAsset",
"description": "",
"params": [
{
"name": "id",
"schema": {
"type": "string"
}
},
{
"name": "color",
"schema": {
"type": "string"
}
},
{
"name": "size",
"schema": {
"type": "string"
}
},
{
"name": "owner",
"schema": {
"type": "string"
}
},
{
"name": "value",
"schema": {
"type": "string"
}
}
],
"returns": []
}
],
"events": [
{
"id": "d456a505-cdd5-4a18-860a-5c738b9d95d6",
"interface": "b7247cfe-79ee-4a1f-a323-c2e6b4bf07c4",
"namespace": "default",
"pathname": "AssetCreated",
"signature": "",
"name": "AssetCreated",
"description": "",
"params": null
}
]
}
#FFI API response
POST <http://localhost:5000/api/v1/namespaces/default/apis>
{
"id": "e440b9fb-9f5e-43fa-aa7e-6c22edaba186",
"namespace": "default",
"interface": {
"id": "b7247cfe-79ee-4a1f-a323-c2e6b4bf07c4"
},
"location": {
"channel": "firefly",
"chaincode": "basic"
},
"name": "basic",
"message": "22b54002-3563-4bb0-9d13-09785e3cce85",
"urls": {
"openapi": "<http://127.0.0.1:5000/api/v1/namespaces/default/apis/basic/api/swagger.json>",
"ui": "<http://127.0.0.1:5000/api/v1/namespaces/default/apis/basic/api>"
}
}
#Chaincode Invoke response
POST <http://localhost:5000/api/v1/namespaces/default/apis/basic/invoke/CreateAsset>
{
"id": "fee4e175-033d-4e6e-890c-aef638920f89",
"namespace": "default",
"tx": "ea6b0a8f-ffec-42a2-bb00-0af5ddf3fb83",
"type": "blockchain_invoke",
"status": "Pending",
"plugin": "fabric",
"input": {
"input": {
"color": "blue",
"id": "asset-01",
"owner": "Harry",
"size": "30",
"value": "23400"
},
"interface": "b7247cfe-79ee-4a1f-a323-c2e6b4bf07c4",
"key": "Org1MSP::x509::CN=org_0,OU=client::CN=fabric_ca.org1.example.com,OU=Hyperledger FireFly,O=org1.example.com,L=Raleigh,ST=North Carolina,C=US",
"location": {
"chaincode": "basic",
"channel": "firefly"
},
"method": {
"description": "",
"id": "d83a1c5f-9243-4549-a11e-cb7dac947f01",
"interface": "b7247cfe-79ee-4a1f-a323-c2e6b4bf07c4",
"name": "CreateAsset",
"namespace": "default",
"params": [
{
"name": "id",
"schema": {
"type": "string"
}
},
{
"name": "color",
"schema": {
"type": "string"
}
},
{
"name": "size",
"schema": {
"type": "string"
}
},
{
"name": "owner",
"schema": {
"type": "string"
}
},
{
"name": "value",
"schema": {
"type": "string"
}
}
],
"pathname": "CreateAsset",
"returns": []
},
"methodPath": "CreateAsset",
"type": "invoke"
},
"created": "2022-08-18T12:50:16.59292334Z",
"updated": "2022-08-18T12:50:16.59292334Z"
}
# Query Chaincode response
POST <http://localhost:5000/api/v1/namespaces/default/apis/basic/query/GetAllAssets>
[
{
"AppraisedValue": 23400,
"Color": "blue",
"ID": "asset-01",
"Owner": "Harry",
"Size": 30
}
]
#Create blockchain event listener response
POST <http://localhost:5000/api/v1/namespaces/default/contracts/listeners>
{
"id": "76b9c322-176e-4ddf-bb0b-5127b8e4d98b",
"namespace": "default",
"name": "sb-b7314cda-a9fc-4089-4c39-f8a72e7a1886",
"backendId": "sb-b7314cda-a9fc-4089-4c39-f8a72e7a1886",
"location": {
"channel": "firefly",
"chaincode": "basic"
},
"created": "2022-08-18T12:55:42.794239407Z",
"event": {
"name": "AssetCreated",
"description": "",
"params": null
},
"signature": "AssetCreated",
"topic": "assets",
"options": {
"firstEvent": "oldest"
}
}
#Subscribe to events from my contract response
POST <http://localhost:5000/api/v1/namespaces/default/subscriptions>
{
"id": "3a118311-b639-411c-9f77-ca4dda398927",
"namespace": "default",
"name": "basic",
"transport": "websockets",
"filter": {
"events": "blockchain_event_received",
"message": {},
"transaction": {},
"blockchainevent": {
"listener": "76b9c322-176e-4ddf-bb0b-5127b8e4d98b"
}
},
"options": {
"firstEvent": "-1",
"withData": false
},
"created": "2022-08-18T12:59:34.369779993Z",
"updated": null
}
#Receive custom smart contract events response
ws://localhost:5000/ws
{
Connected to ws://localhost:5000/ws?tyoe=start&name=basic&namespace=default&autoack=true
}
순서도
주요 차이점
- Firefly는 custom 스마트 컨트랙트를 지원하기 위해 인터페이스를 정의해야 한다.
- FFI (Firefly Interface)는 Json형식으로 이름, 네임스페이스,버전, 메서드 목록 및 이벤트 목록으록 구성된다.
- 인터페이스는 네임스페이스로 범위가 지정된다. 네임스페이스 내에서 각 “고유한” 컨트랙트 이름과 버전을 정의되어 있으며 다른 네임스페이스에는 동일한 이름과 버전의 컨트랙트가 존재할 수 있다.
- fabric과 달리 FFI 인터페이스가 정의되어야 하는 이유
- 블록체인 이벤트 리스너 : 트랜잭션이 네트워크에 submit 되었을 때 클라이언트가 승인되었음을 알림 받는다. 또한 클라이언트는 트랜잭션이 ledger에 커밋될 때 블록체인의 알림을 수신한다.
- 클라이언트 애플리케이션이 추적할 블록체인 이벤트를 지정할 수 있도록 이벤트 리스너를 정의한다. 클라이언트 애플리케이션은 이벤트 구동을 통해 Firefly에서 알림을 수신할 수 있다.
- 이벤트 구독 : 이벤트 리스너는 블록체인에서 발생하는 특정 이벤트를 추적하도록 하지만 이벤트 구독은 이벤트를 클라이언트 애플리케이션에 전달하도록 한다.
온체인 비동기 프로그래밍 로직
- 트랜잭션이 FireFly에 제출되고 ID가 반환된다. 이것은 Operation ID 이다.
- 트랜잭션 자체는 트랜잭션을 시작한 HTTP 요청에서 비동기적으로 발생한다.
- FireFly 에 특정 유형의 이벤트에 대해 설정된 이벤트 리스너 가 있는 경우 커스텀 온체인 로직(이더리움 스마트 계약, 패브릭 체인코드, Corda streaming 등)에서 발생하는 블록체인 이벤트는 FireFly의 데이터베이스에 저장된다. FireFly는blockchain_event_received상황이 발생하면 이벤트를 내보낸다.
'블록체인' 카테고리의 다른 글
블록체인 해커톤 후기 (0) | 2022.12.02 |
---|---|
프로젝트 - 서버에 파일 업로드, 다운로드 기능 개발 (0) | 2022.10.01 |
Hyperledger Fabric SDK를 활용한 트랜잭션 수행 (0) | 2022.09.04 |
하이퍼 레저 패브릭 - 개요 (0) | 2022.06.29 |