[Bitcoin] - ch9-1. 채굴과 합의(1)

‍허진·2023년 3월 8일
0

Blockchain

목록 보기
10/19
post-thumbnail

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

> 들어가기

'채굴'은 단순히 보상금을 목적으로 새로운 코인을 생성하는 행위가 아니다.
채굴은 비트코인 시스템을 안전하게 보호하고 전 네트워크에 걸쳐 중앙 권력 없이 합의를 이룰 수 있게 해준다. 새롭게 생성된 코인에 대한 보상 및 거래 수수료는 채굴자들의 행위가 네트워크의 보안을 지켜주고 동시에 통화 공급을 실행하도록 해 주는 동기를 부여한다.

채굴자들은 새로운 거래를 유효화한 후 전 세계에 존재하는 장부에 승인된 거래들을 기록한다. 새 블록에는 지난 블록 이후에 발생한 거래들이 들어 있으며 10분마다 '채굴되어' 블록체인에 추가된다. 블록의 일부가 되어 블록체인에 추가된 거래는 '승인'되었다고 간주되며, 승인된 거래를 전송받은 새로운 소유주는 해당 비트코인을 소유할 수 있게 된다.

채굴자들은 채굴 작업에 대해 두 가지 종류의 보상을 받는다.
1. 새 블록 각각에서 새로운 코인을 생성한 것
2. 해당 블록 내에 들어 있는 거래 전부로부터 거래 수수료를 받는 것

보상금을 받기 위해서 채굴자들은 암호화 해시 알고리즘을 기반으로 하는 어려운 수학 문제를 풀기 위해 서로 경쟁한다. 이 수학 문제에 대한 해답을 작업증명(Proof-of-Work)이라고 하고, 새 블록에 포함되어 채굴자가 중요한 계산을 하려고 노력했다는 사실을 증명하는 역할을 한다. 보상금을 받고 거래를 블록체인에 기록하는 권리를 얻기 위해서 작업증명 알고리즘을 풀기 위해 경쟁하는 과정은 비트코인의 보안 모델을 위한 근간이 된다.

비트코인의 통화 공급은 채굴을 통해서 이루어지며, 이는 중앙은행이 지폐를 찍어 내어 새 돈을 발행하는 방법과 유사하다. 채굴자가 블록에 추가할 수 있는 새 비트코인의 최대 액수는 약 4년마다 반으로 줄어든다. 2009년 1월 한 블록당 50비트코인으로 시작했으며 2012년 11월에는 블록당 25비트코인으로, 2016년 7월 블록당 12.5비트코인으로 계속 줄어들고 있다.

> 분산화된 합의

비트코인 네트워크상에 있는 사용자는 모두 블록체인을 소유권을 증명하는 권위 있는 기록이라고 인정해 준다. 블록체인은 중앙 통제 기관에 의해서 생성되지 않고 네트워크 내에 있는 모든 노드에 의해 독립적으로 수집된다.

사토시 나카모토의 주요 발명품은 합의도출(emergent consensus)을 위한 분산 메커니즘이다. 투표와 같이 명시적인 합의가 이루어지지 않기 때문에 '도출적(emergent)'이라는 단어를 사용했으며, 이는 합의가 일어나는 정확한 시점이나 선출 과정이 없다는 것을 의미한다. 대신 합의는 독립적인 노드 수천 개가 모두 간단한 규칙을 따르면서 만들어 낸 비동기 상호작용의 도출적 결과물이다. 통화, 거래, 지불, 중앙 통제 기관이나 신뢰에 의존하지 않는 보안 모델 등 비트코인의 모든 특성은 이 신생 합의에서 시작된다.

비트코인의 분산화된 합의는 네트워크 상에 있는 노드에게 독립적으로 행해지는 네 가지 프로세스가 서로 상호작용하면서 이루어진다.

  1. 포괄적인 판단 기준에 근거하여 모든 풀 노드가 각 거래마다 독립된 검증 실시
  2. 작업증명 알고리즘을 통해 증명된 계산법을 사용하여 채굴 노드들이 검증된 거래들을 새로운 블록에 독립적으로 추가
  3. 모든 노드들이 새 블록을 독립적으로 검증한 후 체인에 블록을 연결
  4. 모든 노드가 작업증명을 통해 이루어진 최고 누적 연산 체인을 독립적으로 선택

