일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- solidity
- 파이썬
- js
- smart contract
- python
- javascript
- DAPP
- 스마트컨트랙트
- keras
- 주소
- Ethereum
- pythonic
- 레디스
- 비트코인
- 암호화폐
- 개인키
- 마스터링비트코인
- 마스터링 비트코인
- 알고리즘
- 마스터링 이더리움
- 개발
- Redis
- 문자열
- node js
- 공개키
- 솔리디티
- 이더리움
- 블록체인개발
- 블록체인
- 백서
- Today
- Total
개발이야기
[Mastering Bitcoin] 마스터링 비트코인 내 맘대로 정리 - Ch08 본문
Ch 08 - Bitcoin Network
P2P 네트워크 아키텍처
비트코인은 인터넷상에서 PEER TO PEER 네트워크 아키텍처 구조를 이루고 있다. 피어투피어, 즉 P2P라느느 용어는 네트워크에 참여하는 개인은 서로에게 동료이며 모두 동등한 지위를 가지고 있고 ‘’특별한‘ 노드는 존재하지 않으며 모든 노드가 네트워크 서비스를 공급하는 역할을 분담하는 것을 의미한다. 네트워크상의 여러 노드는 서로 ’동등한‘ 토폴로지를 가지면서 그물망 네트워크에서 서로 연결되어 있다. 네트워크내에는 어떠한 서버나 중앙화된 서비스, 위계질서도 존재하지 않는다. P2P 네트워크의 노드는 서비스를 제공하고 동시에 서비스를 이용하며, 네트워크는 본질적으로 회복력이 있고 분산화되어 있으며 개방 체제다. P2P 네트워크는 본질적으로 회복력이 있고 분산화되어 있으며 개방 체제다. P2P 네트워크 아키텍처의 좋은 예는 IP 네트워크상의 노드들이 모두 동등했던 초기 인터넷에서 찾아볼 수 있다. 오늘날의 인터넷 아키텍처는 초기보다는 계층적이지만 인터넷 프로토몰은 여전히 동등한 토폴로지를 유지한다.
비트코인을 제외하고 P2P2기술을 가장 광범위하게 성공시킨 사례는 파일 공유의 선구자이자 비트토렌트의 전신인 냅스터이다.
비트코인의 P2P네트워크 아키텍처는 토폴로지의 선택 그 이상을 의미한다. 비트코인은 설계 측면에서 P2P 체제의 전자화폐 시스템이며 비트코인 네트워크 아키텍처는 이러한 주요 특성을 잘 반영하며 근간으로 삼고 있다. 비트코인 설계의 주요 원리는 분산화된 통제이며, 이는 동등하고 분산화된 P2P합의 네트워크상에서만 시행 및 유지될 수 있다.
‘비트코인 네트워크’라는 용어는 비트코인 P2P 프로토콜을 실행하는 노드의 집합을 말한다. 비트코인 P2P프로토콜 이외에도 스트라텀(Stratum)등의 여러 다른 프로토콜들도 존재하는데, 이들은 라이트웨이트 지갑이나 모바일 지갑에 사용되거나 채굴용으로 사용된다. 이러한 추가적인 프로토콜들은 게이트웨이 라우팅 서버를 통해 제공된다. 이 서버는 비트코인P2P 프로토콜을 이용해서 비트코인 네트워크에 접속한 다음 다른 프로토콜을 실행하는 노드로 해당 네트워크를 확장하는 역할을 한다. 예를 들어 스트라텀 서버는 스트라텀 프로토콜을 통해 스트라텀 채굴 노드와 비트코인 메인 네트워크를 연결하고, 스트라텀 프로토콜과 비트코인 P2P프로토콜을 연결하는 가교 역할을 한다.
‘확장 비트코인 네트워크’란 비트코인 P2P프로토콜, 풀 채굴 프로토콜, 스트라텀 프로토콜 및 비트코인 시스템의 구성요소들을 연결하는 연관 프로토콜 등이 포홤되어 있는 네트워크 전반을 가르킨다.
노드의 유형 및 역할 (Node Types and Roles)
비트코인P2P네트워크 내에 있는 노드들이 서로 동등한 위치에 있다고 할지라도 지원하는 기능에 ᄄᆞ라 각자의 역할은 다르다. 비트코인 노드는 라우팅, 블록체인 데이터베이스, 채굴, 지갑 서비스 등 기능의 집합체이다. 이 네 가지 기능 모두를 보유하고 있는 풀 노드에 대한 그림이 그림 8-1에 나와 있는 풀 노드의 예시에서 라우팅 기능은 ‘네트워크 라우팅 노드‘라는 명칭으로 오렌지색 원으로 표시되어 있다.
그림8-1 지갑,채굴자, 풀 블록체인 데이터페이스, 네트워크 라우팅 등 4개의 기능에 따른 비트코인 네트워크노드
풀 노드라고 불리는 노드는 완전하고 가장 최신의 블록체인 복사본을 가지고 있다.
풀노드는 외부 참조 없이도 독자적이고 신뢰할 수 있는 방법을 통해 어떠한 거래라도 검증할 수 있다. 어떤 노드는 블록체인의 부분집합으로만 유지되기도 하고, 단순지불검증(SPV)이라는 방법을 이용해서 거래를 검증하기도 한다. 이러한 노드를 SPV노드 혹은 라이트웨이트 노드라고 한다. 그림에 나와 있는 풀 노드 예시에서 풀 노드의 블록체인 데이터베이스 기능은 ‘풀 블록체인’이라는 명칭으로 파란색 원으로 표시되어 있다.
그림 8-1에서 파란색 원 없이 그려진 SPV노드들은 블록체인 전체의 복사본을 보유하고 있지 않다는 것을 의미한다.
채굴 노드는 작업증명 알고리즘을 푸는 전용 하드웨어를 실행해서 새로운 블록을 생성하기 위해 경쟁한다. 일부 채굴 노드 역시 풀 노드로 블록체인 전체의 복사본을 보관하고 있는 반면, 일부는 라이트웨이트 노드로 풀 채굴에 참여하고 풀 노드를 유지하기 위해 풀 서버에 의존한다. 이러한 채굴 기능은 ‘채굴자’라는 명칭으로 검정색 원으로 표시되어있다.
사용자들의 지갑은 풀 노드의 일부가 될 수 있는데, 이는 데스크톱 비트코인 클라이언트의 경우에 발생한다. 특히 스마트폰 등 자원 제약이 있는 기기에서 가동되는 점점 더 많은 사용자 지갑들이 SPV노드가 되어 가고 있다. 지갑기능은 그림 8-1에서 ‘지갑’이라는 명칭으로 초록색 원으로 표시되어 있다.
비트코인 P2P 프로토콜상에 있는 주요한 노드 유형들 외에도 전문 채굴 풀 프로토콜과 라이트웨이트 클라이언트 접속 프로토콜 등 기타 프로토콜을 가동하는 서버 및 노드도 존재한다.
그림8-1은 확장 비트코인 네트워크 내에 있는 노드 중 가장 일반적인 형태를 보여준다.
확장 비트코인 네트워크(The Extended Bitcoin Network)
비트코인P2P 프로토콜을 가동하는 주 비트코인 네트워크는 비트코인이의 기본 클라이언트(비트코인 코어)의 다양한 버전을 구동하는 리스닝 노드 5000에서8000개와 BitcoinJ,Libbitcoin,btcd 등 비트코인 P2P프로토콜을 구현한 노드 수백 개로 구성되어 있다. 비트코인 P2P 프로토콜을 구현한 노드 수백 개로 구성되어 있다. 비트코인 P2P 네트워크상에 있는 노드 중 몇몇 노드는 채굴 노드로, 채굴과정에서 경쟁을 하고 거래의 유효성을 검증하고 새로운 블록을 생성한다. 대기업 중 많은 수가 비트코인 코어라는 클라이언트를 기반으로 하는 풀 노드 클라이언트를 가동함으로써 비트코인 네트워크에 연결되어 있다. 이 경우, 블록체인 전체의 복사본과 네트워크 노드는 있지만 채굴이나 지갑 기능은 없다. 이러한 노드들은 네트워크 에지 라우터 역할을 하기 때문에 다양한 서비스(환전,지갑,블록탐사,상거래 등)가 가능하도록 해준다.
확장 비트코인 네트워크에는 이전에도 언급했듯이 비트코인 P2P프로토콜을 가동하는 넽워크가 포함되어 있을 뿐 아니라 특수한 프로토콜을 가동하는 노드도 포함되어 있다. 메인 비트코인 P2P 네트워크에는 수많은 풀 서버와 기타 프로토콜을 가동하는 노드들을 연결시키는 프로토콜 게이트웨이가 붙어 있다. 이러한 프로토콜 노드들은 대대 풀 채굴 노드와 라이트웨이트 지갑 클라이언트로 블록체인 전체의 복사본을 가지고 있지않다.
그림8-2 확장 비트코인 네트워크상에 있는 다양한 유형의 노드들
그림8-3 다양한 노드 유형, 게이트웨이,프로토콜을 보여 주는 확장 비트코인 네트워크
그림8-2는 다양한 형태의 노드, 게이트웨이 서버, 에지 라우터, 지갑 클라이언트가 들어 있는 확장 비트코인 네트워크와 이 유형들을 서로 연결시키는 데 사용되는 다양한 프로토콜에 대해서 나와 있다.
비트코인 릴레이 네트워크(Bitcoin Relay Networks)
비트코인 P2P 네트워크는 다양한 노드 유형의 일반적인 요구를 충족하지만, 비트코인 마이닝 노드의 특수한 요구에 비해 네트워크 지연 시간이 너무 높습니다.
비트코인 채굴자들은 근로증명서 문제를 해결하고 블록체인을 확장하기 위해 시간 경쟁을 벌이고 있다(10장 참조). 비트코인 채굴자들은 시간을 최소하해야한다. 네트워크
지연 시간은 이익 마진과 직접 관련이 있다.
비트코인 릴레이 네트워크는 채굴자 간 블록 전송의 지연 시간을 최소화하려는 네트워크이다. 최초의 비트코인 릴레이 네트워크는 매우 짧은 대기 시간으로 광부들 사이의 블록을 빠르게 동기화할 수 있도록 핵심 개발자인 Matt Corallo에 의해 2015년에 만들어졌다. 이 네트워크는 전 세계의 Amazon Web Services 인프라에서 호스팅되는 여러 가지 전문 노드로 구성되었으며 대부분의 채굴자와 마이닝 풀을 연결하는 데 사용되었다.
원래의 비트코인 릴레이 네트워크는 2016년에 핵심 개발자 Matt Corallo가 제작한 FIBRE(Fast Internet Bitcoin Relay Engine)를 도입하여 대체되었다.
FIBRE는 노드 네트워크 내에서 블록을 릴레이하는 UDP 기반 릴레이 네트워크이다. FIBRE는 콤팩트 블록 최적화를 구현하여 전송되는 데이터 양과 네트워크 대기 시간을 더욱 줄인다. 코넬 대학 연구 결과를 토대로 한 또 다른 릴레이 네트워크(아직 제안 단계)는 Falcon이다. Falcon은 "store-and-forward" 대신 "cut-through-rout"을 사용하여 블록이 수신되는 부분을 대기하는 대신 전파함으로써 지연 시간을 줄인다.
완전한 블록을 받을 때까지. 릴레이 네트워크는 비트코인의 P2P 네트워크를 대체하는 것이 아니다. 대신, 특수한 요구가 있는 노드 간에 추가 연결을 제공하는 오버레이 네트워크입니다. 마치 고속도로가 시골길의 대체물이 아니라 교통량이 많은 두 지점 사이의 지름길처럼, 고속도로에 연결하기 위해 작은 길이 여전히 필요한것과 동일하다고 볼 수 있다.
네트워크 검색(Network Discovery)
새로운 노드를 작동시킬 때는 반드시 네트워크상에 존재하는 다른 비트코인 노드들을 검색해야만 네트워크에 참여할 수 있게 된다. 이러한 프로세스를 시작하기 위해서 새로운 노드는 기존에 네트워크상에 존재하는 노드를 최소 한 개는 검색해서 연결해야한다. 다른 노드들의 지리적 위치는 중요하지 않다. 왜냐하면 비트코인 네트워크의 토폴로지는 지리학적인 위치를 근거로 규정된 것은 아니기 때문이다. 따라서 기존의 비트코인 노드 중 어떤 것이라도 무작위로 선택될 수 있다.
이미 알고 있는 이웃 노드에 연결하기 위해 각 노드는 일반적으로 포트 8333번(보통 비트코인이 사용하는 포트로 알려짐)으로 TCP 커넥션을 연결하거나 누군가가 제공하는 경우 대안 포트로 연결한다. 연결이 되자마자 해당 노드는version메시지를 전송하면서‘핸드셰이크(8-4참조)’를 시작할 것이다. 메시지에는 기본적인 식별 정보가 담겨 있으며, 종류는 다음과 같다.
nVersion
클라이언트가 ‘구사하는’ 비트코인P2P 프로토콜 버전을 규정하는 상수 (예, 70002)
nLocalServices
노드가 지원하는 로컬 서비스 목록, 현재는 NODE_NETWORK
nTime
현재시간
addrYou
원격노드의 IP주소
addrMe
로컬노드의 IP주소
subver
로컬노드에서 구동하는 소프트웨어의 버전 (예 /Satoshi:0.9.2.1/)
BestHeight
로컬노드가 알고 있는 블록체인의 블록 높이
(version네트워크 메시지의 예시를 보기 위해서는 GitHub 참조)
이웃노드는 연결 요청을 승인할 경우 verack 메시지로 응답한다,또한, 양방향 연결요청을 원할 경우 version메시지를 보내 이웃 노드와의 연결을 다시 실시한다.
그렇다면 새로운 노드는 어떻게 이웃 노드를 검색할 수 있을까? 비트코인 내에 특별한 기능을 하는 노드가 없다고 해도 종자노드(seed node)로 클라이언트 목록에 기록되어 있는 노드들이 있는데, 이들은 오랜 기간 동안 안정되게 동작하고 있는 노드들이다. 새로운 노드가 종자노드와 연결되어 있을 필요는 없지만 종자노드를 사용해서 신속하게 네트워크 내 다른 노드를 검색할 수 는 있다. 비트코인 코어 클라이언트에서 종자노드 사용 여부에 대한 옵션은 옵션 스위치인 –dnsseed로 조정한다. 옵션 스위치가 1로 설정되어 있으면 디폴트 값에 의해서 종자노드를 사용하게 된다. 종자노드를 사용하지 않는 경우, 해당 네트워크에 대한 정보가 없는 부트스트래핑 노드는 한 개 이상의 비트코인 노드 IP주소를 받아야만 하며, 그 후, 더 많은 노드들과 연결하게 된다. 명령행 인수인 –seednode는 최초 연결을 위해 한 개의 노드와 연결하는 데 사용될 수 있으며, 해당 노드를 DNS종자로 사용한다. 최초 종자노드가 최초 연결을 생성하는 데 사용된 후에 해당 클라이언트는 종자노드와의 연결을 끊고 새로 검색된 이웃 노드를 사용한다.
하나 이상의 연결이 성립되고 나면 새로운 노드는 자신의 IP주소가 담겨 있는 addr메시지를 이웃 노드들에게 전송한다. 차례로 이웃 노드들은 전송 받은 addr메시지를 그들의 이웃 노드들에게 전송함으로써 새롭게 연결된 노드가 더 잘 알려지고 더 잘 연결되게 한다. 또한 새롭게 연결된 노드는 getaddr 세시지를 이웃들에게 보내서 다른 이웃노드들의 IP주소목록을 다시 전송해 줄 것을 요청한다. 이러한 방식을 통해 노드는 자신과 연결되어 있는 이웃 노드를 검색할 수 있고 다른 노드들이 자신을 검색할 수 있도록 자신의 존재를 네트워크상에 홍보할 수 있게된다. 그림 8-5는 주소 검색 프로토콜이다.
노드는 비트코인 네트워크로 들어가는 경로를 다양하게 만들어 놓기 위해서 여러 다른 이웃노드에 접속해야 한다. 노드가 드나드는 경로는 항상 끊어질 수도 있기 때문에 해당 노드가 경로를 잃어버리게 되면 새로운 노드를 계속해서 검색해야 할 뿐만 아니라 다른 노드들이 부트스트랩을 요청할 경우에는 다른 노드를 도와야한다. 부트스랩을 위해서는 한 노드와의 연결만 있으면 된다. 왜냐하면 첫 번째노드가 이웃 노드들에게 새로운 노드를 소개할 수 있고 그의 이웃노드들도 더 많은 새로운 노드를 소개 할 수 있기 때문이다. 또한 몇 개 이상의 노드에 접속하는 것은 불필요하며 네트워크 자원의 낭비이기도 하다. 부트스트래핑 이후에 노드는 가장 최근에 성공했던 이웃 노드와의 연결을 기억하고 있을 것이다. 이는 노드가 재부팅되는 경우 이전의 이웃 네트워크에 신속하게 다시 연결하기 위함이다. 이전 이웃 노드들 중 연결 요청에 대한 응답이 없는 경우에는 해당 노드가 다시 부트스트랩을 이용하기 위해서 종자노드를 사용 할 수 있다.
비트코인 코어 클라이언트를 실행하고 있는 노드상에서 여러분은 명령어 getpeerinfo를 이용해서 이웃노드들의 연결목록을 볼 수 있다.
이웃노드들의 자종관리를 중단하고 원하는 IP 주소 목록을 명시하기 위해서 사용자들은 옵션으로 –connect=<IPAddresss>를 사용하여 하나 이상의 IP주소를 명시할 수 있다. 이 옵션이 사용되는 경우, 자동적으로 이웃 노드의 연결을 검색하고 유지하는 대신 해당 노드가 선택된 IP주소로만 연결된다.
연결된 상태에서 트래픽이 없는 경우, 노드들은 연결을 유지하기 위한 메시지를 주기적으로 발송한다. 노드에서 90분 이상 트래픽이 없다면 연결이 끊어진 것으로 간주 하고 새로운 이웃 노드를 찾게 될 것이다. 따라서 네트워크는 일시적으로 생성된 노드와 네트워크 문제에 동적으로 적응하며, 어떠한 중앙 토제 없이도 필요에 따라 유기적으로 크기가 커지거나 작아질 수 있다.
풀 노드(FULL NODE)
풀 노드란 모든 거래가 담겨 있는 풀 블록체인을 유지하는 노드를 말한다. 좀 더 정확하게 말하자면 아마 ‘풀 블록체인 노드(full blockchain node)’라고 불러야 할 것이다. 비트코인 초창기 때 모든 노드는 풀 노드였으며 현재 비트코인 코어 클라이언트가 풀 블록체인 노드이다. 하지만 지난 2년 동안 새로운 형태의 비트코인 클라이언트들이 도입되었다. 이들은 풀 블록체인을 유지하지 않고 라이트웨이트 클라이언트로 가동된다. 다음 섹션에서 좀 더 상세히 다룰 것이다.
풀 블록체인 노드들은 모든 거래가 담겨 있는 비트코인 블록체인의 최신 완성본을 보관하고 있다. 풀 블록체인 노드는 제일 첫 블록(최초블록[제네시스블록])부터 시작해서 가장 최근에 알려진 네트워크 내의 블록ᄁᆞ지 독립적으로 거래를 구성하고 검증한다. 풀 블록체인 노드는 독립적이고 신뢰할 만한 방법을 통해 다른 노드들이나 정보 소스에 의존 없이 djEJᅟᅡᆫ 거래도 검증할 수 있다.
풀 블록체인 노드를 가동함으로써 여러분은 비트코인의 이론적 개념을 직접 경험할 수 있을 것이다. 즉, 다른 시스템에 대한 의존이나 신뢰 없이 모든 거래에 대해 독립적으로 검증하는 방식을 보게 될 것이다. 풀 노드 의 시행 여부는 알아내기 쉽다. 왜냐하면 풀 노드를 시행하게 되면 풀 블록체인을 저장하기 위해 20기가바이트 이상의 영구 저장 영역(디스크 공간)이 필요하기 때문이다. 많은 디스크가 필요하고 네트워크와 동기화하는 데 2~3일이 걸린다면 풀 노드를 실행하고 있는 것이다. 이는 중앙 통제로부터 완전한 독립과 자유를 보장받는 것에 대한 대가다.
풀 블록체인 비트코인 클라이언트 구현에 대한 몇 가지 대안이 있는데, 이는 다른 프로그래밍 언어나 소프트웨어 아키텍처를 사용하는 것이다. 하지만 가장 흔하게 사용 되는 구현은 기본 클라이언트인 비트코인 코어이며, 사토시 클라이언트도 알려져 있다. 비트코인 네트워크상에 존재하는 노드의 90% 이상이 다양한 버전의 비트코인 코어를 가동한다. 앞서 설명한 대로 비트코인 코어는 version 메시지 내에서 전송되고 명령어 getpeerinfo를 사용해서 나타나는 하부 버전 문자열 내에서 ‘Satoshi’로 표현한다. .Satoshi:0.8.6/가 그 예이다.
‘인벤토리’교환하기
풀 노드가 이웃 노드에 연결되고 난 후 가장 먼저 하는 작업은 완전한 블록체인을 만드는 일이다. 새로 생성된 노드라서 블록체인을 전혀 보유하고 있지 않은 경우 해당 노드는 단 하나의 블록만을 알고 있다. 바로 최초블록이다. 최초블록은(제네시스블록)최초블록은 클라이언트 소프트웨어에 변경 불가능하게 내장되어 있다. 블록 #0(최초블록)으로 시작하는 새 노드는 네트워크와 동기화하고 풀 블록체인을 다시 생성하기 위해서 수십만 개의 블록을 다운로드해야 할 것이다.
블록체인을 동기화하는 프로세스는 version메시지로 시작한다. 왜냐하면 이 메시지가 노드의 현재 블록체인 높이(블록의 개수)를 알 수 있는 BestHeight를 담고 있기 때문이다. 노드는 이웃들로부터 전송받은 version메시지로 시작한다. 왜냐하면 이 메시지가 노드의 현재 블록체인 높이(블록의 개수)를 알 수 있는 BestHeight를 담고 있기 때문이다. 노드는 이웃들로부터 전송받은 version메시지를 보고 이웃 노드 각각이 몇 개의 블록을 보유하고 있는지를 알아보고 자신의 블록체인 내에 담겨 있는 블록의 개수 와 비교할 수 있다. 이웃 노드끼리는 로컬블록체인상에 있는 상부 블록의 해시(지문)을 담고 있는 getblocks 메시지를 교환할 것이다. 이웃 노드들 중 하나가 전송받은 해시가 상부 블록이 아닌 이전에 생성된 블록에 속해 있다고 확인할 수 있다. 이를 통해 자신의 로컬 블록체인이 이웃 노드의 것보다 길다는 사실을 추론할 수 있다.
길이가 좀 더 긴 블록체인을 가지고 있는 이웃 노드는 그렇지 않은 노드보다 더 많은 블록을 보유하고 있으며 이웃노드를 ‘따라잡기’ 위해 상대 노드가 어떤 블록을 필 요로 하는지 확인 할 수 있다. 해당 노드는 inv(인벤토리)메시지를 이용해서 해시를 공유하고 전송하기 위한 첫 500개 블록을 확인할 것이다. 해당 블록을 가지고 있지 않은 노드는 일련의 getdata 메시지를 전송하여 풀 블록의 데이터를 이웃노드에 요구하고 inv메시지에 있는 해시값을 이용하여 수신받은 블록 데이터가 정확한디를 확인하여 블록체인을 만들어 나간다.
예를 들어, 어ᄄᅠᆫ 노드가 최초블록만 보유하고 있다고 가정해보자. 이 노드는 체인내에서 최초블록 이후에 생성될 500개의 블록에 대한 해시를 담고 있는 inv 메시지를 이웃 노드들로부터 받게 될 것이다. 이 메시지를 통해 연결된 이웃 노드들에게 블록을 요청하고 부하(load)를 전파하며 요청 때문에 어떠한 이웃 노드도 곤란한 상황에 빠뜨리지 않겠다는 확신을 준다. 해당 노드는 이웃노드 간 연결마다 몇 개의 블록들이 ‘전송중(요청은 했지만 전송받지 못한 블록)’에 있는지를 파악해서 그 개수가 한도(MAX_BLOCKS_IN_TRANSIT_PER-PEER)를 초과하지 않도록 확인한다. 많은 블록을 다운받아야 하는 경우 이러한 방법을 이용하여 이전 요청이 완료된 후에 새로운 요청을 실시하여 이웃 노드들에게 업데이트 속도를 조절할 수 있게 해 주고 또한 네트워크에 과부하가 생기지 않도록 한다. 각 블록이 전송되면 이는 블록체인에 포함되는데, 이 내용은 9장에서 살펴볼 것이다. 로컬 블록체인이 점차적으로 쌓이게 되면 요청을 받아 전송받는 블록의 개수가 증가하게 되며, 이러한 프로세스는 해당 노드가 비트코인 네트워크의 다른 노드들을 따라잡을 때까지 지속된다.
로컬 블록체인과 이웃노드를 비교하고 잃어버린 블록에 대해 검색하는 프로세스는 노드가 일정 시간 동안 오프라인 상태에 있을 때에도 발생한다. 노드가 몇 분 동안 오프라인 상태에 있으면서 블록 몇 개를 잃어버리든지 아니면 한 달 동안 오프라인 상태에 있으면서 수천 개의 블록을 잃어버리든지 간에 getblock 메시지를 보내는 것을 시작으로 inv 응답을 얻고 잃어버린 블록을 다운로드하기 시작한다. 그림 8-6은 인벤토리와 블록전파 프로토콜을 보여준다.
그림8-6 이웃노드로부터 블록을 검색해서 블록체인을 동기화하는 노드
단순지불검증(SPV)노드
모든 노드가 다 풀 블록체인을 저장하는 기낭이 있는 것은 아니다. 많은 수의 비트코인 클라이언트가 스마트폰이나 태블릿, 내장형 시스템 등 공간 제약이 있거나 전력 제한이 있는 기기에서 가동되도록 설계되어 있다. 내장형 시스템 등 공간 제약이 있거나 전력 제한이 있는 기기에서 가동되도록 설계되어 있다. 이러한 기기에서는 단순지불검증(SPV)방법을 이용해서 풀 블록체인을 저장하지 않고도 운영이 되도록 하고 있다. 이러한 유형의 클라이언트를 SPV클라이언트 혹은 라이트웨이트 클라이언트라고 한다. 비트코인의 채택이 급속도로 증가하면서 SPV 노드가 비트코인 노드 특히 비트코인 지갑에서 가장 흔한 형태가 되고 있다.
SPV 노드는 블록 헤더만 다운로드하고 각 블록에 들어 있는 거래들은 다운로드하지 않는다. 거래 내용이 없는 블록체인은 풀 블록체인보다 1000배 작다. SPV 노드가 네트워크상의 거래 전부에 대해 잘 알지 못하기 때문에 소비할 수 있는 UTXO 전부에 대한 큰 그림을 그릴 수는 없다. SPV 노드는 이웃 노드들에게 의지하는 조금 다른 방법을 이용해 거래를 검증한다. 이 방법은 요청된 블록체인의 필요한 부분들만을 보여주는 방식으로 진행된다.
비유를 하자면 풀노드는 낯선 도시에 있는 여행객이 거리와 주소 전부가 표시되어 있는 상세 지도를 들고 있는 상황이라고 할 수 있다. 그에 비해 SPV노드는 낯선 도시에 있는 여행객이 방향을 바꿀 때마다 아무에게나 길을 물어보는 상황이다. 두명의 여행객 모두 방문을 통해 거리의 존재를 검증할 수는 있지만 지도를 가지고 있지 않은 여행객은 어떤 골목의 위치나 다른 길의 존재 여부를 알 수 없다.23Church Street 앞에서 서있는 관광객이 지도를 가지고 있지 않다면 이 도시 내에서 ‘23Church Street’의 주소가 여러개 더 있는데 지금 이 위치가 본인이 원하는 주소의 위치인지 알 수가 없다. 지도가 없는 관광객이 누릴 수 있는 최괴의 행운은 되도록 많은 사람에게 물어볼 기회가 주어지고 행인 중 누군가가 그에게 강도짓을 하지 않기를 바랄 뿐이다.
단순지불검증은 블록체인 내에서 해당 블록의 높이 대신 깊이를 참조해서 거래를 검증한다. 풀 블록체인 노드가 (시간적으로) 최초블록까지 연결된 수천 개의 블록과 거래내용을 검증하여 체인을 생성하는 반면, SPV노드는 모든 블록의 체인을 검증하고(거래를 검증하는 것은 아님),확인하고자 하는 거래를 체인에 연결하는 방식을 사용한다. 예를 들면 ,300,000번째 블록의 거래를 검사하는 풀 노드의 경우는 300,000개 블록모두를 최초블록까지 연결시켜 UTXO의 풀 데이터베이스를 생성해서 해당 UTXO가 소비되지 않은 채 존재한다는 사실을 확인함으로써 해당 거래의 유효성을 검사한다. 하지만 SPV노드는 해당 UTXO의 소비 여부는 검증할 수 없다. 대신 머클경로(merkle path)를 이용하여 해당 거래와 그 거래가 담겨 있는 블록을 연결하게 된다. 그 후, SPV 노드는 300,001번째 블록부터 300,006번째 블록까지 6개의 블록이 해당 거래가 담겨 있는 블록 상부에 쌓였는지 확인하고 블록의 깊이가 6에 이르면 해당 거래를 검증한다.네트워크상에 있는 다른 노드가 300,000번째 블록을 승인 한 후 이 블록 위에 올라갈 6개의 블록을 더 만들기 위해 필요한 작업을 시행했다는 사실은 해당 거래가 이중지불 거래가 아니었다는 점을 대신 말해준다.
거래가 실제로 존재하지 않는 경우에도 거래가 블록 내에 존재한다고 SPV 노드를 속일 수 없다. SPV 노드는 머클 경로 증명을 요청하고 블록의 체인에 있는 작업증명의 유효성을 검증하는 방법으로 블록상에 해당 거래의 존재 여부를 확인한다. 하지만 거래의 존재 유무는 SPV노드에게 ‘숨길’ 수 있다. SPV 노드는 거래의 존재 여부는 확인 할 수 있지만 거래를 검증할 수 는 없다.왜냐하면 SPV노드에는 거래 전부에 대한 기록이 없기 때문이다. 서비스거부(DOS) 공격 혹은 SPV노드에 대한 이중지불 공격 시 이러한 취약성을 악용할 수 있다. 방어를 위해서는 SPV 노드가 여러 노드에 무작위로 연결되어 적어도 하나의 정직한 노드와 연결될 가능성을 높이는 수 밖에 없다. 무작위 연결에 대한 필요성이 의미하는 바는 SPV 노드가 네트워크 분할 공격이나 시빌(Sybil) 공격에도 취약하다는 것이다. 이러한 공격을 받으면 SPV노드는 가짜노드나 가짜 네트워크에만 연결되어 정직한 노드 혹은 실제 비트코인 네트워크에 접근하지 못하게된다.
대부분의 경우에 잘 연결된 SPV노드들은 충분히 안전하며 자원에 대한 필요성, 실용성, 보안 사이에서 균형을 잘 유지한다. 하지만 확실한 보안을 위해서는 풀 블록체인 노드를 가동하는 방법이 제일 효과적이다.
풀 블록체인 노드는 UTXO가 소비되지 않았다는 사실을 확인하기 위해 노드 아래에 있는 수천 개의 블록으로 구성된 체인 전체를 체크해서 거래를 검증하지만,SPV노드는 노드 위에 있는 몇 개의 블록을 가지고 해당 블록이 묻혀 있는 깊이가 어떻게 되는지 확인한다.
블록헤더를 얻기 위해서 SPV노드는 getblocks메시지 대신에 getheaders메시지를 사용한다. 이 SPV 노드에 대응하는 이웃 노든 단일 headers 메시지를 이용해서 최대 2,000개의 블록 헤더를 전송할 것이다. 이 경우를 제외하고, 이 프로세스는 풀 블록을 검색하기 위해 풀 노드가 사용하는 프로세스와 동일하다. 또한 SPV노드는 이웃노드들과의 연결되는 부분에 필터를 두어서 이웃 노드가 전송할 미래의 블록 및 거래들(stream)을 필터링 한다. 원하는 djEJᅟᅡᆫ 거래 내용도 getdata요청에 의해서 검색된다. 이웃 노드는 그에 대한 응답으로 거래가 담겨 있는 tx 메시지를 생성한다. 그림 8-7은 블록 헤더들의 동기화 과정을 보여준다.
SPV노드는 선택적으로 특정 거래를 검증하기 위해서 해당 거래를 검색해야 하기 때문에 프라이버시가 노출될 위험 요소를 가지고 있다. 각 블록 내에서 모든 거래를 수집하는 풀 블록체인 노드와는 달리 SPV 노드가 특정데이터에 대해 요청할 경우 자신들의 지갑 내에 있는 주소가 의도하지 않게 노출될 수 있다. 예를 들어 네트워크를 모니터링하는 제 3자가 SPV노드상에 있는 지갑이 요청한 거래 전부를 추적할 수도 있고 해당 거래를 이용해서 비트코인 주소와 지갑 사용자를 연관시켜 사용자의 프라이버시를 파괴할 수도 있다.
SPV/라이트웨이트 노드가 도입된 직후, 비트코인 개발자들은 SPV노드의 프라이버시 노출문제를 해결하기 위해 블룸필터(Bloom filter)라는 기능을 추가했다. 블룸필터를 이용하면 고정 패턴이 아닌 확률을 이용하는 필터링 메커니즘을 통해 SPV노드에 관여하는 주소가 정확히 어떤 것인지를 밝힐 필요 없이 해당 거래의 일부만 SPV노드가 수신하게 된다.
8-7그림 블록헤더를 동기화하는 SPV노드
블룸필터
블룸필터는 확률적 검색 필터, 원하는 패턴이 무엇인지 정확하게 규정할 필요 없이 원하는 패턴을 설명하는 방식이다. 블룸필터는 프라이버시를 보호하면서 검색 패턴을 표현하기 위한 효율적인 방법을 제공한다. SPV노드가 블룸필터를 사용해서 이웃노드들에게 특정 패턴과 일치하는 거래를 제공해 줄 것을 요청하게 되는데, 이때 노드가 검색 중인 주소가 정확히 어떤 것인지 밝힐 필요는 없다.
이전 예에서 보았듯이, 지도가 없는 관광객이 ‘23Church St.’라는 구체적인 주소에 대한 방향을 묻고 있다고 가정해보자. 만약에 그녀가 낯선 사람들에게 이 거래의 방향을 묻는다면 의도와는 달리 목적지를 노출하게 되는 셈이다. 블룸필터는 ‘근처에 명칭이 R-C-H로 끝나는 거리가 있을ᄁᆞ요?’라고 묻는 방식이다. 이런 유형으로 질문하게 되면 ‘23Church St.’라고 묻는 것보다는 원하는 목적지에 대한 정보를 훨씬 적게 노출시킬 수 있다. 이 기법을 이용해서 이 관광객은 좀 더 구체적으로 ‘U-R-C-H로 끝나는 거리는요?’라고 묻거나 좀 덜 상세하게 ‘H로 끝나는 거리는요?’라고 물을 수도 있다. 검색의 정확도를 다양하게 변화시킴으로써 이 관광객은 더 많은 정보 혹은 더 적은 정보를 노출시키게 되고, 노출 정도에 따라 좀 더 특정한 혹은 덜 특정한 결과를 얻을 수 있다. 덜 구체적으로 질문을 한 경우 목적지 가능성이 있는 주소를 더 많이 얻게 되고 프라이버시는 지켜진다. 하지만 결과로 얻은 값들 중 많은 수가 관련이 없는 정보일 것이다. 매우 특정한 패턴을 이용해서 질문을 했다면 결과값의 범위는 줄어들지만 프라이버시는 좀 더 노출된다.
블룸필터는 SPV노드가 정확도와 프라이버시 중에 어느 쪽에 초점을 맞출지에 따라 검색 패턴을 지정할 수 있게 함으로써 위의 예에서 보여진 것과 같은 기능을 수행하게한다. 좀 더 구체적인 블룸필터를 사용하게 되면 정확한 결과값을 얻을 수는 있지만 그 대가로 어떤 주소가 사용자의 잡에서 사용되었는지 밝혀진다. 덜 구체적인 블룸필터를 사용하게 되면 더 많은 거래에 대한 더 많은 데이터를 얻어야 하며, 이 중 많은 수가 해당 노드와 관련이 없다. 하지만 그 대신 노드가 좀 더 나은 프라이버시를 유지 할 수 있도록 해 준다.
SPV노드는 ‘비어 있는’ 상태로 블룸필터를 초기화하고, 이 초기화 상태에서 블룸필터는 어떠한 패턴과도 일치하지 않는다. 그 후 SPV노드가 자신의 지갑 내에 있는 주소 전부에 대한 목록을 만들고 각 주소에 대응하는 거래 출력값과 일치하는 검색 패턴을 생성한다. 대개 검색 패턴은 Pay-to-Public-Key-Hash 스크립트이다. 잠금 스크립트는 공개키 해시로 지불되는 거래 속에 들어있다. SPV노드가 P2SH주소의 잔액을 추적하는 경우라면 검색 패턴은Pay-to-Public-Key-Hash 스크립트 대신 pay-to-script-hash스크립트가 될 것이다. 이과정이 끝나면SPV노드가 검색 패턴 각각을 블룸필터에 추가해서 해당 검색 패턴이 거래 내부에 존재하는 경우 그 패턴을 인지할 수 있ㄱ 된다. 마지막으로 블룸필터는 이웃 노드들에게 전송되고 이웃노드가 동일한 블룸필터를 사용해서 SPV노드로 전송되기 위한 거래를 검색한다
블룸필터는 2진수 N(비트 단위의 필드)의 가변적 크기 배열과 M개의 해시 함수로 이루어진 가변수로 구현된다. 해시 함수는 1에서 N사이의 값을 가지는 출력값을 항상 생성해 내도록 설계되었다. 이 해시 함수는 정해진 방식대로 만들어 지기 때문에 블룸필터를 실행하는 어떠한 노드라도 항상 동일한 해시 함수를 사용하고 특정 입력값에 대해 동일한 결과를 얻을 수 있도록 해준다. 다른 길이(N)의 블룸필터와 다른 숫자(M)의 해시 함수를 선택함으로써 브룸필터는 정확도와 그에 따른 프라이버시 수준을 다양하게 조정할 수 있다.
그림8-8 단순한블룸필터 예시(16비트 필드와 3개의 해시함수)
그림8-8에서는16비트의 아주 작은 배열과 3개의 해시함수를 사용해서 블룸필터가 어떻게 작동하는 지 보여준다.
비트배열이 모두 0이 되도록 블룸필터를 초기화한다. 패턴을 블룸필터에 추가하기 위해서 피턴이 차례대로 각 해시 함수에 의해 해싱된다. 첫 번째 해시 함수를 입력값에 적용시키면 1에서N사이의 숫자가 결과값으로 나온다. 이 결과값에 대응하는 비트가 배열 (1부터N까지 번호를 매겨 놓았음) 속에서 발견되면 숫자 1로 설정된다. 이 과정까지 끝나면 다음 해시 함수를 사용해서 또 다른 비트를 설정하고 이 과정이 계속 반복된다. M개의 해시 함수가 모두 적용되고 나면 검색 패턴은 블룸필터에 M개의 비트로‘기록’되며, 해당 비트는 0에서1로 값이 변한다.
그림8-9는 ‘A’라는 패턴을 그림 8-8에 나와 있는 간단한 ㅏ블룸필터에 추가하는 과정에 대한 예시이다.
두 번 째 패턴을 추가하는 과정은 위 과정을 반복하는 것처럼 간단하다. 추가될 패턴이 각 해시 함수에 의해 차례대로 해싱되고 그에 따른 결과값은 비트를 숫자1로 변경해서 기록된다. 블룸필터에 추가되는 패턴이 증가하게 되면 해시 함수 결과값은 이미 1로 설정되어 있는 비트와 일치할 수 도 있다. 이 경우 비트 값은 바뀌지 않는다. 본질적으로 중첩되는 비트 위에 기록되는 패턴이 증가하게 되면 블룸필터에는 1로 설정되어 있는 비트가 포화상태가 된다. 그래서 블룸필터가 확률적 데이터 구조를 가지는 것이다. 즉,추가되는 패턴이 증가할수록 정확도는 떨어진다. 정확도는 비트 배열의 크기(N)과 해시함수의 개수(M)에 대한 추가 패턴 수에 따라 달라진다. 비트 배열이 크고 해시 함수의 개수가 많을수록 정확도가 높은 패턴을 더 많이 기록할 수 있다. 비트 배열이 작거나 해시 함수의 개수가 적을수록 정확도가 떨어지는 결과값을 생성하고 기록하는패턴의 수도 적어진다.
그림8-9패턴‘A’을 단순한 블룸필터에 추가하기
그림8-10 두 번째 패턴‘B’를 단순한 블룸필터에 추가하기
그림 8-10은 두 번째 패턴‘B’를 단순한 블룸필터에 추가하는 예시이다.
패턴이 블룸필터의 일부가 되었는지 테스트해 보기 위해 해당 패턴은 각 해시 함수로 해싱되고 그에 따른 비트패턴 결과 값을 비트배열과 비교해서 검사한다. 해시 함수에 의해 생성된 비트 모두가 1로 설정되어 있다면 해당 패턴은 아마 블룸필터에 기록되어 있는 것이다. 여러 개의 패턴이 중첩되면서 비트들이 설정 될 수도 있기 때문에 대응되는 값은 특정한 값이라기보다는 확률적 개념에 가깝다. 간단하게 이야기하면 블룸필터의 정합(positive match)은 ‘그럴 가능성(Maybe , yes)’의 개념이다.
그림 8-11은 단순한 블룸필터 내에서 패턴‘X’의 존재를 테스트하는 과정의 예시다.
대응되는 배트들은 1로 설정되어 있기 때문에 해당 패턴은 아마 필터에 존재할지도 모른다.
반대로 패턴이 블룸필터와 비교해서 테스트를 거친 수에 결과값 중 어떤 값이라도 0으로 남아 있다면, 이는 해당 패턴이 블룸필터에 기록되지 않았다는 사실을 입증한다. 부정적인 결과값의 경우에는 확률이 아니라 확실성을 띠게된다. 간단하게 이야기하면 블룸필터상의 부정합(nagative match)은 ‘절대적 부정(Definitely Not!)’의 개념이다.
그림8-11 단순한 블룸필터에서 패턴‘X’의 존재를 테스트하는 과정, 결과값은 확률적으로 정합이며‘가능성’을 의미
그림8-12 단순한 블룸필터 내에서 패턴 ‘Y’의 존재를 테스트하는 과정, 결과값은 절대적 부정합이며‘절대부정’을 의미
그림 8-12는 단순한 블룸필터 내에서 패턴‘Y’의 존재를 테스트하는 과정의 예시다. 대응되는 비트 중 하나가 0으로 설정되어 있기 때문에 해당 패턴은 절대 사용한 블룸필터에 존재하는 값이 아니다.
블룸필터로 구성되어 있는 비트코인 구현은 비트코인 개선 데안37(BIP0037)에 규정되어 있다.
거래 풀(Transaction Pools)
비트코인 네트워크상에 있는 거의 대부분의 노드들은 메모리 풀(memory pool) 혹은 거래 풀(transaction pool)이라고 불리는 미승인 거래로 이루어진 임시 목록을 보관하고 있다.
노드들은 이 풀을 이용해서 네트워크에 알려졌지만 아직 블록체인에 포함되지는 않은 거래들을 추적한다. 예를들어, 사용자의 자갑을 가지고 있는 노드는 이 거래 풀을 이용해서 사용자지갑으로 전송되었지만 아직 승인이 나지 않은 거래를 추적할 수 있게 된다.
거래가 수신되어 검증을 받고 나면 거래 풀에 추가되고 네트워크상에 전파되기 위해 이웃노드로 전달된다.
몇몇 노드 구현들 역시 고아거래로 구성된 독립 푸을 보관하고 있다. 거래에 사용된 입력값이 부모를 잃어버린 것처럼 네트워크상에 알려져 있지 않은 경우 해당 고아거래는 부모거래가 도착할 때까지 고아거래 풀에 임시로 저장될 것이다.
거래가 거래 풀에 추가될 때 해당 고아 풀은 이 거래의 출력값(자식거래)를 차조하는 고아거래가 있는지 체크한다. 만약 일치하는 고아들이 발견되면 이 고아거래들은 유효성을 인정받게 된다. 유효화된 고아거래는 고아 풀에서 빠져 나와서 거래 풀에 추과되면서 이들의 부모 거래로 시작된 체인은 완료된다. 새롭게 추가된 거래는 이제 더 이상 고아거래가 아니며, 이 프로세스는 다음세대의 자손들이 더 이상 발견되지 않을 때까지 계속 반복된다. 이 과정을 통해 부모거래가 수신되고 나면 고아거래와 부모거래가 재결합되어 독립적인 거래들로 구성된 체인 전체가 연속적으로 이어져 내려가면서 재구성된다.
거래 풀과 고아 풀 (구현되어 있는 경우)은 로컬 메로리에 저장되고 영구 저장소에는 저장되지 않는다. 오히려 이 두 개의 풀은 입력되는 네트워크 메시지로 동적으로 채워지게 된다. 노드가 시작되면 거래 풀과 고아 풀은 비어있지만 점차 네트워크에서 전송받은 새 거래들로 채워진다.
비트코인 클라이언트로 구성된 몇몇 굿현들은 UTXO데이터베이스 혹은 UTXO풀을 보관하기도 한다. UTXO 데이터베이스는 블록체인상에 존재하는 소비되지 않은 출력값 모두가 들어 있는 집합이다. ‘UTXO 풀’이라는 명칭이 거래 풀과 유사하다고 여겨질 수도 있지만 UTXO풀은 데이터로 구성된 다른 집합이다. 거래 풀 및 고아 풀과는 달리 UTXO풀은 초기에 비어 있지 않고 대신 소비되지 않은 거래 출력값의 항목 수백만 개를 포함하고 있다.
UTXO풀은 로컬 메모리에 저장되거나 영구 저장소에 색인 데이터베이스 테이블의 형태로 저장된다.
거래 풀과 고아 풀이 단일 노드의 로컬 관점을 나타내기 때문에 해당 노드가 시작 혹은 재시작인지에 따라 노드마다 현저하게 차이가 날 수 있는 반면 UTXO거래 풀은 해당 네트워크의 새로운 합의를 의미하기 때문에 노드 간 차이가 적다. 게다가 거래 풀과 고아 풀은 미승인 거래만 담고 있지만 UTXO 풀은 승인된 출력값을 담고 있다.