얼마전에 블록체인사 CTO분들하고 대화중에 하이퍼레저 패브릭의 합의 알고리즘에 대해서 얘기하다가 "뇌정지"가 온적이 있다. 비트코인 POW부터 POS,DPOS,PBFT,텐더민트식,캐스퍼등에 대한 이해를 거친후에 더 이상은 컨센서스 알고리즘에 대한 공부는 그만 뒀고, (분산네트워킹만이라도 잘하자 싶어서..) 하이퍼레저 패브릭은 그냥 실행-오더링-커밋이지 뭐...라고 평소에 생각했었는데 이번 기회를 통해 정리를 좀 해보려 한다. 알고리즘 자체에 대한 내용이라기 보다는 전체조망이랄까? 주저리주저리 해 볼 생각이다.

거의 유일한 하이퍼레저 패브릭 서적이라고 볼 수 있는데,
이 책을 완독한 후에도 합의 관련된 이해는 할 수 는 없다. 관련 내용이 (구체적으로) 없으니까~
즉 모든 원흉은 이 책이다. 농담이다..
400페이지가 넘어가며 정말 많은 내용을 충실히 작성해 놓은 이 책에서 합의알고리즘 내용은 
58page에 합의 항목이 나오는데 "하이퍼레저패브릭에서 합의 시스템은 보증-오더링-검증모델 기반하에 플러그인 될 수 있다. 하이퍼레저 패브릭의 오더링 서비스는 합의 시스템을 표현한다." 정도의 표현만 있다. 
(근데 사실 이게 핵심이자 모든것이기도 하다.) 

이제 본격적으로 히스토리를 살펴보자.
하이퍼레저 패브릭 0.6버전에서는 PBFT를 사용했다고 한다. (PBFT에 대한 좀 더 구체적인 것은 여기 참고)

그림 - 하이퍼레저 패브릭 0.6

위의 0.6 도식도와 같이 오더러가 없으며, (컨센서스가 대행함) 보증하는 부분과 커미팅하는 부분이 나뉘지도 않았다.
이 Peer들끼리 아래와 같은 PBFT를 수행했으며 간락하게 설명하면 

그림 - PBFT 

Pre-prepare단계에서 트랜잭션을 모두 공유하고, 
Prepare단계에서 각자 Peer들은  트랜잭션을 받았다는 것을 알리며,
Commit단계에서 각자 Peer들은 이 트랜잭션에 대해서 합의를 해준다라는 것을 모두에게 알리며 
마지막으로 동료Peer들의 합의 상태에 따라서 OK인지 아닌지를 각자 확인해서 Reply 해준다.

이 알고리즘은 보통 2/3 이상의 합의가 있으면 통과이고, 대략 2n^2번의 커뮤케이션이 필요하게 된다.
즉 Peer숫자가 50개만되도 엄청 느려진다는 말이다. 처음 하이퍼레저패브릭을 설계했을때, 허가형블록체인으로 소수의 노드를 대상으로 서비스 한다고 생각 했을 테니 일리가 있지만, 무리가 따랐나보다. 1.0에서는 아키텍쳐가 달라진다.
* 하이퍼레저 0.6 PBFT에 대한 좀 더 자세한 설명은 여기  
근데 중국어라는게 함정 (간자체로 번역하세요)

그림 - 하이퍼레저 패브릭 1.0  Endorsing - Ordering - Validating 3단계 구조 

PBFT식으로 Peer들간에 커뮤니케이션 하는 부분이 너무 느려서 없어지고,  Endorsing - Ordering - Validating 3단계 구조를 기반으로 합의 알고리즘이 완성된다.  Endorsing 에서는 보증역할을 맡은 Peer들이 트랜잭션에 대해 실행을 하고 결과 값 사인한후에 클라이언트에 돌려준다. 여기서 Peer들간의 커뮤니케이션은 없다. 이런 값을 오더러에게 전달하면 오더러는 트랜잭션에 순서를 매기고, 블록으로 완성 한후 Validator 에게 전달하면 Validatior에서는 보증이 어떻게 되있는지 확인하여 만족 시키면 장부에 기입한다.(좀 더 자세한 설명 여기) 자 이렇게 되면 커뮤니케이션 비용은 확실히 낮아지게 되는데 병목 부분을 생각해보면 3군데 있는데
1. Endorsing 하는 부분에서 체인코드를 실행하는 비용
2. Signning (서명 및 확인)부분이다. 
3. 앞으로 말할 Ordering 서비스에 어떤 합의 알고리즘이 들어가냐의 문제이다.

