📦챕터 3

3장 · 트랜잭션

주소가 생겼다. 개인키로 서명도 할 수 있다. 이제 "철수가 영희에게 1 ETH 보낸다"는 메시지를 네트워크에 뿌리면 끝일까? 막상 구현해보니 그렇지 않았다. 유효한 서명이 담긴 메시지를 복사해서 반복 전송하면, 노드는 이게 중복 요청인지 알 방법이 없어 여러 번 처리할 수 있다. 중간에 누군가 금액만 바꿔치기할 수 있다. 노드마다 메시지를 다르게 해석하면 합의가 깨진다.

이 챕터의 질문

서명한 요청이 복사되거나 변조되거나 노드마다 다르게 읽히지 않도록, 어떤 표준 구조에 담아 보내야 할까?
🔍 비트코인(UTXO) vs 이더리움(계정 모델) 비교

비트코인은 "계좌 잔액"이라는 개념이 없어요. 이전 거래에서 받은 사용되지 않은 출력(UTXO, Unspent Transaction Output) 을 통째로 입력에 넣고, 새 출력으로 쪼개는 방식이에요. 현금에 비유하면, 이더리움이 통장 잔액에서 차감하는 방식이라면, 비트코인은 5만원권을 내고 거스름돈을 받는 방식이에요.

비트코인 (UTXO)이더리움 (계정 모델)
기본 단위사용되지 않은 출력(UTXO)을 입력으로 소비계좌 잔액에서 차감
재사용 방지한 번 쓴 UTXO는 소멸 → 구조적으로 재사용 불가Nonce 카운터
수수료입력 합 − 출력 합Gas 사용량 × 단가(Base Fee + 팁)
Data 필드없음 (제한적인 스크립트만 지원)있음 → 4장 스마트 컨트랙트의 기반
직렬화비트코인 고유 포맷RLP

이 챕터가 제기하는 세 가지 문제(복사 공격, 바꿔치기, 파싱 불일치)는 어느 블록체인이든 풀어야 하는 보편적인 문제예요. 비트코인도 같은 문제를 풀었고, 푸는 방식이 다를 뿐이에요. 재사용은 UTXO 소멸로, 바꿔치기는 전체 서명으로, 파싱은 고유 직렬화 포맷으로요.

트랜잭션: 세 문제를 한 번에 해결하는 표준 묶음

블록체인은 이 세 가지 문제를 트랜잭션이라는 표준 데이터 구조로 한 번에 해결했어요. 모든 필드를 하나의 바이트 덩어리로 포장해서 묶고, 그 전체에 서명을 씌우는 거예요.

각 데이터 앞에는 "이 데이터는 몇 바이트짜리"라는 길이 정보(RLP, Recursive Length Prefix)를 붙여요. 포장 방식이 이렇게 표준화되니 어떤 노드든 똑같이 해석하죠. 그리고 포장된 전체에 서명을 씌우니까, 내용이 한 바이트라도 바뀌면 서명 검증이 곧바로 실패해요.

필드역할막는 공격
From / To / Value보내는 주소, 받는 주소, 금액RLP 인코딩으로 파싱 통일
Nonce내 지갑의 N번째 요청동일 Nonce 재사용 불가 → 복사 공격 차단
Gas Limit / Max Fee실행 한도 + 낼 수수료의 상한다음 섹션에서 설명
Data스마트 컨트랙트 호출 데이터단순 송금이면 비어 있음
Signature (v, r, s)전체 필드에 개인키로 서명한 글자라도 바뀌면 서명 실패 → 바꿔치기 차단
Signature (v, r, s): 전체 필드에 서명트랜잭션: RLP 인코딩From / To보내는 주소 · 받는 주소Value보낼 금액Nonce내 지갑의 N번째 요청Gas Limit / Max Fee실행 한도 · 수수료 상한Data컨트랙트 호출 데이터RLP: 파싱 통일어떤 노드든 동일하게 해석재사용 불가복사해서 100번 뿌려도 1번만 처리단순 송금이면 비어 있음4장에서 이 자리가 주인공이 된다바꿔치기 차단1바이트만 바뀌어도 검증 실패
트랜잭션: RLP로 포장을 표준화하고, 전체에 서명을 씌워 세 가지 공격을 한 번에 막는다