이제 위의 네 가지 프로세스를 살펴보면서, 어떠한 비트코인 노드라도 자신들이 보유하고 있는 권위 있고 신뢰할 수 있는 전 세계 공개 장부를 수집할 수 있게 해 주는 네트워크 전체의 합의를 얻어내기 위해 위 네 가지 프로세스가 어떻게 상호작용하는지에 대해서 알아보자.

> 거래의 독립적 검증

5장에서 우리는 지갑 소프트웨어가 UTXO를 수집해서 거래를 생성한 후 적절한 해제 스크립트를 제공하고 새로운 소유주에게 할당된 새 출력값을 만들어 내는 방법에 대해서 알아보았다. 이 거래는 비트코인 네트워크 내에 있는 이웃 노드들에게 전송된 후에 비트코인 네트워크 전체로 전파된다.

이 과정에서 이웃 노드들에게 거래를 전달하기 전에 모든 비트코인 노드는 전송받은 거래를 우선 검증해야 할 것이다. 검증 과정을 통해 유효한 거래들은 네트워크상으로 전파되지만 유효하지 않은 거래들은 전송된 첫 노드에서 폐기된다.

각 노드는 아래의 체크리스트를 바탕으로 모든 거래를 검증한다.

  • 거래의 구문(syntax)과 데이터 구조가 정확해야 한다.
  • 입력값이나 출력값 목록이 비어 있지 않다.
  • 바이트 단위의 거래 크기가 MAX_BLOCK_SIZE보다 작다.
  • 출력값 금액과 노드의 총 금액이 허용된 가치 범위(dust threshold보다 크고 2,100만 비트코인보다 작음) 내에 있어야 한다.
  • 입력값 중 해시값은 0, N값은 -1이어서는 안 된다(코인베이스 거래는 전송할 수 없음.)
  • nLocktime은 INT_MAX과 동일하거나 nLocktime과 nSequence 값이 Median Timepast에 따라 만족한다.
  • 바이트 단위의 거래 크기가 100보다 크거나 동일해야 한다.
  • 거래에 담겨 잇는 서명 작업(SIGPOS) 건수가 서명 작업 한도 내에 있어야 한다.
  • 해제 스크립트(scriptSig)는 스택 상부에 숫자를 추가할 수만 있고 잠금 스크립트(scirptPubkey)는 isStandard 형태와 일치해야 한다.
  • 풀이나 메인 브랜치에 있는 블록에 짝을 이루는 거래가 존재해야 한다.
  • 각각의 입력값에 대해, 참조 출력값이 풀 내의 어떠한 거래 내부에 존재한다면 해당 거래는 거부되어야 한다.
  • 각각의 입려값에 대해, 참조 출력값이 거래 내에 있는지 검색하기 위해 메인 브랜치와 거래 풀을 살펴보자. 만약 출력 거래의 입력값에 대한 이전 출력값을 찾을 수 없을 때는 이 거래는 고아거래가 될 것이다. 짝을 이루는 거래가 풀에 존재하지 않는 경우 고아거래 풀에 추가하라.
  • 각각의 입력값에 대해 참조 출력값이 코인베이스 출력이라면, 최소 COINBASE_MATURITY(100) 승인을 받아야 한다.
  • 각각의 입력값에 대해 참조 출력값은 존재해야 하며, 이미 소비되었으면 안된다.
  • 참조 출력 거래에서 입력값을 가져올 때 각 입력값 금액과 입력값 총액이 허용된 가치 범위(0보다 크고 2,100만 비트코인보다 작음) 내에 있어야 한다.
  • 입력값 금액이 출력값 총액보다 작은 경우 해당 거래를 거절하라.
  • 거래 수수료가 비어 있는 블록에 들어가기에 너무 작을 때는 해당 거래를 거절하라.
  • 각 입력값에 대한 해제 스크립트는 그에 해당하는 출력값 잠금 스크립트에 대해 검증해야 한다.