그럼 글 서두에 말한 "하이퍼레저 패브릭의 Ordering 서비스는 합의 시스템을 표현한다." 는 무엇인가? 
https://github.com/hyperledger/fabric/tree/master/orderer  다음 링크를 살펴보면 아래와 같이 나온다.

  • Solo ordering 서비스 (테스팅 목적): 쉽게 이용되도록 만들어진 극히 간단한 서비스로써 프로덕션용은 아니다. 싱글 프로세스로 구성되어 있으며, 하나가 모든 클라이언트들에 대해 서비스 한다. 따라서 사실상 합의라는게 없다. availability 나 scalability에 대해 고려되지 않으며 따라서 이것은 그냥 테스트용~
  • Kafka기반 오더링 서비스(프로덕션)Pub/Sub구조의 메세지큐 미들웨어인 Kafka 기반의 ordering service 이다. Peer 오더러 클라이언트 코드가 카프카에 대해 상세히 작성되지 않도록 ab.proto 정의로 이것을 추상화 한다.Kafka는 현재 높은 처리량과 고가용성을 요구하지만 byzantine 내결함성은 요구하지 않는 운영 배치에서 선호되는 선택이다.
  • PBFT 오더링 서비스(지연됨):  BFT적인 방식에 의해 메세지들을 나열하고 순서 매이기 위한 구현으로 만들어 질 것이다. (현재 개발중) 

즉 위와 같이 구현 할 수 있으며, 현재는 Zookeeper/Kafka기반하여 속도중시/부하분산/복제와리더재선출에 의의한 HA/오더러가 순서매기는데 도움/ 정도의 역할로 외부시스템을 이용해서 이루어져 있는 것이다. 하지만 카프카가 오더러들에 대한 HA까지 보장해주진 않는다. 멀티오더러에 대해서는 node sdk를 사용하는 미들웨어 단에서 잘 작동하는 오더러에 대한 선택을 하는 수동적인 방식이 있는 것 같다. 만약 좀 더 신뢰/오더러에 대한HA를 중시하고 싶으면 BFT계열(PBFT등)를 추가 구현 할 수도 있을것이다. 개인적으로도 허가과정등을 통해 신뢰비용에 대해 어느정도 보완 했다고 판단하기 때문에 Kafka기반이면 충분하지 않나 싶기도 하는데 외부모듈을 무겁게 가져다 사용하는건 문제다. 그리고 Kafka가 하는 역할에 대해  CFT (Crash Fault Tolerance) 같은 용어를 쓰는데, BFT처럼 제대로된(?) 합의 알고리즘이 아니라, 주키퍼-카프카 구성으로 장애에 대한 대처가 가능한 상태에서 오더링을 하기 때문이다. 아무튼 개인적으로는 현재 카프카-주키퍼 오더링 부분과 앞으로 나올 Raft식의 오더링에 대한 행위에 대해서 '합의' 는 POW식의 '신뢰의 합의' 는 아니고 고전적인 분산시스템에서의 내고장 합의를 말하는 것이다. (오더러 부분도 각 조직들에 의해 권한을 분산해서 나누어 갖는 형태가 되면 신뢰의 합의까지 되겠지만 확실하지 않다. 만약 그렇게 까지 하는건 좀 오버인거 같다.)

그림 - 하이퍼레저 패브릭 로드맵 

구글링을 해보면 위의 표를 많이 볼 수 있는데 1.3 에서는 RAFT오더러, 1.4에서는 BFT오더러의 구현을 계획했는데 2019년 1월 현재 1.4가 출시된 상황에서 어떻게 되었을까?

What’s new in v1.3 
에는 RAFT오더러에 관련된 내용이 없다.
What’s new in v1.4 에도 BFT 오더러에 대한 내용은 없다.

그럼 2.0버전에서는 어떻게 될까? 프로젝트 현황에 대해 지라 와 제안문서 살펴보니 RAFT / etcd/raft 기반으로 개발중인듯 싶은데 비교적 단순한 알고리즘으로 
BFT처럼 무겁지 않고 CFT 역할에 그치더라도 1) 카프카-주키퍼에 의존하지 않는 오더링 서비스를 위함. 즉 굳이 외부미들웨어 가져다 복잡하게 설치해서 쓸 필요 있냐 하는 2) 차후에 개발될 BFT 개발을 위한 기반쯤으로 생각하는 듯하다. 카프카-주키퍼 모델에 비해 성능이 어떨지에 대한 예측 및 어떻게 BFT개발을 위한 기반이 될 까에 대해서는 깊이 파보진 않았다. 

제안문서 B.II)   Raft 는 어떻게 BFT개발의 주춧돌이 되어 줄 수 있나?
RAFT는 BFT와 마찬가지로 리더 기반 프로토콜입니다. 잘 검증 된 리더 기반 합의 프로토콜을 통합한다는 것은 Fabric이이 프로토콜 군에 대한 합의 된 (confensus) 플러그인 작성자에게 제공하는 인터페이스 개선에 초점을 맞추는 것을 의미합니다. 그러한 의미에서 Raft에 대한 실험은 우리가 PBFT 기반 오더링 서비스의 토대를 마련하는 데 도움이됩니다. 연장선 상에서 Raft가 CFT 프로토콜 임에도 불구하고 BFT 컨텍스트에서만 의미가 있는 제안 된 구현에서 특정한 결정을 내립니다. 우리는 그것을 의도적으로 수행하여 BFT 기반 서비스로 전환 할 때 Fabric 핵심 변경 사항의 수를 최소로 유지 하려고 합니다. (역주: Kafka 분산복제처리도 리더기반인데..리더가 읽기/쓰기 담당하고 팔로워는 복제만) 

