[Bitcoin] - ch8. 블록체인

‍허진·2023년 3월 6일
0

Blockchain

목록 보기
9/19
post-thumbnail

본 글은 '비트코인, 공개 블록체인 프로그래밍(Andreas M. Antonopoulos 저, 최은실, 김도훈, 송주한 옮김, 2018)'을 바탕으로 작성되었습니다.

> 들어가기

블록체인 데이터 구조는 거래가 담겨 있는 블록이 그 이전 블록과 연결되어 있는 형태의 정돈된 목록이다. 비트코인 코어 클라이언트는 구글의 LevelDB 데이터베이스를 이용해서 블록체인의 메타데이터를 저장한다. 블록 각각은 '뒤로' 연결되어 있다. 이는 각 블록이 체인 내에서 이전 블록을 참조한다는 것을 의미한다.

블록체인 내에 있는 블록 각각은 해시를 이용해서 식별된다. 해시는 블록의 헤더에서 SHA256 암호화 해시 알고리즘을 이용해서 생성된다. 또한 각 블록은 블록 헤더에 있는 '이전 블록 해시' 필드를 통해 부모블록이라고 알려진 이전 블록을 참조한다. 즉, 각 블록은 자신의 헤더 내에 있는 부모블록의 해시를 포함하고 있다. 각 블록과 그 부모블록을 연결해 주는 해시의 배열은 최초블록이라고 알려진 첫 생성 블록까지 이어진 체인을 만든다.

블록은 단 한 개의 부모블록을 가지지만 일시적으로 여러 개의 자식블록을 보유할 수 있다. 여러 개의 자식 블록 각각은 동일한 부모블록 해시를 가지고 있는데, 이는 블록체인 분기(다른 채굴자들에 의해 거의 동시에 다른 블록들이 발견되는 경우 발생하는 일시적 상황)가 발생하는 동안 생성된다. 하나의 블록이 한 개 이상의 자식블록을 가질 수 있지만, 각 블록은 단 하나의 부모블록만 가질 수 있다.

'이전 블록 해시' 필드는 블록 헤더 내에 들어 있으며, 이러한 특성 때문에 현재 블록의 해시에 영향을 끼친다. 부모노드가 수정되면 부모노드의 해시가 수정되고, 그러면 자식노드의 '이전 블록 해시' 포인터도 수정되고, 자식노드의 해시가 수정되고, 손자 노드의 포인터까지 수정된다. 이러한 연쇄효과 덕분에 블록 하나가 그 아래에 여러 세대를 두는 경우 나중에 생성된 블록 전부를 재계산하지 않고서는 해당 블록의 내용을 변경시킬 수 없다. 이러한 재계산을 위해서는 엄청난 규모의 계산을 실행해야 하기 때문에 블록체인의 누적된 기록은 변경되지 않으며, 비트코인의 보안이 유지된다.

> 블록 구조

블록은 공개 장부인 블록체인에 거래들을 포함시키기 위해 한데 합쳐 놓은 컨테이너 데이터 구조다. 평균적으로 블록에는 500개 이상의 거래가 담겨 있다.

크기필드설명
4바이트블록 크기필드 뒤에 따라 나오는 블록의 크기 (단위 : 바이트)
80바이트블록 헤더여러 필드가 블록 헤더를 생성
1~9바이트(Varlnt)거래 카운터거래의 갯수
가변적거래블록에 기록된 거래

[표 - 블록구조]

> 블록 헤더

블록 헤더는 블록 메타데이터의 3가지 집합으로 구성되어 있다.

  1. 이전 블록 해시값 : 현재의 블록이 블록체인에 있는 이전 블록과 연결되었음을 나타냄.
  2. 난이도, 타임스탬프, nonce : 채굴경쟁과 연관
  3. 머클 트리 루트 : 블록 내에서 거래 전부를 효율적으로 요약
크기필드설명
4바이트버전소프트웨어/프로토콜 업그레이드 추적을 위한 버전 번호
32바이트이전 블록 해시체인 내 이전 (부모) 블록의 해시에 대한 참조값
32바이트머클 루트해당 블록에 포함된 거래로부터 생성된 머클 트리의 루트에 대한 해시
4바이트타임 스탬프블록의 대략적인 생성 시간(유닉스 기준일로부터 초단위로 계산)
4바이트난이도 목표블록의 작업증명 알고리즘에 대한 난이도 목표
4바이트nonce작업증명 알고리즘에 사용되는 카운터

[표 - 블록 헤더의 구조]