거래 각각이 전송되어 전파되기 전까지 독립적으로 검증됨으로써 각 노드는 거래 풀, 메모리 풀(memory pool), 또는 mempool로 알려진 유효한(그러나 unconfirmed) 거래 풀을 구성한다.

> 채굴 노드

비트코인 네트워크상에 있는 몇몇 노드는 채굴자라고 불리는 특수 노드들이다. Jing이라는 비트코인 채굴자를 가정해보자. Jing은 비트코인 채굴을 목적으로 고안된 전문 컴퓨터 하드웨어 시스템인 '채굴 리그'를 가동해서 비트코인을 채굴한다. 여느 풀 노드처럼 Jing의 노드는 비트코인 네트워크상에 있는 미승인 거래를 전송받아서 전파한다. 하지만 미승인인 거래들을 새로운 블록에 추가하기도 한다.

Jing의 노드는 여느 노드들이 하는 것처럼 비트코인 네트워크상에 전파된 새로운 블록이 도착하기를 기다린다. 하지만 새로운 블록의 생성 여부는 채굴 노드에 있어 특별한 중요성을 가진다. 채굴자들 사이의 경쟁은 새로운 승자를 알리는 새로운 블록의 전파와 함께 실질적으로 종료된다. 새로운 블록을 수신한다는 것은 채굴자들에게 있어 해당 경쟁에서 다른 누군가가 승리하고 본인이 패배했다는 것을 의미한다. 그리고 바로 다음 블록을 위한 경쟁이 시작된다.

> 블록에 거래 추가하기

비트코인 노드는 검증된 거래들을 메로리 풀 또는 거래 풀에 추가한다. 거래 풀은 거래들이 블록 내에 포함될 수(채굴될 수) 있을 때까지 기다리는 장소다. Jing의 노드는 다른 노드들처럼 거래를 수집하고 검증하며 전송한다. 하지만 여느 노드들과는 달리 Jing의 노드는 해당 거래들을 후보 블록(candidate block)에 추가하게 된다.

Alice와 Bob의 커피 거래를 다시 떠올려보자. Alice의 거래는 블록 #277316에 포함되었다. 해당 블록이 Jing의 채굴 시스템에 의해서 채굴되었다고 가정해보자.

Jing의 채굴 노드는 해당 블록체인의 로컬 복사본을 보관하고 있다. Alice가 커피 한 잔을 구매할 때쯤, Jing의 노드는 블록 #277314까지의 블록으로 체인을 구성했다. Jing의 노드는 거래들을 수집하며 새로운 블록을 채굴하려 하고 있다. Jing의 노드는 채굴을 하는 동안 비트코인 네트워크를 통해 블록 #277315를 받게 된다. 이렇게 블록이 도착하고 나면 블록 #277315에 대한 경쟁이 끝나고 블록 #277316이 생성되는 경쟁이 시작된다.

이전 10분동안 Jing의 노드가 블록 #277315에 대한 솔루션을 찾는 동시에 다음 블록에 대비하여 거래들을 수집하고 있었다. 이제 수백 개의 거래를 메모리 풀에 수집했다. 블록 #277315가 도착해서 검증되자마자 Jing의 노드는 메모리 풀 내에 있는 모든 거래를 비교해서 블록 #277315에 포함되어 있는 거래들을 없앨 것이다. 메모리 풀에 남아 있는 모든 거래는 미승인 상태이며 새로운 블록에 기록되기 위해 대기 중이다.

Jing의 노드는 즉시 비어 있는 블록을 새로 만들며, 이 블록이 블록 #277316의 후보가 된다. 이 블록은 유효한 작업증명을 담고 있지 않아서 아직 유효한 블록이 아니기 때문에 후보 블록이라고 한다. 이 후보블록은 채굴자가 작업증명 알고리즘에 대한 솔루션을 찾는 데 성공한 경우에만 유효화된다.

