[Bitcoin] - ch5-1. 거래

‍허진·2023년 3월 2일
0

Blockchain

목록 보기
5/19
post-thumbnail

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

> 비트코인에서의 거래

비트코인에서 거래는 가장 중요한 요소로, 거래를 제외한 다른 모든 요소들은 거래가 생성되고 네트워크 상에서 전파된 후 승인되어 최종적으로는 전 세계에 걸친 거래 장부(블록체인)에 거래가 추가될 수 있도록 설계되었다. 거래란 비트코인 시스템 내에 있는 참가자들 간 가치를 전송하는 행위를 인코딩한 데이터 구조를 말한다. 각 거래는 전 세계적인 복식부기 장부에 들어있는 공개된 항목이다.

[그림 - 거래 예시]

위의 화면에서는 송신자의 주소에서 수신자의 주소로 이동하는 거래를 보여준다. 하지만 위에서 제공되는 정보들은 사실 거래 내에 존재하는 것이 아니고 블록 익스플로러 어플리케이션에서 구성해주는 것이다.

거래 이면을 보면, 실제 거래는 블록 익스플로러가 제공하는 거래와 매우 다르게 보인다. 실제로 사용자가 인터페이스에서 볼 수 있는 고급 구성 요소들은 비트코인 시스템 내에 실제로 존재하지 않는다.

다음은 비트코인 거래에 실제로 담겨있는 정보들이다.

{
  "version": 1,
  "locktime": 0,
  "vin": [
    {
      "txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
      "vout": 0,
      "scriptSig" : "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 0.01500000,
      "scriptPubKey": "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": 0.08450000,
      "scriptPubKey": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG",
    }
  ]
}

거래 정보를 보면, 송신자와 수신자의 주소나 잔액, 계좌 등은 찾아볼 수 없다.

> 거래 출력값과 입력값

비트코인 거래로 구성되어 있는 블록을 구성하는 기본 요소는 거래 출력값(transaction output) 이다. 거래 출력값은 블록체인상에 기록되어 있으며 전체 네트워크에 의해 통화 단위로 인정받은 불가분의 비트코인 통화 덩어리다.
비트코인 풀 노드는 소비되지 않은 거래 출력값(unspent transaction output), 즉 UTXO라는 사용 및 소비가 가능한 모든 출력값을 추적한다. UTXO 세트는 새로운 UTXO가 생겨나면 커지고 UTXO가 소비되면 작아진다. 모든 거래는 UTXO 세트 내의 변화(상태 변환)를 의미한다.

보통 사용자의 지갑이 비트코인을 '수령'했다고 하면 그 지갑이 UTXO를 감지했다는 것을 의미한다. 이때 UTXO는 사용자의 지갑이 소비할 수 있고 수백 개의 거래와 수백 개의 블록 중 어딘가에 산재해 있을 수 있다. 대부분의 지갑은 데이터베이스를 유지하거나 소비할 수 있는 UTXO 전부를 빠르게 참조할 수 있는 자료를 저장하기 위해 데이터베이스 서비스를 이용하기도 한다.

거래 출력값은 사토시(satoshi) 단위로 표현되는 임의의 값(정수)을 가질 수 있으며, 이는 개별적이고 나눌 수 없는 가치의 단위이다. 즉, 소비되지 않은 출력값은 거래에서 통째로 소비될 수만 있다.

UTXO가 한 거래에서 원하는 금액보다 높은 가치를 가지고 있는 경우, 해당 UTXO 전액을 소비하고 해당 거래 내에서 잔액이 생성되어야 한다. 예를 들어 1비트코인을 지불하는 거래에서 20비트코인에 해당하는 UTXO를 보유하고 있다면, 거래에서는 20비트코인 UTXO 전액을 소비하고 두 개의 출력값을 생성해야 한다. 하나는 수령인에게 지불하는 1비트코인에 대한 출력값이고, 하나는 잔액으로 돌아올 19비트코인에 대한 출력값이다.

즉, 거래 시에는 이전에 기록된 소비되지 않은 거래 출력값(UTXO)을 소비하고 향후 거래에서 소비될 수 있는 새로운 거래 출력값(UTXO)을 생성한다. 이런 식으로 UTXO를 소비하고 생성하는 거래 체인 속에서 비트코인 가치 덩어리들이 한 소유주에서 다른 소유주로 이동한다.

[그림 - 거래 과정]

> 거래 출력값

모든 비트코인 거래는 출력값을 생성하며, 출력값은 비트코인 장부에 기록된다. 출력값 대부분은 UTXO라고 불리는 소비 가능한 비트코인 덩어리를 생성한다. UTXO는 생성된 후 네트워크 전체의 승인을 받게 되고, 향후 거래에서 소유주가 사용 가능하게 된다.