트랜잭션 처리 과정

서명된 트랜잭션이 네트워크에 들어오면 어떤 일이 벌어질까요?

1단계: 수집 블록 생성 노드가 네트워크에 떠돌아다니는 트랜잭션들을 Mempool(메모리 풀)에 수집해요. Mempool은 아직 블록에 포함되지 않은 트랜잭션들의 대기실이에요.

2단계: 수수료 정렬 검증자에게 주는 팁(Priority Fee)이 높은 순서로 처리 우선순위를 정해요. 빨리 처리받고 싶으면 팁을 더 내는 구조예요. (수수료가 어떻게 구성되는지는 5장에서 자세히 설명해요.)

3단계: 선언 트랜잭션을 실행하기 전에 Gas fee를 확인하고 송신 계정의 Gas를 확보해요.

4단계: 실행 트랜잭션 내용에 따라 자산을 이동하거나 스마트 컨트랙트를 실행해요. 이 과정에서 Gas를 소모해요.

5단계: 잔여 반환 실행 후 남은 Gas는 송신자에게 돌려줘요. Gas가 부족하면 실행이 취소(revert)되고 상태는 원래대로 돌아가요. 단, 소모된 Gas는 돌려주지 않아요.

6단계: 블록 추가 이상 없는 트랜잭션을 블록에 담아요. 1블록 안에 담을 수 있는 총 Gas 한도(Block Gas Limit)를 초과할 수 없어요.

① 수집Mempool 대기실에 모음② 수수료 정렬팁(Priority Fee) 높은 순③ 선언송신 계정의 Gas 확보④ 실행자산 이동 · 컨트랙트 실행⑤ 잔여 반환남은 Gas 돌려줌⑥ 블록 추가Block Gas Limit 이내Gas 부족 → revert (상태 원복, 소모된 Gas는 미반환)블록 확정 = 결제 완결성(Finality)
서명된 트랜잭션이 블록에 담기기까지: 6단계 처리 과정

그래서 왜 "블록체인"인가

방금 6단계에서 트랜잭션이 "블록"에 담겼어요. 1장부터 미뤄온 질문을 여기서 풀게요. 블록이 뭐고, 왜 이름이 블록체인일까요?

블록은 트랜잭션 묶음이에요. 일정 시간(이더리움은 약 12초)마다 그동안 모인 트랜잭션들을 한 묶음으로 포장한 게 블록 하나예요. 그리고 모든 블록의 머리에는 바로 앞 블록 전체를 해시한 값이 들어가요.

이 연결이 핵심이에요. 누군가 과거 블록의 내용을 한 글자라도 바꾸면 그 블록의 해시가 달라져요. 그러면 그 해시를 품고 있는 다음 블록과 안 맞고, 다음 블록을 고치면 그다음 블록과 안 맞고, 결국 그 뒤의 모든 블록을 다시 만들어야 해요. 블록이 쌓일수록 과거 조작은 기하급수적으로 어려워져요.

1장의 "장부"가 무엇을 기록하는지였다면, 블록체인이라는 이름은 어떻게 기록하는지예요. 트랜잭션을 블록으로 묶고, 블록을 해시로 사슬(chain)처럼 이어서 과거를 사실상 불변으로 만든 구조.

