Jason Dev
About
Taproot and Ordinals
published: 2023-10-29
bitcoin
p2tr
taproot
ordinals
inscription

Taproot

Taproot는 2021년 업그레이드를 통해 등장했다. Taproot 업그레이드 이전에 존재했던 여러 단점을 보완했는데, 아래는 Taproot의 주요 장점이다.

  1. 프라이버시(privacy) 향상: 다양한 유형의 트랜잭션(단일 서명, 다중 서명 등)이 모두 동일해 보이므로 타인이 특정 유형의 트랜잭션을 구분하기 어렵다.
  2. 데이터 효율성 증가: 스크립트의 모든 내용을 공개하지 않아도 되므로 트랜잭션 크기를 줄일 수 있다. (낮은 수수료로 연결됨)
  3. 유연성: 여러 가지 스크립트를 준비할 수 있고 비트코인을 사용할 때 필요한 스크립트만 사용할 수 있다.

장점 3번 덕분에 매우 다양한 경우를 처리할 수 있는데, 예를 들어 A, B, C 세 사람이 다음과 같은 조건으로 비트코인을 관리할 수 있다.

  1. A, B 모두 동의할 경우
  2. 특정 시간(ex. 30일) 경과 후 A가 동의할 경우
  3. C가 동의할 경우

P2TR

P2TR은 Taproot 업그레이드와 함께 새롭게 추가된 스크립트 유형이다. P2TR 주소는 bc1p로 시작한다.

P2TR의 스크립트 구성은 다음과 같다.

  • 해제 스크립트: empty
    • 트랜잭션 데이터에 없다는 의미이며 실제로는 Witness에 저장되어 있다.
  • 잠금 스크립트: OP_1 <pubKey>

P2TR은 SegWit v1이라서 잠금 스크립트는 OP_1로 시작한다. 참고로 SegWit v0인 P2WPKH, P2WSH는 OP_0으로 시작한다.

아래 그림에서 실제 트랜잭션의 P2TR 잠금 스크립트를 확인할 수 있다. (트랜잭션 링크)

P2TR 방식으로 비트코인을 사용할 때는 key path와 script path 중에 하나를 선택할 수 있다. key path는 단일 서명처럼 특별한 로직이 필요없는 경우에 사용할 수 있다. script path는 위에 다중 서명 예제처럼 로직이 들어가는 경우에 사용할 수 있다.

key path 방식은 P2WPKH와 서명 방식만 다를 뿐 나머지는 비슷한 방식으로 처리된다(Taproot에서는 Schnorr 서명을 사용). 따라서 witness에 있는 서명 데이터를 읽어와서 서명이 유효한지 판단한다.

script path

script path 방식은 로직이 들어가는 경우에 사용하며 MAST(Merkelized Abstract Syntax Trees)라고 불리는 방식으로 모든 스크립트의 구조를 표현한다. 이전 다중 서명 예의 MAST는 아래와 같이 표현할 수 있다.

필요한 스크립트는 3개이지만 짝수로 맞추기 위해 Script3을 복사해서 네 번째 스크립트를 만든다. 스크립트의 해시값을 계산해서 최종적으로 Merkle Root까지 완성한다. script path 방식을 사용할 때 잠금 스크립트의 공개키는 Merkle Root에 의해 수정된 공개키 값이 들어간다. 그렇게 함으로써 나중에 스크립트를 사용할 때 유효한 스크립트인지 검증할 수 있다.

Script1으로 비트코인을 사용하는 경우를 살펴보자. Script1을 실행해야 하므로 Script1 스크립트가 필요하다. 그리고 Script1이 유효한 스크립트인지 증명하기 위해서는 Merkle Root를 만들 수 있는 중간 요소들을 제공해야하며 이 경우에는 Hash2, Hash34가 필요하다. Script1, Hash2, Hash34를 제출하면 비트코인 노드는 스크립트의 유효성 검사를 할 수 있고, 유효하다고 판단되면 Script1을 실행한다.

다음은 script path 방식의 Witness에 들어가는 데이터 구조다.

  • <Signature> <Tapscript> <Control Block>

Tapscript에는 여러 스크립트 중 실제 사용되는 스크립트가 들어간다. 위 예에서는 Script1이 Tapscript에 들어간다. Control Block에는 스크립트의 유효성을 증명하는 내용이 들어가며 위 예에서는 Hash2, Hash34가 들어간다. Signature에는 잠금 스크립트의 공개키에 대응하는 서명이 들어간다. 이 또한 유효성 검사 대상이 된다.

이 과정에서 Script2, Script3은 노출되지 않았다는 사실에 주목할 필요가 있다. 필요한 스크립트만 트랜잭션 데이터에 포함되므로 트랜잭션 용량을 효율적으로 사용한다. 또한 스크립트의 복잡성에 따라 트랜잭션의 크기나 모양이 크게 바뀌지 않으므로 프라이버시 향상에 도움이 된다.

입력의 잠금 스크립트만 봐서는 key path 방식을 사용할지 script path 방식을 사용할지 유추할 수 없고, script path 방식이더라도 스크립트의 내용은 알 수 없으므로 이 또한 프라이버시 향상에 큰 도움이 된다.

script path 주의 사항

key path 방식은 니모닉(Mnemonic)만 잘 관리하면 개인키와 공개키를 생성해서 저장된 비트코인을 사용할 수 있다. 하지만 script path 방식은 Merkle Root에 의해 변형된 공개키를 사용하므로 MAST 구조에 포함된 스크립트까지 잘 관리해야 한다.

ordinals

ordinals는 2023년에 등장한 비트코인 NFT 프로토콜이다. 2023년 초 비트코인의 트랜잭션 수수료와 블록 사용량을 한껏 높이며 비트코인 커뮤니티를 뜨겁게 달궜다. 이더리움에서 유행했던 Bored Ape Yacht Club NFT의 ordinals 버전도 있다.

ordinals는 P2TR의 script path 방식을 이용한다. script 안에 NFT 데이터를 심어놓는 방식을 사용한다. 이렇게 script 안에 데이터를 넣는 방식을 inscription이라고 부른다.

그렇다면 NFT 소유권은 어떻게 처리하고 있을까?

sat 번호

ordinals는 지금까지 채굴된 (그리고 앞으로 채굴될) 모든 sat(비트코인의 가장 작은 단위)에 번호를 부여한다. 가장 빨리 채굴된 sat를 0으로 하고 이후 순차적으로 번호를 부여해서 모든 sat에 유일한 숫자를 할당한다. 이렇게 순서를 나타내는 수를 사용한다고 해서 ordinals(ordinal numbers)라는 이름을 갖고 있다.

아래는 ordinals가 각 sat에 번호를 부여하는 방식을 파이썬 코드로 나타낸 것이다.

# 해당 블록의 채굴 보상
def subsidy(height):
return 50 * 100_000_000 >> height // 210_000

# 해당 블록의 첫 번째 ordinal 번호
def first_ordinal(height):
start = 0
for height in range(height):
start += subsidy(height)
return start

# 블록 내 모든 출력 sat에 ordinal 번호 부여
def assign_ordinals(block):
first = first_ordinal(block.height)
last = first + subsidy(block.height)
# 블록 보상으로 받는 모든 sat의 ordinal 번호
coinbase_ordinals = list(range(first, last))

# coinbase 트랜잭션 제외하고 반복
for transaction in block.transactions[1:]:
ordinals = []
# 모든 입력 sat의 ordinal 번호를 변수에 담는다
for input in transaction.inputs:
ordinals.extend(input.ordinals)

# 모든 출력 sat에 ordinal 번호 부여
for output in transaction.outputs:
output.ordinals = ordinals[:output.value]
del ordinals[:output.value]

# 트랜잭션 수수료의 ordinal 번호를 저장
coinbase_ordinals.extend(ordinals)

# coinbase 트랜잭션의 출력 sat에 ordinal 번호 부여
for output in block.transaction[0].outputs:
output.ordinals = coinbase_ordinals[:output.value]
del coinbase_ordinals[:output.value]

모든 sat는 블록 보상으로 생성되며 생성 시점에 처음으로 ordinal 번호를 부여받는다. input.ordinals값은 이전 블록까지 계산된 output.ordinals로부터 얻을 수 있다.

inscription

inscription은 비트코인 스크립트 안에 데이터를 넣는 것을 의미한다. P2TR 스크립트는 입력 부분에 노출된다. P2TR 출력이 있어야 입력을 할 수 있으므로 inscription을 위해서는 2개의 트랜잭션이 필요하다. 출력 트랜잭션을 생성하는 것을 commit 단계, 입력 트랜잭션을 생성하는 것을 reveal 단계라고 부른다. commit 단계만으로는 그 누구도 inscription의 존재를 알 수 없다. reveal 단계에서 스크립트를 노출하면서 데이터가 공개된다.

P2TR 스크립트 안에 아래와 같은 구조로 데이터를 넣는다.

OP_CHECKSIG
OP_FALSE
OP_IF
OP_PUSH "ord"
OP_PUSH 1
OP_PUSH "text/plain;charset=utf-8"
OP_PUSH 0
OP_PUSH "Hello world"
OP_ENDIF

먼저 스택에 있는 서명과 공개키를 OP_CHECKSIG로 검증한다. OP_FALSE 실행으로 OP_IF 안에 있는 스크립트는 실행되지 않으며 데이터를 표현하는 역할만 하게 된다. Hello world 부분에 실제 데이터가 들어간다. 그 위에 text/plain는 데이터 형식을 나타낸다.

한 번의 PUSH 명령어로는 최대 520바이트만 처리할 수 있으므로 이미지와 같이 많은 데이터를 처리할 때는 520바이트씩 쪼개서 여러 번의 PUSH 명령어로 처리한다.

inscription 입력에서 사용하는 비트코인의 첫 번째 sat가 해당 ordinals NFT의 소유권을 나타낸다.

아래는 ordinals.com에서 보여주는 특정 ordinals NFT 정보다

1242278969222785 번째 sat를 소유한 사람이 이 NFT의 소유자라는 것을 확인할 수 있다.

지표로 보는 ordinals NFT

아래 그림은 814,310 블록에 포함된 일부 ordinals NFT를 보여준다. 현재(2023년 10월말)도 블록 하나에 수백에서 수천 개의 ordinals NFT가 생성(inscription)되고 있다.

아래는 현재(2023년 10월말) 시점 ordinals NFT의 주요 지표다. (출처)

  • ordinals NFT 총 발생 수: 35,560,304
  • ordinals NFT 발생을 위해 지불된 총 수수료: $ 58,774,941

아래 그림을 통해 2023년 5월 초에 ordinals 트랜잭션이 가장 활발했다는 것을 알 수 있다. 2023년 5월 8월 주간에 (1주간) ordinals 수수료로 사용된 금액만 $ 17,840,319에 달한다.

아래 그림은 비트코인 전체 트랜잭션에서 1%도 안되던 Taproot 사용률이 ordinals NFT가 나오면서 30%를 넘겼다는 사실을 알 수 있다.

2023년 2월 2일에는 역사상 가장 큰 3.95MB 블록이 탄생했다. SegWit 업그레이드로 1MB 제한이 4MB까지 늘어났는데, 그 한계에 거의 근접했다. 하지만 ordinals NFT가 아무리 활발하더라도 4MB는 넘어설 수 없다.

여러 지표를 통해 ordinals NFT가 비트코인의 여러 지표에 큰 영향을 주고 있다는 것을 확인할 수 있다

댓글 삭제 시 메일 주소가 필요합니다