Chapter 5. 트랜잭션

Yeonuk
Programming Bitcoin
12 min readMay 31, 2020

아래 글에서는 “밑바닥부터 시작하는 비트코인(Programming Bitcoin) -한빛미디어(2019)”의 Chapter 5. 트랜잭션( Transaction ) 에 대한 내용을 다룬다. 트랜잭션이 무엇인지, 즉, 블록체인을 배우는 입장에서 트랜잭션이 어떤 컴포넌트로 구성되어 있는지에 대해 구체적으로 설명한다. CS 에서의 효율적인 접근 및 수정을 위한 일부 자료구조가 포함되어 있는 부분은 이미지 파일을 통한 간단한 예제로 접근하였다.

Programming Bitcoin Series

Chapter 1. 유한체
Chapter 2. 타원곡선
Chapter 3. 타원곡선 암호
Chapter 4. 직렬화
Chapter 5. 트랜잭션
Chapter 6. 스크립트
Chapter 7. 트랜잭션 검증과 생성
Chapter 8. p2sh 스크립트
Chapter 9. 블록
Chapter 10. 네트워킹
Chapter 11. 단순 지급 검증
Chapter 12. 블룸 필터
Chapter 13. 세그윗

Contents

  1. 트랜잭션 이란?
  2. 트랜잭션 구성 요소

2–1. 버전

2–2. 입력

2–3. 출력

2–4. 록타임

2–5. 트랜잭션 수수료

2–6. 마치며

3. 참조

트랜잭션 이란 ?

블록체인 상에서 발생하는 거래이다.

우리가 알던 기존의 거래 방식은 일반적인 은행이 모든 거래 내역을 소지하고 거래 내역을 중앙은행이 증명하고 거래의 당사자들은 중앙은행을 신뢰하는 형식으로 거래 내용과 증명을 모두 맡기는 형태였다.

반면, 블록체인 상에서의 거래는 거래내역을 중앙은행이 아닌 모두가 볼 수 있고 저장할 수 있는 여러 곳에 저장하는 것이다.

즉, 송금한 사실을 거래에 참여하고 있는 모든 이가 저장한다는 것이다.

모든 이가 저장을 하기 때문에 송금의 증명 또한 가능해진다.

이러한 거래형태는 모르더라도 거래를 할 수 있다. 그러나 알고 하는 것과 모르고 하는 것에는 큰 차이가 있기 때문에 이런 거래형태가 이뤄지는 과정과 구조에 대해 알아보도록 하자.

트랜잭션 구성 요소

트랜잭션은 비트코인의 핵심이며, 모든 토큰의 중요한 요소이다.

이는 총 네 가지 요소로 구성이 된다. 하나씩 알아보도록 하자.

1. 버전

버전은 트랜잭션의 버전을 의미한다.

즉, 이 트랜잭션이 어떤 부가 기능을 사용할 수 있는가에 대해 규정한다.

  • 버전의 표현

버전은 비교적 간단한 정보를 담고 있다. 따라서 버전을 알고 있다면, 트랜잭션 상에서 어떤 기능을 갖게 되는지 알 수 있게 된다는 것이다.

비트코인의 경우 트랜잭션 버전은 보통 1 또는 2 이다. (대체로 1을 사용한다.)

16진수로 표현하기 때문에 맨 앞에 표시한다.

ex) 0x01000000

이 4 byte 값을 리틀 인디언으로 읽게 되면 1이 된다.

2. 입력

입력은 사용할 비트코인을 정의 하며, 각각의 입력은 이전 트랜잭션의 출력 내용과 연관되어 있다.

비트코인을 사용하기 위해서는 먼저 비트코인을 어딘가에서 받아야 한다.

소유한 돈이 없으면 사용할 수 없듯이 말이다.

입력에서 본인이 소유한 비트코인을 정확히 가리키기 위한 2가지 조건이 있다.

  • 소유의 증명을 위한 2가지 조건
  1. 과거 내가 수신한 비트코인을 가리키는 정보
  2. 받은 비트코인이 나의 소유라는 증명

1번 조건을 충족하기 위한 내용은 뒤에서 보충하도록 하고, 2번의 증명으로 넘어가면, 간단히 비트코인 거래를 하기 위해 생성한 개인키 속 전자서명으로 증명을 하면 된다.

  • 입력의 표현

입력은 여러 개를 포함할 수 있다.