결국 Pluggable 하기 때문에 업체에 따라서 자신들이 만들어 추가 할 수도 있다지만 하이퍼레저 패브릭 자체에서도 추가하는데 오래걸리는데 이걸 직접 자신의 입맛에 맞게 요리해서 사용하려는 업체가 얼마나 될런지는 모르겠다. 특히 BFT알고리즘에 대한 논문은 많지만 성공적으로 구현하는것은 굉장히 어렵다. 

참고로 BFT계열의 컨센서스 플러거블 라이브러리(BFT-SMART)도 있다. 현재 정식버전으로 들어 간것은 아니며 추후 RAFT 이후에 BFT계열로 SBFT가 들어갈지, BFT-SMART가 들어갈지 모르겠다. BFT-SMART는 논문상에 10,000TPS 급의 성능을 보여주며, SBFT는 아직 테스팅된게 없는것으로 알고 있다.

결론 )

개인적으로는 카프카 대체제로는 RAFT로 충분하고 BFT계열은 간단하든 복잡하는 오버스펙이라 시작할맘도 없을 거 같습니다.참고로 JP모건 애들이 만드는 콘소시엄체인은 RAFT랑 IstabulBFT 라는것을 쓰는데 패브릭도 BFT계열을 겨우 오더링하는데 사용 할 바엔 E-O-V 프로세스를 폐기하는게 낫다고 봅니다. 아마 거기 아키텍트도 똑같은 생각하고 있을듯..ㅎㅎ



 

 

3줄 정리

- 자신과 연계된 UTXO 를 소비 하려면 그때 자신의 서명을 생성해서 트랜잭션 내부의 INPUT에 넣어 보낸다.
- 검증노드들은 해당 서명을 이전 트랜잭션의 OUTPUT과 매칭이 되면 ㅇㅋ 해줌
- 즉 현재 트랜잭션 내부의 INPUT은 이전 트랜잭션의 OUTPUT과 매칭용이고, 현재 트랜잭션의 OUTPUT은 받는 사람의 계정과 연결되되, 나중에 받는 사람이 이 UTXO를 사용하는 트랜잭션을 만들 때 그 INPUT과 매칭될 것이다. 
- 최종적으로 TxID를 만드는 과정은 : 
https://steemit.com/kr/@niipoong/id-create-bitcoin-txid 를 참고한다.

받는 사람 : ScriptPubKey(잠금스크립트)에서  OP_HASH160 다음에 위치한 문자열(B라고하자)를 이용해서 실질적 비트코인 주소 생성( 비트코인 주소는 Private Key -> Publick Key -> B -> 20바이트비트코인 주소로 만들어진다. 따라서 ScriptPubKey에서 받는 사람 주소를 얻을 수 있다)

보내는 사람 : ScriptSig 에서는 서명+공개키가 포함되어있으므로, 해당 공개키로 비트코인 주소를 만들면 된다. 

* 비트코인 주소 생성 방법 : https://ihpark92.tistory.com/6

참고로 아래 트랜잭션 경우는 한개의 UTXO 에서 한개의 UTXO로 보내고 있다.vin (trnasaction input)이 1이고 vout(transaction output) 도 1이다. 보내야 할 돈이 많이 필요해서 한개의 계정에 묶인 여러개의 UTXO를 통해 보내고, 잔액까지 받아야 한다면vin 이 n이 되고, vout은 2가 될 것이다.




윤대근님의 하이퍼레저 패브릭으로 배우는 블록체인의 내용을 참조하여 구성되었습니다.

간단정리:

Fabric-CA를 통한 보안메터리얼들 생성 

가. Fabric-CA 를 이용해서 각 조직의 admin msp 를 생성한다.
나. 각 조직의 admin은 조직이 가지고 있는 각 Peer의 msp 를 생성한다.
                   ---- 여기까지가 8번 -----

인프라 (채널등) 구성하고 시작하기 
다. genesis.block 을 각 조직의 공개키를 가지고 생성하여 오더러를 구동한다. 
라. 각 peer 들을 구동한다.
마. 채널을 생성한다.
바. 채널에 peer들을 참여시킨다.
사. 앵커피어 업데이트
                 ------ 여기까지가 15번 ----

체인코드 설치 및 읽고,쓰기
아. 각 Peer에 체인코드 설치
자. 하나의 peer 에서 체인코드 인스턴스화
차. 분산원장 읽고/쓰기 


설치도우미들

-  
FABRIC_CFG_PATH 설정 : core.yaml , configtx 관련요소를 실행시키기위한 패스정보. 
-  configtx.yaml: 컨소시엄정보,조직정보,채널정보,오더러설정,제네시스블록,앵커피어등을 생성하기위한 설정파일이다.
- core.yaml : peer를 실행시키기 위한 설정파일을 담고 있다. 
- orderer.yaml : orderer 를 실행시키기 위한 설정파일을 담고 있다. 



 
퍼블릭 블록체인 (이더리움) 철학은 화폐의 이동에 대한 "신뢰 비용"을 줄이기 위해서라면
콘소시엄 블록체인 (하이퍼레저 패브릭) 철학은  조직간의  "신뢰 비용" 을 줄이기 위해서이다.(코인이 없으며 굳이 넣을 수도있겠지만 그게 의미 있는지에 대해 매우 회의적입니다. 퍼블릭체인과의 인터체이닝도 마찬가지 개념에 대한 변화가 심하며 앞으로도 계속 변화 할 것이기 때문에 쉽사리 규정짓기 힘들기도 합니다만..)