거래 출력값은 두 부분으로 구성된다.

  • 비트코인의 최소 단위인 사토시로 표현되는 비트코인 금액
  • 출력값은 소비하기 위해 필요한 조건을 결정하는 암호 퍼즐

암호 퍼즐은 잠금 스크립트(locking script), 서명 스크립트(witness script), scriptPubkey라고도 한다.

JSON 인코딩에서는 출력값이 vout라는 이름의 배열에 들어있다.

"vout": [
  {
    "value": 0.01500000,
    "scriptPubKey": "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY
    OP_CHECKSIG"
  },
  {
    "value": 0.08450000,
    "scriptPubKey": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG",
  }
]

위 거래에는 두 개의 출력값이 들어 있다. 각 출력값은 값(value)과 암호 퍼즐(scriptPubKey)로 나타난다. 거래 자체에서 값은 사토시 단위로 기록된다. 암호 퍼즐은 소비 조건을 설정하는 것으로, 비트코인 코어에서는 이 부분이 scriptPubKey로 보이며 사람이 읽을 수 있는 스크립트로 표현된다.

> 거래 직렬화 : 출력값

거래가 네트워크상으로 전송되거나 어플리케이션 간 교환이 이루어지는 경우 해당 거래는 직렬화 된다. 직렬화란 데이터 구조의 내부 표현 방식을 한 번에 1바이트 크기로 전송할 수 있는 포맷으로 전환하는 과정을 말하며, 바이트 스트림(byte stream)으로 알려져 있기도 하다.

크기필드설명
8바이트(little-endian)총액사토시 단위로 표현되는 비트코인 가치
1~9바이트(Varlnt)잠금 스크립트 크기따라 나오는 바이트 단위의 잠금 스크립트 길이
가변적잠금 스크립트출력값을 소비하는 데 필요한 조건을 규정하는 스크립트

[표- 거래 출력값의 직렬화]

대부분의 비트코인 라이브러리와 프레임워크는 바이트 스트림으로 내부적으로 거래를 저장하지는 않는다. 왜냐하면 이 작업에는 단일 필드에 접속하기 위해서 필요한 경우 복잡한 파싱이 필요하기 때문이다. 편리성과 가독성을 위해 비트코인 라이브러리는 데이터 구조(보통 객체 지향 구조) 내에 내부적으로 거래를 저장한다.

바이트 스트림 표현 방식으로 되어 있는 거래를 라이브러리의 내부 표현 방식 데이터 구조로 변환하는 과정을 역직렬화(deserialization) 혹은 거래 파싱(transaction parsing)이라고 한다. 네트워크로의 전송이나 해싱, 디스크상의 저장 등을 위해 바이트 스트림 표현 방식으로 전환하는 과정은 직렬화(serialization)다. 대부분의 비트코인 라이브러리는 거래 직렬화 및 역직렬화를 위한 내장형 함수를 보유하고 있다.

다음은 거래 출력값을 직렬화된 16진법 형식으로 디코딩한 예시이다.

0100000001186f9f998a5aa6f048e51dd8419a14d8a0f1a8a2836dd73 4d2804fe65fa35779000000008b483045022100884d142d86652a3f47 ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039 ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813 01410484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade84 16ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc1 7b4a10fa336a8d752adfffffffff0260e31600000000001976a914ab6 8025513c3dbd2f7b92a94e0581f5d50f654e788acd0ef800000000000 1976a9147f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a888ac 00000000

> 거래 입력값

거래 입력값은 어떤 UTXO가 사용되고 해제 스크립트를 통해 소유권을 증명할 것인지를 (참조를 이용하여) 식별한다. 거래를 빌드하기 위해 지갑은 통제하고 있는 UTXO 중 하나를 선택한다. 지불에 사용될 UTXO 각각에 대해 해당 지갑은 UTXO를 지정하는 입력값을 생성하고 해제 스크립트를 이용해 UTXO를 해제한다.

거래 입력값은 네 부분으로 구성된다.

  • 거래 ID : 소비될 UTXO가 담겨 있는 거래를 참조
  • 출력값 인덱스(vout) : 해당 거래에서 어떤 UTXO가 참조될지 식별(첫 번째 UTXO의 값은 0)
  • 스크릅트시그(scriptSig) : UTXO의 조건을 만족하며, 소비를 위해 UTXO를 해제
  • 일련번호

