블록체인 4 - Transactions

Bitcoin에서 Transaction 이란 무엇인가.

그 것에 대해서 게시물 내내 아주 자세하게 알아보도록하자.

  • 트랜잭션이란, 비트코인 네트워크 상에서 가치를 이전하는 행위로, 누가 어떤 UTXO를 사용해서 누구에게 새로운 UTXO를 보냈는가를 정의한다.
    • UTXO : 이전 트랜잭션의 Output 중 아직 사용되지 않은 “잔액 단위”로, 밑에서 자세히 설명한다.

  • 복식부기로서의 트랜잭션
    • 트랜잭션은 마치 장부같은거다. 얼마가 들어왔고, 얼마를 내보낼건지 적는 회계 장부!

input의 총합 = output의 총합 + transaction fee (수수료)


  • David 가 Sandara 에게 5BTC를 전송한다고 해보자.
  • David의 개인키로 해당 트랜잭션에 서명을하고, 비트코인 네트워크로 방송한다.
  • 이 메세지를 받은 노드들은 David의 공개키를 이용해 이게 진짜 David가 서명한게 맞는지 검증하고, 맞다면 옆 노드에게 전파한다.
트랜잭션에 서명을 한다는 것은 무엇일까?
  • 트랜잭션에 대해서 설명한 후에 서명에 대해서 설명해주겠다.
    • 트랜잭션의 구조 4가지
      • Version : 이 트랜잭션이 어떤 규칙으로 만들어졌는지 설명. 대부분 1 아니면 2고, 특별한 의미는 없음.
      • inputs : UTXO 사용하는 부분
  Input:
  - 이전 UTXO가 있던 트랜잭션의 ID
  - 그 UTXO의 Output index
  - ScriptSig (잠금 해제 스크립트) - 즉, 서명 + 공개키 이다. (ex <signature> <public_key>)
  - Sequence
      • outputs : UTXO 새로 만드는 부분
      • Locktime : 트랜잭션이 언제부터 유효해질지를 지정하는 시간(또는 블록번호)
        • ex) 0 → 즉시 유효 / 760000 → 블록 760000 이후에만 유효 / 또는 유닉스 타임스탬프 / 일반적으로는 0이다.
  • 서명 : 트랜잭션에서, 서명하려는 해당 input의 ScriptSig만 빈 값으로 한 값에 SIGHASH 타입을 추가하고 sha256으로 더블해시한 후에, 해당 해시값을 ECDSA(타원곡선알고리즘)으로, 개인키를 이용해서 서명해서 (r,s)값을 받는다.
  • David의 거래는, 바로 확정되는게 아니라 임시 Mempool이라는 대기실에 들어간다.
  • 채굴자(노드)는 이 Mempool 속의 트랜잭션들 중 몇개를 블록에 골라 담는다.
  • 이전 블록의 해시를 현재 블록에 포함시켜 기존 블록에 연결한다.

  • 트랜잭션 생성 -> 블록 생성 과정
    • 사용자는 '지갑' 어플리케이션을 통해 개인키를 보관하고 관리하며 비트코인 네트워크와 상호작용한다. (가치를 이전하는, 트랜잭션을 발생시킨다)
    • 생성된 트랜잭션은 전세계의 네트워크 노드들로 전송된다.
      • 이 노드들은 모든 네트워크 전송을 담당하고, 트랜잭션 정보를 서로에게 전파한다
    • 아직 블록에 담기지 않은 '미확인 트랜잭션' 들은 모든 노드의 Mempool에 저장되고,
    • 채굴자(Miner)는 Mempool에서 트랜잭션을 가져와서 하나의 블록을 구성하고 Pow라는 계산과정을 수행한다.
    • 작업증명을 가장 먼저 성공한 채굴자가 새로운 블록을 생성하고, 이를 네트워크에 방송(Broadcast)한다.