즉 하이퍼레저 패브릭을 공부하거나 먼가를 만드는 목적이 일반인들을 위해서 DApp을 만들려고 한다면 이상한거다. 또한 무슨 보안을 위해서라든지 위변조 방지를 위해서라든지 이런 구실을 만들어서 장부에 저장되는 어떤 기록에 대한 주체가 하나인 경우임에도 하이퍼레저패브릭로 해야 한다고 주장하지 말자. 보안,위변조방지,분산저장으로인한안전성등은 도구 혹은 부수효과 에 불과하다. 크나큰 낭비가 될 수 있다. 

하이퍼레저 패브릭을 적용하기 위해서는 먼저 해당 분야에 "조직" 이라는 네트워크가 존재해야하며, 그 "조직" 간에 어떠한 신뢰 비용이 생기는지 대략적으로 라도 파악 할 수 있어야 한다. (장부에 담겨질 내용은 이 다음 얘기) 그런 후에 하이퍼레저패브릭이라는 나름 거대한 인프라를 구축하고 관리하는데 드는 비용보다 그 비용(당장의 신뢰비용 + 미래의 기대비용) 이 대단히 크다고 생각 할 경우, 도입 할 여지가 생기게 된다. 

따라서 하이퍼레저패브릭을 하려는 업체나 개인은 그 조직들에 대한 도메인을 잘 알아야하며,(준비를 해야하며) 그 조직을 설득 할 수 있는 힘이 있어야 한다. 이 얘기는 반대로 조그마한 스타트업이나 개인이 공부하기에는 낭비가 될 수가 있다는 사실을 염두해 두어야 한다. (물론 내부 톱니바퀴를 이루는 p2p,보안,컨센서스,분산인프라 등에 대한 이론 공부는 피가되고 살이 될 수 있다. 문제는 트레이드 오프) 

초반에 IBM Cloud 계정가입에 문제가 생겨서 차질이 있었지만, 한달동안 하이퍼레저 프로젝트를 잘(?) 완료 하였다. 해당 프로젝트는 웹서비스단(React,Express,Mongo)와 블록체인단(Composer Rest Server, IBM Blockchain) 으로 이루어졌는데, 중간에서 Mongodb가 캐싱역할을 하며, 웹서비스단에서 블록체인에 대한 호출 즉 Composr API 호출을 위임하고 있는 형태. 따라서 Composer Rest 서버를 멀티유저(혹은 싱글서버를 카드별로 여러개) 가 아닌 단일유저가 사용하므로 신뢰의 분산에는 적합치 않은 모습..차후에 이걸 어떻게 분산시킬지.. 분산을 꼭 시켜야할지에 대한 고민과 동시에 하이퍼레저를 다루는 방식이 굉장히 다양할수 있으며, 버전에 따라서 예전 문서가 잘 적용이 안되는 경우도 많아서 나름 고전했던거 같다. 마지막으로 IBM의 구성원들이 얼마나 노력을 많이 하고 있는지에 대해 정말 많이 느꼈다. 그들이 만들어 나가는 기술블로그들은 정말 대단~이번에 레드햇도 인수했던데, 상위권으로 도약하길 바란다. 

p,s

프로젝트하면서 느낀게 중간에 미들웨어에서 다른 트랜잭션이 Composer 트랜잭션과 동시에 일어나는데, 이런 경우 어떻게 완결성을 맺을까 하는 점이었다. 돈이 오고가는 프로젝트가 아니라서 대충 얼버무렸지만.. 장부에는 letter of credit 이 완결되어 Close 시켰다고 트랜잭션이 일어났는데, 은행 트랜잭션에서 송금이 실패했다면?? 외부 트랜잭션과 All or Nothing 전략은 어떤식으로 할 수 있을까?? 생각해볼게 많은거 같다. hyperledger fabric에 rollback 기능이 없고.... 실제 사례에 대한 아티클을 찾아보아야겠다. (요즘 유행하는 마이크로 서비스 패턴들을 잘 버무려야함. SAGA패턴 같은) 

