Skip to content

Instantly share code, notes, and snippets.

@Curzy
Last active May 29, 2018 17:56
Show Gist options
  • Save Curzy/b510ceae00dde221273e3a56782fe356 to your computer and use it in GitHub Desktop.
Save Curzy/b510ceae00dde221273e3a56782fe356 to your computer and use it in GitHub Desktop.
Bitcoinbook Chapter 07 정리

Bitcoinbook Chapter 07 정리

https://github.com/bitcoinbook/bitcoinbook/blob/second_edition_print3_rc2/ch07.asciidoc

Advanced Transactions and Scripting

지난 챕터에서는 비트코인 트랜잭션 소개, P2PKH 스크립트 살펴봄

Multisignature

  • M-of-N
    • N: 키의 개수
    • M: 증명에 필요한 서명의 threshold
    • ex) 2-of-3: 2 3 CHECKMULTISIG
    • 위의 locking script는 signature와 public key의 상으로 이루어진 unlocking script와 같이 validation script를 만듬
    • ex) 2 3 CHECKMULTISIG
  • CHECKMULTISIG 실행의 버그
    • 위의 2-of-3 validation script 로 보면
    • 2 3 CHECKMULTISIG
    • CHECKMULTISIG - 3 - PK C - PK B - PK A - 2 - S C - S B 순서로 pop 해야하지만 버그로 인해서 M +1개를 가져옴
    • 마지막에 가져온 값은 validation에서 무시되지만 빈 스택을 pop할때 오류가 발생해서 맨 앞에 unlocking script의 맨 앞에 0을 더해줌
    • 결과적으로 사용할 2-of-3 validation script: 0 <서명 B> <서명 C> 2 <공개 키 A> <공개 키 B> <공개 키 C> 3 CHECKMULTISIG

P2SH(Pay-to-Script-Hash)

  • 모하메드의 가게가 다중서명을 사용하고 있음
  • 2 <Mohammed's Public Key> 5 CHECKMULTISIG
  • 모하메드의 공개키, 파트너들의 공개키, 대리인의 공개키까지 들어간 2-of-5 locking script가 너무 김
  • multisignature 스크립트는 강력한 대신 사용하기 까다로움, 위 예에서 모하메드는 모든 고객에게 스크립트를 줘야하고, 모든 고객은 custom transaction script를 만들 수 있는 비트코인 지갑을 사용해야 함. + 긴 public key가 포함되니까 간단한 지불 트랜잭션보다 길이가 5배 길어짐(수수료도 증가) + 모든 노드의 UTXO에서 처리될때까지 램에 상주함
  • P2SH는 위 문제를 해결
  • P2SH 트랜잭션에서 locking script는 hash로 대체되기 때문에 redeem script로 부름
    1. without P2SH:
    • Locking Script: 2 PubKey1 PubKey2 PubKey3 PubKey4 PubKey5 5 CHECKMULTISIG
    • Unlocking Script: Sig1 Sig2
    1. with P2SH
    • Redeem Script: 2 PubKey1 PubKey2 PubKey3 PubKey4 PubKey5 5 CHECKMULTISIG
    • Locking Script: HASH160 <20-byte hash of redeem script> EQUAL
    • Unlocking Script: Sig1 Sig2
  • 20-byte hash로 변환됨
    • SHA256 - RIPEMD160
    • 결과: HASH160 54c557e07dde5bb6cb791c7a540e0a4796f5e97e EQUAL
  • 두 단계
    1. Locking script + redeem script: <2 PK1 PK2 PK3 PK4 PK5 5 CHECKMULTISIG> HASH160 EQUAL
    2. 위의 hash가 일치하면 unlocking script실행
  • P2SH 주소
    • script hash를 주소로 인코딩.
    • Bitcoin의 주소가 공개 키의 20-byte hash를 Base58Check인코딩 하는것과 동일한 원리.
    • P2SH 주소는 version prefix 5 를 써서 Base58Check로 인코딩, 인코딩 된 주소는 prefix 3
    • ex) 모하메드의 P2SH주소는 39RF6JqABiHdYHkfChV6USGMe6Nsr66Gzw로 인코딩 됨
  • P2SH의 장점
    • 스크립트를 짧게 변환하여 트랜잭션 크기 감소
    • 스트립트를 주소로 인코딩해서 발신자 지갑에 P2SH구현이 필요하지 않음
    • 수신자에게 부담 전가
    • 긴 스크립트 저장의 짐을 UTXO set의 output에서 input으로 넘김
    • 긴 스크립트 저장의 짐을 지불 시점(현재)에서 지출 시점(미래)으로 넘김
    • 긴 스크립트의 수수료 비용 부담을 발신자에서 수신자에게 넘김
  • Bitcoin Core client v0.9.2
    • standard type의 비트코인 스크립트에만 적용 가능 isStandard()함수로 검사
      • P2PK, P2PKH, or multisig nature, excluding RETURN and P2SH itself(OP_RETURN으로 조작가한거 안되나봄)
    • recursion한건 아니라 P2SH를 P2SH redeem script에 적용할 수 는 없음