왜냐하면 가령 1000원을 소지했다고 할 때, 이 1000원권 하나를 소비할 수도, 100원짜리 동전을 10개 소비할 수도 있기 때문이다.

코드 스크립트상에서 입력의 수는 트랜잭션 버전 부분 다음에 덧붙여 기술된다.

입력의 수를 표시하는 데 대부분 1 Byte 를 사용한다. 그렇기 때문에 ²⁸ 개(Unit : Bit) 이상의 수를 표현하기 위해서 Varints 의 개념을 도입한다.

  • 더 많은 표현을 위한 Varints 란?

Varints 란 입력 개수를 표현하는 것으로 가변 정수(Variable Integer)의 약자로 2⁶⁴ 개 까지의 정숫값을 Byte로 표현하는 방법이다.

즉,2⁶⁴ 개 까지 표현하기 위해서는 항상 8 Byte 로 표현하면 된다. 그러나 이렇게 계속 사용하게 된다면 사용하는 값의 빈도 수에 따라 Byte 의 낭비가 심할 수 있다. 이에 대한 절충안으로 나온 것이 Varints 로 섹션 별 표현 법을 달리 하는 것이다.

아래 그림은 Varints 를 위한 표와 그와 관련한 1, 2, 4 Byte Random Value를 통한 예제를 첨부하였다.

Varint Table inLittle Endian ( 아이패드를 통한 작성자의 필기 자료 )
1 Byte 예시 ( Hex To Decimal )
2 Byte 예시 ( Swap Endian, Hex To Decimal )
4 Byte 예시 ( Swap Endian, Hex To Decimal )

0401 이 많이 나온 이유는 작성자의 생일이기 때문이다 :)

  • 입력의 구성

입력은 총 네 가지의 하부 필드를 가지고 있다.

  1. 이전 트랜잭션 해시값 혹은 ID
  2. 이전 트랜잭션 출력 번호
  3. 해제 스크립트
  4. 시퀀스

이전 트랜잭션 해시값 혹은 ID

각각의 입력은 이전 트랜잭션의 출력을 가리키고 있다. 이전 트랜잭션의 출력은 해시값으로 표현이 되며, 이 해시값은 Hash256을 통해 표현이 된다. 이 값은 해시 충돌이 거의 없기 때문에 (Chapter 1, 2 참고) 이전 트랜잭션을 특정 지을 수 있다. 때문에 이 값은 ID 라 표현되기도 한다.

이전 트랜잭션 출력 번호

각 트랜잭션은 적어도 하나 이상의 출력을 가지고 있다. 출력도 여러개가 존재할 수 있기 때문에 정확히 몇 번째 출력인지에 대한 정보도 특정 지을 필요가 있다. 출력 번호는 4 Byte 로 구성이 된다. 출력 단에서는 총 8 Byte 까지 표현이 가능한데 이에 따라 발생할 수 있는 문제에 대해서는 뒤에서 배우도록 하자.

해제 스크립트

해제 스크립트는 비트코인의 스마트 계약 언어인 Scripts 를 구성하는 한 부분이다.

간단히, 트랜잭션 출력의 소유자만이 할 수 있는 무언가를 나타낸다고 생각하면 된다.

해제 스크립트의 필드는 이례적으로 길이가 가변적이다. 정확한 길이를 먼저 알아야 파싱( Pasing )이 가능하기 때문인데(트랜잭션 조회와 증명을 위해서) , 이를 위해 해제 스크립트의 필드는 variant 형식으로 시작해서 먼저 필드의 길이를 설정한다.

시퀀스

시퀀스(Sequence) 는 개인적으로 비트코인 내에서 흥미로운 필드이다.

사토시가 시퀀스를 고안한 계기는 빈번한 거래 때문이다.

빈번한 거래가 발생할 때, 그 거래를 일일이 블록체인에 기록하지 않고 거래할 수 있도록하는 것이 시퀀스인데 이는 최종 마지막 정산 결과만 기록하기 위해서 이다.

때문에 굉장히 좋은 생각이라고 보일 수 있으나 안타깝게도 단점이 있었다.

바로 채굴자들이 악용하기 쉽다는 점인데, 정확한 정산이 이뤄지기 전에 최종 결과만을 담고 트랜잭션의 정산을 끝낸다면 최종적인 시퀀스 넘버의 거래만 이뤄지는 점을 악용하는 것이였다.