아래는 그러한 트랜잭션에서 고려할만한 전략을 정리한 글이다.

    1) 취소 전략: 비즈니스 트랜잭션의 오류 해결책으로 가장 간단한 전략이다. 즉 지금까지 진행된 개별 트랜잭션들을 모두 취소시킨다. 어떻게 보면 이 전략은 2단계 커밋의 롤백 전략과 유사하다. 그리고 별로 좋은 전략 같아 보이지도 않는다. 그러나 현실 세계에서는 그런대로 쓸만하다. 취소함으로 발생하는 손실이 거래를 복구함으로 얻는 이익보다 큰 경우 특히 유효하다. 애플리케이션 개발 시 실행(삽입, 갱신) 기능과 취소(삭제, 갱신)기능을 함께 고려하고, 트랜잭션 조정자는 오류를 감지한 후 각 참여 자원의 취소 기능을 요청한다. 2단계 커밋의 롤백과 다른 점은 하나 이상의 요청이 트랜잭션 중간에 개입될 수 있고 긴 시간의 트랜잭션에서 발생한 오류를 해결하는 전략으로, 이런 문제는 2단계 커밋의 롤백으로는 해결되지 않는다.

    2) 재시도 전략: 재시도를 통해 비즈니스 트랜잭션이 성공할 수 있는 업무인 경우 다시 동일한 비즈니스 기능을 시작한다. 예를 들어 외부 자원이 일시적으로 중지된 경우 재시도를 통해 극복될 수 있다. 업무 규칙을 위반한 비즈니스 기능의 요청인 경우 이 전략을 사용하면 안된다. 참여 시스템이 멱등 수신자(Idempotent Receiver)[EIP]가 된다면, 이 전략은 좀더 효과를 발휘한다. 멱등 수신자란 동일한 요구에 대해 수신자의 상태가 변하지 않는 수신자를 말한다. 즉 재시도 전략을 비즈니스 트랜잭션 오류의 전략으로 선택한 경우 각 참여 자원을 멱등 수신자로 만들어야 한다. 멱등 수신자 패턴에 대한 자세한 설명은 [EIP]나 [SDP]를 참조한다. 재시도에는 재시도 횟수를 지정할 수 있다. 재시도 횟수를 넘어선 오류인 경우 다른 해결 전략으로 오류 해결 방법을 변경해야 한다.

    3) 보상 전략: 이미 처리된 비즈니스 오류를 별도의 비즈니스 기능으로 보상하는 전략이다. 예를 들어 은행이 고객의 이체 처리 중 출금은 성공했으나 입금에 실패한 경우 출금 액만큼 은행이 고객에게 입금해주는 전략이다. 이를 위해서는 트랜잭션 오류 상태를 해결 상태로 전이할 수 있는 기능(메소드)을 참여 애플리케이션에 포함해야 한다. 비즈니스 트랜잭션 오류가 발생하면 비즈니스 트랜잭션 조정자는 보상 비즈니스 기능을 참여 시스템에 요청해 비즈니스 트랜잭션의 오류 상태를 정상 상태로 전이시킨다.

인용 및 참고 링크

1. 분산 비즈니스 트랜잭션과 오류 해결 방법
2. 스타벅스는 2단계 커밋을 사용하지 않는다.
3. 2단계 커밋과 3단계 커밋이란?
4. 3단계 커밋이란?




사족
하이퍼레저 컴포저는 분명히 하이퍼레저 패브릭 네트워크/어플리케이션을 만들기 쉽게 해주지만, 패브릭을 추상화 하는데 있어서 어려움도 많습니다. (패브릭에서 추가된 기술을 따라 잡지 못한다던가, 모습이 전혀 달라서 처음 진입하는 사람들에게 큰 혼동을 초래. 예를들어 컴포저의 Participant 가 fabirc의 무엇과 매칭되는가? 컴포저의 Card 개념은 fabric의 무엇인가? 컴포저로 멀티유져/조직을 다루는 방법등~) 현재 몇몇 문제 때문에 IBM에서 컴포저에 대한 지원을 줄였지만, 업데이트는 계속 될 것이라고 하네요. 


개인적으로는 컴포저의 역할이 매우 중요하리라 생각합니다. 이쪽이 훨씬 더 키워드들이 실세계와 매칭되며 간단하니까요~사람들이 사용하지 않는 기술,어려운 기술은 사장되기 마련입니다. 

(이 글을 쓴 2018년인데, 2020년이 시작되는 현재 컴포저는 하이퍼레저군에서 제외되었네요. 모든 경우에 대한 추상층을 쌓아 올리는데 실패했으며, 굉장히 어려워 보이긴 했습니다. 사용자가 패브릭을 이해하고 사용하기도 그 레이어 때문에 더 어려워서 쓸모가 없어졌습니다.)


관련
Developing multi-user application using the Hyperledger Composer REST Server (18/2월)
IBM Blockchain Starter Plan 에 비지니스 네트워크 디플로이 (18/4월)

Composer REST Server 를 Cloud Foundry application로 디플로이| (18/5월)
Passport-JWT Authentication for Hyperledger Composer Rest Server (18/5월)
Deploy a blockchain business network to the cloud using the IBM Blockchain Starter Plan (18/6월)

위 글이 쓰여질 때는 IBM Blockchain network 가 fabric 1.1 기준이었지만 현재 (2018년 10월6일) 는 1.2.1 로 업데이트 되었다. 따라서 문서에는 composer 를 0.19버전을 설치하라고 나왔지만  0.20 버전으로 올려줘야 한다.

fabric 1.1 => composer 0.19.x
fabric 1.2 => composer 0.20.x