> 블록 식별자 : 블록 헤더 해시와 블록 높이

  • 블록 헤더 해시
    : 블록의 주요 식별자로 디지털 지문 역할을 하는 암호화 해시이다. SHA 256 알고리즘을 통해 블록 헤더를 2회 해싱하여 얻어진다. 결과값으로 나온 32바이트 크기의 해시를 블록 해시라고 하지만 좀 더 정확하게 말하면 블록 헤더 해시다. 왜냐하면 블록 헤더만 이 해시를 계산하는 데 사용되기 때문이다.
    블록 해시는 블록의 데이터 구조에 포함되지 않는다. 또한, 블록이 네트워크로 전송될 때나 블록체인의 일부로 노드의 영구 저장소에 저장될 때에도 데이터 구조에 포함되어 있지 않다.
    대신 블록 해시는 해당 블록을 네트워크에서 전송받으면서 각 노드에 의해 계산된다. 따라 블록의 메타데이터의 일부로 별도의 데이터베이스 테이블 내에 저장되어 디스크로부터 블록에 대한 색인을 용이하게 하고 검색 속도를 높인다.

  • 블록 높이
    : 블록 높이는 결국 블록체인 내에서 블록의 위치를 파악하는 것이다. 블록 해시와 다르게 블록 높이는 특유의 식별자는 아니다. 두 개 이상의 블록들이 블록체인 내에서 동일한 블록 높이를 가지게 될 수도 있기 때문이다(블록체인 분기). 또한 블록의 높이는 블록 데이터 구조의 일부가 아니기 때문에 블록 내부에 저장되지 않는다. 블록의 높이는 빠른 검색을 위해 색인 작업을 거친 데이터베이스 테이블 내에 메타데이터로 저장될 수 있다.

> 최초블록

블록체인 내의 첫 번째 블록을 최초블록이라고 하며 2009년에 생성되었다. 최초블록은 블록체인 내에 있는 모든 블록의 공통된 선조다. 또한, 비트코인 클라이언트 소프트웨어 내에서 고정적으로 인코딩되어 있기 때문에 모든 노드는 적어도 하나의 블록으로 구성된 블록체인으로 시작하며, 이러한 이유로 최초블록은 변경이 가능하지 않다. 모든 노드는 최초블록의 해시와 구조, 최초블록의 생성 시간, 최초블록 내에 있는 단일 거래까지 항상 '알고' 있다. 즉, 최초블록은 신뢰받는 블록체인을 만드는 기반이 되는 안전한 '루트'이다.

> 블록체인에 블록 연결하기

노드가 네트워크로부터 새로 생성된 블록들을 전송받고 나면, 수신된 블록의 유효성 검사 후에 유효하다고 검증되면 기존의 블록체인에 블록들을 연결시킨다. 새로운 블록을 블록체인에 연결하기 위해 노드는 새로 생성된 블록 헤더를 검사하고 '이전 블록 해시'를 찾는다.

예를 들어 블록체인의 로컬 복사본 내에 277,314개의 블록을 가진 노드가 있다고 가정해 보자. 이 노드가 알고 있는 마지막 블록은 277,314번째 블록으로 00000000000000027e7ba6fe7bad39faf3b5a83daed765f05f7d1b71a1632249인 블록 헤더 해시를 가지고 있다.
그 후, 비트코인 노드는 네트워크로부터 새로운 블록을 전송받으며, 새 블록에 대한 분석 결과는 다음과 같다.

{
    "size" : 43560,
    "version" : 2,
    "previousblockhash" :
        "00000000000000027e7ba6fe7bad39faf3b5a83daed765f05f7d1b71a1632249",
    "merkleroot" :
        "5e049f4030e0ab2debb92378f53c0a6e09548aea083f3ab25e1d94ea1155e29d",
    "time" : 1388185038,
    "difficulty" : 1180923195.25802612,
    "nonce" : 4215469401,
    "tx" : [
        "257e7497fb8bc68421eb2c7b699dbab234831600e7352f0d9e6522c7cf3f6c77",

 #[... many more transactions omitted ...]

        "05cfd38f6ae6aa83674cc99e4d75a1458c165b7ab84725eda41d018a09176634"
    ]
}

노드는 새 블록을 검토한 후 부모블록의 해시를 담고 있는 previousblockhash 필드를 찾아낸다. 이 해시는 노드에 알려져 있는 가장 마지막 블록, 즉 높이가 277,314인 최종 블록의 해시값이다. 따라서 이 새로운 블록은 체인의 마지막 블록의 자식블록이며 현재의 블록체인 길이를 연장한다. 노드는 이 새 블록을 체인의 제일 끝에 추가함으로써 블록체인의 길이를 연장해서 높이가 277,315가 되게 만든다. 다음 그림은 연결된 블록 3개의 체인을 보여준다.

[그림 - 체인 내 연결된 블록들, 참조를 이용해서 블록 헤더의 해시에 연결]

> 머클 트리

머클 트리는 블록 내에 있는 모든 거래를 요약하기 위해 비트코인에서 사용되며, 특정 거래가 블록 내부에 포함되는지 여부를 검증하는 데 매우 효율적인 프로세스를 제공한다. 루트 혹은 머클 루트라고 부르는 해시 하나가 남을 때까지 노드 쌍을 반복적으로 해싱해서 머클 트리를 만든다. 비트코인의 머클 트리에 사용되는 암호 해시 알고리즘은 SHA 256이며, 두 번 적용되기 때문에 '더블 SHA 256'이라고도 한다.