그러나 이런 단점에도 불구하고 이러한 생각들이 발전하여 이후 ‘ 지불 채널 ’ 이 고안이 되고 현재의 ‘ 라이트닝 네트워크 ’의 토대가 되기도 하였다. 지불 채널과 라이트닝 네트워크에 대해서는 추후에 다루도록 하자.

3. 출력

출력은 비트코인이 어디로 향하는지를 정의한다.

개개의 트랜잭션은 하나 이상의 출력을 갖고 있는데, 하나 이상의 출력을 가질 수 있기 때문에 받는 사람이 여러 명일 때 한 번의 트랜잭션으로 모든 사람에게 보낸다.

  • 출력의 표현

출력의 표현도 입력과 동일하게 기능한다.

Varints 형식으로 필드를 구성한다.

출력의 구성과 출력의 중요한 개념인 UTXO 에 대해 알아보자.

  • 출력의 구성과 UTXO
  1. 토큰의 금액
  2. 잠금 스크립트
  3. UTXO (Unspent transaction output) 란?

토큰의 금액

토큰의 금액은 출력이 내포하는 비트코인의 양이다. 단위는 ‘사토시’ 라고 불린다.

1 사토시는 1 억 분의 1 비트코인으로 매우 작은 단위 이다. 최대 금액은 4 Byte 로 담을 수 없기 때문에 8 Byte 를 사용한다. 이 금액은 리틀엔디언으로 정리하며 직렬화를 사용한다. 이는 입력의 출력번호의 크기인 4 Byte 를 초과하는 크기이기 때문에 4 Byte 의 개수를 초과하는 출력 번호를 참조하지 못하는 문제가 발생한다.

이에 대한 해결책으로, 비트코인 발행량을 사토시 단위까지 변환한 뒤 2^N 승으로 표현하면 대략의 출력 하부필드 크기를 유추할 수 있다. 이를 바탕으로 Varints 형식을 활용해 최대 2⁶⁴ — 1 까지의 정수를 나타내는 것으로 초과하는 필드의 문제점을 보완한다.

잠금 스크립트

해제 스크립트와 동일하게 비트코인의 Smart Contract언어인 Script 로 사용된다.

누구나 입금할 수 있는 통장이지만 통장의 소유주만 출금할 수 있는 통장이라고 생각하면 될 것이다.

잠금 스크립트도 Variant 형식으로 시작하는 가변적인 길이를 갖는 필드이다.

그렇다면 출력이 되지 않은 사용하지 않은 출력에 대해서 어떤 식으로 증명이 될까?

총 출력 양에서 사용되지 않은 출력인 UTXO 에 대해 알아보도록 하자.

UTXO (Unspent transaction output) 란?

UTXO 는 아직 사용하지 않은 트랜잭션의 출력을 의미한다.

이러한 미사용 트랜잭션 출력의 전체 집합을 ‘UTXO 집합’ 이라고 정의한다.

UTXO은 토큰에서 중요한 부분 중 하나이다.

현재 사용 가능한 모든 비트코인을 의미하기 때문에 이 집합이 현재 유통 중인 모든 비트코인을 의미한다.

네트워크상의 풀 노드는 UTXO 집합을 항상 최신 상태로 유지해야 한다. 새로운 트랜잭션의 검증을 빠르게 할 수 있게 도와주기 때문이다.

UTXO 를 활용한 Use Case 중 하나는 UTXO 집합에서 이전 트랜잭션을 출력을 확인해보는 것으로 손쉽게 이중 지불을 막을 수 있다. 만약 새 트랜잭션의 입력이 UTXO 집합에 없는 이전 트랜잭션의 출력을 가리키고 있다면 이중 지불 시도로 보거나 단순히 없는 출력을 참조하는 것이므로 새 트랜잭션은 바로 검증에서 탈락하고 네트워크로 전파되지 않고 버려지게 할 수 있다.

즉, 트랜잭션의 검증을 위해 이전 트랜잭션 출력으로부터 비트코인 금액과 잠금 스크립트를 자주 확인해야 하기 때문에 UTXO 의 갱신은 매우 중요하다.

4. 록타임

록타임은 트랜잭션의 유효시점을 규정한다.

즉, 트랜잭션 전파 후 실행을 지연시키는 방법을 제공한다는 것이다.

규정된 록타임 값은 트랜잭션 상 블록은 개수를 초과할 수 없다.

록타임은 시퀀스와 같은 맥락으로 원래 빈번한 거래 상황을 위해 고안 되었으나, 이후 보안상의 문제가 밝혀져 수정이 된 사례가 있다.