UTXO vs STXO (안 쓴 돈 vs 이미 쓴 돈)

  • UTXO (unspent transaction output)
  • STXO (spent transaction output)

  • 우리는, 유저의 지갑이 비트코인을 '받았다' 고 하지만 그것은 지갑이, 블록체인에서, 지갑의 키로 사용할 수 있는 UTXO 를 감지한 상태를 말한다.
  • 지갑 어플리케이션은 유저의 밸런스(잔고)를 계산할 수 있다.
  • 트랜잭션 아웃풋은 정수 satoshi 값을 가질 수 있으며, 1BTC는 10^8사토시 이다.
  • 사용되지 않은 아웃풋은 트랜잭션에 의해 통째로만 사용될 수 있다. 부분사용은 안된다는 말이다.

위 사진은 Alice 의 transaction이 포함된 블록체인이다.

  • 가장 좌측은 블록체인의 모습
  • block height 는 전체 길이를 뜻한다
  • block depth는 특정거래(alice)를 포함해, 몇개의 블록이 쌓였는가를 의미한다.
  • 위변조 난이도는 block depth가 깊어질수록 어렵다.

  • 트랜잭션의 흐름
    • 이 그림은, transaction에서 이전 거래의 output이 다음거래의 재료로 계속해서 쓰이는 모습을 보여주는 도표다.
    • Joe는 모두 사용한거고 앨리스와 밥은 들어온 UTXO로 새로운 UTXO를 만들어서, 전부 사용하지 않은거고, 고페쉬는 아직 사용하지 않은거다.

이건, 순서대로 transaction 1, 2, 3을 보여주는 도표다.

  • 화살표는, 해당 Tx가 그 전의 Tx에서 사용할 아웃풋을 가리키는거다. 즉, 나 전꺼 아웃풋 중에 이거 쓸거에요~ 알려주는거임.
  • 보면 전 트랜잭션의 아웃풋이랑, 해당 트랜잭션의 아웃풋 총합과 fee의 합이 같은걸 알 수 있다.

Transaction 의 3가지 종류

  • Common Transaction
    • 가장 일반적이며 1개의 입력이 들어와서 2개의 출력으로, 하나는 송금액, 하나는 거스름돈으로 나간다.
  • Aggregating Transaction ( 집계 거래)
    • 여러개의 입력이 1개의 출력으로 나간다
  • Distributing Transaction (분산거래)
    • 하나의 인풋으로 여러개의 아웃풋으로 나간다. - 급여지급 등

  • 앨리스가 밥에게 일정 금액의 비트코인을 지불하고 싶다고 가정해보자.
  • 앨리스는 Full nodes 들이 그들의 데이터베이스를 업데이트해 '앨리스의 비트코인 중 일부가 이제 밥에 의해 통제된다' 고 기록하도록 설득하여 밥에게 돈을 지불한다.(이 과정에는 앨리스나 밥의 신원이 사용되지 않는다.)
  • 바로, 앨리스가 풀노드들이 데이터베이스를 업데이트하도록 설득하기 위해 사용하는 데이터를 Transaction 이라고 부르는거다.
  • 앨리스는 먼저 풀노드들에게, 앨리스가 소비하려는 코인을 받았던 이전 전송을 찾는 방법을 알려줘야 한다.
  • 아웃포인트 : 앨리스는 아웃포인트 필드를 사용해서 이전 출력을 가리킨다.
    • 앨리스가 소비하려는 비트코인을 받았던 트랜잭션의 32byte txid + output index ( 해당 transaction의 아웃풋 중 사용할 아웃풋의 index임 )
💡
정리해보면, 앨리스가 밥에게 비트코인을 지불하고 싶다면, 그건 앨리스가 밥에게 돈을 지불하는 '트랜잭션'이라는걸 발생시키는건데, 그 트랜잭션이라는 것의 의미는, 풀노드들에게 이제 앨리스의 비트코인 중 일부가 밥에 의해 통제된다. 라고 기록하도록 설득하는 과정이고, 설득하기 위해서 앨리스는, 자신이 소비하려는 그 코인의 이전 트랜잭션을 알려줘야하는데, 이 방법이 바로 트랜잭션 input 구성요소 중 하나인 아웃포인트라는걸 풀노드에게 공개하는거고, 그 아웃포인트는 뭘로 구성돼있냐면 32바이트의 트랜잭션 아이디와 아웃풋 인덱스다.