사용자의 거래에서는 입력값이 거래 ID와 입력값 인덱스 0을 지시한다. 우선 사용자의 지갑이 참조된 UTXO를 추적하고 그에 대한 잠금 스크립트를 점검한 후 잠금 스크립트를 이용해 필요한 해제 스크립트를 만들게 된다. 입력값에서 참조함 UTXO를 검색해야 하는 대상은 사용자 뿐만 아니라, 거래가 네트워크로 전파된 이후에 모든 승인 노드들 역시 해당 거래를 승인하기 위해 검색해야 한다.
상기 입력값의 참조 UTXO를 얻게 되면 다음과 같은 형태를 볼 수 있다.

"vin": [
 {
   "txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
   "vout": 0,
   "scriptSig" : "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
   "sequence": 4294967295
 }
]

위 거래에서는 아까 말한 입력값의 네 가지 구성 요소를 확인할 수 있다.

> 거래 직렬화 : 입력값

거래가 네트워크상으로 전송되기 위해 직렬화되는 경우 해당 거래의 입력값은 다음과 같이 바이트 스트림으로 인코딩된다.

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

다음은 거래 입력값을 직렬화된 16진법 형식으로 디코딩한 예시이다.

0100000001186f9f998a5aa6f048e51dd8419a14d8a0f1a8a2836dd73 4d2804fe65fa35779000000008b483045022100884d142d86652a3f47 ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039 ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813 01410484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade84 16ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc1 7b4a10fa336a8d752adfffffffff0260e31600000000001976a914ab6 8025513c3dbd2f7b92a94e0581f5d50f654e788acd0ef800000000000 1976a9147f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a888ac00000 000
  • 거래 ID는 바이트의 역순으로 직렬화되었다. 그래서 (16진법으로) 18로 시작해서 79로 끝난다.
  • 출력값 인덱스는 0으로 구성된 4바이트 크기의 그룹이어서 식별하기 쉽다.
  • scriptSig의 길이는 139바이트 혹은 16진법으로 8b이다.
  • 일련번호는 FFFFFFFF로 설정되어 있어 식별하기 쉽다.

> 거래 수수료

대부분의 거래는 수수료를 포함한다. 거래 수수료는 비트코인 네트워크를 안전하게 유지해 주는 역할을 하는 비트코인 채굴자들에게 제공하는 일종의 보상금이다. 대부분의 지갑에서는 수수료를 자동으로 계산하고 그 값을 거래에 포함시키지만, 프로그램에 따라 거래를 구상하거나 명령행 인터페이스를 활용하는 경우라면 수동으로 수수료를 계산하고 거래에 포함시켜야 한다.

거래 수수료는 모든 거래에 소액의 비용을 부과함으로써 다음 블록에 거래를 포함시키는(채굴하는) 데 대한 동기부여(incentive)의 역할도 한다. 블록체인에 거래 내용을 기록하는 블록을 채굴하는 채굴자에 의해서 거래 수수료가 수집된다.

거래 수수료는 비트코인 단위로 표현되는 거래 가치보다는 킬로바이트 단위의 거래 크기를 근거로 계산된다. 결국 비트코인 네트워크 내에 존재하는 시장의 힘에 의해 거래 수수료는 결정된다. 채굴자는 수수료 등 여러 가지 기준에 따라 거래의 우선순위를 정하게 된다. 이는 적정한 가격의 수수료가 포함되어 있는 거래는 차순위 채굴대상 블록에 포함될 가능성이 높아지는 반면 수수료가 충분하지 않거나 아예 없는 경우 거래가 지연되거나 처리되지 않는 경우도 있다는 것을 의미한다.

비트코인 코어에서는 수수료 중개(fee relay) 정책이 '최소 중개거래 수수료(minrelayfee)' 옵션에 의해 설정되어 있다. 현재 디폴트 되어 있는 최소 중개거래 수수료 0.0001비트코인 미만의 수수료를 가지는 거래는 무료로 간주된다. 중개가 이루어지지 않으면 거래가 중단된다.

[그림 - 수수료 계산 서비스의 한 화면]

위의 그래프를 보더라도 수수료가 높아질수록 거래가 지연되지 않고 빠르게 처리되는 것을 확인할 수 있다.

거래 수수료는 입력값에서 출력값을 뺀 값이다.

Fees = Sum(Inputs) - Sum(Outputs)

사용자들은 거래를 구성할 때 입력값 전체에 대해서 내역을 파악하고 있어야 하며 필요한 경우 잔액도 생성해야 한다. 그렇지 않으면 결국 채굴자에게 아주 큰 금액의 수수료를 주게 되는 셈이다. 예를 들어, 1비트코인을 지불하기 위해 20비트코인(UTXO)를 사용했는데 19비트코인이 잔액 출력값으로 돌아오지 않으면, 남겨진 19비트코인은 '거래 수수료'로 채굴자에게 넘어가게 된다.

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

0개의 댓글