VarInt
CompactSize
blockchain bitcoin distributed
VarInt
비트코인 블록체인에서 공간(space)는 곧 돈이다. 1MB(혹은 4M Weight)라는 한정된 블록 공간에 최대한 많은 트랜잭션을 담아야 수수료를 아끼고 처리량을 높일 수 있기 때문 이다. 그래서 비트코인은 정수를 표현할 때 고정된 8바이트(uint64)를 무작정 사용하지 않는다. 숫자의 크기에 따라 길이가 늘어났다 줄어드는 가변 길이 정수(Variable Length Integer), 줄여서 VarInt 를 사용한다. 즉, VarInt 는 비트코인을 ‘작고, 빠르고, 전 세계에서 동기화 가능하게 만든 데이터 압축형 정수 포맷’ 이다. 비트코인은 P2P 글로벌 시스템이라 1바이트라도 줄이는 게 탈중앙성 비용을 줄인다.
VarInt 는 비트코인에서 거래(transaction), 블록(block) 및 P2P 네트워크 데이터 내 필드의 길이를 나타내는 데 널리 사용되는 정수 형식이다. 비트코인 코드베이스에서는 이를 CompactSize 라고 부르기도 한다.
VarInt 는 정의되는 객체의 크기에 따라 1, 3, 5 또는 9바이트 길이의 가변 길이 필드이다. 가변 길이 객체를 사용할 때 8바이트 필드를 사용하는 것보다 공간 효율성이 뛰어나기 때문에 VarInt 형식을 사용한다. VarInt 값은 거의 항상 Little Endian 방식으로 표현됩니다.
인코딩 규칙:
- VarInt 의 핵심은 "첫 번째 바이트(Prefix)" 를 보면 전체 길이가 얼마인지 알 수 있다는 점이다.
-
1 Byte: [ Value ] 3 Bytes: [ 0xFD ] [ Value(2 bytes) ] 5 Bytes: [ 0xFE ] [ Value(4 bytes) ] 9 Bytes: [ 0xFF ] [ Value(8 bytes) ]
| 값의 범위 (Value) | 첫 바이트 (Prefix) | 추가 데이터 길이 | 총 길이 | 엔디안 |
|---|---|---|---|---|
0 ~ 252 (0xFC) |
없음 (값 자체가 데이터) | 0 바이트 | 1 바이트 | - |
253 ~ 65,535 (0xFFFF) |
0xFD |
2 바이트 (uint16) |
3 바이트 | Little |
65,536 ~ 42억 (0xFFFFFFFF) |
0xFE |
4 바이트 (uint32) |
5 바이트 | Little |
42억 ~ 최대 (uint64 Max) |
0xFF |
8 바이트 (uint64) |
9 바이트 | Little |
- 1바이트 구간 (0~252):
- 가장 흔한 케이스이다. 트랜잭션 입력 개수가 1개라면 그냥
0x01이라고 쓴다. 8바이트를 쓸 때보다 7바이트나 절약된다.
- 가장 흔한 케이스이다. 트랜잭션 입력 개수가 1개라면 그냥
- 3바이트 구간 (Prefix 0xFD):
- 숫자가 253 이상이면 1바이트로 표현할 수 없다.
- 이때 비트코인은 "자, 이제부터 2바이트 더 읽어!"라는 신호로
0xFD를 먼저 보낸다. - e.g 숫자 255 (0x00FF) -> FD FF 00 (Little Endian 이므로 FF 00 순서)
- 5바이트 (0xFE), 9바이트 (0xFF) 구간:
- 같은 원리로 각각 uint32, uint64를 뒤에 붙인다.
VarInt 는 어디에 사용되는가?:
- 비트코인 블록을 뜯어보면 VarInt 가 없는 곳이 없다.
- 트랜잭션 입력/출력 개수 인코딩 시: "이 트랜잭션은 입력이 2개야" 할 때 0x02 (VarInt)를 쓴다.
- 스크립트 길이 표시: 잠금 스크립트(ScriptPubKey) 앞에 "이 스크립트는 25바이트짜리야"라고 알릴 때 쓴다.
- 블록 내 트랜잭션 개수 표시: 블록 헤더 바로 뒤에 "이 블록에는 2,500개의 트랜잭션이 있어"라고 알릴 때 쓴다.