Create a fair trade supply network with Hyperledger Composer and IBM Blockchain Starter Plan (18/9월)
Deploy a sample application to the IBM Blockchain Platform Starter Plan  (18/10월)


기타

- Setup Hyperledger Fabric in multiple physical machines (18년 9월)
- Publish a Business Network in Multi-host HyperLedger Fabric (18년9월)

Hyperledger composer 일반강좌

한글 : https://www.youtube.com/watch?v=smytS8dQCtk  (후반부 10여분)
영어 : https://www.youtube.com/watch?v=nS_MRqAeEbQ




1. Gossip 프로토콜 일반 

이더리움의 DEVp2p 네트워킹보다는 비교적으로 간단한 편인 하이퍼레저 패브릭에서의 네트워킹구조 를 살펴보자.
참고로 이더리움의 DEVp2p 에 관련되어 이전에 작성한 글이 있으니 Public 체인에서는 어떻게 하는지 참고 하자.

-> [Ethereum] Node Discovery with Kademlia 
-> [이더리움 코어] DevP2P 소스코드 분석 (feat. golang) 

암튼 둘다 Goosip 을 이용하는데, Gossip 즉 소문이란 무엇인가? 내가 주변 몇사람한테 연예인에 대한 잘못된 소문을 내는 순간에 그들이 또 각자 소문을 내고 이런식으로 내가 전체에게 알리지 않아도 전체가 알게 되는 것을 말하며 특징은 이런것이 있을 수 있겠다..

- 전체에 말하지 않아도 되는 편리함.
- a 라는 사람에게 도착하는 순서가 정해져 있지 않음.  
- 어떤 경로가 끊어져도, a 는 다른 경로를 통해서 전달 받을 수 있다.

- 중복 전달 될 수도 있다. 
- 최악의 상황에선 전달 못 받을 수도 있다. 
- 구라가 횡횡 할 수 있다. 

이런 특징을 그대로 구현한것이 Goosip 프로토콜이다. 근데 좀 룰을 정한게 있는데 

- 한 노드는 부트스트랩 노드를 통해 시작하며, 부트스트랩 노드 각각이 가지고 있는 Alive 노드정보를 합쳐서 셋 구성. 
- 한 노드는 주변 연결된 노드들이 살아있는지 계속 확인 해야한다. 
- 한 노드는 자기가 알고 있는 노드들의 전체 정보를 주변에 주기적으로 알려줘서 전체 네트워크가 현재 상황에 대해 알 수 있게 한다.
- 소문을 낼 때에는 전체노드중 몇개를 랜덤하게 정해서 소문을 퍼트린다.
- 소문을 반복해서 퍼트리지 않는다.전에 받은 소문은 다시 처리하지 않는다.
- 이더리움은 구라를 수용하면서 신뢰를 만들고, 하이퍼레저 패브릭은 인증을 통해서 원천봉쇄한다. 

자 이 아이디어를 머리에 담고 하이퍼레저 패브릭을 살펴보자.

이미 아시는 분도 있겠지만 하이퍼레저 패브릭의 워크플로우를 간단히 설명하면,

1. 클라이언트는 어플리케이션(SDK)를 통해서 Peer 들에게 트랜잭션을 실행 시킨다.
2. Endorsement역할을 하는 이 Peer 들은 체인코드를 실행시키고 장착된 체인코드 로직에 따라서 결과를 내어 다시 클라쪽으로 read/write 셋을 전달 한다.(이 과정에서 장부를 업데이트 하지 않음)
3. 이 결과 셋을 가지고 orderer 서비스에게 순서를 정해서 블록화 해달라고 요청한다.
4. orerer 서비스는 블록화 하면 Peer 들은 이 블록을 가져와서 검증하고 저장한다.

이 과정 중에서 Gossip 프로토콜이 이용되는것이 바로 4번 flow 에서이다. 
즉 orderer 는 모든 peer과 커뮤니케이션을 하는게 아니라, 조직별 대표 peer 하나에게 알리면 이 peer 가 gossip 을 통해 점진적으로 전체로 전달되게 되는 것이다. 각 피어는 전달받은 블록(트랜잭션 뭉치들)을 검증하고 장부(상태DB&블록체인) 에 저장한다. (Gossip은 또한 Peer간 Sync를 맞추는데도 사용된다.)



조금 더 구체적인 위의 그림에서는 5번에 해당한다. 리더피어(그림이 잘못됨. 앵커피어가 아니다) 에게만 전달하면 그것이 소문(블록정보)을 퍼트리기 시작한다. 그림에는 브로드캐스트 처럼 보이지만 저기서 가쉽이 사용되는데, 조직마다 리더피어가 있으며, 그 녀석이 오더러에게서 Pull 하면서 시작된다. 그림에는 구분이 안되어 있지만 추가적으로 하나의 조직이 다른 조직의 Peer 와 연계할 때에 Anchor Peer 를 이용한다. 리더피어=Anchor Peer 로도 설정 할 수도 있다.

2. Gossip 프로토콜 with 하이퍼레저 패브릭 

