본문 바로가기

Blockchain/Bitcoin

거래 (Transaction)

1. 거래의 생성
거래는 간단하게 돈을 송금한다는 의사표시로 생각할 수 있으며, 실제로 제출되기 전까지는 금융 시스템 내에 보이지 않는다.
거래는 온라인 혹은 오프라인 상에서도 가능하며, 이는 거래의 내용과 서명이 체인상에서 발생하는 것이 아니라는 것을 의미한다.
즉 거래는 체인과 무관하게 발생하며, 이를 실제로 의미있는 거래가 되게 하기 위해서는 체인 상에 전파하는 것이 필요하다.
거래는 간단하게 그 거래의 내용이 존재하며, 서명으로 그 거래가 유효한 거래임을 표시하는 과정으로 구성되어 있다.
거래에는 개인키를 비롯하여 어떠한 민감한 정보가 포함되어 있지 않기 때문에 네트워크 상에서 공개되어도 무방하다.

2. 거래의 전송
비트코인 기준 거래의 크기는 300~400바이트 크기이며, 노드 중에 하나에 도달해야 블록체인에 포함될 수 있다.

3. 거래의 전파
거래가 한 노드로 전송되면 해당 노드에 의해 거래가 유효화 된다.
유효화된 거래는 해당 노드와 연결된 다른 노드에 전파되고, 동시에 성공 메시지가 생성자에게 전달된다.
유효하지 않은 거래는 생성자에게 거절 메시지가 돌아간다.
스패밍, 서비스거부 공격 등 네트워크에 위해가 가해질 수 있는 공격을 사전에 차단하기 위해 모든 노드는 독립적으로 모든 거래를 유효화한 뒤 해당 거래를 다른 노드로 전파한다.

4. 거래의 구조
거래는 비트코인 기준 버전, 입력값 카운터, 입력값, 출력값 카운터, 출력값, 잠금시간으로 구성되어 있다.
===================================
버전: 4바이트, 해당 거래가 따르는 규칙을 명시
입력값 카운터: 1 ~ 9바이트, 포함된 입력값의 개수
입력값: 가변적, 하나 이상의 거래 입력값
출력값 카운터: 1 ~ 9 바이트, 포함된 출력값의 개수
출력값: 가변적, 하나 이상의 출력값
잠금시간: 4바이트, 유닉스 타임스탬프나 블록 개수

5. 거래 출력값과 입력값
비트코인에서는 소비되지 않은 거래 출력값(UTXO: Unspent Transaction Output)이 블록을 구성하는 기본 요소다.
네트워크는 이용 가능한 UTXO를 모두 추적하며, 사용자가 비트코인을 수령할 때마다 해당 금액을 블록체인 내에 기록한다.
사용자가 보유한 비트코인 잔액이라는 개념은 실제로 존재하는 개념이 아니며, 소유한 UTXO의 잔액 전부를 더한 것에 불과하다.
비트코인은 소수점 8자리의 사토시로 표현된다.
채굴한 블록에 대한 보상은 코인베이스(coinbase)라는 거래이며, 이 경우 다른 거래와 다르게 입력값 없이 출력값만 존재한다.

5.1. 거래 출력값
모든 비트코인 거래에서는 거래 출력값이 존재하며, 대부분의 출력값은 UTXO다. (OP_RETURN의 경우 데이터 출력)
거래 출력값은 두 부분으로 구성된다.
=======================================
총액: 8바이트, 사토시 단위로 표현되는 비트코인 가치
잠금스크립트 크기: 1 ~ 9 바이트, 따라 나오는 바이트 단위의 잠금 스크립트 길이
잠금스크립트: 가변적, 출력값을 소비하는 데 필요한 조건을 규정하는 스크립트

