💡 비트코인 스크립트
비트코인에서는 스크립트라는 스크립터 언어를 이용해 스마트 컨트랙트를 구현한다. 일반적으로 비트코인에서 사용하는 스크립트는 비트코인 스크립트라고 부른다. 비트코인 스크립트는 일반적인 프로그래밍 언어와는 다르게 어떤 공식적인 문법이나 구문이 있는 것은 아니다. 대신 간단한 연산 목록으로 구성되어 있다. 스크립트에서 사용하는 연산들은 Opcode에 해당하며, 이 연산들은 C++로 작성되어 있다.
스크립트는 트랜잭션에 연결되어 있다. 네트워크의 모든 노드는 트랜잭션을 받을 때마다 자신의 로컬 컴퓨터에서 트랜잭션에 연결된 스크립트를 실행하며 이를 통해 비트코인의 송금이 이루어진다. 이러한 특징으로 인해 비트코인은 프로그래밍 가능한 화폐에 대한 대중성을 부여했다고 볼수 있다. 트랜잭션은 블록체인에 한 번 올라가게 되면 위변조가 매우 어렵기 때문에, 모든 노드는 동일한 스크립트를 실행하고 정확히 동일한 결과를 얻게 된다. 만약, 악의적인 노드가 변조한 트랜잭션을 퍼뜨린다면, 변조된 트랜잭션의 스크립트 실행 결과와 다른 트랜잭션의 스크립트 실행 결과가 달라질 것이다.
✓ 입력값과 출력값
비트코인 트랜잭션은 입력과 출력 목록을 가지고 있다. 출력은 잠금과 값을 가지고 있으며, 입력은 연결된 과거의 출력을 가리키는 포인터와 해제 키를 가지고 있다. 스크립트는 이 잠금과 해제 메커니즘에 관한 것이다. 입력과 출력의 구조는 다음과 같다.
입력 구조에 있는 Prev. Tx ID 와 Tx Index 는 해제하고자 하는 이전 출력을 가리킨다. ScriptSig는 이전의 출력을 해제하는 키이다.
입력구조
- Prev. Tx ID, TxIndex : 해제하고자 하는 이전의 출력을 가리키는 포인터
- ScriptSig : 이전의 출력을 해제하는 키
출력구조
- ScriptPubkey: 잠금. ScriptPubkey의 소유자(해당 공개키의 소유자) 만이 ScriptSig를 만들 수 있다.
- Amount: 잠긴 비트코인의 양(단위: 사토시)
노드는 피어로부터 트랜잭션을 받으면 먼저 해당 트랜잭션 안에 들어있는 입력과 출력 목록에서 각 입력과 출력에 해당하는 ScriptSig와 ScriptPubkeys 를 추출한다. 그리고 기존 블록들을 찾아보며 입력과 연결된 이전 출력을 찾고, 각 입력과 출력에 들어있는 ScriptSig와 ScriptPubekey를 연결시킨다. ScriptSig와 ScriptPubkey는 각각 연속적인 정보를 담고 있다. 노드가 ScriptSig와 ScriptPubkey를 연결하고, 그 연결한 전체 시퀀스를 파싱하면 온전한 스크립트 코드가 나타나게 된다. 노드는 이 코드를 단계별로 실행한다.
✓ 스크립트 동작 원리
스크립트는 역폴란드 표기법으로 작성된 스택 기반 튜링 부완전 언어이다. 스택 구조는 간단히 말해서 프링글스 감자침과 같다. 프링글스 공장에서는 길쭉한 통 안에 감자칩부터 순서대로 넣을 것이다. 나중에 우리가 감자칩을 먹을 때는 가장 나중에 들어온 감자칩부터 먹게 될 것이다. 가장 나중에 들어온 감자칩이 가장 먼저 나가게 될 것이고, 그 반대로 마찬가지일 것이다. 이것이 바로 스택이며, 스택을 쉽게 FILO(First In Last Out) 이라고 부르기도 한다.
스크립트는 빈 스택에서 시작하며, 이 스택에서 데이터가 들어오거나 나가게 된다. 스크립트 프로그램은 두 종류의 객체를 가지고 있다.
- Opcode: 덧셈, 뺄셈, 곱셈과 같은 연산 작업을 나타낸다.
- 데이터: OP_CODE가 아닌 모든 데이터는 원시 데이터로 해석되며, 스택에 들어가게 된다.
* Opcode란?
Opcode는 로우 레벨 기계 언어로, 약 140 종류의 연산이 있다. Opcode의 연산 종류는 다음과 간다.
스택 조작 연산: POP, PUSH, DUP, SWAP
산술/비교/비트연산: ADD, SUB, GT, LT, OR
환경 연산: CALLER, CALLVE, NUMBER
메모리 조작 연산: MLOAD, MSTORE, MSTORE8, MSIZE
스토리지 조작 연산: SLOAD, SSTORE
프로그램 카운터 관련 연산: JUMP, JUMPI, PC, JUMPDEST
작업 중지 연산: STOP, RETURN, REVERT, INVALID, SELEDESTRUCT
스크립트는 이 Opcode와 DATA를 일렬로 늘어놓은 것이다. 여기서 포인터는 일렬로 늘어진 Opcode와 데이터를 순서대로 하나씩 가리킨다. 만약 포인터가 데이터를 가리키면 데이터를 스택에 넣고, Opcode를 가리키면 스택에서 데이터를 꺼내온다. Opcode는 스택에서 데이터를 하나 이상 가져올 수 있지만, 중요한 것은 스택 구조이기 때문에 가장 나중에 들어온 데이터부터 가져온다는 것이다. 스크립트 실행이 성공적이면, 스택의 가장 상단에 있는 요소는 1이 된다. 만약 스크립트를 끝까지 실행했는데도 스택 최상단에 1이 아닌 다른 값이 들어있다면 스크립트 실행을 실패한 것으로 간주한다.
노드가 네트워크로부터 새로운 트랜잭션을 받으면, ScriptSig와 ScriptPubkey 필드를 추출하여 연결하여 최종적으로 <ScriptSig><ScriptPubkey> 형태의 스크립트를 얻게 된다. 노드는 이 스크립트와 빈 스택 하나를 사용해 스크립트를 실행하고, 실행이 완료되면 최상위 스택 요소가 1인지 확인한다. 1이면 트랜잭션이 유효하다고 간주하고 노드는 트랜잭션을 주변 노드들에게 전파한다. 만약 트랜잭션이 유효하지 않은 경우 트랜잭션을 보내지 않고, 이런 경우 주변 노드들에게 전파되지 않으므로 네트워크에 트랜잭션이 공유되지 않게 된다. 트랜잭션은 네트워크에 있는 모든 노드들이 받을 수 있기 때문에, 네트워크의 모든 노드들은 전체 네트워크의 상태를 지키는 문지기 같은 역할을 하게 된다.
'블록체인 > 블록체인이란?' 카테고리의 다른 글
비트코인 스마트 컨트랙트의 한계 (0) | 2022.07.07 |
---|---|
비트코인 스크립트 (P2PK - Pay To PubKey, P2PKH - Pay To PubKeyHash) (0) | 2022.07.07 |
UTXO 동작 원리 (0) | 2022.07.07 |
스마트 컨트랙트란? (0) | 2022.07.07 |
이더리움과 이더리움 클래식은 뭐가 다를까? (0) | 2022.07.06 |
댓글