머클 트리 내에서 N개의 데이터 요소가 해시되고 요약되면 특정 데이터 요소가 트리에 포함되는지 여부를 알아보기 위해 최대 2*log2(N)번의 연산이 필요하게 되기 때문에 매우 효율적인 데이터 구조를 만들어준다.

예시로 4건의 거래(A, B, C, D)가 머클 트리의 리프를 형성하는 것을 볼 수 있다. 거래들은 머클 트리 내에는 저장되지 않고 대신 거래 데이터를 해싱해서 나온 결과 값이 각 리프 노드에 Ha, Hb, Hc, Hd로 저장된다.

Ha = SHA256(SHA256(Transaction A))

그리고 붙어 있는 리프 노드끼리 두 개의 해시를 연결하여 함께 해싱한 해시값을 부모 노드 내에서 요약한다. 예를 들어, 부모노드인 Hab를 만들기 위해 자식노드의 32바이트 크기의 해시 두 개를 연결해서 64바이트 문자열을 만든다. 그 후, 이 문자열은 이중 해시 처리되어 부모 노드의 해시를 생성한다.

Hab = SHA256(SHA256(Ha + Hb))

이 프로세스는 상위에 노드가 하나 남을 때까지 계속되며, 마지막 노드를 머클 루트라고 한다.

[그림 - 머클 트리에서 노드 계산하기]

위와 같은 예시를 일반화해서 동일한 방법으로 어떤 크기의 트리라도 구성할 수 있다. 그리고 만약 노드가 홀수 개여서 연결이 불가능하다면 마지막 노드를 복사한다.

특정 거래가 블록 내에 포함되어 있다고 입증하기 위해서는 노드가 log2(N)개의 32바이트 해시를 생성해서 특정 거래와 트리의 루트를 연결하는 인증 경로(authentication path)머클 경로(merkle path)를 구성하기만 하면 된다.

다음 예시에서는 32바이트 크기의 해시 4개의 길이(총 128바이트)인 머클 경로를 생성함으로써 거래 K가 블록 내에 포함되어 있다는 사실을 노드가 입증할 수 있다는 것을 보여준다. 머클 경로는 Hl, Hij, Hmnop, Habcdefgh 이렇게 4개의 해시로 구성되어 있다. 인증 경로로 제공된 이 4개의 해시를 가지고 어떤 노드라도 4개의 해시에 대응하는 해시 쌍인 Hkl, Hijkl, Hijklmnop와 머글 트리 루트를 계산함으로써 Hk가 머클 루트에 포함되어 있다는 사실을 증명할 수 있다.


[그림 - 데이터 요소의 포함을 입증하는 데 사용된 머클 경로]

머클 트리의 크기가 커지면 커질수록 그 효용성은 명백해진다. 다음은 어떤 거래가 블록의 일부임을 증명하기 위해 머클 경로로 교환해야 하는 데이터 양을 보여준다.

거래 건수블록의 대략적 크기경로 크기(해시)경로 크기(바이트)
16건4kB해시 4개128byte
512건128kB해시 9개288byte
2,048건512kB해시 11개352byte
65,535건16mB해시 16개512byte

[표 - 머클트리의 효용성]

> 머클 트리와 단순지불검증(SPV)

모든 거래를 보유하지 않고 블록 헤더만 가지고 있는 SPV 노드는 머클 경로를 사용하여 거래가 블록 내에 포함되어 있는지 여부를 검증한다.

SPV 노드는 본인이 관심 있는 주소들로 수신되는 거래들만을 모니터링하기 위해서 이웃 풀 노드와의 연결 통로에 블룸필터를 설치할 것이다. 이웃 노드가 블룸필터의 조건을 만족시키는 거래를 보게 되면 merkleblock 메시지를 사용해서 해당 블록을 전송할 것이다. merkleblock 메시지에는 블록 헤더와 머클 경로가 담겨 있으며, 머클 경로는 블록 내에서 관련 거래와 머클 루트를 연결한다.

SPV 노드는 이 머클 경로를 이용해서 해당 거래를 블록에 연결하고 거래가 블록에 포함되었는지 검증한다. 또한 SPV 노드는 블록 헤더를 이용해서 해당 블록이 블록체인에 연결되어 있는지 확인한다. 거래와 블록 간 그리고 블록과 블록체인 간의 결합 두 종류가 조함되어 해당 거래가 블록체인에 기록된다는 것을 증명할 수 있다. 이 과정에서 SPV 노드는 블록 헤더와 머클 경로를 위해 1kB 미만의 데이터를 받게 되며, 이 데이터 양은 풀 블록(현재 약 1mB)의 1000분의 1수준밖에 되지 않는 크기다.

profile
매일 공부하기 목표 👨‍💻 

0개의 댓글