다시 좀 더 자세히 알아 보자. 위에서 설명했듯이 하이퍼레저 패브릭에서는 트랜잭션 실행 피어와 트랜잭션 정렬 피어 사이에서 업무를 분담해서 CPU부하(고루틴을 통함)  및 네트웍 부하를 처리한다. 이런 분리된 네트워크에서 확장성,보안성, 일관성 등에 대한 처리를 유연하게 하기 위해 패브릭은  가쉽 데이터 전파 프로토콜 을 만들었다. 

각 가십메세지들은 서명되어서 전달되며, 그에 따라 중간에 악의적인 노드의 메세지도 쉽게 확인되며, 가쉽 프로토콜 특성상 늦게 도착하거나, 몇몇 노드들의 네트워크 분단 상황에서도 결국 싱크는 맞춰지게된다.   

패프릭 네트워크에서 가쉽 데이터 전파 프로토콜  주요 3가지 기능으로는 다음과 같다.

  1. 피어 발견 및 채널 멤버쉽을 관리한다. (이용 가능한 피어들을 계속해서 체크함)
  2. 장부에 기록 할 데이터들을 모든 채널 상의 피어들에 전파.싱크가 안맞는 피어들을 확인하여 모자란 블럭 정보들을 계속해서 공급해줌. 
  3. 새로운 피어가 참여하면 peer to peer 로 장부 데이터들을 업데이트 해줌. 

동일한 채널위의 피어들은 메세지를 계속해서 수신하고,주변 피어에 전파하며, 싱크를 맞추게 된다. 이웃피어의 갯수는 설정으로 정해져 있으며, Pull 메커니즘을 따른다. 따라서 메세지가 올 때 까지 기다리는게 아니라, 적극적으로 가지고 오려는 행동을 한다. 채널 상의 각 조직의 리더 피어는 오더러에게 데이터를 가져(Pull)온 후 자신의 조직에 포함된 피어들에게 전파하기 시작한다.

리더 선출 

다음과 같이 2가지 방식이 있다.

  1. Static – 시스템 관리자는 조직마다 하나의 피어를 설정으로 정한다.

    core.yaml: 파일에서 

    peer: gossip: useLeaderElection: false orgLeader: true

    환경 설정에선 이렇게 하면 core.yaml을 덮어 쓴다. 

    export CORE_PEER_GOSSIP_USELEADERELECTION=false
    export CORE_PEER_GOSSIP_ORGLEADER=true
  2. Dynamic – 리드 선출 프로세스에 따라 결정되는데, 리드 피어가 문제가 생기면 각 피어들은 리드 선출과정에 돌입한다. 리드 선출 프로세스는 피어의 메타데이터에 기반하는데 각 피어가 가지고 있는 ID를 정렬해서 낮은 것이 리드가 되는데,  이 과정에서 여러개의 피어가 자신이 리더라고 주장 할 수 있지만 가장 낮은 이름을 가진 피어가 결국 우선권을 가지며  정해 진 시간 동안 선출이 안되면 그 다음 낮은 피어가 자신이 리더라고 주장 할 수 있게 된다.   좀 더 자세히 -> 요기 

3. 앵커(Anchor) 피어 

앵커 피어는 다른 조직들 간의 네트워크 정보를 가지고 있으며,  Service Discovery에 의해 사용 될 수 있다 즉 클라이언트는 네트워크에 누가 있는지 없어졌는지 등에 관한 상태정보를 알아야 한다. 또한 가쉽 커뮤니케이션을 용이하게 하기 위해 사용된다. 즉 하나의 조직에서 다른 조직에 메세지를 전달 할 때 앵커피어에게 전달한다. 체인코드를 호출 할 때 보증을 맡는 피어가 자신의 조직에만 있는 것은 아니기 않나. 그리고 이 말은 앵커피어는 조직 간 커뮤니케이션에 SPOF도 된다는 의미이다.앵커피어에 대한 정보는 채널 설정에서 정의 되어 있다. 참고로 앵커피어가 리더피어 역할을 해 되도되며, 독립적일 수 도 있다. 

Note

1. 각 피어간의 메세지 보안은 TLS 레이어에 의해 작동하며 서명을 요구하지 않는다. 피어들은 그들의 신원서(CA에 의해 부여된 certificates) 로 인증(authenticated)되며, TLS certs(ECerts를 가지고 TCA에 의해 만들어지는)가 사용될 지라도, 가쉽레이어에서 인증되는 것은 피어신원서이다. 장부블록은 오더러 서비스에 의해 서명되며, 채널의 리더피어들에게 전달된다. 

2. 인증(Authentication)은 피어의 "MSP" 에 의해 조정받는다. 피어가 처음으로 채널상에 접속하게 되면,TLS 세션은 멤버쉽 아이덴터티와 엮이는데, 이것은 기본적으로 각각의 피어를 채널과 네트웍상의 멤버쉽으로 인증하는 것이 된다. 

4. Dissenmination protocol

가십 구성요소는 다음 2개의 모듈로 구성된다.

discovery 모듈 - 활성 상태 및 응답하지 않는 피어 세트 유지

communication모듈 - 연결 유지 및 메시지 배포