5.2. 거래 입력값
거래 입력값은 UTXO가 블록체인 내에 기록되는 경우 해당 거래의 해시와 일련번호를 참조하여 특정한 UTXO를 지정한다.
UTXO를 소비하기 위해서 거래의 입력값에는 UTXO에 의해 설정된 소비 조건을 만족시키는 해제 스크립트도 포함되어야 한다.
해제 스크립트는 대개 잠금 스크립트내에 있는 비트코인 주소의 소유권을 입증하는 서명이다.
UTXO가 출금을 위해 선택되면 지갑은 UTXO 각각을 위한 서명을 담고 있는 해제 스크립트를 생성함으로써 UTXO가 잠금 스크립트 조건을 만족시켜서 소비될 수 있도록 해 준다.
==================================================
거래 해시: 32바이트, 소비될 UTXO를 담고 있는 거래에 대한 지시자
출력값 인덱스: 4바이트, 소비될 UTXO의 색인번호(최초는 0)
해제 스크립트 크기: 1 ~ 9 바이트, 따라 나오는 바이트 단위의 해제 스크립트 길이
해제 스크립트: 가변적, UTXO 잠금 스크립트의 조건을 충족하는 스크립트
일련번호: 4바이트, 현재 장애가 있는 Tx대체 기능, 0xFFFFFFFF로 설정

6. 거래 수수료
대부분의 거래는 수수료를 포함하며, 이는 비트코인 채굴자들에게 제공하는 일종의 보상이다.
거래 수수료는 모든 거래에 소액의 비용을 부과함으로써 다음 블록에 거래를 포함시키는 데 대한 동기부여의 역할과, 스팸거래나 시스템 오용에 대해서 동기상실의 역할도 한다.
거래 수수료는 킬로바이트 단위의 거래 크기를 근거로 계산된다.
거래 수수료는 거래의 우선순위에 영향을 미치며, 수수료가 없는 거래도 언젠가 처리될 것이지만 처리시간이 지연된다.

7. 거래 수수료 추가하기
거래 수수료는 입력값에서 출력값을 뺀 값이며, 비트코인 기준 수수료 필드가 거래에 따로 존재하지 않기 때문에 유의해야한다.
수수료는 이동하는 금액에 따라 늘어나는 것이 아니라 거래의 복잡도와 규모의 크기에 따라 변동된다.

8. 거래 사슬과 고아거래
거래는 사슬을 형성하고 있으며, 사슬에 따라 이전거래의 출력값을 소비하여 다음 거래를 위한 출력값을 생성한다.
서로 연결되어 있는 거래 사슬 전체 구성요소가 동시에 생성될 수도 있다.
이 경우 유효한 자식거래에 먼저 서명을 받은 후 부모거래에 서명을 받아야 하는 복잡한 거래 흐름에 따라 거래를 실행하기 위함이다.
코인조인(CoinJoin) 거래에 이와 같은 기법이 사용된다.
사슬이 네트워크 상에 전송될 때, 항상 차례대로 도착하는 것은 아니기 때문에 자식거래가 부모거래보다 먼저 도착할 때도 있다.
이 경우 자식거래는 거부되는 것이 아니라 고아거래 풀(Orphan Transaction Pool)에 저장되었다가 부모거래가 도착하면 재유효화되서 올바른 순서대로 기록되게 된다.
비트코인의 경우 노드에 대한 서비스거부(DoS) 공격을 예방하기 위해 메모리 속에 보관할 수 있는 고아거래 건수는 제한되어 있다.
제한건수는 기본 클라이언트의 소스코드 내에 있는 MAX_ORPHAN_TRANSACTUINS에서 정한다.
풀 내의 고아거래 건수가 제한 건수를 초과하는 경우 무작위로 하나 이상의 고아거래를 선택해서 풀에서 내보낸다.

9. 거래 스크립트와 스크립트 언어
비트코인 클라이언트는 포스(Forth) 언어처럼 구성된 스크립팅 언어로 작성된 스크립트를 실행해서 거래를 유효화한다.
UTXO의 잠금, 해제 스크립트는 모두 이 스크립팅 언어로 작성된다.