사례를 보기 전, 록타임의 필드가 무시되는 경우부터 알아보자.

  • 록타임 필드가 무시되는 경우

입력에 포함된 시퀀스 값이 ffffffff 가 되면 록타임 값은 무시된다.

이는 코드 상 트랜잭션 입력의 시퀀스가 1개여도 록타임이 무시되는 것을 의미한다.

다시 돌아와 발생한 보안 문제에 대해 알아보도록 하자.

  • 록타임의 보안 문제

서두에 잠깐 다룬 보안상의 문제에 대해 다뤄 보도록 하자.

초기의 록타임은 록타임 값이 일정 크기와 같거나 크게 되면, 유닉스 타임으로 해석하며 일정 크기 이하이면 블록 높이로 해석하는 것 문제가 있었다.

이러한 문제는 트랜잭션이 록타임에 도달했을 때 트랜잭션의 수신자가 트랜잭션이 유효한지 확신할 수 없다는 점으로, 마치 부도 가능성이 있는 은행수표를 오래 지니는 것과 같은 상황이였다.

이러한 문제를 해결하기 위해 조금의 수정이 이뤄 졌는데 이를 BIP 65 에서 다룬다.

  • BIP 65

BIP 65 는 간단히 록타임 출력을 사용하지 못하게 하여 이러한 상황을 방지한다.

BIP65 는 잠금 가능 시간 증명 및 확인을 위한 비트코인 코어 0.12 버전에서 OP_Code 를 재정의하기 위한 소프트포크이다.

록타임이 최고점일 때의 규모가 거래의 록타임 필드보다 큰 지 확인하여 조건에 부합하는지 확인한다. 조건에 부합하는 조건이 하나라도 존재하는 경우, 유효하지 않은 거래로 분류하는 것으로 문제를 해결하였다.

5. 트랜잭션 수수료

비트코인 합의 규칙 중 하나는 모든 트랜잭션의 입력 합은 출력의 합보다 같거나 커야한다. ( 코인베이스의 트랜잭션은 예외이지만 다음에 다루는 것으로 하자. )

그러나 입/출력이 동일한 경우는 거의 없다. 그 이유는 수수료 때문이다.

만일 트랜잭션의 수수료가 0 원이라면 무슨 일이 발생할까?

당연한 생각이지만 채굴자가 트랜잭션을 블록에 포함시킬 동기가 사라진다.

채굴자가 무상으로 트랜잭션을 검증해줄 작업증명 작업을 하려 하지 않기 때문이다.

수수료는 컴퓨팅 파워를 제공해주는 채굴자에게 주어지는 인센티브라고 생각 하면 된다.

그렇다면 수수료를 책정하는 기준을 알아보도록 하자.

  • 수수료 계산

비트코인의 경우 단순히 입력의 합에서 출력의 합을 뺀 값이다.

이 차이를 채굴자가 가져간다.

이쯤에서 한 번 생각해본다면 비트코인이 다른 자산에 비해 안전한 이유가 무엇일까?

내가 생각하기에 많은 이유 중 하나는 수수료 제도를 통한 자발적인 컴퓨팅 파워를 제공 받아 거래의 검증을 하는 것, 이를 통해 주어진 데이터를 그대로 믿지 않고 여러 가지 방법으로 검증하기 때문이라고 생각한다.

6. 마치며

많이 접했겠지만 1998년 Smart Contract 기반의 암호화폐인 비트골드( bit gold )를 고안한 사람인 닉 사보는 그의 저명한 에세이에서 ‘ 신뢰하는 제 3자가 보안의 구멍이다 ’ 라는 말을 남겼다. 이는 신뢰하는 제 3 자가 주는 정보이기에 정보에 오류가 없을 것이라는 생각은 보안적인 측면에서 좋지 못한 방법임을 말한다.

제 3자는 현재 어떠한 문제가 없더라도 언제 달라질지 모른다.

제 3자의 중요한 데스크톱이 해킹을 당하든 기업 속 사원들이 금전적, 또는 다른 이유로 악의적인 마음을 먹거나여러 상황에 따라 고객의 이익에 반하는 정책을 수립할 수도 있다.

토큰의 트랜잭션, 이 작은 한 부분에서도 사람이 아닌 시스템상에서 이처럼 검증방법을 도입하고 다양한 암호화를 진행하기 때문에 우리는 암호화한 토큰을 신뢰할 수 있는 것이라고 나의 빈약한 생각을 전하며 글을 마친다.

--

--