Hyperledger Composer Composite Journey Part 2 데모 실습 내용을 정리한 글이다.

Part 2는 하이퍼레저 컴포저를 사용하여 간단한 경매 네트워크를 실습해 보는 과정이다.

앞선 튜토리얼과 유사하지만 판매자와 입찰자 권한을 나누고, 각 권한에 맞는 트랜잭션을 submit 할 수 있다. 판매자는 상품을 등록한 후에 경매를 시작하고, 각 입찰 참여자들은 경매 원하는 입찰가를 포함하는 트랜잭션을 발생시킨다.

최종적으로 판매자가 경매를 종료하면 최고 입찰가를 제출한 입찰자의 잔액이 작성했던 입찰가 만큼 줄어들고 상품 소유자가 되며, 판매자는 입찰가만큼 잔액이 증가한다. 즉, 별도의 중개인이 없이 판매자와 입찰자간의 거래가 성사되는 것이다.

공식 사이트에서 쿼리 튜토리얼을 보기 전에 한글로 정리된 예제를 한두개 더 보는게 내용 정리하는데 도움이 될 것 같아 검색을 하다 발견한 데모인데 이렇게 한글로 잘 설명된 가이드를 찾게 되서 다행이다!!

Table of Contents

  1. 아카이브 생성
  2. 컴포저 플레이그라운드를 이용한 경매 네트워크 데모
    1. 참여자 생성
    2. 상품 등록 및 경매 시작
    3. 경매 입찰
    4. 경매 종료

아카이브 생성

하이퍼레저 컴포저 개발 툴 설치 후 저장소를 복제한다.

1
git clone https://github.com/IBM/BlockchainSmartContractTrading-CompositeJourney.git

저장소에서 복제한 디렉토리로 이동 후 다음 명령을 사용하여 네트워크 아카이브(.bna)를 생성한다:

1
npm install

명령을 실행하면 아래와 같은 결과가 나온다:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
> mkdirp ./dist && composer archive create --sourceType dir --sourceName . -a ./dist/product-auction.bna

Creating Business Network Archive

Looking for package.json of Business Network Definition
Input directory: /Users/LeeJaeSeok/demo/BlockchainSmartContractTrading-CompositeJourney

Found:
Description: Sample product auction network
Name: product-auction
Identifier: product-auction@0.0.1

Written Business Network Definition Archive file to
Output file: ./dist/product-auction.bna

Command succeeded

composer archive create 명령을 통해 dist 폴더에 product-auction.bna 파일이 생성되었다.

프로젝트 디렉토리 내에는 dist 폴더 외에도 test 폴더에 productAuction.js 라는 비즈니스 네트워크를 테스트 할 수 있는 스크립트가 있다.

이 테스트 스크립트는 프로젝트 디렉토리에서 아래 명령을 통해 실행 할 수 있다:

1
npm test

이 명령은 아래와 같이 Node.js의 테스트 프레임워크인 Mocha를 통해 현재 경로의 test/디렉토리에 있는 모든 .js파일의 테스트를 진행한다:

1
2
3
4
5
6
7
8
9
10
11
> product-auction@0.0.1 test C:\Users\LeeJaeSeok\demo\BlockchainSmartContractTrading-CompositeJourney
> nyc mocha -t 0 test/*.js

#org.acme.product.auction
√ Authorized owner should start the bidding (75ms)
√ Members bid for the product (199ms)
√ Close bid for the product (243ms)

3 passing (4s)

...

컴포저 플레이그라운드를 이용한 경매 네트워크 데모

플레이그라운드를 열어 product-auction.bna 파일을 배포한다.

이전에 플레이그라운드를 사용한 적이 있다면, 웹브라우저 콘솔에서 localStorage.clear()를 사용해 웹브라우저 로컬 저장소를 지운다.

참여자 생성

Test 탭에서 비즈니스 네트워크를 테스트 하려면:

PARTICIPANTS > Seller 에 새 참여자를 생성한다.

1
2
3
4
5
6
7
{
"$class": "org.acme.product.auction.Seller",
"organisation": "ACME",
"email": "auction@acme.org",
"balance": 100,
"products": []
}

PARTICIPANTS > Member 에는 다음의 두명의 참여자를 생성한다.

1
2
3
4
5
6
7
8
{
"$class": "org.acme.product.auction.Member",
"firstName": "Amy",
"lastName": "Williams",
"email": "memberA@acme.org",
"balance": 1000,
"products": []
}
1
2
3
4
5
6
7
8
{
"$class": "org.acme.product.auction.Member",
"firstName": "Billy",
"lastName": "Thompson",
"email": "memberB@acme.org",
"balance": 1000,
"products": []
}

이제 admin 탭을 클릭하여 새로운 ID를 생성한다.

참고한 가이드에는 ID생성 > 월렛에 추가 하는 방식으로 설명되어 있는데 컴포저나 플레이그라운드 버전이 바뀌면서 변경된 것인지 ID 생성과 함께 월렛에 추가되었다는 notification을 볼 수 있어 별도 월렛 추가 과정은 필요하지 않았다.

add_seller_id

ID 추가에는 위 화면과 같이 ID NAMEParticipant가 필요하다. 앞에서 생성한 1개의 seller 정보와 memberA, memberB의 정보를 이용하여 3개의 ID를 생성한다.

1
2
ID NAME : seller
Participant : resource:org.acme.product.auction.Seller#auction@acme.org
1
2
ID NAME : memberA
Participant : resource:org.acme.product.auction.Member#memberA@acme.org
1
2
ID NAME : memberB
Participant : resource:org.acme.product.auction.Member#memberB@acme.org

상품 등록 및 경매 시작

ID 생성 후 seller를 사용하도록 선택하고 test 탭으로 이동하여 Submit Transaction을 클릭하여 AddProductStartBidding 트랜잭션을 수행한다.

use_seller_id

addProduct

owner에는 seller ID 생성시 입력한 participant 정보를 입력하면 된다.

참고한 가이드에는 JSON Data에 productId는 없는데 원하는 값을 입력하거나 팝업 하단의 Generate Random Data를 클릭하면 자동으로 값이 채워진다.

이 버튼을 이용할 경우 다음에 수행할 StartBidding 트랜잭션에 사용하기 위해 productId값을 복사해 두는 것이 좋다.

StartBidding 트랜잭션도 가이드에서는 listingId값에 대한 설명이 언급되지 않지만 임의의 값이 필요하다.

JSON Data의 product 에는 위에서 복사해 둔 productId값이 사용되며, resource:org.acme.product.auction.Product#<productId> 의 형태로 입력하면 된다.

reservePrice는 경매 예상가격이다.

startBidding

seller는 이 두 트랜잭션을 통해 상품을 경매에 등록한 것이다. Test 탭의 ProductListing에서 상품 리스트를 볼 수 있다.

경매 입찰

이제 Member에 속하는 memberAmemberB는 경매에 참여하기 위해 Offer 트랜잭션을 submit할 수 있다.

각각 ID 리스트에서 member ID 를 선택하고 Submit Transaction 버튼을 클릭하여 경매에 참여한다.

memberA_Offer

테스트를 위해 아래와 같이 경매 입찰가격을 다르게 하여 memberAmemberBOffer 트랜잭션을 submit했다.

1
2
3
4
5
6
7
// memberA
{
"$class": "org.acme.product.auction.Offer",
"bidPrice": 50, // 경매 입찰가
"listing": "resource:org.acme.product.auction.ProductListing#<ListingId>", // ProductListing에서의 listingId
"member": "resource:org.acme.product.auction.Member#memberA@acme.org"
}
1
2
3
4
5
6
7
// memberB
{
"$class": "org.acme.product.auction.Offer",
"bidPrice": 100, // 경매 입찰가
"listing": "resource:org.acme.product.auction.ProductListing#<ListingId>", // ProductListing에서의 listingId
"member": "resource:org.acme.product.auction.Member#memberB@acme.org"
}

ProductListing 에서 모든 입찰 내역을 확인 할 수 있다.

offers에는 경매에 참여한 모든 입찰자들의 입찰정보가 포함된다.

productListing_after_offer

경매 종료

이제 다시 seller ID를 선택하여 CloseBidding 트랜잭션을 통해 경매를 종료시킨다.

트랜잭션 JSON Data 내용은 위의 StartBidding 트랜잭션 JSON Data 입력하는 방법을 참고하면 쉽게 작성할 수 있다.

경매 종료 후 ProductListing으로 이동하면 아래와 같이 상품의 판매상태가 FOR_SALE 에서 SOLD로 변경된 것을 확인할 수 있다.

productListing_after_closebidding

Product에서 판매된 상품의 owner가 경매 최고입찰가를 제시한 memberB로 변경된 것을 확인할 수 있다.

product_owner_changed

Member를 보면 memberB의 잔액(balance)이 입찰가인 100 만큼 줄어들었고 products에 구매한 상품이 추가된 것을 볼 수 있다.

memberB_after_bidding