Data Recording Output(RETURN)

  • 블록체인 장부를 결제만이 아니라 지분증명, 디지털 공증, 스마트 컨트랙트 등으로 사용하려는 시도가 있어왔음, 비트코인에 관게없는 데이터를 블록체인에 저장하는게 논란이 있기도 하다.
  • 목적지의 bitcoin address를 위한 20-byte field를 데이터를 위해 사용하므로 사용되지 않는 UTXO를 만든다(fake payment), 절대 사용되지도 없어지지도 않음. UTXO database의 사이즈도 계속 커짐.
  • 0.9버전의 비트코인 클라이언트에서 RETURN 오퍼레이터가 등장
  • RETURN은 80-byte의 결제와 상관없는 데이터를 transaction output에 추가 가능(기존의 fake UTXO와 다름), 명시적으로 소비될 수 없는 output을 만듬. UTXO집합에 저장 안됨. 블록체인에 RETURN output이 저장됨.
  • 결과적으로 블록체인의 사이즈를 키우지만, UTXO집합과 메모리풀을 늘리지는 않음.
  • RETURN 스크립트의 형태는 RETURN <data>
    • data의 크기는 80-byte 로 제한되어 있고 대개 SHA256으로 해시화 된 32-byte의 문자열이 들어간다.
    • 많은 어플리케이션의 경우 prefix를 붙여 데이터를 구별한다.
    • RETURN에는 unlocking script가 없음.
    • output with a zero bitcoin amount
    • transaction의 input에 RETURN이 쓰이면 script validation engine은 transaction이 invalid하다고 표시함.
    • RETURN의 실행은 FALSE또는 정지를 유발함.
  • 표준 transaction은 단 하나의 RETURN output만을 가질 수 있음.
  • Bitcoin Core v0.10에서 두개의 옵션이 새로 추가됨.
    • datacarrier: relay and mining of RETURN transaction(무슨 의민지 모르겠음)
    • datacarriersize(83-byte): 80-byte RETURN data, 1 byte RETURN opcode, 2-byte PUSHDATA opcode