9.1. 스크립트 구성(잠금+해제)
잠금 스크립트는 출력값에 위치한 예상지출로, 향후 출력값을 소비하기 위해 충족되어야 하는 요건을 명시하고 있다.
잠금 스크립트에는 보통 공개키 혹은 비트코인 주소가 담겨 있기 때문에 스크립트펍키(ScriptPubKey)라고 부르기도 했다.
해제 스크립트는 잠금 스크립트가 출력값에 놓아 둔 조건을 해결하거나 충족시켜서 출력값이 소비될 수 있도록 하는 스크립트다.
해제 스크립트는 모든 거래의 입력값에 들어있는 요소이며 대부분의 경우 해제 스크립트는 사용자의 지갑이 개인키로부터 생성한 디지털 서명을 담고 있다.
해제 스크립트에는 보통 디지털 서명이 담겨 있기 때문에 스크립트시그(ScriptSig)라고 불러왔다.
모든 비트코인 클라이언트는 잠금 스크립트와 해제 스크립트를 함께 실행해서 거래를 유효화시킨다.
최초의 비트코인 클라이언트에서는 잠금 스크립트와 해제 스크립트를 동시에 실행시켰으나, 비정상적인 해제 스크립트를 이용하여 잠금 스크립트 오류를 발생시키는 취약성 때문에 현재는 따로 작동한다.
실행순서
1. 해제 스크립트는 스택 실행 엔진을 이용하여 실행된다.
2. 해제 스크립트가 오류 없이 실행되는 경우 메인 스택이 복사되면서 잠금 스크립트가 실행된다.
3. 해제 스크립트로부터 복사된 스택 데이터와 함께 실행된 잠금 스크립트의 결과가 TRUE면 해제 스크립트는 잠금 스크립트가 부과한 조건을 해결하는 데 성공한 것이다.

9.2. 스크립팅 언어
비트코인의 스크립팅 언어는 스택이라고 불리는 데이터 구조를 사용하기 때문에 스택 기반 언어라고 한다.

9.2.1. 튜링 불완전성
스크립트 언어는 조건부 흐름 제어 기능 외에는 루프나 복잡한 흐름제어 능력을 가지고 있지 않다.
이를 통태 스크립트 언어는 튜링이 완전하지 않다는 사실을 확인할 수 있다.
즉 비트코인 거래 스크립트는 복잡성이 제한되고 실행 시간이 예측 가능하다.

9.2.2. 무상태형 검증
비트코인 거래의 스크립트 언어는 무상태형이며, 스크립트 언어 내에서는 스크립트 실행 전 혹은 실행 후에 저장되는 상태가 없다.
따라서 스크립트를 실행하는데 필요한 모든 정보는 스크립트 내에 담겨 있다.

9.3. 표준거래
비트코인의 개발자들은 기본 클라이언트로 처리할 수 있는 스크립트의 형태를 몇 가지로 제한했다.
5가지 표준거래 유형
1. pay-to-public-key-hash(P2PKH)
2. 공개키
3. 다중서명(15개의 키로 제한)
4. pay-to-script-hash(P2SH)
5. 데이터 출력(OP_RETURN)

9.3.1. Pay-to-Public-Key-Hash(P2PKH)
비트코인 거래 대부분을 차지하며, 공개키 해시를 이용해 출력값에 대한 예상지출을 실행하는 잠금 스크립트가 포함되어 있다.
P2PKH 스크립트로 잠겨 있는 출력값은 공개키와 공개키에 대응하는 개인키가 생성한 디지털 서명을 사용하여야만 해제가 가능하다.

9.3.2. Pay-to-Public-Key(P2PK)
Pay-to-Public-Key는 P2PKH보다 단순한 비트코인 지불 방식이다.
공개키가 잠금 스크립트 내에 자체적으로 저장되어 길이가 훨씬 짧아지게 된다.
P2PKH의 경우 공개키 해시가 저장된다.
P2PKH는 사토시가 비트코인 주소를 짧게 만들어 쉽게 사용하기 위해 발명하였다.
P2PK는 코인베이스 거래에서 자주 나타난다.

9.3.3. 다중서명
다중서명은 N개의 공개키가 스크립트 내에 기록되어 있고, 예상지출 상태를 풀기 위해서는 이 중 적어도 M개 이상의 개인키가 서명을 제공해야 한다는 조건을 설정한다.
M-of-N 제도로도 알려져 있는 다중서명 제도 하에서는 N의 키의 총 개수이며 M은 유효화를 위해 필요한 서명의 기준값(threshold)이다.