Jing의 노드가 메모리 풀에 있는 모든 거래를 결합할 때, 새로운 후보 블록이 총 0.09094928비트코인의 거래 수수료를 가진 418개의 거래를 포함하게 된다.

> 코인베이스 거래

어떤 블록에서든지 첫 번째 거래는 특별하며, 이 첫 거래를 코인베이스 거래(Coinbase transaction)라고 한다. 코인베이스 거래는 Jing의 노드에 의해 구성되고 채굴 노력에 대한 보상을 포함하고 있다.

Jing의 노드는 Jing의 지갑으로 지불하는 금액의 개념으로 코인베이스 거래를 생성한다. 즉, '징의 주소로 25.09094928비트코인을 지불'하는 것이다. Jing이 블록을 채굴한 대가로 수집한 보상금 총액은 코인베이스 보상금(새로 생성된 25비트코인)과 블록에 포함된 모든 거래에서 얻은 거래 수수료(0.09094928)다.

일반적인 거래들과는 달리 코인베이스 거래는 입력값으로 UTXO를 쓰지(소비하지) 않는다. 대신 무에서 비트코인을 생성해 내는 코인베이스라고 불리는 하나의 입력값을 보유하고 있다. 코인베이스 거래는 하나의 출력값을 가지고 있다. 이 출력값은 채굴자 본인의 비트코인 주소로 지불 가능하다. 코인베이스 거래의 출력값은 25.09094928비트코인이라는 금액을 채굴자의 비트코인 주소로 전송한다.

정규 거래의 입력값과 코인베이스 거래의 입력값 구조를 비교하면 다음과 같다.

크기필드설명
32바이트거래 해시소비될 UTXO를 담고 있는 거래에 대한 지시자
4바이트출력값 인덱스소비될 UTXO의 색인번호(최초는 0)
1~9바이트(VarInt)해제 스크립트 크기따라 나오는 바이트 단위의 해제 스크립트 길이
가변적해제 스크립트UTXO 잠금 스크립트의 조건을 풀 수 있는 스크립트
4바이트일련번호현재 장애가 있는 Tx-대체 기능 0xFFFFFFFF로 설정

[표 - '정규' 거래의 입력값 구조]

크기필드설명
32바이트거래 해시모든 비트가 0, 거래 해시 참조 아님
4바이트출력값 인덱스모든 비트가 1, 0xFFFFFFFF로 설정
1~9바이트(VarInt)코인베이스 데이터 크기2~100 바이트까지 코인베이스 데이터의 길이
가변적코인베이스 데이터버전-2 블록에 있는 추가적인 난스와 채굴 태그에 사용되는 임의적인 데이터
4바이트일련번호0xFFFFFFFF로 설정

[표 - 코인베이스 거래의 입력값 구조]

코인베이스 거래의 경우, 처음 두 개의 필드가 UTXO 참조를 표현하지 않는 값들로 설정되어 있다. '거래 해시' 대신에 첫 번째 필드는 32바이트 크기로 모두 0으로 설정되어 있다. '출력값 인덱스'는 4바이트 크기로 모두 0xFF로 설정되어 있다. '해제 스크립트(스크립트 시그)'는 채굴자들이 사용하는 임의적인 데이터인 코인베이스 데이터로 대체되었다.

> 코인베이스 데이터

코인베이스 거래는 해제 스크립트(scriptSig) 필드를 보유하고 있지 않다. 그 대신 코인베이스 데이터로 교체되며 그 크기는 2~100바이트여야 한다. 처음에 나오는 몇몇 바이트를 제이하고 코인베이스 데이터의 나머지 부분은 채굴자들이 원하는 방식으로 사용될 수 있다. 예를 들어, 사토시 나카모토는 최초블록의 코인베이스 데이터 내에 'The Times 03/Jan/2009 Chancellor on brink of second bailout for banks'라는 텍스트를 추가해서 날짜에 대한 증빙자료로 삼고 메시지를 전달하고자 했다. 현재 채굴자들은 채굴 풀을 검색하는 역할을 하는 추가 난스와 문자열을 포함하기 위해 코인베이스 데이터를 사용한다.