Timelocks

  • 타임락은 transaction이나 output에 특정 시점 이후부터 소비될 수 있게 제한함, 이는 비트코인의 시작부터 있었던 기능. transaction의 nLocktime필드
  • 2015년 후반 - 2016년 중반에 UTXO-level timelock기능이 소개됨. CHECKLOCKTIMEVERIFY, CHECKSEQEUNCEVERIFY
  • 타임락은 transaction을 미래 시점으로 미룰 수 있음. 중요! 비트코인 스크립트를 시간의 차원으로 확장시킴, 복잡한 스마트 컨트랙트가 가능하게 함.
  • Transaction Locktime(nLocktime)
    • A -> B 3달 locktime으로 송금함
    • B는 3개월 뒤에 받을 수 있음
    • 그러나 A는 다른 새로운 transaction으로 송금 가능
    • B가 3개월 뒤에 받을 수 있다는 보장이 되지 않음
    • timelock은 UTXO에서 locking script의 일부로 이루어져야함
  • Check Lock Time Verify(CLTV)
    • 15년 12월에 soft fork upgrade와 함께 소개됨. (bips/bip-0065.mediawiki at master · bitcoin/bips · GitHub)
    • OP_CHECKLOCKTIMEVERIFY
    • 위 OP코드를 vout의 redeem script에 넣으면 실제 그 시간이 지나기 전까지 output이 input에 의해 소비될 수 없게 함.
    • nLocktime을 대체하는 수단은 아님, 그러나 특정 UTXO에 제한을 거는 방식
    • block height나 유닉스 타임으로 시간을 입력받음
    • ex)
      • without CLTV: DUP HASH160 <Bob's Public Key Hash> EQUALVERIFY CHECKSIG
      • with CLTV: <now + 3 months> CHECKLOCKTIMEVERIFY DROP DUP HASH160 <Bob's Public Key Hash> EQUALVERIFY CHECKSIG
    • CHECKLOCKTIMEVERIFY가 실패하거나 실행을 중지하는 경우. transaction이 invalid하다고 표시
      1. 스택이 비었거나
      2. 스택의 최상위 아이템(CLTV locktime, 위의 <now + 3 months>)이 0보다 작거나
      3. Lock-time type이 nLocktime(input)과 top stack item(output)의 타입이 다르거나
      4. 스택의 최상위 아이템이 transaction의 nLocktime보다 클때(CLTV 락타임이 지나지 않았을 때)
      5. the nSequence field of the input is 0xffffffff(??)
    • CLTV가 충족되었을때 스택의 최상위 아이템을 DROP하고, 뒤의 OP코드 실행
  • Relative TimeLocks
    • nLocktime, CLTV는 모두 절대 시간을 사용함(block height, 유닉스 타임). 아래 소개할 두 timelock은 codition of spending an output이나 output의 컨펌 이후부터의 시간을 사용함.
    • 상대적 timelock은 2개 이상의 상호의존적인 transaction을 체인에서 분리할 수 있게 함, 한 transaction이 다른 transaction의 승인과 연계되어 있다면. UTXO가 블록체인에 기록될때까지는 실제로 시간이 흐르지는 않음.
    • Absolute timelocks랑 비슷하게 transaction-level, script-level opcode 두가지가 존재함.
      1. transaction-level은 nSequence. Transaction field로 모든 transaction input에 설정됨
      2. script-level은 CHECKSEQUENCEVERIFY(CSV) opcode
  • Relative Timelocks with nSequence
    • 트랜잭션의 각 input에 설정될 수 있는 상대적 timelock, input의 nSequence 필드로 설정한다
    • nSequence의 원래 의미는? mempool에서 트랜잭션을 변경할 수 있도록 의도됨(하지만 그렇게 쓰이지는 않았음)
      • 트랜잭션이 2^32(0xFFFFFFFF)이하의 nSequence값을 가진input을 포함하고 있을때 트랜잭션이 “Finalized”되지 않았다고 표시함.
      • 같거나 더 큰 nSequence값을 가진 트랜잭션에 의해 대체되기 전까지는 mempool에 잡혀있음.
      • nSequence값이 2^32인 트랜잭션이 들어오면 “Finalized”됬다고 하고, 채굴됨
    • 합의에 의해 강요된 relative timelock의로의 nSequence
      • BIP-68이후로 n^31(bit 1<<31 is not set)미만의 nSequence값을 가지는 모든 트랜잭션에 대한 합의 규칙이 추가됨
        1. 맨 왼쪽 비트(bit 1<<31)이 0이면 “relative locktime”이라는 의미의 플래그.
        2. 맨 왼쪽 비트(bit 1<<31)이 1이면 CHECKLOCKTIMEVERIFY, nLocktime, Opt-In-Replace-By-Fee 등의 용도로 사용됨.
      • relative timelock을 가진 트랜잭션은 relative timelock 값이 지난 뒤에 유효함
        • ex) 30블록의 nSequence relative timelock을 가진 input하나만 보유한 트랜잭션의 경우 30블록이 지난 뒤에 채굴된다.
      • 그런데 nSequence필드는 각각의 input에 존재할 수 있는데. 이럴경우 모든 timelock이 지나야 트랜잭션이 유효해진다.
      • 트랜잭션은 timelocked(nSequence < n^31), without relative timelock(nSequence >= 2^31) 두 유형의 input을 함께 가질 수 있음.
      • nSequence값은 블록이나 초로 사용될 수 있음 nLocktime에서 쓰던 양식과는 다르게 type-flag(23번째 비트. 1<<22)가 있음.
        1. type-flag(bit 1<<22)가 1이면 nSequence값은 512초의 배수
        2. type-flag(bit 1<<22)가 0이면 nSequence값은 블록 수
      • nSequence값을 relative timelock으로 해석할때는 16개의 하위 비트가 사용된다. 두개의 플래그(bit 32 relative timelock여부, bit 23 type-flag)를 검사한 뒤에는. nSequence값은 대개 16-bit로 마스킹됨.(0x0000FFFF)
      • BIP-68을 보자
  • Relative Timelocks with CSV
    • CLTV & nLocktime처럼 relative timelock에도 script opcode가 있음.
      • CHECKSEQUENCEVERIFY 짧게 CSV
    • CSV opcode는 transaction input의 nSequence값이 CSV 변수보다 같거나 클때만 UTXO가 소비될 수 있게 함.
    • CLTV에서랑 같이 nSequence값이랑 타입이 같아야 함. 블록 수 or 초
    • BIP-112를 보자
  • Median-Time-Past
    • 비트코인은 분산 네트워크라 각각 참여자(노드를 의미하는듯?)마다 상대적인 시간을 가짐. 네트워크 위에서 즉각적으로 모두 같은 시간을 가질 수 없음. 네트워크 지연시간 반영 필요.
    • 전체 동기화가 된 뒤에 공통 ledger를 만듬. 비트코인은 과거의 ledger에 대해 10분마다 합의함.
    • Median-Time-Past 는 마지막 11block의 타임스탬프의 중간값으로 계산됨. 이에 의해 nLocktime, CLTV, nSequence, CSV에 대한 시간 계산부분 구현을 바꿈. Median-Time-Past로 합의되는 시간은 실제 시간보다 1시간 늦음.
    • 그래서 timelock transaction을 만들때는 원하는 시간을 계산해야함.
    • bip-113
  • Timelock Defense Against Fee Sniping
    • Fee Sniping은 이론상의 공격 시나리오. 채굴자가 미래의 수수료가 높은 block을 저격하기 위해 과거의 블록을 다시 쓸 수 있음(수익률을 높이기 위해서)
    • ex) 가장 높은 블록이 block #100,000. #100,001 블록을 채굴하는 대신. #100,000블록을 다시 채굴하려고 함. 이 채굴자들은 #100,000블록의 valid transaction그러나 채굴되지 않은걸 포함할 수 있음. 동일한 transaction으로 다시 채굴할 필요가 없음. ~~
    • 현재는 block reward가 블록당 총 수수료보다 매우 커서 효율적이지 않지만. 미래의 어떤 시점에서는 transaction fee가 주된 보상이 될 수 있음.
    • Bitcoin Core가 Fee Sniping을 막기위해 디폴트로 nLocktime값을 다음 블록으로 걸어둠.

