블록체인 라이트 클라이언트
블록체인이 정확히 무슨 기능을 하는지 최대한 짧게 설명해달라고 묻는다면 저는 트랜잭션을 영구적으로 기록하여 남기는 방식에 대한 분산된 합의를 제공한다고 말하고 싶습니다. 블록을 생성하는 노드는 사용자들이 성사시키고자하는 트랜잭션들을 모아서 블록을 만들고, 이를 실제 체인에 추가시켜 인센티브를 받으려고 노력합니다. 그렇게 새 블록이 추가되는 것에 합의가 이뤄진다면 그 블록은 체인에 영구적으로 남게 되며 블록 안에 들어있던 트랜잭션도 마찬가지입니다. 이런 과정을 거치고서야 비로소 트랜잭션, 즉 거래가 성사되었다고 볼 수 있습니다.
하지만 블록체인을 통해 토큰 등을 거래하려는 유저들은 실제로 블록을 어떻게 새로 생성하고 합의하는지에 대해 전혀 관심이 없습니다. 단지 자신이 요청한 거래가 실제 체인에 포함됐는지, 자신이나 거래 상대의 계좌 잔액이 얼마인지 등 전체 프로토콜 중 극히 부분적인 정보만 알고 싶어할 뿐입니다. 다행히도 이런 일반 유저들이 알고 싶어하는 정보만 빠르게 검증하는 방법이 가능하며 이를 구현한 것이 ‘라이트 클라이언트’입니다.
앞으로 설명할 내용을 이해하기 위해선 PoW, PoS, 머클증명에 대한 지식이 필요하므로 아직 익숙하지 않은 분들은 저 개념들에 대해 먼저 공부하시길 권장합니다.
목표
블록체인에는 기본적으로 ‘풀 노드’가 존재합니다. 풀 노드는 블록체인에 대한 필요한 정보를 전부 로컬 컴퓨터에 저장하고 그걸 통해 트랜잭션을 수행하고 체인에 새로 들어갈 블록을 제안/검증하는 중요한 역할을 합니다. 풀 노드는 복잡한 자료구조 안에 필요한 트랜잭션/스테이트 등을 가지고 있기에 그 용량이 상당히 크고 트랜잭션을 직접 수행하다보니 연산량도 많습니다.
블록체인을 실생활에서 사용하려면 이런 풀 노드를 항상 구동하고 있어야 한다는 것은 큰 문제입니다. 당장 스마트폰에서 사용하는 것도 불가능하기 때문입니다. 다행인 것은 일반 사용자들이 블록을 검증하진 않는다는 것입니다. 단순히 자신이 관련되어있는 트랜잭션이나 스테이트를 확인해보는 것으로 충분하고, 이 경우에는 풀 노드가 하는 무거운 연산과 디스크 사용이 필요 없을 수도 있습니다. 라이트 클라이언트는 그런 필요 없는 기능을 없앤 대신 훨씬 작은 연산과 사용 용량을 목표로 합니다. 다음과 같이 정리해볼 수 있습니다.
- 클라이언트가 가볍더라도 검증 능력은 같아야 합니다. 즉 암호학적으로 신뢰할 수 있는 방법으로 트랜잭션과 스테이트를 검증하는 것이 가능해야합니다.
- 블록체인의 극히 일부분에 해당하는 정보만 저장하고 있어야 합니다.
- 블록체인의 상태변화, 예컨대 트랜잭션이나 스테이킹 같은 것이 어떻게 일어나는지 알 필요가 없어야 합니다.
- 풀 노드들에게 특정 정보를 요청 할 수 있지만, 그 풀 노드들을 신뢰할 필요는 전혀 없어야 합니다.
블록체인의 구조
한 블록체인을 구성하는 데이터는 헤더, 트랜잭션, 스테이트, 캐쉬 정도로 나눠볼 수 있습니다. 이들을 누적적으로 모은 집합을 생각해보면 각각 고유한 특징이 있습니다.
- 헤더 — 헤더는 ‘체인’을 형성하는 제일 작은 단위의 구조입니다. 헤더에는 이전 블록의 해쉬, 타임스탬프 등의 기본 정보가 들어있고 추가적으로 트랜잭션과 스테이트들에 대한 머클루트가 적혀있습니다. 라이트 클라이언트는 이 헤더와 아주 관련이 깊은데, 결론적으로 말하면 라이트 클라이언트는 헤더를 검증하는 것이 목표입니다. 헤더만 검증하면 머클트리에 있는 모든 정보를 검증할 수 있기 때문입니다. 따라서 라이트 클라이언트는 헤더체인(헤더들의 체인)을 검증/보관하고 있습니다.
- 헤더 + 트랜잭션 — 헤더에 트랜잭션까지 더한 집합은 우리가 말하는 ‘블록체인’ 자체가 됩니다. 블록을 제안하거나 채굴하는 노드들은 ‘블록’을 발표하고 다른 노드들은 그 ‘블록’을 검증합니다. 실제 체인에 쓰여지는 기본단위로서, 이 블록체인 만으로 스테이트를 연역할수 있으므로 네트워크 전체를 표현할 수 있는 최소한의 정보집합이라고 볼 수 있습니다.
- 헤더 + 트랜잭션 + 스테이트 — 여기에 스테이트까지 더한 집합은 헤더로 검증할 수 있는 최대 범위입니다. 프로토콜이 모든 노드가 정확히 같은 값을 가진다는 것을 포말하게 보장해주는 최대 집합이기도 합니다. 풀 노드는 이 정보집합을 가지고 있으며 업데이트합니다. 블록 전체를 검증하는 데 필요한 최소한의 정보이기도 합니다. 따라서 새로 제안된 블록을 검증하고 투표하려면 여기까지의 정보가 필요합니다
- … + 캐쉬 — 여기서부터는 프로토콜과 상관없이 각 노드가 마음대로 가질 수 있는 값입니다. 즉 구현에 따라 달라지는 정보이고, 검증을 해볼 이유도 없으며 해볼 수도 없습니다.
헤더의 검증
위에서 설명한 체인구조를 이해했다면 헤더의 중요성을 알아채셨을 겁니다. 헤더는 머클루트를 가지고 있는 한 트랜잭션과 스테이트를 검증할 수 있기에 헤더만 믿을 수 있다면 사실상 모든 준비가 완료된 것입니다. 그렇다면 헤더를 검증해야 할텐데 별로 어렵지 않습니다.
PoW의 경우에는
- 이전 해쉬, 타임스탬프, 포맷과 같은 기본적인 것을 검증하고
- 헤더에 적힌 논스를 확인해 작업증명을 완료합니다.
트랜잭션이나 스테이트를 확인할 필요가 전혀 없기 때문에 이전 헤더만 가지고 있다면 간단히 검증할 수 있습니다. (체인의 길이에 대한 이야기는 일단 생략하겠습니다)
PoS의 경우에도 간단하지만 해야할 일이 조금 더 있습니다.
- 이전 해쉬, 타임스탬프, 포맷과 같은 기본적인 것을 검증하고
- 위원회 정보를 검증하고
- 투표를 검증하고
- 그 투표들이 지분의 2/3을 넘는지 확인합니다.
PoW와 다르게 스테이트의 일부인 ‘위원회 정보’을 필요로 하지만 여전히 간단하게 확인할 수 있습니다. 다만 이러한 과정만으로 Long range attack를 해결할 수는 없고 이는 풀 노드도 가지고 있는 PoS의 고질적인 문제입니다. 이 글에서는 Long range attack을 고려하지 않습니다.
알고리즘
만약에 라이트 클라이언트가 검증하고 싶은 트랜잭션이나 스테이트가 있다면 검증된 헤더의 머클 루트를 이용해 주변 풀 노드들에게 머클 증명을 요청해 테스트해보는 것으로 충분합니다. 그럼 헤더도 검증해야하고 앞서 설명했듯이 그 절차 자체는 간단하지만, 자세히 읽어보면 헤더 하나를 검증하기 위해 필요한 다른 정보들에 다소 특이한 점이 있습니다. 바로 이전 블록에 의존적이라는 것입니다. 예컨대 ‘이전 해쉬’는 이전 블록의 헤더를 검증해야 알 수 있는 것이고, ‘위원회 정보’는 이전 블록의 스테이트를 검증해야 알 수 있는 것입니다. 그렇다면 내가 관심 있는 헤더를 검증하기 위해 필요한 이전 블록에 대한 정보는 어떻게 검증할까요? 대답은 간단합니다. 똑같은 방법을 이용해 재귀적으로 검증하면 됩니다. 즉 헤더 하나를 검증하기 위한 절차를 귀납적으로 깔끔하게 표현할 수 있으며, PoW, PoS 둘 다 그런 관점에서 각각 설명드리겠습니다.
PoW
PoW의 대표주자인 비트코인은 Simplified Payment Verification(SPV)라는 개념을 소개했습니다. 사실 라이트 클라이언트가 하게 될 일에 이름이 붙은 것 뿐인데요, 비트코인은 특별히 스테이트를 헤더에서 관리하지 않기 때문에 Payment, 즉 트랜잭션을 검증하는 일만 가능하고 이를 특별히 SPV라고 명명했던 것입니다. 물론 이더리움과 같이 스테이트의 머클루트도 헤더에 저장하면 스테이트도 검증할 수 있습니다.
전반적인 알고리즘은 다음과 같습니다.
- 노드가 검증하고 싶은 트랜잭션이 있는 블록의 헤더를 하나 받아옵니다. 이를 H라고 합시다. 자기 주변의 다른 노드들에게 부탁해서 하나 얻어올 수도 있고, 아니면 노드가 로컬 컴퓨터에 갖고 있었으나 아직 검증이 되지 않은 걸 고를 수도 있습니다.
- 만약에 갖고 있는 H가 이미 검증되었다면 6. 으로 갑니다. 검증된 H는 H’라고 합시다. 만약에 H가 제네시스 블록의 헤더거나, 노드가 전에 이미 검증했던 헤더거나, 아니면 믿을 수 있는 노드가 제공한 헤더라면 일어날 수 있는 일입니다.
- H의 직전 헤더를 얻어옵니다. 이를 H_p라고 합시다.
- H_p를 이 모든 과정의 재귀로 검증합니다. 이를 H_p’라고 합시다. 앞서 말씀드렸듯이 라이트 클라이언트의 검증 과정은 귀납적으로 이루어집니다. 내가 최종적으로 관심있는 헤더를 검증하기 위해서는 이전 헤더를 검증해야 하는데 이는 1번-6번까지에 해당하는 루틴을 다시 재귀하면 간단하게 해결됩니다. 이때 베이스케이스는 2.에서 설명되어 있습니다.
- H_p’를 이용하여 H를 검증합니다. 이를 H’라고 합시다. 이전 헤더를 가지고 헤더를 다시 검증하는 방법은 위에서 설명드렸듯이 1. 이전 해쉬를 포함한 헤더의 기본정보를 검증하고 2. 작업증명의 결과인 논스를 검증하면 끝입니다. 이때 ‘이전 해쉬’를 알기 위해 H_p’가 필요했다고 볼 수 있습니다.
- 만약에 노드가 처음 검증하고 싶었던 트랜잭션/스테이트가 포함된 블록의 헤더가 H’라면 7. 으로 갑니다. 즉 여러분은 재귀를 전부 마치고 스택의 맨 위에 있는 것입니다! 만약 그게 아니라면 4.로 재귀를 리턴합니다.
- 노드가 검증하고 싶은 트랜잭션/스테이트를 T라고 합시다. T를 검증한다는 말은 T가 블럭에 실제로 쓰였는지를 알아본다는 뜻입니다. 다행히도 우리는 이미 해당 T가 존재하는 블록의 검증된 헤더 H’를 갖고 있습니다. 마지막 단계에서 T를 검증하기 위해 필요한 머클증명(머클루트로 가는 경로에 존재하는 다른 노드들)을 풀 노드에게 요청해서 받아둡니다.
- 현재 보고 있는 체인이 가장 긴 체인인지 확인합니다. PoW는 가장 길이가 긴 (가장 연산이 많이 들어간) 블록체인에 합의합니다. 라이트 클라이언트가 보고 있는 것은 정확히는 블록체인이 아니라 헤더의 체인이지만 PoW의 원리를 생각해보면 헤더만의 체인을 가장 길게 만드는 것도 블록 전체의 체인을 길게 만드는 것과 동일하게 어렵고 시간이 많이 드는 일입니다. 따라서 체인 헤더의 길이만 확인하면 실제 합의가 이뤄진 가장 긴 블록체인의 헤더들이라고 검증할 수 있습니다.
- 이제 마지막 단계입니다. T와 그 머클증명을 계산하여 H’에 적힌 Merkle root와 같은지 확인합니다.
PoS
PoS의 라이트클라이언트는 PoW보다 다소 복잡합니다. 한 헤더를 검증하기 위해서는 이전 헤더를 검증해야할 뿐만 아니라 이전 스테이트도 검증해야하기 때문입니다.
그림이 다소 복잡하지만 화살표들과 각 구성요소들을 하나하나 살펴보면 이해하기 쉽습니다.
- Header, Transactions, State : 이 글의 초반부에서 설명한 블록체인의 구조에 대응되는 요소들로, PoW와 PoS 둘다 존재합니다.
- Votes : PoS에서 위원(validator)들이 서명하여 넣은 투표를 의미합니다. PoS에서는 지분을 가진 참여자들의 투표로 블록이 확정되기 때문에 이를 확인해야 해당 블록의 검증을 완료할 수 있습니다. 코드체인에서 사용하는 Tendermint 알고리즘에서는 ‘Pre-commit’에 해당합니다. 코드체인은 투표들을 다음 블록의 헤더에 보관하지만 이는 구현 세부사항이고 아래에서 설명할 알고리즘을 보면 저장 위치가 중요하진 않다는 것을 알 수 있습니다.
- Voting behavior : 이때까지의 헤더들에 담겨있는 투표에 대한 누적적인 정보입니다. 위원회(validator set)의 행동을 추상화한 정보집합으로, 실제로 구현체에 존재하진 않을 수도 있습니다. 예를 들어 코드체인에서는 일정기간 투표에 참여하지 않은 위원(validator)을 감옥에 보내버리는데, 이와 같은 정책은 해당 기간 동안의 누적적인 헤더(투표 여부를 담고 있는)로부터 연역하는 상태변화입니다. 다만 신고와 같은 특수한 행위는 여기가 아닌 트랜잭션에 포함될 수도 있습니다.
화살표들의 의미는 다음과 같습니다.
- Previous Hash (보라색) : 블럭 전체의 해쉬를 가지고 있다는 뜻입니다. PoW에서와 같이 헤더를 검증하기 위해 필요합니다.
- Merkle tree (연두색) : 머클트리를 구성하고 그 루트가 적혀있다는 뜻입니다. PoW에서와 같이 헤더를 가지고 검증하고 싶은 정보들은 이러한 연결이 있어야 합니다.
- Proves validness (빨간색) : PoS에서 필요한 추가적인 절차로, 커밋된 블록에 합의해준 위원들의 정보를 검증하기 위해 필요한 의존성을 나타냅니다.
- Deduces (검정색) : 화살표의 입력만으로 화살표의 출력을 완전하게 연역할 수 있다는 것을 의미합니다. 예를 들어 All headers(이때까지의 위원들이 투표를 성실히 했는지에 대한 정보)와 트랜잭션, 이전 스테이트만 있으면 다음 스테이트를 연역할 수 있습니다. 하지만 라이트 클라이언트에서는 이런 연역과정을 전혀 몰라도 상관없는데 왜냐하면 이미 연역된 다음 상태를 풀 노드로 부터 받아 Merkle proof로 검증만 하면 되기 때문입니다. (글 초반부의 라이트 클라이언트의 조건을 잘 생각해보세요!)
정보들의 분류는 다음과 같습니다
- Current Step(마젠타) : 현재 검증하려는 헤더를 의미합니다. PoS의 알고리즘 역시 재귀적이므로 현재 재귀 스텝을 나타낸다고 볼 수도 있습니다.
- You wanna verify these(하늘색) : 노드가 실제로 검증하고자 하는 정보들입니다. 이를 검증하기 위해서는 검증된 머클루트가 있어야 하고, 이는 Current Step에 해당하는 헤더 안에 있습니다.
- You need these(주황색) : ‘Previous Hash’나 ‘Proves validness’를 가진 요소들입니다. 즉 헤더를 검증하기 위해 먼저 검증해야하는 것들입니다.
알고리즘은 다음과 같습니다. PoW 케이스와 비슷한 부분은 설명을 생략했습니다.
- 노드가 검증하고 싶은 트랜잭션이 있는 블록의 헤더를 하나 받아옵니다. 이를 H라고 합시다.
- 만약에 갖고 있는 H가 이미 검증되었다면 9. 으로 갑니다. 검증된 H는 H’라고 합시다.
- H의 직전 헤더를 얻어옵니다. 이를 H_p라고 합시다.
- 이전 스테이트로의 일부인 위원회 정보를 풀 노드로 부터 얻어옵니다. 이를 S_p라고 합시다. 이는 H에 행해진 투표들의 유효성과 지분을 계산하기 위해 필요합니다. 이런 계산에는 단순히 위원들의 목록뿐만 아니라 각자의 위임량, 밴 여부, 투옥 여부 등도 필요할 텐데 그런 것들을 전부 포함한 정보라고 생각합시다.
- H에 대한 투표(Tendermint에서는 pre-commit에 해당)들을 모아옵니다. 이를 C라고 합시다. 투표라는 것은 특정 블록(의 제안)에 대해 이뤄지는 것이고 비밀키로 서명되어 있기 때문에 ‘어떤 위원이 어떤 블록에 대해 투표를 했다’는 위조할 수 없는 사실 그 자체를 나타냅니다. 단순히 공개키와 투표 내용을 가지고 확인만 해보면 바로 검증해 볼 수 있으며, 따라서 어디서 갖고 왔는지조차 중요하지 않습니다. 서명값과 투표원본(혹은 이를 연역할 수 있는 정보), 그리고 투표자의 공개키를 묶어서 C로 본다면 C는 존재 자체로 검증되어 있습니다. 이를 C’라고 합시다. 코드체인의 경우에는 다음 블록헤더에 C를 넣어 놓는데요, 설명했듯이 C는 존재 자체로 검증되므로 단순히 출처에 해당하는 다음 블록헤더는 검증할 필요가 없고 심지어 그 블록이 가짜라도 상관없습니다. (저는 C를 길거리에서 주워와도 된다고 표현하고 싶습니다)
- H_p를 이 모든 과정의 재귀로 검증합니다. 이를 H_p’라고 합시다.
- H_p’로 S_p를 검증합니다. 이를 S_p’라고 합시다. 이는 간단합니다. 헤더에 스테이트 전체에 대한 머클루트가 있으므로 풀 노드에게 머클증명을 얻어와서 확인할 수 있습니다.
- H_p’, S_p’, C’로 H를 검증합니다. 이를 H’라고 합시다. PoW와 마찬가지로 헤더의 기본적인 사항과 이전 해쉬를 확인한 이후에, S_p’와 C’를 조합하여 유효한 위원회의 일원들이 H에 투표 했으며 그 지분을 계산했을 때 전체의 2/3이 넘었음을 검증합니다. 여기서 중요한 점은 체인마다 스테이킹 룰, 예를 들어 언제 밴을하고 언제 감옥에 보내고 위원을 언제 어떻게 선출하는지 등을 아예 몰라도 상관없다는 것입니다. 그런 변화가 모두 적용된 S_p는 이미 풀 노드가 제공했고, 이를 우리가 H_p’를 이용해 검증했기 때문입니다.
- 만약에 노드가 처음 검증하고 싶었던 트랜잭션/스테이트가 포함된 블록의 헤더가 H’라면 10. 으로 갑니다. 만약 그게 아니라면 6.으로 재귀를 리턴합니다.
- 노드가 검증하고 싶은 트랜잭션/스테이트를 T라고 합시다. 마지막 단계에서 T를 검증하기 위해 필요한 머클증명을 풀 노드에게 요청해서 받아둡니다.
- 이제 마지막 단계입니다. T와 그 머클증명을 계산하여 H’에 적힌 머클루트와 같은지 확인합니다.
위 알고리즘에서 고려할 사항이 하나 있는데, 다른 풀 노드가 과거의 스테이트도 얼마나 저장하냐에 따라 최대로 내려갈 수 있는 재귀스텝이 달라진다는 것입니다. 구현체에 따라 쭉 저장할 수도 있고, 일정 블록 이상의 과거는 지워버릴 수도 있습니다. 전자의 경우에는 제네시스 블록까지 가더라도 그 시점의 스테이트를 항상 알려줄 풀 노드들이 있으니 재귀를 끝까지 해도 상관이 없습니다. 반면 후자의 경우에는 풀 노드들이 과거의 스테이트인 S_p를 일정 스텝까지만 저장하고 있으므로 그 범위를 벗어나기 전에 라이트 노드가 예전에 이미 검증했던 S_p'를 만나 재귀를 빠져나와야 합니다. 즉 라이트 클라이언트가 너무 뒤쳐지기 전에 주기적으로 새로운 블록을 자신의 검증된 로컬 헤더체인에 반영할 필요가 있습니다. 모든 풀 노드들이 과거의 스테이트를 바로 지워버리는 최악의 경우에는 라이트 노드가 새로운 블록의 헤더를 한번이라도 놓친다면 다시는 따라잡을 수 없습니다. 재귀를 1번 이상 해야하지만 이에 응해줄 풀 노드가 없기 때문입니다.
최적화
여기까지만 해도 아주 훌륭한 테크닉입니다. 헤더만 알아서 검증하고 나머지는 풀 노드한테 받아와서 머클증명만 확인한다는, 간단하면서 빠르고 가벼운 해결책이기 때문입니다. 그런데 여기서 더 최적화를 할 수 있다면 어떨까요? 전체 과정에서 제일 자원소모가 큰 부분은 아마 헤더를 직접 검증하는 부분일 것입니다. 이는 앞서 보았듯이 앞선 헤더에 대한 재귀를 요구합니다. 적당한 과거의 헤더를 제공해줄 신뢰할 수 있는 노드가 있는지에 따라, 또 내가 예전에 검증해 놓은 헤더가 있는지에 따라 재귀의 깊이는 달라지며 최악의 경우에는 베이스케이스인 Genesis 블록까지 갈 수도 있습니다. 이를 빠르게 스킵하는 것이 최적화의 주된 목표입니다. 이와 관련하여 PoS에서 적용할 수 있는 두 가지 기법을 살펴보겠습니다.
첫 번째는 체크포인트를 만드는 것입니다. 만약 프로토콜 설계상 블록이 자주 생성된다면 매 블록마다 위원회를 바꾸지 말고 한동안 지속되는 기간을 둘 수도 있습니다. 그 지점을 ‘체크포인트’라고 부르고, 체크포인트는 추가적으로 이전 체크포인트의 해쉬와 다음 체크포인트의 위원회 정보를 포함하게 할 수 있습니다. 그렇다면 라이트 클라이언트는 체크포인트 사이를 한번에 뛰어다닐 수 있게 됩니다. 예를 들어 체크포인트가 100블록마다 있고 우리가 관심있는 헤더가 412블록이라면, Genesis 블록으로부터 4번의 체크포인트간 검증을 하여 400번의 체크포인트로 가고, 그 다음 12개의 블록만 한 개 한 개 검증을 하면 총 16번의 검증으로 완료됩니다. 412번 보다는 훨씬 작은 숫자입니다.
두 번째는 내가 이미 검증했던 헤더의 위원회들을 믿고 검증을 스킵하는 방법입니다. PoW는 잘못된 체인에 참여하는 대가가 CPU 연산을 낭비한 것이 전부고 메인 체인에서는 아무런 페널티가 없습니다. 반면 PoS는 잘못된 체인에 참여하면 실제로 메인 체인에서 보증금을 잃게 됩니다. 이 과정에서 신고를 한 유저는 일정 비율의 보상금을 받습니다. 이런 특성은 특이한 최적화를 가능하게 하는데요, 바로 내가 잘못된 블록을 보고 있을 리스크를 그냥 갖고 가는 것입니다.
예를 들어 이미 검증된 헤더 H1가 있고 H2를 검증하고 싶다고 생각해봅시다. H1의 위원회와 H2의 투표한 위원들 사이에 별 차이가 없으면 H2의 실제 위원회 목록을 검사하지 않고 그냥 검증된 것으로 처리할 수 있습니다. H2에 유효한 위원들의 집합을 모르기 때문에 H2에 이뤄진 투표가 유효한 투표인지, 아니면 자격없는 투표인지는 알 수 없습니다. 하지만 만약에 그 투표참여자들이 H1의 위원회와 비슷하다면 (Tendermint 팀에서는 ⅓ 미만의 변화를 기준으로 제안했습니다) H2에 던져진 투표의 대부분이 이미 내가 검증한 H1의 위원들의 것이고, 따라서 실제로 보증금을 냈던 사람들인 것도 알 수 있습니다. (물론 보증금의 보유기간을 따져봐야하는 문제가 있습니다.) 따라서 리스크를 안고 가더라도 정말 틀렸을 경우에 나만 틀린게 아니라 거기에 투표한 대부분의 사람들이 보증금을 잃었을 것이라는 확신을 할 수 있습니다. 물론 운이 좋으면 1등으로 신고해서 보상금을 받을 수다는 보너스도 있습니다. 따라서 속도가 중요하다면 자신을 속이기 위해 모든 사람이 그 보증금을 다 걸진 않았을 거라는 믿음하에 이 최적화를 시행할 수 있습니다.
또한 H1과 H2의 위원회가 차이가 크다면 그 사이에 있는 다른 블록 H3을 골라 이진분할을 해서 징검다리를 놓을 수도 있습니다. 당연히 H1과 H3, 혹은 H3과 H2의 차이가 크다면 재귀적으로 이진분할을 또 시행할 수도 있습니다.
마치며
체인에 새로운 블록을 합의하여 추가하는 것과 별개로 이미 추가된 내용을 검증하는 것은 상당히 중요면서 빈번한 일이며 이를 효율적으로 잘 처리하는 알고리즘은 필수적입니다. 이를 위해 고안된 라이트 클라이언트는 복잡해 보이지만 재귀적으로 헤더를 검증하고 검증된 헤더의 머클루트를 이용해 원하는 트랜잭션/스테이트를 검증한다는 간단한 원리를 가지고 있습니다. PoW와 PoS에 모두 적용가능할 뿐만 아니라 다양한 세부프로토콜에 대해서도 구체적인 최적화가 가능하고, ‘헤더를 검증한다’라는 기능만 분리하여 다른 곳에도 응용할 수 있습니다.
라이트 클라이언트는 IBC에서도 중요한 역할을 합니다. (IBC와 라이트 클라이언트의 관계)
코드체인은 현재 IBC에 참여할 계획을 가지고 있고, 그에 필요한 라이트 클라이언트도 개발중입니다.
감사합니다.
참고자료
https://github.com/tendermint/light-client
https://godoc.org/github.com/tendermint/tendermint/lite
https://blog.ethereum.org/2015/01/10/light-clients-proof-stake/