약 12초마다 트랜잭션 묶음이 블록 하나로, 그리고 해시로 연결제네시스블록까지블록 N−1트랜잭션 묶음이전 블록의 해시블록 N트랜잭션 묶음이전 블록의 해시블록 N+1트랜잭션 묶음이전 블록의 해시✗ 이 블록을 조작하면?해시가 달라져 다음 블록과 안 맞는다 → 그 뒤 블록 전부를 다시 만들어야 한다블록이 쌓일수록 과거 조작은 사실상 불가능. 그래서 이름이 블록“체인”
모든 블록은 이전 블록의 해시를 품고 있다. 과거를 바꾸면 그 뒤 전부가 어긋난다
🔍 블록 안의 거래는 어떻게 한 값으로 묶이나: 머클 트리

블록 하나에는 트랜잭션이 수백 건씩 담겨요. 헤더에 이 목록을 다 넣을 수는 없으니, 값 하나로 요약해서 넣어요.

방법은 단순해요. 거래를 둘씩 짝지어 해시하고, 그 결과를 또 둘씩 짝지어 해시해요. 하나만 남을 때까지 반복하면 나무 모양이 되고, 맨 위에 남은 값이 머클 루트(Merkle Root) 예요.

               머클 루트
           ┌───────┴───────┐
         H(AB)           H(CD)
       ┌───┴───┐       ┌───┴───┐
      H(A)    H(B)    H(C)    H(D)
       │       │       │       │
      Tx A    Tx B    Tx C    Tx D

거래 하나만 손대도 그 위의 해시가 줄줄이 달라지면서 머클 루트가 바뀌어요. 헤더의 머클 루트만 대조하면 블록 안 거래 전체가 그대로인지 알 수 있어요.

여기서 하나가 더 따라와요. 머클 증명(Merkle Proof) 이에요. "내 거래가 이 블록에 들어 있다"를 확인하려면 블록 전체를 받아봐야 할 것 같지만, 트리 덕분에 몇 개만 받아도 돼요. 위 그림에서 Tx A가 들어 있는지 보려면 H(B)H(CD)만 있으면 끝이에요. 내가 가진 Tx A를 해시해 H(A)를 만들고, H(B)와 합쳐 H(AB)를, 다시 H(CD)와 합쳐 나온 값이 머클 루트와 같으면 그 블록에 들어 있는 거예요.

필요한 값이 트리 높이만큼뿐이라, 거래가 1,000건이면 10개, 100만 건이면 20개로 끝나요. 스마트폰 지갑이 수백 GB짜리 장부 없이 "내 거래가 블록에 담겼다"를 확인하는 게 이 원리예요. 크로스체인의 라이트 클라이언트PQC의 XMSS 서명도 같은 머클 구조를 씁니다.

합의 프로토콜: 누가 다음 블록을 쓸 자격이 있는가

블록에 트랜잭션을 담을 자격을 어떻게 결정할까요? 아무나 블록을 만들 수 있다면 누가 만든 게 맞는 건지 알 수 없어요.

그래서 블록체인은 이 자격을 얻는 데 큰 비용이 들도록 설계됐어요. 공격해서 얻는 이득보다 공격 비용이 더 크면 아무도 공격하지 않거든요.

PoW (Proof of Work): 비트코인

해시 퍼즐 경쟁이에요. SHA-256 해시를 반복 계산해서 특정 조건을 만족하는 값을 가장 먼저 찾은 노드가 블록을 작성해요. 전기와 하드웨어가 비용이에요.

  • 특징: 확률적 Finality, 최장 체인 규칙
  • 단점: 에너지 소비가 막대하고, Finality까지 시간이 걸려요

PoS (Proof of Stake): 이더리움

ETH를 예치(Staking)하면 검증자 자격이 생기고, 무작위로 블록 제안자를 선출해요. 부정행위 시 예치금을 몰수(Slashing)해요. 예치금이 비용이에요.

  • 특징: 2 Epoch(≈12.8분) 후 결정론적 Finality. 한번 확정된 블록은 사실상 뒤집을 수 없어요. 경제적 보안
  • 개선: 에너지 소비를 PoW 대비 99.95% 절감

BFT (Byzantine Fault Tolerance): Hyperledger Besu

