지난번 네트워크를 solo로 구성할때는 go로 체인코드를 작성 했었는데, 이번엔 나에게 조금더 친숙한 node js를 통해서 체인코드를 작성 할 것이다.
node js 로 체인코드를 작성 해본 적이 없어서 자료를 찾아보다 미디움에서 처음 작성할때 좋은 글이 있어서 가져왔다.
https://medium.com/coinmonks/start-developing-hyperledger-fabric-chaincode-in-node-js-e63b655d98db
what is Chaincode in hyperledger Facric term?
하이퍼 레저에서 체인코드란?
하이퍼레저에서 체인코드는 어플리케이션이 원장과 어떻게 상호작용하는지에 대한 비지니스 로직을 구현하기 위해 네트워크 피어 위에서 실행되는 코드이다. 트렌젝션이 제안되면, 어떤 상태변경을 장부에 적용해야 할지를 결정하는 체인코드를 실행한다. 그래서 하이퍼레저에서 탈 중화화 어플리케이션을 개발하기 위해서 체인코드를 꼭 작성해야 한다.
체인코드는 Go, Nodejs, Java로 쓰여질 수 있다. 다른 두개의 언어에 비해 Node js 는 쉽게 이해하고 찾을 수 있는 언어이다. 하지만, node js 체인코드는 하이퍼레저 패브릭의 다큐먼트에 정보가 거의 없어서 쓰고 배포하기 조금 까다롭다. 그래서 나는 node js 체인코드의 개념들과 간단한 체인코드를 작성과 배포를 위해 단계 단계로 설명할 것이다.
Hyperledger Fabric Database
하이러페저 패브릭 데이터베이스
체인코드 이야기로 넘어가기전에, 하이퍼레저 패브릭 네트워크에서 데이터는 어디에 저장되는지 보자. 하이퍼레저는 상태를 저장하기 위해 데이터 베이스에서 key-value를 쓴다. 기본적으로, 패브릭은 LevelDB를 쓴다. 이 DB는 키를 사용하여 쿼리할 수 있는 특정 객체의 이진 데이터를 가지고 있다. 기존 데이터베이스는 중앙에 있는것과 다르게, 블록체인 데이터베이스는 모든 피어마다 있다. 따라서 이것을 분산형 네트워크라고 부른다.
LevelDB말고 하이퍼레저 패브릭에서 사용하는 CouchDB라는 데이터 베이스가 있다. CouchDB는 옵션인 외부 플러그형 상태 데이터베이스 이다. LevelDB가 key-value 인거처럼, CouchDB도 체인코드로 모델링된 모든 이진 데이터들을 저장 할 수 있다. 그러나 JSON 저장소로써, CouchDB는 체인 코드 값(예: 자산)이 JSON 데이터로 모델링될 때 체인 코드 데이터에 대한 풍부한 쿼리를 추가로 가능하게 한다.
Chicncode Components
체인코드 구성 요소
fabric-contract-api : 스마트 계약을 구현하기 위한 높은 수준의 계약 API(NPM 모듈로 제공)
fabric-shim: 스마트 계약을 구현하기 위한 낮은 수준의 계약 API (NPM 모듈로 제공)
우리는 fabric-shim이 fabric-contract-api의 이전 버전이라고 생각 할 수 있다. 패브릭의 새로운 버전을 위해 높은 수준의 API를 사용하는것은 좋은 연습이다. 그러나 fabric-contract-api는 shim이 할 수 있는 모든것을 할 수 있다. 물론 더 많은것도 할 수 있다.
stub : fabric-contract-api의 인터페이스로, 원장(데이터베이스 상태)에 접속해 수정하는데 사용한다. 장부를 읽고 쓰기위한 체인코드의 메인 인터페이스이다. 어떻게 데이터를 읽고 쓸 수 있을까? Stub 인터페이스의 함수들을 ㅂ자.
Common Methods in stub interface
- Stub interface의 함수들
- getState(k): 이미 알고있듯이, 하이퍼레저 패브릭 데이터베이스는 key-value 조합으로 데이터를 저장한다. 이 함수는 ledger에서 데이터를 읽는다. k값을 넣고 k와 관련된 값들을 return한다.
- putState(k,v): 이 함수는 ledger에 데이터를 저장한다. K를 key로, v를 value로 가진다. 더 쉽게 말하자면, 우리가 Alice의 나이를 장부에 저장하고자 한다면 Alice는 Key값이고 Age는 Value이다.
- deleteState(k): 이 함수는 Key값 K와 관련된 Value를 장부에서 지운다.
- getStateByRange(k1,k9): 이 방법은 장부의 키 집합에 걸쳐 범위 반복기를 리턴한다. startKey(k1) 부터 endKey(k9) 까지 반복하며, 두 키 사이의 모든 Key values를 리턴한다. 자바 스크립트의 반복문과 비슷하다. 만약 우리가 k1-k99까지의 키를 저장했다고 하였을때 우리는 간단히 이 메소드를 통해 Value값을 가져올 수 있다.
- getTxID(): 이 함수는발생한 트렌젝션의 트렌젝션 id를 반환한다. 트렌젝션 id는 체인 위에 모든 트렌젝션에서 유니크 하다(단 하나). 그래서 트렌젝션 id는 거래를 추적하는데 중요한 역활을 한다.
- getTxTimestamp() : 이 함수는 트렌젝션이 만들어진 시점의 타임 스탬프를 리턴한다. 트랜젝션 채널 해더로 부터 가져오며, 그러므로 클라이언트의 타임 스탬프를 나타낸다. 그리고 모든 엔도서들을 거쳐 같은 타임 스탬프 값을 가질 것 이다.
Write your First Chaincode
체인코드를 node js로 작성하기 위해서는 package.json, index.js 같은 것들을만들어야 한다.
만약 package.json이 익숙하지 않다면,
- package.json
- 프로젝트가 의존하는 패키지들의 리스트
- 프로젝트에서 사용하는 시멘팅 버전 규칙 패키지들의 특정 버전
- 빌드를 재현하고, 다른 개발자들에게 공유하기 쉽게 함
간단히, 우리 체인코드는 farbic-contract-api와 fabric-shom 모듈에 의존한다. 우리는 이 패키지들과 버전을 package.json에 언급할 것 이다.
또한 fabric-chaincode-node start를 우리의 start script에 더할 것이다. (체인코드를 피어에 설치하기 위해 필요)
package.json
1 |
|
위의 코드를 잘 보았다면 **”mian” : “index.js”**이라는 줄이 있다. 무슨 의미냐면, 시작할때(체인코드설치하는 동안), npm 모듈은 index.js를 확인하고 피어들에 언급된 contract를 설치한다. 그래서 index.js는 contract를 모듈로 내보낸다.
여기 index.js 파일이다
1 | ; |
The Contract:
우리의 비지니스 로직은 뭘까?
학생들의 점수를 더하기, 검색하기 그리고 지우기
- 장부에 점수들을 적는다. 그래서 우리는 체인코드 stub 인터페이스인 putState 함수를 쓸 것 이다.
- 데이터 읽기로 데이터를 검색한다. 그래서 우리는 getState 함수가 필요하다
- 데이터 지우기로 데이터를 지운다. 그래서 우리는 deleteState 함수가 필요하다
체인코드는 fabric-contract-api 모듈에서 scope key 클래스 Contract 를 불러오는것으로 시작한다. 이 클래스는 write logic이 될 것 이다. 모든 체인코드 기능들은 이 라이브러리 클래스를 사용해야 한다.
1 | const { Contract}=require(’fabric-contract-api’); |
Adding Marks:
우리는 value와 studentId를 키값으로 객체를 저장하고, 각각의 과목에 대한 학생들의 점수를 저장하는 자바 스크립트 객체를 만들 것이다. 서버를 통해 데이터를 데이터베이스로 보낼때, 데이터는 string 이여야 한다. 그래서 먼저 우리는 marks 객체를 **JSON.stringify()**를 통해 String 타입으로 바꿔준다. 그리고 데이터베이스에 바이너리 데이터로 보내기 위해 buffer를 적용한다.
1 | async addMarks(ctx,studentId,subject1,subject2,subject3) { |
Delete Marks
1 | async deleteMarks(ctx,studentId) { |
Query Student Marks:
우리는 이전의 addMarks() 함수를 통해 값을 buffer 형식으로 넣었다. 쿼리를 하면, buffer 형식으로 return 될 것 이다. 그래서 우리는 buffer를 string 타입으로, 그래서 원래의 자바 스크립트 객체로 parse 한다.
1 | async queryMarks(ctx,studentId){ |
Final Contract
여기 final contract 가 있다.
1 | ; |
이 체인코드를 테스트하고 설치하기 위해서, 나는 basic-network(single peer)를 사용할 것이다. 이 네트워크에서 우리는 mycc라는 이름의 체인코드를 peer0.org1.example.com에 설치하고 mychannel에 instantiate 할 것 이다. 그리고 나면 우리는 체인코드 함수들을 invoke 할 수 있다.
도커는 꼭 설치 되어있어야 한다. 간결하게 하기 위해, 나는 chaincode files(logic.js, index.js, package.json)를 chaincode/newcc 디렉토리에 마운트 해놓았다. 전체 코드는 여기서 볼 수 있다.
먼저, 우리는 네트워크를 시작하고 채널을 만들어야 한다
1 | git clone https://github.com/Salmandabbakuti/chaincode-essentials.git |
네트워크가 준비되기 까지 시간이 걸릴 것 이다. 만약 permission 에러가 나면, 그냥 root user 로 돌려라. 네트워크가 피어 하나랑 up 되어 가동되면, 우리는 체인코드를 설치할 준비가 되었다.
체인코드를 설치하고 invoke 하기 위해서 우리는 피어의 cli container를 사용할 것이다.
cli 컨테이너로 들어갈려면,
1 | docker exec -it cli bash |
Installing and Instantiating Chaincode
체인코드 설치 및 인스턴스화
1 | peer chaincode install -n mycc -v 1.0 -p "/opt/gopath/src/github.com/newcc" -l "node" |
Adding Marks of Student
학생의 점수 adding
1 | peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n mycc -c '{"function":"addMarks","Args":["Alice","68","84","89"]}' |
Query Marks of Student “Alice”
“Alice” 라는 학생 검색
1 | peer chaincode query -o orderer.example.com:7050 -C mychannel -n mycc -c '{"function":"queryMarks","Args":["Alice"]}' |
Deleting Marks of “Alice” from ledger
1 | peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n mycc -c '{"function":"deleteMarks","Args":["Alice"]}' |
위의 스크립트는 “Alice” 키와 관련된 데이터를 장부에서 지울 것 이다. 만약에 다시 Alice를 query한다면 studentId가 존재 하지 않는다고 에러가 날 것이다.
나는 자동으로 설치되고 테스트가 되는 체인코드를 클라이언트 디렉토리에 만들었다.
앞으로 나오는 것들을 따라해보자.
먼저, cli 컨테이너를 종료하고 클라이언트 디렉토리안에 스크립트를 실행한다.
1 |
|
client/start.sh안에 정의되어있는 스크립트들을 통해서 체인코드를 invoke 할 수도 있다.
Conclusion
결론
우리는 여기서 체인코드 , 체인코드 stub 인퍼페이스안의 함수, 체인코드의 배포 구조 들이 무엇인지 그리고 체인코드를 작성하고 배포하는것이 얼마나 쉬운지에 대해 알아보았다. 나는 이 기사가 체인코드를 시작하면서 작성하고 배포하는데 도움이 되었으면 한다.
Curious to know how we can build end-user Applications on Hyperldger Fabric? Check this: Walkthrough of Hyperledger Fabric Node SDK and Client Application
하이퍼레저 end-user 어플리케이션 빌드 하는 방법이 궁금하다면 클릭!
References:
https://fabric-shim.github.io/release-1.4/index.html
https://fabric-sdk-node.github.io/master/index.html
https://hyperledger-fabric.readthedocs.io/en/release-1.4/chaincode.html
https://medium.com/coinmonks/start-developing-hyperledger-fabric-chaincode-in-node-js-e63b655d98db