Ethanos — 이더리움 용량을 줄여보자
킹재윤! 킹재윤! 킹재윤!
Title : Ethanos: Efficient Bootstrapping for Full Nodes on Account-based Blockchain
Principal Author : Jae-Yun Kim — Mr. Blockchain of Korea & Korean Vitalik & the Sushi Lover
Keywords : Blockchain, Synchronization, State trie
Accepted at EuroSys 2021필자 주
확장성 문제만큼은 아니지만(뇌피셜) 블록체인, 특히 이더리움의 스토리지 이슈는 블록체인 분야에서 꾸준히 연구가 진행되는 카테고리 중 하나이다. 아무리 최근 SSD가 저렴해졌다고 해도 2021년 4월 현재 (아카이브 노드 기준) 약 7 TB에 육박하는 스토리지 요구사항의 진입장벽은 대단히 높다.본 논문은 미스터 블록체인, 한국의 비탈릭 등 다양한 이명(?)의 보유자이면서 디사이퍼(Decipher)와 본 그룹 CURG의 파운더(founder)인 모 유명인에 의해 작성되었는데, 의외로 이 논문을 국문으로 소개한 자료가 검색되지 않아 이번 글을 통해 아이디어를 소개 (중요)하고자 하였다.
* 논문 소개를 위해 원문을 읽어보는 과정에서 오타를 몇 개 찾아 저자로부터 치킨 기프티콘을 받았다. 역시 인심은 곳간에서 나오는 것 같다.
** 글이 너무 길어지는 것을 방지하기 위해 일부 챕터는 통편집되었다. 절대로 귀찮다거나 해서 넘어가는 것은 아니다 !
Abstract
계정(account) 기반의 블록체인인 이더리움은 그 인기에 힘입어 수많은 계정과 트랜잭션 데이터를 쏟아냈고, 그 결과 일반적인 PC나 스마트폰에서 풀노드(full node)의 부트스트랩(bootstrap)이 어렵게 되었다. 블록의 상태 트리(state trie)에 있는 모든 계정의 상태를 동기화하는 과정에서 심각한 오버헤드가 생기며, 이 용량만 수십 GB에 이른다.
미스터 블록체인은 약 95%의 계정이 휴면 상태라는 점에 착안하여 새로운 상태 최적화 기술을 제안하고 Ethanos(에타노스 or 이타노스)라 명명하셨다. Ethanos는 주기적으로 상태 트리를 비움(emptying)으로써 그 크기를 줄이고, 해당 주기(period)에 작성된 트랜잭션에서 사용되는 활성(active) 계정들만으로 상태 트리를 재구축한다. 이를 위해 이전 주기의 상태 트리의 정보를 활용하며, 이전 주기와 현재 주기의 트리 어느 쪽에도 없는 계정의 경우 복원(restore) 트랜잭션을 통해 그 정보를 복구한다. 이 방법을 통해 각 노드는 가장 최근 주기의 상태 트리만으로 부트스트랩이 가능해진다.
실제 이더리움의 700만 번째 블록부터 30만개 블록에 담긴 트랜잭션을 대상으로, 약 1주의 주기를 적용하여 평가가 진행되었으며, Ethanos가 매우 적은 수의 복원 트랜잭션과 함께 상태 트리의 크기를 크게 축소시킴을 보였다. 이더리움의 상태 트리가 시간이 지남에 따라 지속적으로 증가하는 반면, Ethanos의 경우 이 크기가 수백 MB 정도에 맞춰진다(bounded).
Introduction
계정 기반 시스템인 이더리움은 UTXO 기반인 비트코인과 달리 각 계정의 잔고를 명시적으로 기록한다. 이 계정의 상태를 활용하여 프로그램을 수행하는 스마트 컨트랙트 개발의 수월함 덕분에 계정 기반 모델이 주류가 되었지만, 역으로 이더리움의 인기가 계정 기반 블록체인의 문제점을 드러내었으니, 그것은 계정과 트랜잭션의 폭발적인 증가가 데이터 크기를 어마어마하게 증가시킨다는 점이다(비트코인과 달리 트랜잭션 뿐만 아니라 계정의 상태까지 저장해야 하므로). 이는 제한된 성능의 디바이스 사용자의 풀노드 구축을 어렵게 만들고, 이러한 사람들이 채굴자와 같은 다른 풀노드에 의존하게 한다.
이더리움은 머클 패트리샤 트리(Merkle Patricia Trie, MPT)라고 불리는 데이터 구조를 사용하여 모든 계정 상태를 저장하는데, 제네시스 블록부터 현재 블록까지의 모든 트랜잭션을 수행하여 현재 상태 트리를 생성하는 풀 싱크(full sync)는 매우 긴 시간과 스토리지를 요구한다. 가장 널리 쓰이는 구현체인 Geth 클라이언트에서 제공하는 패스트 싱크(fast sync)의 경우 피봇 블록(pivot block, 현재 블록에서 64번째 이전 블록)의 상태 트리 스냅샷을 받아 그 이후의 트랜잭션을 통해 상태 트리를 완성하지만, 이 경우에도 (2020년 1월 기준) 약 235 GB의 스토리지가 요구되고, 이는 여전히 평범한 클라이언트에게 부담으로 작용한다.
1주일 내지는 1개월 동안 활동이 없는 계정을 휴면 계정이라 하면, 이더리움 계정의 약 95%를 휴면 계정으로 간주할 수 있다. 이 배경으로부터 미스터 블록체인은 휴면 계정을 주기적으로 배제(sweep)하여 상태 트리의 크기를 줄이는 최적화 기법인 Ethanos를 제안하신다. 이 기법을 통해 상태 트리는 각 주기별로 빈 트리에서 시작되어 해당 주기 동안에 활성화된 계정만으로 재구축된다. 특히 현재 주기에서 불가용(unavailable)한 계정이 사용될 때를 대비하여 이전 주기로부터 상태 트리를 캐싱하고, 현재 주기에서 이 트리에 포함된 계정이 사용될 때 이를 현재 상태 트리에 업데이트한다. 현재와 이전 주기의 상태 트리 양 쪽 모두에서 불가용한 계정 정보가 필요할 때는, 해당 계정이 트랜잭션의 sender인 경우 복원 트랜잭션을 제출하여 정보를 확보하고, receiver인 경우 일단 가계정(밑에서 다룰 crumb 계정)을 만들어 사용한 뒤에 원래 계정이 sender로서 필요하게 될 때 복원 트랜잭션을 통해 확보한 오리지널 계정과 병합(merge)한다.
Ethanos
Sweep
주기적으로 휴면 계정을 쳐내는 에폭을 정의하고(원문의 경우 약 1주에 해당하는 40320 블록), 각 에폭의 마지막 블록을 체크포인트라고 부른다. 전체 상태 트리를 탐색해가며 휴면 계정을 찾아 제거하는 것은 비용이 높으므로, 각 에폭이 시작될 때 빈 트리를 만들어 활성 계정으로 채워나가는 방법을 택하는데, 각 에폭의 초기에는 트리가 비어 있어 어떤 계정도 불가용 상태에 있게 되므로, 이전 체크포인트의 상태 트리를 캐싱(즉, 정보를 미리 복사해 놓음)하여 찾고자 하는 계정의 상태를 찾고 필요한 경우 새 트리에 업데이트한다.
Restoration
위 그림에서 현재 트리와 캐싱된 트리 어느쪽에도 존재하지 않는 계정, 가령 a7이라 하면, 이는 휴면 계정이고 이후 트랜잭션의 sender 혹은 receiver가 될 때 재활성화된다. 휴면 계정이 트랜잭션의 sender가 될 경우 복원 트랜잭션을 작성하여 현재 트리에 계정 정보를 확보하게 되고, receiver가 될 경우 crumb 계정이라 부르는 새로운 계정을 생성하여 일단 그 계정에 정보를 저장한다. crumb 계정은 이후 트랜잭션의 sender가 될 때 잔고가 충분하지 않으면 복원 트랜잭션을 통해 기존에 휴면 상태에 있었던 오리지널 계정과 병합된다.
Restore Transaction
복원 트랜잭션은 휴면 계정의 owner에 의해 개시되지만(initiated), 트랜잭션 자체는 owner 대신 아카이브 노드에 의해 생성되고 전파된다.
세 가지 역할군이 있으며 각각 다음과 같다.
- 소유자(owner) : 대상 계정의 마지막 트랜잭션으로부터 두 번의 에폭이 지났는지 체크하거나, 계정이 현재 에폭에서 접근 가능한지 체크하여 계정의 휴면 여부를 결정한다.
- 아카이브 노드(archive node) : owner로부터 요청을 받아 관련 상태 트리에 접근하여 필요한 데이터(1. 복원할 계정이 마지막으로 활성 상태였던 체크포인트의 머클 증명, 2. 1번의 체크포인트로부터 최신 체크포인트 바로 이전까지의 각 체크포인트에 대해서, 복원할 계정의 void proof)들을 수집하여 복원 트랜잭션을 생성한다. 다시 말해서, 복원 트랜잭션은 복원할 계정이 마지막으로 활성 상태였던 체크포인트 이후로 쭉 비활성화 상태였다는 증명을 포함해야 한다. (최신 체크포인트의 void proof를 포함하지 않는 이유는, 이는 캐싱된 상태 트리에서 확인할 수 있기 때문)
- 채굴자, 검증자(miner, verifier) : 복원 트랜잭션이 트랜잭션 풀에 존재할 경우 이를 실행한다.
한 가지 이슈는 마지막으로 활성화되었던 체크포인트와 최신 체크포인트 사이의 텀이 길 수록 void proof의 수가 증가하여 복원 트랜잭션이 비대해진다는 것이고, 이 문제의 해결을 위해 각 체크포인트의 블록헤더에 블룸필터를 저장하면 대상 계정의 존재여부를 효율적으로 체크하여 void proof의 수를 줄일 수 있다. 그럼에도 불구하고, 악의적인 복원을 방지하기 위하여 검증자들은 복원 트랜잭션 수행 시 직접 블룸필터를 통해 void proof가 없는 체크포인트를 재차 확인할 필요가 있다. 또한 복원 트랜잭션이 아카이브 노드에 의해 생성되는 이유는, Ethanos의 풀노드는 최신 체크포인트와 현재 주기의 트랜잭션만으로 부트스트랩하기 때문에 복원 트랜잭션 수행을 위한 데이터가 충분하지 않을 수 있기 때문이다.
Crumb Accounts
Ethanos의 풀노드는 모든 체크포인트의 상태 트리를 갖고 있지 않으므로, 현재 불가용한 계정에 대해 생성하는 계정이 crumb 계정인지(즉, 아카이브노드로부터 오리지널 계정 정보를 가져올 수 있는 실제 휴면 상태의 계정인지) 혹은 아예 새로 만들어지는 계정인지 확인할 방법이 없다. 그렇다고 crumb 계정을 단순히 새로운 계정으로 취급하고 논스를 0으로 설정하면, 해당 계정의 오리지널 계정에서 과거에 실행되었던 트랜잭션의 리플레이 어택이 발생할 수 있다. 따라서 Ethanos는 계정의 초기 논스를 현재 블록 넘버와 평균 블록당 트랜잭션 수를 곱한 값으로 설정하여, 이 값이 과거의 어떠한 논스보다 크게 되도록 한다.
crumb 계정이 있는 어떤 계정을 복원하기 위해서는, 과거에 기록된 오리지널 계정과 (아마도) 다수의 체크포인트에 산재해 있을 crumb 계정들을 병합할 필요가 있다. 따라서 복원 트랜잭션은 대상 계정이 마지막으로 활성화된 체크포인트 뿐만 아니라 해당 계정의 crumb 계정이 있는 모든 체크포인트의 머클 증명을 포함해야 한다. 단, 위 그림 5-(a)처럼 다수의 연속된 체크포인트에 crumb 계정이 있는 경우에는 해당 리스트의 마지막 체크포인트의 crumb 계정만 병합하면 된다.
검증 측면에서 한 가지 이슈가 있는데, 우선 머클 증명 1개를 사용한 복원 트랜잭션(ex. 그림 4)의 경우 마지막으로 활성화된 체크포인트(그림 4의 경우 오른쪽 노란 체크포인트) 이전의 체크포인트로부터 시도되는 복원 트랜잭션은 실패한다는 것을 짚고 넘어갈 필요가 있다. (마지막으로 활성화된 체크포인트의 void proof가 실패할 것이므로)
만약 crumb 계정을 포함한 복원 트랜잭션이 (그림 5-(a)처럼) 2개 이상의 머클 증명, 가령 PM1과 PM2를 포함한다고 가정하면, PM1이 마지막으로 활성화된 계정이고 PM2가 crumb 계정이라고 해석될 것이다. 그런데 만약 PM2가 PM1으로부터 복원된 계정이어서, PM2가 마지막으로 활성화된 계정이고 PM1은 그 이전 시점의 계정이라면, 이는 잘못된 해석이 된다. 이 문제를 해결하기 위해 Ethanos에서는 각 계정의 상태에 1bit의 복원 플래그(restored flag)가 추가되었다. (기본값 0, 계정이 복원될 때 검증자에 의해 1로 설정)
Synchronization
Ethanos는 두 가지 동기화 모드가 있는데, 하나는 이더리움의 풀 싱크와 같은 아카이브 싱크이고, 제네시스 블록부터 모든 블록을 받아 모든 트랜잭션을 실행하여 현재 상태 트리를 생성한다. 다른 하나는 이더리움의 패스트 싱크와 같은 컴팩트 싱크로, 피봇 블록의 상태 트리를 다운받아 그로부터 현재 블록까지의 트랜잭션만 실행하여 현재 상태 트리를 생성한다. 컴팩트 싱크의 경우 최신 체크포인트의 상태 트리도 다운받는데, 이는 캐싱된 상태 트리로 쓰기 위함이고, 제네시스 블록부터 피봇 블록까지의 트랜잭션은 실행하지 않으므로 다운받지 않는 대신 필요한 경우 아카이브 노드에 요청한다.
Evaluation
이더리움 700만 번째 블록부터 730만 번째 블록까지 약 3000만개의 트랜잭션을 대상으로 Ethanos의 평가가 진행되었는데..
Trie nodes 항목을 보면 유의미하게 사이즈가 줄어드는 것 같다. 필자도 본 글의 사이즈를 유의미하게 줄이기 위해 해당 챕터는 편집하려고 한다. 자세한 내용은 앞으로 공개될 원문 최신본에서..
Summary
주기적으로 휴면 계정을 제거하고 활성 계정만으로 상태 트리를 재구성하되, 필요에 따라 휴면 계정을 복원하는 Ethanos를 제안하였다. Ethanos는 상태 트리의 크기를 약 220 MB까지 줄일 수 있으므로, 오래된 트랜잭션과 덜 중요한 블록 헤더를 생략하는 최적화 방법과 결합되면 1 GB보다 적은 데이터로도 부트스트랩이 가능하다. 이는 풀노드와 채굴자의 수를 증가시켜 블록체인의 보안을 개선할 뿐더러 가끔씩 온라인 상태가 되는 유저들도 스스로 풀노드가 될 수 있게 한다. Ethanos는 높은 tps를 목표로 하는 어떠한 상태 기반 블록체인, 심지어 이더리움 2.0에도 적용할 수 있다.
급 마무리
원문 후반부에 있는 Discussion 챕터의 내용(스마트 컨트랙트의 복원에 대해서 & 블록 헤더 크기를 줄이는 것에 대해서)도 쓰려고 했었지만 지금은 안될 것 같다. 필자의 오버헤드 오브헤드가 괜찮아지면 업데이트를 하는 방법도 있을듯.