9.3.4. 데이터 출력(OP_RETURN)
비트코인에서 목적지 비트코인 주소의 20바이트 공간을 자유로운 목적으로 사용함으로써 소비될 수 없는 UTXO를 생성할 수 있다.
목적지 비트코인 주소는 데이터용으로 사용되기 때문에 개인키에 대응하지 않아서 결과값으로 산출된 UTXO는 절대 소비될 수 없다.
이는 인메모리 UTXO 세트 크기를 증가시켜서 절대 소비될 수 없는 거래를 메모상에서 제거할 수 없게 만든다.
결국 비트코인 노드가 이 거래들을 RAM 속에 영원히 보관하면서 더 많은 비용을 초래하게 된 것이다.
이에 비트코인 코어 클라이언트 버전 0.9에서는 OP_RETURN 연산자를 도입하였다.
OP_RETURN을 통해 개발자들은 40바이트 크기의 비지불데이터를 거래 출력값에 추가할 수 있게 되었다.
OP_RETURN 연산자는 명백하게 지출될 수 없음이 입증되느 출력값을 만들기 때문에 해당 출력값은 UTXO 세트에 저장될 필요가 없다.
OP_RETURN 출력값은 블록체인에 기록되므로 디스크 공간을 소모하여 블록체인의 크기가 커지게 만들지만, UTXO 세트에는 저장되지 않기 때문에 UTXO 메모리 풀을 확장시키지도 않고, 풀 노드에게 RAM 비용 부담을 안기지도 않는다.

9.3.5. Pay-to-Script-Hash(P2SH)
P2SH는 해당 출력값이 소비된 후에 제공되며 해시와 일치하는 스크립트로 지불하는 방식이다.
P2SH 거래에서 해시로 대체되는 잠금 스크립트를 리딤 스크립트(Redeem Script)라고 한다.
왜냐하면 이 스크립트는 잠금 스크립트라고 하기보다 거래 금액이 현금화하는 시기에 시스템에 제공되기 때문이다.
P2SH로 인코딩되는 경우 출력값을 소비하는데 필요한 조건을 상세히 열거한 복잡한 형태의 스크립트(리딤 스크립트)는 잠금 스크립트에서는 제시되지 않는다.
대신 리딤 스크립트의 해시만이 잠금 스크릅트 내에 존재하고 리딤 스크립트 자체는 출력값이 소비되는 때에 해제 스크립트의 일부로 제시된다.
P2SH의 거래에서는 리딤 스크립트가 해시와 잠금 스크립트의 해시와 일치하는지 확인하는 단계를 거친 뒤, 일치하는 경우 해제 스크립트는 리딤 스크립트를 해제하기 위해 스스로 실행된다.

9.3.5.1. Pay-to-Script-Hash의 이점
복잡한 스크립트는 거래 출력값에서 더 짧은 지문으로 대체되어 해당 거래의 크기를 줄인다.
스크립트는 주소로 코딩될 수 있다. 따라서 송싱자와 그 지갑은 P2SH를 실행하기 위해 복잡한 작업이 필요하지 않다.
P2SH는 스크립트를 만드는 부담을 송신자가 아니라 수취인에게 부담시킨다.
P2SH는 출력값(출력값은 UTXO 세트 내에 들어 있기 때문에 메모리에 영향을 끼침)이 가지고 있던 데이터 저장에 대한 부담을 입력값(입력값은 오직 블록체인상에서만 저장)으로 옮긴다.
P2SH는 긴 스크립트를 저장해야 하는 부담을 현재에서 미래로 미룬다.
P2SH는 긴 스크립트의 거래 수수료 비용 부담을 송신자에서 수취인으로 옮긴다. 수취인은 거래의 출력값을 소비하기 위해서는 길이가 긴 리딤 스크립트를 거래의 입력값에 포함시켜야 한다.

 

참고

마스터링 비트코인