풀 노드가 받는 정보들

  • 이전 출력에 할당된 비트코인의 양
  • 이전 출력에 대한 인증 조건
  • 증명 - 더블스팬드 방지 목적
  • 타임락 정보

트랜잭션은 어떻게 생겼는가 - 트랜잭션의 바이트 맵

    • version : 트랜잭션이 사용하는 시스템 버전. ex) 1
    • marker & flag : segwit이란 최신 방식을 쓴다는 표식
    • inputs : 돈가져올 곳 목록 (여기 outpoint가 들어감)
    • outputs : 돈 보낼 곳 목록 ( Bob의 계좌 주소와 금액)
    • witness structure : 증인구조 - 서명 도자이 찍히는 곳. (예전에는 inputs 칸 안에 서명이 있었는데 segwit 업그레이드 후 서명 칸이 따로 생김)
    • lock time : 거래의 유효기간이나 시작시간 설정칸. 보통은 즉시처리, 0

  • transacion 중 Input 칸 확대해서 보기
    • count : 인풋의 갯수. 몇개의 utxo가 포함된 transaction인지 알려준다.
    • previous output txid : 32byte - 이 전 거래의 txid
    • previous output index : 4byte - 이전 transaction 중 쓸 아웃풋
    • length : 과거에는 여기 서명을 넣었는데 지금은 많이안씀
    • sequence : 4byte - 원래는 거래를 수정하려고 만들었는데 지금은 RBF(수수료 높여 새치기) 기능이나 상대적 잠금 시간 (이전 블록 생성 후 1시간 뒤 전송 가능 등) 설정 용도로 사용됨

Sequence의 원래 의도

  • 사토시 나카모토는 원래, 트랜잭션을, 블록에 넣기전에 수정할 수 있게 만드려고 했고, 시퀀스는 그걸위한 버전번호 칸이었다.
  • 하지만 악용가능성이 밝혀져 비활성화 됐다.
  • 그래서 지금 상대적 잠금시간, Relative Timelock로 사용됨.
    • 돈을 받은지 x블록 이상 지나야만 쓸 수 있다. 같은 조건부 시간제한을 걸 수 있음
  • disable flag : 이 기능을 킬지 끌지 결정함
  • Type flag : 시간을 잴 때 블록갯수로 할 지 초단위로 할지 결정
  • Value : 실제 기다려야하는 시간

  • 출력의 해부도
  • Amount : 8바이트 크기로, 보낼 비트코인 양을 적고, 단위는 사토시이다.
  • Output Script : 흔히 잠금장치( Locking Script)라고 부르며 여기에 '이 돈을 사용하려면 밥의 개인키로 만든 서명을 가져와야함' 이라는 조건이 프로그래밍 언어(script)로 적혀있다.
  • 우리가 흔히 말하는 비트코인 주소가 이 스크립트 안에 포함되어있다.

Witness Structure - 증인구조 와 문제점

  • 기존의 방식은 인풋 스크립트 안에 서명(witness) 데이터를 넣었다.
  • 서명데이터가 트랜잭션 id 계산에 포함되며 심각한 문제가 생김
    1. 순환 의존성
    2. 제3자 트랜잭션 가변성
    3. 당사자 간 트랜잭션 가변성

순환의존성

  • 앨리스와 밥이 돈을 모아 공동계좌 Tx0를 만들려고 하는데, 먼저 환불 서약서를 써놓고 싶은 경우에
    • 환불 계약서 Tx1를 만들려면 원본 계약서의 id를 적어야하는데,
    • 원본 계약서인 Tx0의 id 는 앨리스와 밥의 서명이 들어가야 확정됨
    • 즉, 서명을 해야 id 가 나오는데 id를 알아야 서명을 안전하게 할 수 있는 상황.