현재 코인베이스 데이터는 다음과 같은 요소들로 구성된다

  • 코인베이스 필드를 시작할 때 스크립트 '푸시' 연산에 사용하기 위한 블록 높이 인덱스
  • 작업증명 해답을 찾는 데 사용되는 적절한 추가 난스(nonce)
  • 해당 블록을 채굴했던 채굴 노드가 따르는 개선 제안(ex. /P2SH/)

> 블록 헤더 구성하기

블록 헤더를 구성하기 위해서 채굴 노드는 다음의 필드를 채워야 한다.

크기필드설명
4바이트버전소프트웨어/프로토콜 업그레이드 추적을 위한 버전 번호
32바이트이전 블록 해시체인 내 이전 (부모)블록의 해시에 대한 참조
32바이트머클 루트블록 거래의 머클 트리의 루트에 대한 해시
4바이트타임스탬프블록의 대략적인 생성시간(유닉스 기준일자로부터 초단위로 계산)
4바이트난이도 목표블록의 작업증명 알고리즘에 대한 난이도 목표
4바이트난스작업증명 알고리즘에 사용되는 카운터

[표 - 블록 헤더의 구성]

블록 #277316이 채굴되던 당시 블록 구조를 설명해 놓은 해당 버전번호는 버전 2다.
이는 리틀엔디안 포맷으로 4바이트 크기로 0x02000000로 인코딩된다.

다음 과정에서는 채굴 노드가 '이전 블록 해시'를 추가해야 한다. 네트워크에서 전송 받은 이전 블록인 블록 #277315의 블록 헤더 해시다. 이는 Jing의 노드가 후보 블록인 277316dml 부모블록으로 승인하고 선택한 블록이기도 하다. 블록 #277315에 대한 블록 헤더 해시는 다음과 같다.

#이전 블록 해시
0000000000000002a7bbd25a417c0374cc55261021e8a9ca74442b01284f0569

다음은 블록 헤더에 머클 루트를 추가하기 위해 모든 거래를 머클 트리로 요약하는 과정이다. 코인베이스 거래는 블록 내에서 첫 번째로 추가된 거래다. 그 후로 418건의 거래가 추가되어 총 419건의 거래가 블록 내에 생기게 된다. 제일 마지막 거래를 복사하여 420개의 노드를 만들고, 노드 각각에는 한 거래에 대한 해시가 들어 있다. 그다음 거래 해시는 짝으로 결합되어 모든 거래가 머클 트리의 '루트'에서 하나의 노드로 요약될 때까지 트리의 각 단계를 형성한다. 머클 트리의 루트는 거래 전부를 단 하나의 32바이트 값으로 요약하며, 이는 다음과 같다.

#머클 루트
c91c008c26e50763e9f548bb8b2fc323735f73577effbc55502c51eb4cc7cf2e

그리고 나서 Jing의 채굴 노드가 4바이트 크기의 타임스탬프를 추가해서 유닉스 '기준 일자' 타임스탬프로 인코딩한다. 이 값은 UTC/GMT 기준 1970년 1월 1일 자정부터 경과한 시간을 초 단위로 계산한 숫자다.

Jing의 노드는 해당 노드를 유효한 거래로 만들기 위해 필요한 작업증명을 정의하는 목표값으로 채워지게 된다. 해당 목표값은 블록 내에 '목표값 비트' 단위로 저장되어 있으며 목표값에 대해 가수-지수 형태로 인코딩된 값이다.

마지막 필드는 난스로 0으로 설정되어 있다.

모든 필드가 다 채워지고 나면 블록 헤더는 완성되고 채굴 프로세스가 시작된다. 채굴의 목표는 난이도 목표보다 낮은 블록 헤더 해시가 결과적으로 나올 수 있게 하는 난스값을 찾는 것이다. 채굴 노드는 요건에 맞는 난스를 발견하기까지 기하학적인 횟수로 테스트를 해야할 것이다.

실제 작업증명 과정과 관련해서는 다음 장부터 살펴보도록 하자.

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

0개의 댓글