소프트웨어 아키텍트는 무엇인가? (개나 소나 다 자기 생각이 있는데 대충 끄젹꺼려 봄...) 보통 아키텍트 - 디자인 - 개발로 구성되는데 하이퍼레저 패브릭으로 설명 해 보면 (분야 및 조직규모등에 따라서 달라 질 순 있다)
소프트웨어 아키텍트는 "정체성" 을 확립하고 "균일성" 을 보장하는 롤을 갖는다. 즉 이 소프트웨어는 도대체 뭘 하는 것인가? 각 기업들이 서로 간의 신뢰성을 갖는데 최소의 비용으로 그것을 처리하게 하는게 목적이다. 성능 및 컨트랙트 활용성에 중점을 두고, 보안은 xxx 이상의 수준 이상으로 올리고..유저신원이 discolose 되야하고 플러그인 방식으로 컴포넌트 유연성을 갖추고..등등 이 솔루션이 커져가는데 있어서, 지켜야할 선과 확장되는데 있어서 중구난방하지 않게 사용자들이 혼동하지 않게 균일한 시스템을 보장하며... 그런 역할을 한다.
디자인 은 어떤 개별 컴포넌트가 작동함에 있어서 작동방식과 문제가 될 부분에 대해서 정리해 두는 롤을 갖는다. 즉 카프카 기반 오더러를 예르들면 그것은 어떻게 작동해야 하는가? 블록은 어떻게 만들어지나 (시간, 갯수기반) 채널은 어떻게 만들어 지는가 카프카 특성에 따라서 오더러끼리 통신하지 않고 어떻게 블록을 각자 가지고 있는가 각자 가지고 있는 방식에는 무엇이 있고 어떤 문제가 있는가..어떻게 해결하면 되는가? 하나의 오더러가 다운되면 어떻게 처리 되는가?
개발 은 컴포넌트를 실제 설계/구현한다. 위에 디자인단에서 비지니스로직적 문제해결이라면 여기서는 개발유연성, 성능 및 컴퓨팅 리소스 차원에서의 문제해결에 집중한다. 즉 어떻게 구현하면 가장 좋은가에 대해서 생각하고 설계/개발 해야 한다. 즉 아키텍트-디자인-개발의 모든 레이어에서는 각자 레이어에 맞는 창조적인 생각을 해야 한다. 개발에서는 객체모델 / 객체간의 관계 설정 / 시퀀스 설정 등을 하며, 가장 좋은 자료구조,알고리즘에 대해서도 고민하면서구현에 돌입한다. 어떤 라이브러리, 어떤 버전을 가지고 사용 할 것인가를 결정하고, 위의 디자인단에서 예측해 놓은 Problem과 그것에 따른 solution을 단계별로 구축해 간다. 개발자도 많은 생각을 해야하는 직군이며, 그냥 누가 모든것을 다 결정해 주길 바라며, 단순히 코드로 옮기는 롤이 아니다.
3줄요약
- 아키텍쳐는 크게 상위 아키텍쳐, 하위 아키텍쳐로 구분한다. - 상위 아키텍쳐는 목적에 촛점을 맞춘다. 즉 프로그램의 목표를 분명히 유지하기 위해 고민을 한다. - 하위 아키텍쳐는 구현에 촛점을 맞춘다. 즉 어떻게 구현 할 건지에 대한 고민을 한다.
Improvement 1: Orderer - Seperate transaction header from payload\
- You stated that we should reduce the amount of data sent from Orderer to Kafka by keeping the RWSet at the Orderer and send only the transaction's header to Kafka - This works well when there's only one Orderer, but in case there's multiple Orderers to distribute load, how can the Orderer that made the block retrieves the body of transactions from the other Orderers?
Improvement 2: Orderer - Process transactions in parallel
- We think it's a good idea to distribute transactions into multiple threads inside Orderer as this utilizes hardware more efficiently - However the disruptor pattern (https://lmax-exchange.github.io/disruptor/) maybe faster for this task. What are your thoughts on applying this pattern?
Improvement 3: Peer - Replacing the world state database with a hash table
- As we understood, you wanted to replace LevelDB with a completely in-memory lightweight structure like a hash table. We think this is a good improvement, but it comes with its own problems: - What if the stateDB grows in size to be more than the machine's memory? @There must be a mechanism to save memory to disk, change the hardware and boot up the node a again @Physically upgrade the node in this way cost a lot of time and resources - What if the node goes down suddenly? All data stored in memory would be lost, whereas with LevelDB it would be recovered partly from disk.
Improvement 4: Peer- Store blocks using a cluster
- As we understood, you suggest peers should store files in a Hadoop or Spark cluster - We think this will greatly increase the complexity of the Peer with little benefit, since State DB storage has more impact on TPS than block storage. Do you have any other reason for this suggestion than to increase block write speed?
Improvement 5: Peer - Separate commitment and endorsement
- We agree with splitting committer and endorser into different servers since this will reduce context switching. - We will make the endorser's DB a read-only replica of the committer's State DB as designed after Improvement 3. - This approach comes with committer - endorser synchronization overhead (due to the need to use networking to synchronize states). We think more testing is needed to see if this overhead is worth the benefits.
Improvement 6: Peer - Parallelize validation
- From what we've read, this mean parallelize packet consistency check, signature check an RWSet correctness check. - We see there's a potential for double spending when we process transactions to the same account in parallel. Do you have any solution for this without impacting performance? - Also, concurrent processing comes with context switching overhead, will this be a problem when the system's under load? - We intend to offload signature verification to hardware using FPGA or ASIC, do you think this will result in good improvements in processing speed?
Improvement 7: Peer - Cache marshaled blocks
- We mostly agree with this since this make the cache more versatile and reduce memory allocation. - We will perform benchmark on this to see how much performance improvements can be gained while not increasing the complexity of the system.
Response from U.Waterloo
We found that Kafka got exorbitantly slower for bigger message sizes. That is why we split of the body from the tx header. For multiple orderers, each would need to broadcast their tx bodies to other orderers out of band of Kafka, which we found to be faster in preliminary tests, but we didn’t fully implement the broadcast. Note that this might be obsolete now that Fabric is using Raft.
I’m not very familiar with the disruptor, but it seems to me that this is an orthogonal optimization. Currently, all orderer cores but one are idle, so we definitely need to optimize for concurrent execution. It seems to me that the disruptor is simply managing access to the tx queue. Therefore it would need to be tested if the disruptor is faster than using a go channel for this.
For most reasonable workloads a peer’s memory should be able to store billions of keys in memory. If this is not enough, some paging mechanism would need to be implemented, but we did not address this in our paper. Peers are still writing to disk, they just outsource the task to a secondary storage server. Therefore the latest permeated state could be recovered from there. We did not check if Fabric’s recovery mechanisms still work with the external storage, but it should be “relatively” easy to reroute recovery to the storage server.
We suggest Hadoop or Spark as a possibility to be able to easily do data analytics on the peer backend. However, it is not necessary and in our proof of concept implementation we still use LevelDB (the storage server simply has to catch up to the fast peer whenever it is not running at maximum throughput)
After implementing all our improvements, the throughput was still CPU bound (crypto computations), so we didn’t feel the network overhead yet.
In FastFabric, we only parallelize the crypto verification, RWset correctness validation is still done sequentially to prevent double spending. In our most current work (https://arxiv.org/abs/1906.11229) we add a tx dependency analyzer to be able to parallelize RWset correctness validation for independent txs as well. I think offloading crypto to specialized hardware is the way to go forward to increase performance further.
Using a unmarshalling cache as described in the paper is a workaround for better performance so we didn’t need to completely rewrite Fabric. In our most current implementation, each block is caching it’s own unmarshalled data, so we don’t need a centralized cache anymore (so no potential locking issues with multiple threads reading/writing blocks). Ideally, the unmarshalling would happen directly at the network interfaces and, internally, Fabric would only deal with domain model objects.
* fabric과 Goquorum등 모든 컨소시엄 블렉체인의 사용예에서 어떻게 거버넌스를 이루어서 어떻게 사용했다라는 구체적인 기술 정보 및 비용감소에 대한 결과 정보가 부족해서 아쉽다. (사용 결과에 대한 효율 증가 분석표같은건 기대도 안함)
* 컨소시엄 블록체인을 진짜 컨소시엄을 해서 제대로 합의하고 견제하면서 하려면 Fabric을 사용해야 하는게 좋으며 (기능셋이 많다.) 좀 간략히 사용하려면 quorum이나 Besu중 아무것이나 선택해도 된다. Corda는 최근 거의 사용되지 않는 듯하며, CDBC쪽에서나 소식이 들리는 듯 하다.
* 성능의 경우 체감상 예상외로 Fabric이 빠른데.. (Fabric > GoQuorum > Besu) 전체 구조상으로는 동일 RAFT컨센서스 기준으로 패브릭이 단계가 더 많으므로 (E-O-V) 불리하지만, 이더리움 계열 시스템들은 (besu, quorum) 머클패트리샤트리와 EVM 구조를 그대로 사용하고, Gas가 큰 의미가 없음에도 사용되는 Gas비용계산등 퍼블릭체인의 유산들 때문에 성능 문제가 생겼으리라 생각된다
체크1) Hyperledger Fabric에서는 기본적으로 네트워크에 트랜잭션을 보내는 user 또한 허가받은 사람만 가능하며, 그들의 실체는 X.509로 규정되어진다. 하지만 Qourum , Besu는 그냥 user 는 이더리움과 같은 공개키로 만들어지는 anonymous 이다. Genesis 파일상에서 만들어지는 어카운트들을 이용해서 주로 사용하며, ACL은 스마트컨트랙트에서 관리한다.
체크2) Hyperledger Fabric에서는 ZKP 를 Identity Mixer 모듈을 가져다가 사용한다. 패브릭에서 트랜잭션을 보낼 때 보통 X.509 인증서를 포함해서 보내게 되는데, 여기에는 User의 정보가 모두 노출되어 있다. 선택적으로 노출시키고 트랜잭션 마다의 연계성을 끊기 위해 영지식증명이 사용된다. 결론은 패브릭은 용도에 따라서 선택 할 수 있다. 노출 할 건지, 숨길 건지
체크3) Order → Execute / Validate 모델과 달리 하이퍼레저 패브릭의 EOV(Execute → Order → Validate) 모델은 이는 체인코드 실행시 발생 할 수 있는 다양한 악의적 혹은 비결정적 문제에 대해 Client 와 Validate 시점에 Endorsement Policy에 의해 걸러지게 해 최종적으로 동일한 상태를 보장 할 수 있게 도와준다. 비결정적 문제에 대해 어떻게 제한을 가 할 지는 네트워크 구성원 끼리의 거버넌스에 따라 달라 질 것이다.
3-1) Fabric에서 Endorser로 부터 반환된 R/W Set이 악의적인 결과인지 비결정적인 문제인지는 클라이언트에서 판단 할 수 없다. differentiation 을 auto resolve 할 수 있는 방법도 없다. Avis에서는 Proxy에서 과반이 아닌 Peer에 emergency recovery call 을 보내는 설계를 고려하고 있으나 더 생각을 해 봐야 한다.
3-2) Corda 는 특이하게 피어들끼리 트랜잭션을 먼저 검증한 후에, Notary를 통해 이중지불을 확인 한 후에 최종적으로 양쪽에 커밋된다. (모든 피어들이 커밋정보를 가지고 있는 것과 다르게 관심을 공유하는 피어들 끼리만 공유한다)
체크6) Hyperledger Besu는 Hyperledger 재단의 첫번째 퍼브릭(가능)제품으로써, 합의 알고리즘에 따라서 캐릭터가 달라질 수 있다. 즉 PoA계열 알고리즘을 통해서 엔터프라이즈향에 적합해 질 수도 있다. IBFT2.0 (이스탄불 BFT 2.0)은 GoQuorum의 IBFT1.0을 개선하여 적용하였다.
체크7) 성능에 관해서 제일 궁금 하실 텐데, 사실 패브릭 제외하고는 다양한 설정등에 기반한 성능지표에 대한 자료가 너무 부족하다.
체크8) Besu의 경우 그룹별 프라이빗 원장 공유로 Orion이라는 기술을 이용한다. 패브릭의 채널과 비슷하다고 보면 된다. 사실 Orion은 Qourum에도 적용 될 수 있긴 하다.
체크9) Qourum의 경우 프라이빗 트랜잭션으로 Tessera 를 이용한다. Orion과 Tessera의 차이점은 따로 블로깅 하려한다. 최근에 Besu도 Tessera를 지원하게 됬다.
최근 추가 내용
Hyperledger besu ) - EIP-1559 적용 (가스비 산정 변경, EIP-1559를 포함한 런던하드포크는 8월적용됨) - EthStat 적용
GoQuorum ) - QBFT 추가 - EIP1559랑 무관. 가스비는 여전히 무의미(0) 하며 가스개념은 존재
Hyperledger Besu ans GoQuorum 상호운용성) - 동일한 컨센서스하 (QBFT) 에서 상호운용 가능 개선 - Tessera 를 활용한 Privacy 기능이 이제 양쪽 모두에서 가능
툴 개선) - Web3js-Quorum 새로운(기능보완) web3js 라이브러리로 ConsenSys Quorum node를 좀 더 잘 사용 할 수 있게 한다.
Hyperledger Indy에 대해서 정리해봤습니다. Indy는 변화,발전되고 있으며, 인사이드에 대한 정밀한 조사,검증을 하진 않았기 때문에 참고용으로만 읽어 주십시요. 4년전 처음 이글을 적을 때에는 Indy-SDK가 모든 것(블록체인과 인터페이스, DID,VC를 다루는 공통 함수들, 지갑역할, P2P역할, 익명성 역할) 을 다 담고 있었으나 2023년 3월 현재 Indy-SDK는 다양한 모듈별로 나누어진 버전들이 있습니다. (Aries, Indy-vdr,AnonCreds 등)
개요
Hyperledger Fabric과 Ethereum의 경우 Smart Contract/ChainCode 를 통해서 DID/SSI를 (저장역할을) 실현 할 수 있는 범용 플랫폼인 반면에 Indy는 오직 DID를 구축하고자 하는 상황에 맞춤으로 만들어진 public(사용자) - permissioned (네트워크) 블록체인 플랫폼이며 다음과 같은 특징이 있습니다.
@ Sovrin Foundation (개발조직: Evernym) 에서 제공된 코드 기반의 프로젝트 @ 사용자는 Public 이고 (아무나 사용가능) @ 노드 관리는 Permissioned (선출된 대표노드: 일명 Steward가 Validation / Write 역할을 함) @ ZKP에 기반한 비 노출적 신원 증명 암호학 처리 @ ZKP에 기반한비 연결적 Identity @ 자체적인 합의 시스템이 있다-> RBFT (PBFT에서 View Change 부분을 개선한 버전) @ 자신의 지갑에 개인정보 보관 및 관리 (지갑의 개념이 이더리움,비트코인의 그것보다 넓다. 즉 키 이외의 것도 저장) @ 자체 장부를 가지고 있으며, 신뢰성있게 선출된 분산 장부에 Public 정보들을 저장 / 읽기 한다. @ 보통 Agent라고 부르는 연관 End-Point 간에 암호화 된 연결 후 필요 정보 요청/검증 프로세스 @ 스마트 컨트랙트 기능은 없다.
Indy의 Credential / ZKP기반은 Fabric의 Identity Mixer와 같으며 Camenisch-Lysyanskaya (CL) signature scheme or BBS+ 으로 어떤 속성에 대해서 올바른 서명을 알고있다는 것을 실제 서명 자체를 노출하지 않고도 증명 할 수 있는 방식) Indy의 암호학적 근거에 대해서 더 자세하게 이해 하려면https://www.evernym.com/white-papers/: Evernym 백서인 핵심적인 레퍼런스를 읽어야 합니다.
네트워크 구성
Validate Node validator 노드는 RBFT구현인 Plenum 프로토콜에 의해 작동하며 주로 장부에 기록이 이루어 집니다.
Observer Node 원장의 읽기 전용 사본이며 아래 3가지 역할을 합니다. Read requests: Validate Node의 성능에 영향을 주지 않고 ID 레코드에 대한 수요가 확장될 수 있도록 함. Hot standbys: 기존 Validate Node에서 기술적 문제가 발생할 경우 active Validate Node로 서비스 전환될 수 있음. Push subscriptions: 이벤트 알림을 배포하는 수단을 제공함.
Agent 에이전트는 P2P 메시징 엔드포인트를 제공하여 일반적으로 자체 메시징 엔드포인트를 제공하지 않는 인디 클라이언트의 통신을 용이하게 합니다. Sovrin 에이전트는 다양한 장치에서 작동하는 여러 Sovrin 클라이언트 간에 메시지와 상태를 조정하며 Agent 는 Indy 키체인들의 암호화된 백업을 유지할 수 있고, ID 소유자를 위해 데이터를 단순하게 저장하고 공유할 수 있습니다. Indy에서 이 부분은 Hyperledger aries로 이전되었다.
App (Client) 신원 소유자(백서상 Identity owner 에서 Identity holder로 변경됨)들은 그들의 신원 정보를 Indy클라이언트를 통해 통제하고 관리하는데, Client의 가장 중요한 기능은 Owner의 키 체인을 관리하고 보호하는 것으로 볼 수 있습니다. 쉡게 풀어 무슨얘기냐하면 Indy sdk 클라이언트에 지갑기능이 있고, 그 지갑에 DID관련 키가 저장되어있다는 말
DIDs 와 Verifiable Credential
DID
사용자는 자신의 ID에 대해 기억할만한 이름을 만들어서 원장에 DID 형식으로 변환하여 저장합니다. (당연히 개인키는 자신의 지갑에 분리되어 저장됨) DID는 탈중앙형 식별자로, pure DID는 암호학적 속성을 가지고 있지 않으며 version 4 UUID를 사용하여 유니크하며 원장에 저장되고 원장에서 읽을 수 있습니다.
각 DID는 주어진 네트워크에 특정한 method사양과 연관되어 있으며, DID method는 해당 네트워크에서 DID가 등록, 확인, 업데이트 및 해지되는 방법에 대한 규칙을 지정합니다.
DID Document
DID Docuement에는 주로 해당 DID를 어떻게 검증 할 수 있는지에 대해서 나와있다. DID가 진짜 그 사람의 소유인지를 확인하려면 DID의 쌍인 Private key를 가지고있는지 확인하면 된다. Document에 있는 DID 소유자의 끝점을 통해 테스팅 할 수 있다. 또한 DID의 소유를 확인하기 위해서는 단일소유주 뿐만아니라 다양한 방식으로 테스트 할 수 있는데 예를들어 소유자가 회사의 구성원이라면 회사가 대신해서 검증 해 줄 수 도 있을 것이다.
Verifiable Credential
정체성과 관련된 단일 속성을 Claim이라고 하는데Claim은 한 명의 신분 소유자(사람 또는 조직)가 자신이나 다른 신분 소유자에 대해 제공하는 속성 정보를 말합니다. 예를들어 Claim은 주민등록증 상의 나이를 나타낸다고 생각하면 됩니다. 혹시 Credential하고 헤깔릴수도 있을텐데, 2018년에 Evernym 백서상에서 claim들의 묶음인 claims라는 용어를 credential로 바꿨다고 합니다. 참고로 주민등록상(혹은 운전면허증) 상의 모든 정보를 Verifiable Credential 이라고 하고, 해당 정보 중에 편의점에서 필요로 하는 최소한의 노출 정보(나이겠죠?)를 Verifiable Presentation 이라고 합니다.
Claim(단일속성) -> Credential(단일속성들의 전체합) -> Presentation (노출시키고자 하는 속성만의 합)
DID 말고 CID는?
CIDs는 Cryptographic IDentifiers의 약자로써, pure DID가 단순UUID인것 비해서 공개키,공개키의 해시와 같은 암호학적 특징을 가지고 있으며 제안된 cid-1 스키마는 아래와 같습니다. • The starting value is a 256 bit Ed25519 public key. • This value is then base58Check encoding to produce a 44 character string
먼가 복잡해 보인다면 하나만 기억하세요. DID나 CID나 사용자가 스스로 만든다는 것이며 중앙기관에서 누군가가 만들어 주는 게 아닙니다. 여담이지만 Hyperledger Indy는 SSI는 잘 지켜지지만, DID로써는 조금 약한게 사실입니다. 중앙화는 탈피 했지만 완벽한 분산(탈중앙)은 아니라는 말이데, 작동 가능한 정도의 합리적인 탈중앙성을 보유하고 있다라고 말하고 싶습니다.
Interoperability of Digital Certificates
디지털 인증서는 상호운용성을 보장하는 필수적인 형식인데, X.509는 식별자와 필요한 메타데이터로 암호키를 바인딩하여 공개키 인증서를 정의하는 표준입니다. 이 X.509 인증서는 일반적으로 계층적 PKI 모델에서 작동하는 CA에 의해 배포되는 반면 DID와 DDO는 디지털 아이덴티티가 피어로서 상호 운용될 수 있도록 합니다. 검증 가능한 Credential을 상호 작용, 연결 및 공유할 때 Peers는 필요에 따라 복수의 겹치는 "신뢰의 거미줄"을 형성 하는데 X.509 인증서를 생성하는 데 DID 및 DDO 핵심 자료와 메타데이터를 사용할 수 있으며, X.509 인증서는 DID/DDO 모델과 함께 검증 가능한 Credential으로 사용할 수 있습니다. 이런 식으로 두 모델 모두 서로와 상호작용 될 수 있습니다. (사실 이 부분에 대한 정확한 작동 방식은 아직 분명하진 않습니다. 추후에 보충 설명하겠습니다)
DIDComm
에이전트간의 통신인 DIDComm 및 구현체인 Aries에 대해선 나중에 기회되면 서술합니다. https://identity.foundation/didcomm-messaging/spec/
스토리 라인
대략적인 스토리 라인을 살펴 보겠습니다. (이 스토리라인은 Indy와 Aries을 이용해서 구현 가능합니다.)
Actor
공통) KeyPair 생성 -> Ledger 에 DID 및 DID Document 저장 , 지갑에 Secret key 저장.
@Government : 기본 schema 를 설정하는 역할. (schema란 졸업증명서라든지 재직증명서등의 기본구성요소를 정의해 놓은 것이다.) @Alice: Faber College에 성적표 요청 Acme Corp에 입사신청 (prover 및 credential holder 롤) @Faber College : Alice에게 성적표 발급(credential issuer 롤) @Acme Corp : 지원 서류 중 하나로 지원자에게 학교 성적표 요구 (credential verifer 롤) Alice에게 재직 증명서 발급 (credential issuer 롤)
Step 1. Steward의 Trust Anchor 생성
Steward 는 분산되어 DID 관련 데이터를 블록체인에 저장/읽기 한다. Steward는 참여하는 모든 actor (Trust Anchor) 들을 생성할 수 있고 각 actor마다 적당한 역할을 부여한다.
Step 2. 각자의 DID를 Ledger에 생성
아래 글은 백서(The Technical Foundations of Sovrin) 중 First-Time Provisioning에 나오는데, 새로운 Sovrin ID의 최초 설정 (Provisioning)을 위한 기본 단계는 다음과 같다. (즉 엘리스가 자신의 ID를 만들고 DID를 Ledger에 등록하는 상황)
ID Owner는 먼저 Aries같은 Sovrin 클라이언트(브라우저/스마트폰 혹은 클라우드에 연계된) 를 사용 하여 Trust anchor의 웹서비스나 웹싸이트에 연결 한다. (이때 DID 말고 해당 웹싸이트에서 요구하는 개별적 인증을 사용함)
1.Sovrin 클라이언트(SDK) -> Trust anchor 로 연결 2. Trust anchor -> Sovrin 클라이언트로 챌린지 토큰을 리턴함. 3.Sovrin 클라이언트는 KeyPair 생성 3-1. Sovrin 클라이언트는 Owner의 Sovrin Keychain에 추가 3-2. KeyPair 중 Public(verification) key는 Sovrin identifier를 생성하기 위해 사용됨. 3-3. KeyPair 중 Private (signing) key는 챌린지 토큰을 서명하는데 사용됨. 4. Sovrin 클라이언트 -> Trust Anchor로 서명된 챌린지 토큰 보냄. 5.Trust Anchor 는 챌린지 토큰의 서명을 확인하여 새 키쌍을 인증한 다음 새로운 Sovrin Identifier를 Sovrin Ledger에 등록하는 프로세스 진행 6. Trust Anchor -> Sovrin 클라이언트로 등록에 대한 receipt 메세지와 자신의 private key 서명을 리턴함.