허가된 노드(Validator)들만 참여해요. Pre-Prepare → Prepare → Commit 3단계 투표로 2/3 이상 동의해야 블록이 확정돼요.

  • 특징: 결정론적 즉시 Finality (1~4초), Fork 불가
  • 적합: 금융 인프라, 컨소시엄 블록체인
⛏️ PoW비트코인참여 자격누구나치르는 비용전기 · 하드웨어선출 방식해시 퍼즐 경쟁Finality확률적 (~6블록, 1시간)🪙 PoS이더리움참여 자격ETH 예치자치르는 비용예치금 (부정 시 몰수)선출 방식무작위 제안자 선출Finality결정론적 (≈12.8분 후 확정)🗳️ BFTHyperledger Besu참여 자격허가된 노드만치르는 비용허가 · 신원 공개선출 방식3단계 투표 (2/3 동의)Finality즉시 확정 (1~4초)공통 설계: 공격 비용 > 공격 이득
세 방식 모두 원리는 하나. 블록을 쓸 자격에 비용을 매겨, 공격 비용이 이득보다 크게 만든다
🛠 시스템을 운영해봤다면: 익숙한 개념과의 대응표

분산 시스템을 다뤄본 개발자라면 이 챕터의 개념이 낯설지 않을 거예요. 비슷한 점과 결정적 차이를 정리하면 이래요.

블록체인비슷한 것결정적 차이
노드DB 레플리카 (전 노드가 같은 데이터)마스터가 없고, 서로를 신뢰하지 않음
Mempool메시지 큐의 대기열전 세계가 공유하는 하나의 큐, 수수료 순 처리
합의 (PoW/PoS/BFT)Raft·Paxos 같은 분산 합의참여자가 악의적일 수 있다는 가정(비잔틴 장애)에서 출발
Block FinalityDB 트랜잭션의 커밋한번 확정되면 롤백이라는 개념 자체가 없음
스마트 컨트랙트 (4장)저장 프로시저(Stored Procedure)배포 후 누구도(만든 사람도) 수정할 수 없음

요약하면, 블록체인은 "참여자를 믿을 수 없는 환경에서 돌아가는 분산 DB"예요. 기존 분산 시스템이 장애(crash)를 견디도록 설계됐다면, 블록체인은 거짓말(byzantine fault)을 견디도록 설계됐어요.

그런데 새로운 문제가 생겼어요

트랜잭션으로 숫자를 옮기는 건 해결했어요. 그런데 비트코인을 쓰면서 사람들이 깨달았어요. 블록체인이 결국 "장부에 숫자 옮기기"밖에 안 된다는 걸요.

에스크로, 대출, 보험 등 현실의 금융 계약은 거의 다 조건부예요. "집 등기가 넘어오면 대금을 지급", "담보 가치가 기준 이하로 떨어지면 자동 청산". 이걸 지금은 전부 사람이 중간에서 판단하고 실행해요. 은행, 변호사, 공증인이 그 역할을 하고요.

다음 챕터의 질문

은행도 변호사도 공증인도 없이, 조건이 맞으면 계약이 저절로 실행되게 할 수는 없을까?

4장에서 이 문제를 어떻게 해결했는지 알아볼게요.

핵심 요약

개념역할
Nonce재사용 방지. 복사 공격 차단
Signature전체 필드 서명. 바꿔치기 차단
RLP표준 직렬화. 파싱 불일치 차단
Mempool블록 포함 전 트랜잭션 대기실
블록트랜잭션 묶음 + 이전 블록 해시. 해시 연결로 과거 불변
Gas처리 수수료 + 실행 한도
Block Finality블록 확정 = 결제 완결성
PoW해시 퍼즐 경쟁. 확률적 Finality
PoSETH 예치 + Slashing. ≈12.8분 후 결정론적 Finality
BFT허가 노드 투표. 결정론적 즉시 Finality
📚 참고자료 보기