discovery 모듈은 통신 모듈을 사용하여 자신의 정보를 보내고, 통신 모듈은 discovery 관련된 메세지를 discovery 모듈에 전달.

discovery 프로토콜 흐름 
각 피어는 생성시 부트스트랩 피어 세트 B를 받는다.
각 피어는 알려진 멤버 집합을 나타내는 <id, endpoint, logical_timeestamp> 의 세트 V응답하지 않는 피어의 유사한 세트 H를 가지고 있으며, V[id]는  ID 요소를 가진 피어의 마지막 활성 메시지를 나타낸다.
메시지는 네트워크 CA에서 발급한 Pub(Priv) 키를 이용하여 암호화된 방식으로 서명(검증)할 수 있다.

discovery 프로토콜 정의 

1) H=BV={}
2) 시작할 때 H의 모든 p에 연결을 시도 하고 성공하면 p를 V에 추가하고 통신 모듈을 업데이트.
3) 
각 p(i) 로 부터 그들이 가지고 있는 V 를 통합하여 자신의 V를 구성. 
4) 
V가 변경된 경우 통신 모듈을 업데이트하여 새로 추가된 모든 피어에 대한 연결을 생성하고 응답하지 않는 피어에 대한 연결을 제거
5) 매 T초 마다 
피어 p는 다른피어들(랜덤이지 않을까)에 자신의 alive 메시지를 전달.메시지에는 다음이 포함된다.  

          P(id), P(endpoint), m (inc_number: P가 돌기 시작한 시간, seq# :각 alive메세지마다 하나씩 증가 )
6) 
discovery 세트 V의 각 p 멤버에 대해, Alive 메시지의 마지막 시간을 추적한다. 받은지 5초가지났다면 
         V세트로부터 그 p를 제거 / H세트에 그 p 추가 / 통신모듈에서 커넥션을 종료 
7) 어떤 
피어 p에서 Alive 메시지 m 을 수신 시:
     - m.id이 V에 없으면 추가 
    - m.timestamp.inc_number > V[id].timestamp.inc_number , m.timestamp.seq# > V[id].timestamp.seq# 면 V에 추가 

Communication 프로토콜 흐름 
원장에 전달되지 않은 메시지에 대한 내부 버퍼 유지
피어에서 수신한 각 메시지에는 확인할 수 있는 ID가 있는데 이 ID는 Alive 메시지인 경우 <m.timeestamp, p.id> 또는 원장 배포 블록인 경우 원장 블록의 해시입니다. 어느 쪽이든 프로토콜 통신 프로토콜은 메시지의 ID를 m.id로 참조합니다. - 각 피어는 이전에 발생한 메시지 ID의 세트 R과 수신 시간을 주기적으로 보유하고 5 초 이상 전에 수신 된 오래된 메시지 아이디를 삭제합니다.

 Communication 프로토콜 정의  1) 시간 t에 피어 p(i)로부터 메시지 m을 수신하면 -> 메시지가 Alive 메시지 인 경우 ->discovery 모듈로 전달 2) 이전에 m.id ID를 받은 경우 (R에서 발견할수있음) 메시지를 삭제 3) 그렇지 않다면    3-1)  <m.id, m.t> 를 R 로 추가 
   3-2)  V로 부터 
k = log (| V |) + 3 개의 무작위 피어를 선택 - 각각의 p(i)가 응답하지 않으면 discovery 모듈을 업데이트하여 p(i) 를 H에 추가 - m 을 무작위 피어 p(i) 들에 전파 (모아 보낼 수도)
4) T 초마다 한 번, V의 각 P에 대해 k = log (| V |) + 3 개의 무작위 응답 피어 세트를 선택하고 4-1) V 전체를 p(i) 들에게 보냄.
   4-2) V(p,i), H(p,i)를 얻어서 V(p,i) , H(p,i) 에 있는 각 p를 V,H에 추가한다. 4-3) Send to p your highest ledger originated message sequence number s for which you received before all m s.t ,i < s 4-4) If you have before received a message m(j) that wasn't passed to the ledger yet such that j>s , send to p a bitmap b of all sequence numbers from s to j , And receive back from p(i) a set of messages M(i) and (optionally) its own s , b 4-5) M의 메시지를 내부적으로 저장 4-6) (Optionally) send back to p(i) a crafted M of your own according to p(i) 's s(i) , b(i) sent 5) 사용자 또는 discovery 모듈로부터 메시지 m을 수신하면 : 5-1) <m.id, m.t>를 R에 추가하십시오. 5-2) k = log (| V |) + 3 개의 랜덤 피어 집합을 선택하고 m을 그들에게 보낸다.

이렇게 정리된 내용을 토대로 다음에는 실제 하이퍼레저 패브릭의 gossip 에 관련된 코드를 분석해 보도록 한다. 언제하냐고? 신이 나면~~

개인적으로 간략하게 구현 해 본 블록전파/가쉽프로토콜 바로가기  



레퍼런스:

https://hyperledger-fabric.readthedocs.io/en/release-1.2/gossip.html
https://github.com/hyperledger/fabric/tree/release-1.2/gossip
https://jira.hyperledger.org/browse/FAB-170


+ Recent posts