안녕하세요. 지난 글에서는 이더리움을 본격적으로 설명하기에 앞서 논문의 서론 부분 중 "Bitcoin As A State Transition System" 섹션을 알아보았습니다.
이전 글
비트코인 논문 리뷰
이더리움 논문 리뷰 01 Bitcoin As A State Transition System
다음 글
이더리움 논문 리뷰 03 머클 트리 (해시 트리, Merkle Trees)
이번 글에서는 이더리움 논문 서론 부분의 "채굴 (마이닝, mining)"에 대한 설명을 공부해보겠습니다. 이미 비트코인 논문을 리뷰하면서 공부하였던 개념이지만, 이더리움 논문에서 비트코인을 State Transition System으로 보는 패러다임을 바탕으로 다시 한번 채굴 과정에 대해 복습해보겠습니다.
마이너(Miner), 즉 채굴을 하는 노드가 새로운 블록을 네트워크에 추가하기 위해서는 블록이 유효한지 확인하는 과정이 필요합니다. 비트코인을 State Transition System으로 보는 패러다임에서 블록이 유효한지 확인하는 과정을 pseudo-code로 정리하면 다음과 같습니다.
struct Block { timestamp, prev, nonce, transactions, state }
// 실제 state는 Block에 기록되지는 않지만 설명 편의상 추가하였음.
function isBlockValid(block):
// block 이전 블록이 블록체인 네트워크에 존재하는지, 블록이 유효한지 확인
if not exists(block.prev): raise ERROR
if not isBlockValid(block.prev): raise ERROR
// 현재 block의 타임스탬프가 유효한지 확인
if not isTimestampValid(block.timestamp, prev.timestamp): raise ERROR
// block의 작업 증명(PoW)이 유효한지 확인
if not isPowValid(block): raise ERROR
// block의 state를 정의
S = prev.state
for TX : block.transactions
S = APPLY(S, TX) // APPLY function 내부에서 ERROR가 raise 될 수 있음.
block.state = S
return True
function isTimestampValid(curr, prev):
/*
curr: 현재 block의 타임스탬프
prev: 이전 블록의 타임스탬프
현재 block의 타임스탬프와 이전 블록의 타임스탬프를 비교하여 다음 조건을 만족하는지 확인
(정확히는, 이전 블록의 타임스탬프 == 이전 11개 블록 타임스탬프의 중간값)
- 조건 1: block의 타임스탬프 > 이전 블록의 타임스탬프
- 조건 2: block의 타임스탬프 < 이전 블록의 타임스탬프 + 2시간
*/
return (curr > prev) and (curr < prev + 2)
(이하 코드는 지난 포스트 "이더리움 논문 리뷰 01"에서의 코드와 동일.)
function APPLY(S, TX):
// 거래 TX가 유효한 거래인지 확인
if not is_valid(TX): raise ERROR
// 새로운 state S'를 정의
S' = delete(S, TX.inputs)
S' = insert(S', TX.outputs)
// UTXO 금액 합계로 sanity check
if sum_of_utxos(S) < sum_of_utxos(S'): raise ERROR
return S'
function is_valid(TX):
for utxo in TX.inputs:
if utxo not in S: raise ERROR
if not is_matched(utxo.owner, TX.signature): raise ERROR
function sum_of_utxos(S):
sum = 0
for utxo in S.utxos:
sum += utxo.amount
return sum
작업 증명(PoW)을 하는 과정은 랜덤하게 nonce 값을 trial and error로 시도해서 맞추는 방법밖에 없기 때문에 엄청난 계산을 필요로 합니다. 이 때문에 채굴에는 어느 정도의 시간과 연산량이 필요하고, 최종적으로 유효한 블록을 체인에 추가하게 되면 보상을 받게 됩니다.
이처럼 채굴의 과정이 많은 연산량을 요구하도록 설계된 이유는, 외부 해커가 블록체인을 오염시키기 힘들도록 하기 위함입니다. 예를 들어, 어떤 해커가 블록체인의 특정 블록의 내용을 임의로 바꾸고 싶다고 할 때, 다음과 같은 방법으로 공격을 시도할 수 있습니다.
- 해커가 어떤 물건을 구입하고 100BTC를 지불. (거래 1)
- 해커가 자기 자신에게 100 BTC를 보내는 거래를 만들어 냄. (거래 2)
- 블록체인 네트워크에 거래 2가 거래 1보다 먼저 등록되도록 함.
즉, 해커는 자신이 가지고 있는 100 BTC로 거래 1과 거래 2를 이중으로 생성하여 더블 스펜딩(double-spending)을 시도하게 됩니다. 먼저, 거래1이 발생하면 거래1이 다른 채굴자들이 채굴하고 있는 블록(블록 넘버 270)에 포함됩니다. 그리고 약 1시간 뒤, 예를 들어 5개의 블록(블록 271-275)이 그 이후에 추가되었다고 생각해봅시다.
해커가 거래2를 만들어내면 마찬가지로 다른 채굴자들이 이를 자신들의 블록에 추가하는 과정에서 APPLY(채굴자 블록의 State, 거래 2)를 실행하게 되는데, is_valid(거래 2)에서 에러가 발생하게 됩니다. 왜냐하면 거래 2의 인풋 UTXO가 이미 사용되어 채굴자 블록의 State에 없기 때문입니다.
대신에, 해커가 시도할 수 있는 대안이 있습니다. 거래 1이 포함된 블록 270 바로 이전의 블록 269의 지점에서 블록체인의 포크(fork)를 만들어 블록 270을 대체할 수 있는 거래 2를 포함한 새로운 블록을 채굴하기 시작합니다. 그리고 이 이후의 모든 거래들을 포함한 블록들은 재 생성하여야 합니다. 가장 긴 블록체인만이 인정을 받기 때문에, 만약 해커가 자신의 체인으로 블록체인을 완전히 바꾸고 싶다면 정말 빠른 속도로 나머지 채굴자들이 채굴해놓은 블록 270-275들을 따라잡아야 합니다. 하지만 블록 하나를 채굴하려면 작업 증명(PoW)을 다시 해야 하는데 소수의 해커 집단이 이를 따라 잡기는 현실적으로 불가능합니다.
'공부하는 삶 > 암호화폐 101' 카테고리의 다른 글
이더리움 논문 리뷰 05 이더리움 디자인 철학 (Ethereum Design Philosophy) (1) | 2021.06.22 |
---|---|
이더리움 논문 리뷰 04 스크립팅, 스마트 계약 (Scripting, Smart Contracts) (0) | 2021.06.19 |
이더리움 논문 리뷰 03 머클 트리 (해시 트리, Merkle Trees) (2) | 2021.06.18 |
이더리움 논문 리뷰 01 Bitcoin As A State Transition System (3) | 2021.06.14 |
비트코인 논문 리뷰 (3) | 2021.05.30 |