제 3자 가변성

  • 해커가 트랜잭션 id를 몰래 바꿔치기 하는 공격.
    • 2를 표현할 때 OP_2 라고 할 수 도 있고 OP_PUSH1 0x02라고 할 수 도 있다.
    • 앨리스가 트랜잭션을 보냈는데, 공격자가 중간에 숫자표현 방식만 살짝 바꾸면
    • 내용은 같으니 거래는 성사됐지만 데이터 모양이 바뀌어 트랜잭션id가 완전히 달라져서, 밥은 그걸 쓸 수 가 없게 된다.

당사자 가변성

  • 거래 상대방, 밥이 나쁜 마음을 먹고 사기를 치는 시나리오다
  • - 앨리스와 밥이 공동자금 Tx0를 만들고, 나중에 돈을 나누어 갖는 환불 트랜잭션도 미리 서명해서 준비해 둔다.
  • 안전을 위해 환불 트랜잭션 Tx1에 먼저 서명하고, 그 다음 자금 입금 Txo를 진행한다.
  • 근데 밥이 자신의 서명을 조작해서 앨리스에게 사기를 치고 싶다.
  • 밥은 Tx0에 서명할 때 서명 알고리즘의 난수를 살짝 바꾼다.
    • 이러면 Tx0의 ID 가 달라진다.
  • 밥이 조작한 Tx0가 블록에 기록되고, 앨리스가 쥐고있던 환불 트랜잭션Tx1은 원래 예정이던 Tx0의 id를 가리키고있다.
  • Tx0의 id가 바뀌었으므로 앨리스의 환불 트랜잭션은 존재하지 않는 id를 가리키게 된다.

Segregated Witness - 세그윗.

IDEA : 서명(witness) 때문에 자꾸 id가 바뀌니까, 서명데이터를 트랜잭션 id 계산에서 빼버리자.

방법 : 서명데이터를 별도의 공간으로 분리한다.

소프트 포크 : 이 업그레이드는 기존 노드들과 호환되도록 소프트 포크 방식으로 진행한다.

입력칸을 비워둬서, 구형노드는 검사면제로 속여서 통과시키고, 신형모드는 별첨 서명을 따로 검사하게 만드는 soft fork를 썼다.


  • 코인베이스 트랜잭션이란 무엇인가
    • 블록의 맨 첫번째에 위치하는 트랜잭션이다.
    • 입력이 단 하나뿐. 즉, 이전 출처가 없다.
    • 이전 트랜잭션 ID 는 0(NULL)로 채우고, 인덱스는 최댓값으로 채워서, 참조할 과거가 없다는 것을 표시한다.
    • 일반 거래의 입력 스크립트 (서명) 자리에는 '코인베이스'라고 불리는 데이터가 들어간다.
    • 여기는 서명이 필요없으므로 아무말(Arbitary data)를 적을 수 이다.
      • 사토시 나카모토가 제네시스 블록에 "은행구제금융" 신문기사 제목을 적은 곳이 여기다.
    • 채굴자가 가져가는 총 금액은 블록보상 + 그 블록에 담긴 모든 거래 수수료의 합계이다.
    • 이 코인베이스 트랜잭션으로 받은 돈은, 100개 블록이 쌓일 때까지 절대 사용할 수 없음 (immature 한 상태)

Weight and Bytes

  • 세그윗을 도입하고, 블록 크기를 측정하는 단위가 바뀌었다.
  • 옛날방식
    • 블록크기는 1mb를 넘지 못한다
  • 새로운 방식 - weight
    • 블록 무게는 400만 weight를 넘으면 안된다.
  • 무게 계산법
    • 중요 거래 데이터 : 1바이트당 무게 4
    • 별첨 서명 데이터 : 1바이트당 무게 1
  • 의도 : 서명을 별도로 분리하는 세그윗 방식을 사용하면, 데이터를 4분의 1 가격으로 처리해주겠다는 인센티브 이므로, 기존 방식을 사용할 이유가 없음.