Script with Flow Control(Conditional Clauses)

  • IF…THEN...ELSE의 분기절이 Script에서 사용 가능.
  • 기본 수준에서 conditional opcode가 TRUE/FALSE 결과에 따라 두개의 방법으로 사용할 수 있는 redeem script 작성 가능함.
  • Script의 조건 분기는 무한하게 중첩사용 가능함. 조건에 조건 사용가능. Byte 크기로 제한됨.
  • IF, ELSE, ENDIF, NOTIF opcode들. BOOLAND, BOOLOR, NOT같은 불대수 포함 가능
  • Bitcoin Script가 stack language라 보기 헷갈릴 수 있음.
    • ex) 1 + 1이 Script에서는 1 1 ADD
일반적인 프로그래밍 언어에서 분기 처리
if (condition):
  code to run when condition is true
else:
  code to run when condition is false
code to run in either case  
Bitcoin Script에서의 분기 처리
condition
IF
  code to run when condition is true
ELSE
  code to run when condition is false
ENDIF
code to run in either case
  • VERIFY opcode를 사용하는 조건분기

    • VERIFY opcode는 조건이 TRUE가 아닌경우 스크립트 실행과정을 종료하고 transaction이 invalid한것으로 간주함.

    • IF와는 다르게 조건이 충족될때만 스크립트가 실행됨. Guard clause

    • ex) EQUALVERIFY를 사용한 script

      • HASH160 <expected hash> EQUALVERIFY <Bob's Pubkey> CHECKSIG
      • 이 스크립트를 사용하기 위해서 Bob은 valid한 pre-image와 서명을 넘겨야함 unlocking script: <Bob's Sig> <hash pre-image>
      • IF를 사용한 예는 아래 블록에
      • 두 redeem script는 같은 역할을 하지만 VERIFY를 쓰는쪽이 opcode를 하나 덜 씀.
      • 분기 제어가 필요할땐 IF...ELSE를 쓰고 전제조건이 필요한게 전부라면 VERIFY를 쓰자.
      • EQUAL과 같은 opcode는 TRUE/FALSE 결과를 스택에다 남김, EQUALVERIFY는 남기지 않음.
      IF를 사용한 예
      HASH160 <expected hash> EQUAL
      IF
        <Bob's Pubkey> CHECKSIG
      ENDIF
      
  • Using Flow Control in Scripts

    • 분기 제어를 Bitcoin Script에서 사용하는 가장 일반적인 경우는 redeem script가 실행되는 방법을 다양하게 만드는것.
    1-of-2 multsig script처럼 동작함
    IF
    <Alice's Pubkey> CHECKSIG
    ELSE
    <Bob's Pubkey> CHECKSIG
    ENDIF
    
    • 근데 조건이 어디갔지? IF앞에 아무것도 없다.
      • 는 상태를 unlocking script에 붙일 수 있다.
        1. <Alice's Sig> 1
        2. <Bob's Sig> 0
    • IF를 중첩시켜서 실행 분기에 미로을 만들 수 있음.
    IF
      script A
    ELSE
      IF
        script B
      ELSE
        script C 
      ENDIF
    ENDIF    
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment