블록체인 5 - Scripts (1)
트랜잭션에 사용되는 언어, Script 에 대해 알아보자.
트랜잭션에는, 컴퓨터가 자동으로 검사할 수 있는 작은 프로그램(코드) 가 포함되어 거래가 이루어지는데, 이 코드를 스크립트라고 부른다.
- 트랜잭션의 아웃풋

- 트랜잭션의 output이란, 누군가에게 비트코인을 보낼 때 만들어지는 '돈의 도착지 정보'다.
- 구성요소
- 값 : 0.015
- scriptPubKey(누가 쓸 수 있는가) : 잠금 스크립트로, 이 스크립트를 풀 수 있는 개인키를 가진 사람만이 이 돈을 꺼내 쓸 수 있다.
- 트랜잭션의 인풋

- 트랜잭션 input이란 : 돈을 쓸 때, 내 지갑의 어디에서 돈을 가져오는지 증명하는 부분이다.
- 구성요소
- 어느 돈을 쓸래?
- txid : 이전에 받은 돈이 기록된 트랜잭션 id
- vout : 해당 트랜잭션에서 몇번째 출력인지 가리키는 인덱스
- 주인인걸 증명해
- scriptSig : UTXO에 걸린 조건을 만족시켜 잠금을 해제하는 데이터(서명 등) -> output의 자물쇠를 여는 서명과 공개키다.
- 어느 돈을 쓸래?
트랜잭션의 인풋이랑 아웃풋이 각각,
- 아웃풋은 비트코인의 값과 자물쇠, 즉 스크립트펍키로 돼있고,
- 인풋은 전 거래의 id와 인덱스, 그리고 스크립트펍키를 열수있는 개인키의 공개키와 그 서명으로 돼있는 스크립트시그로 돼있다고 이해했다.
근데, 인풋에는 얼마가 들어와있는지 적혀있지 않다.
- 그런데 채굴자(노드)는 수수료를 계산해야한다.
- 수수료 = (입력으로 들어온 돈 총액) - (출력으로 나가는 돈 총액)
- 나가는 돈은 이번 트랜잭션에 적혀있지만 들어온 돈은 알 수가 없다.
- 그래서, 옛날 트랜잭션의 나가는 돈을 봐야하는거다.
다시 복습하면,
- Authorization (권한 부여) = scriptPubKey (자물쇠)
- 아웃풋에 있는 scriptPubkey
- 돈을 보낼 때 발생하고, 이 돈은 철수의 공개키를 가진 사람만 쓸 수있다. 라는 식의 정책을 정해서 자물쇠를 거는 행위임
- Authentication(인증) = scriptSig(열쇠) - 인풋에 적혀있음
- 돈을 쓸 때 발생하고, 철수가 와서, "내가 철수 맞다. 여기 내 서명봐라: 고 증명하는 과정임.
스크립트 언어의 세가지 특징
- 단순한 스택기반
- Stateless : 스크립트 실행 전이나 후에 저장되는 상태(변수 등)이 없다.
- 튜링 불완정성 : 루프나 복잡한 흐름제어가 없다.
- 검증 엔진은, 트랜잭션을 검증하기 위해 input 스크립트와 output 스크립트를 사용한다.
- 입력 스크립트를 복사하고, 참조된 utxo의 출력 스크립트를 가져와서 이어붙여 실행한다.
- 출력 스크립트의 조건을 정확히 만족시켜 결과가 나오면 소비됨 (spent)로 간주된다.
- 어떤 조합이든 결과가 True가 나오면 유효하다.
- P2PKH ( Pay to Public Key Hash) : 가장 흔한 레거시 비트코인 거래방식
P2PKH ( Pay to Public Key Hash) : 가장 흔한 레거시 비트코인 거래방식

- 해제 스크립트와 잠금 스크립트가 결합된 모습
- 왼쪽 : <sig> <PubK> : 사용자가 제출한 서명과 공개키
- 오른쪽 : DUP HASH160 <PubKHash> EQUALVERIFY CHECKSIG : 블록체인에 저장돼있던 자물쇠 - 복사, 해시, 비교, 서명확인의 조건.
- 스택 연산의 작동 방식 설명

- 2 3 ADD 5 EQUAL 이면,
- 2랑 3을 스택에 차곡 차곡 쌓고 (push)
- ADD로 맨위에 두개 숫자를 꺼내서 더하고 결과를 다시 넣는다. (pop & push)
- 비교할 정답숫자 5를 스택에 넣는다
- EQUAL : 맨위에 두개 꺼내서 같은지 보고, 같으면 TRUE를 넣는다.
- 스택 연산자가 이런식으로 작동하는겨
- P2PKH 실행과정 (준비단계)

- 사용자가 입력한
<서명>과<공개키>를 스택에 넣고,OP_DUP명령어를 실행해서 맨위에 있는걸 복사한다.

- OP_HASH160: 맨 위 데이터를 해싱한다.
- OP_EQUALVERIFY: 스택의 해시값과 잠금 스크립트(Output)에 있던 해시값이 같은지 비교하고 제거한다.
- OP_CHECKSIG: 남은 공개키와 서명을 대조하여 유효하면
TRUE를 반환한다.
고급 트랜잭션들
- Multisignature (다중서명) : 여러명 도의 필요
- Pay-to-Script-Hash : 나중에 배움여
- Timelocks : 시간제한 걸기
위에서 도표로 본건 기본 예금이고, 계모임 통장같은 개념이나 특수 기능도 알아보자.
Multisignature
- M of N 구조 : N명의 관리자 중 M 명 이상이 서명해야 출금 가능.
- 스크립트 형태 :
M <키1> <키2> ... <키N> N OP_CHECKMULTISIG예시: 2-of-3 (3명 중 2명 서명 필요).
버그 : CHECKMULTISIG 명령어 구현상의 실수로, 실행 시 스택에서 의도한 것보다 아이템을 하나 더 꺼내는(Pop) 버그가 있다.
해결책 : 입력 스크립트(서명) 맨 앞에 0 또는 OP_0 이라는 의미없는 더미값을 추가해줘야한다.
복잡한 Multisig의 문제점
ex) 모하메드가 5명중 2명의 서명이 있어야 돈을 쓸 수 있는 2 of 5 계좌로 돈을 보내려고 한다.
문제점들
- 복잡성 : 모하메드는 돈을 보내기 전에 파트너 5명의 공개키 목록이 담긴 전체 스크립트 내용을 미리 알아야한다.
- 용량과 수수료 : 공개키가 5개나 들어가서 트랜잭션의 크기가 일반 거래보다 약 5배 커진다. 그러면 수수료가 비싸진다.
- 네트워크 부담 : 이 거대한 스크립트는 누군가 사용할 때까지 계속 모든 비트코인 노드의 UTXO 데이터베이스에 저장되어있어야 해서 네트워크에 부담을 준다.
해결책 : P2SH (Pay-to-Script-Hash)의 등장
- 핵심 아이디어 : 복잡하고 긴 스크립트 전체를 트랜잭션에 넣는 대신, 스크립트의 해시값만 넣는다.
- 작동 방식
- 돈을 보낼 때 짧은 해시값으로만 잠가둔다
- 나중에 돈을 사용할 때, 원래의 긴 (Redeem Script)를 제출해서 해시값이 맞는지 증명한다.
- 결론 : P2SH는, 이 해시값과 일치하는 스크립트를 나중에 가져오면 돈을 주겠다. 는 뜻이다.

- 1. p2sh 적용 전에는, 잠금 스크립트에 모든 공개키가 다들어가 엄청 길어진다.
- 2. p2sh 적용 후에는, 긴 공개키 목록을 별도로 빼두고, 잠금스크립트에는 20바이트의 짧은 해시값만 넣어둔다.
- 나중에 돈을 받는 사람이 돈을 쓸 때, 서명과 함께 원래의 긴 'Redeem Script'를 제출한다.
- 핵심 변화 : 데이터 용량과 수수료 부담이 보내는 사람에서 받는 사람으로 이동했다. 보내는 사람은 짧은 주소로 보내면되고, 쓸 사람이 복잡한 내용을 처리한다.
- p2pkh는 페이 투 퍼블릭 키 해시라는 뜻이다.
- p2sh 라는건, 페이 투 스크립트 해시라는 뜻이다.
- 이름에서 알 수 있듯이, p2sh는, 복잡한 조건이 담긴 스크립트의 해시에다가 지불한다는거니까, 리딤 스크립트(Code = "2 <PubA> <PubB> ... <PubE> 5 CHECKMULTISIG") 다시 해시해서 거기로 돈을 보낸다는거다.
- 그래서 p2sh 로 받은 트랜잭션을 어떻게 쓰는가?

- 본인확인 : 금고를 열기 위해 가져온 설명서(스크립트)가 처음에 약속한 설명서가 맞는가? : 해시값 대조
- 내용 실행 : 설명서가 맞다면, 조건을 만족했는가? : 스크립트 실행
(1) 2 <Mohammed's Public Key> ... 5 CHECKMULTISIG 이건 뭘까?
- 이것이 바로 리딤 스크립트(Redeem Script), 잠금해제 규칙이다.
2: "최소 2명의 서명이 필요하다" (M).<PK1> <PK2> ...: 서명을 할 수 있는 후보자들(모하메드, 파트너1, 변호사 등)의 공개키 목록입니다.5: "후보자는 총 5명이다" (N).CHECKMULTISIG: "스택에 있는 서명들을 확인해서, 위 5명 중 2명의 서명이 맞는지 검사하라"는 명령어(함수)입니다.
(2) HASH160은 뭔가요?
- 이것은 해시 함수 명령어다
- 기능: 스택의 맨 위에 있는 데이터를 가져와서
RIPEMD160(SHA256(데이터))연산을 수행합니다. - 결과: 긴 데이터를 20바이트짜리 고유한 '지문(Hash)'으로 바꿔줍니다.
- 기능: 스택의 맨 위에 있는 데이터를 가져와서
(3) 54c557e0... (파란색 글씨)
위의 긴 리딤 스크립트(규칙)를 HASH160 함수에 넣어서 나온 결과값(해시값)이다. 블록체인에는 이 짧은 값만 기록된다.
2. 검증 과정 단계별 설명
Step 1: "가져온 규칙이 맞는가?" (무결성 검사)- 이미지의 (1)번 박스
코드: <2 PK1 ... CHECKMULTISIG> HASH160 <redeem scriptHash> EQUAL<2 PK1 ...>: 사용자가 돈을 쓰겠다고 리딤 스크립트 원본(Raw Code)을 제출합니다. 이 긴 코드가 스택에 올라감HASH160: 제출된 원본 코드를 해시 ->계산된 해시값이 나옴<redeem scriptHash>: 블록체인에 원래 기록되어 있던(잠겨 있던) 해시값(54c55...)을 스택에 올림EQUAL:계산된 해시값==기록된 해시값인지 비교- 통과: "네가 가져온 코드가 처음에 약속한 그 코드가 맞구나." (다음 단계로)
- 실패: "가짜 코드를 가져왔네?" (거래 거절)
Step 2: "규칙을 만족했는가?" (실행 검사)
Step 1이 통과되면, 이제 제출했던 리딤 스크립트의 주석 처리가 풀리고(Deserialize) 실제로 실행됨.
코드: <Sig1> <Sig2> 2 <PK1> ... <PK5> 5 CHECKMULTISIG<Sig1> <Sig2>: 사용자가 제출한 전자서명 2개가 스택에 쌓임2 <PK1> ... <PK5> 5: 아까 검증된 리딤 스크립트의 내용들이 스택에 쭉 쌓임CHECKMULTISIG: 이 함수가 실행되면서 스택에 있는 데이터들을 싹 가져감.- "후보자 5명(
PK1~PK5) 중에 서명 2개(Sig1,Sig2)가 유효한 게 맞는가?"
- "후보자 5명(
- 결과: 맞으면
TRUE, 틀리면FALSE.
P2SH 의 특징과 주의점
- p2sh 를 사용하면, 데이터용량, 수수료부담, 구현의 복잡성의 부담이 모두 받아서 사용하는 사람에게 이전된다.
- p2sh 안에 또 p2sh를 넣는 건 안된다.
- 또한, 실수로 무효한 스크립트의 해시값을 만들어 돈을 보냈다면, 그 돈은 영원히 못찾는다.
데이터 기록용 OUTPUT (OP_RETURN)
- 비트코인을 화폐가 아닌 데이터 저장소로 사용할 수 있다.
- 하지만 반대론자들이 내세우는 문제점
- 블록체인 비만(Bloat) : 결제가 상관없는 데이터가 쌓이면 풀노드들의 저장공간을 낭비한다.
- 가짜 UTXO 문제 :
- 초기에는 데이터를 남기기 위해 가짜 비트코인 주소를 만들어서 돈을 보냈다.
- 이 주소는 누구의 것도 아니기에 돈을 절대 사용할 수 없다.
- 이는 평생 UTXO로 남아서 utxo set 에 평생 남아서 노드의 성능을 크게 떨어뜨린다.
- 해결책 : OP_RETURN
- 거래 출력에 80바이트까지 데이터를 적을 수 있다.
- OP_RETURN은 명백히 못쓰는 돈이라고 선언하는 것이기에 이 데이터는 블록체인 디스크에는 기록되지만 노드의 메모리(ram)을 낭비하지는 않는다.