Solana 가상 머신(SVM)이란 무엇이며 어떻게 작동하는가?
작성자 Usman Asim

Solana는 암호화폐 업계에서 가장 활발하게 사용되는 블록체인 중 하나로 자리잡았으며, 일일 활성 주소 수와 거래량 기준으로 꾸준히 상위 5위권을 유지하고 있습니다. 2025년 10월 한 달만 해도 Solana 네트워크는 약 7천만 건의 일일 트랜잭션을 처리했고 1,430억 달러 규모의 DEX 거래량을 소화했으며, 피크 시간대의 처리량은 다른 대부분의 체인을 멈춰 세울 만한 수준입니다.
이것을 가능하게 하는 것은 단순히 빠른 합의 알고리즘이나 고사양 하드웨어 요구사항이 아니라, Solana 성능의 핵심에 자리한 근본적으로 다른 실행 엔진, 즉 Solana Virtual Machine(SVM)입니다.
Solana Virtual Machine은 모든 상태 종속성을 사전에 선언하도록 요구함으로써 트랜잭션을 병렬로 실행하는, eBPF 바이트코드 기반의 레지스터 방식 런타임입니다. Ethereum Virtual Machine의 순차적 트랜잭션 모델과 달리, SVM은 처음부터 병렬 실행을 중심으로 설계되었으며, 하나씩 처리하는 대신 여러 CPU 코어에서 수천 개의 트랜잭션을 동시에 처리합니다.
이러한 아키텍처적 선택은 프로그램이 상태를 저장하는 방식, 트랜잭션이 구성되는 방식, 수수료가 계산되는 방식, 그리고 개발자가 온체인 애플리케이션을 구축하는 방식 전반에 영향을 미칩니다.
이 가이드는 SVM을 근본 원리부터 분석합니다. 먼저 핵심 구성요소를 살펴보고, 각 요소가 개별적으로 어떻게 작동하는지 설명한 다음, 이들이 결합하여 Solana의 성능을 어떻게 실현하는지 보여드리겠습니다. 이 글을 다 읽고 나면 SVM이 무엇을 하는지뿐만 아니라 왜 이런 방식으로 설계되었는지도 이해하게 될 것입니다.
가상 머신이란 무엇인가?
SVM을 구체적으로 살펴보기 전에, 가상 머신이 실제로 무엇이며 블록체인이 왜 이것을 필요로 하는지 짚고 넘어가겠습니다.
가상 머신(VM)은 다른 컴퓨터 내부에서 실행되는 소프트웨어 기반 컴퓨터입니다. 코드가 호스트 시스템의 리소스에 직접 접근하지 않고 실행될 수 있는 통제된 환경을 제공합니다. VM은 어디에나 있습니다. Java Virtual Machine은 Java 바이트코드를 실행하고, 브라우저는 VM에서 JavaScript를 실행하며, 클라우드 서버도 종종 VM 내부에서 실행됩니다.
블록체인이 VM을 필요로 하는 데는 명확한 이유가 있습니다. 바로 신뢰할 수 없는 코드의 결정론적 실행입니다. 스마트 컨트랙트를 배포하면 전 세계 수천 개의 검증자가 그 코드를 실행하여 정확히 같은 결과에 도달해야 합니다. VM은 다음을 제공합니다:
- 샌드박싱: 신뢰할 수 없는 코드는 호스트 시스템이나 다른 프로그램의 메모리에 접근할 수 없습니다
- 결정론: 동일한 입력은 하드웨어와 무관하게 항상 동일한 출력을 생성합니다
- 계측: 실행량을 측정하고 제한할 수 있어(gas/compute units) 남용을 방지합니다
- 이식성: 코드는 서로 다른 머신과 운영체제에서 동일하게 실행됩니다
**Ethereum Virtual Machine(EVM)**은 최초로 널리 채택된 블록체인 VM이었습니다. 스택 기반 아키텍처를 사용하고, 트랜잭션을 순차적으로 실행하며, 코드와 상태를 컨트랙트 안에 함께 저장합니다. 잘 작동하지만, 이러한 설계 선택은 근본적인 처리량 한계를 만들어냅니다.
**Solana Virtual Machine(SVM)**은 다른 접근 방식을 취합니다. 레지스터 기반 아키텍처(물리적 CPU에 더 가까운 방식)를 사용하고, 코드와 상태를 분리하며, 무엇보다 트랜잭션을 병렬로 실행합니다.
Solana Virtual Machine(SVM)이란 무엇인가?
핵심적으로 SVM은 Solana의 실행 엔진으로, 프로그램 로직을 실행하고, 트랜잭션을 처리하고, 상태를 업데이트하는 역할을 담당하는 시스템입니다. Ethereum 배경에서 왔다면, EVM에 대응하는 Solana의 답이라고 생각하면 되지만, 여러 면에서 아키텍처적으로 뚜렷이 구별됩니다.
SVM을 이해하려면 먼저 이것이 무엇을 대상으로 작동하는지 알아야 합니다:
- 계정(Accounts): Solana의 범용 데이터 구조입니다. 모든 것이 계정입니다: 사용자 지갑, 토큰 잔액, 프로그램 상태, 심지어 프로그램 자체까지도요. 계정은 데이터를 보유하고 소유자(해당 계정을 수정할 수 있는 프로그램)를 가집니다. 코드와 저장소를 함께 묶는 EVM 컨트랙트와 달리, Solana는 이 둘을 완전히 분리하며, 모든 상태는 계정에 존재합니다.
- 프로그램(Programs): Solana에서 스마트 컨트랙트를 부르는 용어입니다. 프로그램은 상태를 가지지 않으며(stateless), sBPF라는 바이트코드 형식으로 컴파일된 실행 코드만 담고 있습니다. 대부분의 Solana 프로그램은 Rust로 작성됩니다(C와 C++도 지원됩니다). 프로그램이 실행될 때, 전달받은 계정을 읽고 쓰지만 내부적으로는 아무것도 저장하지 않습니다.
- 트랜잭션(Transactions): 하나 이상의 명령어(instruction)의 묶음으로, 각각 특정 프로그램을 대상으로 하며 읽거나 써야 할 계정을 명시합니다. 이러한 상태 종속성의 사전 선언이 모든 것의 핵심입니다. 이것이 병렬 실행을 가능하게 만드는 요소입니다.
이러한 기초를 바탕으로 SVM을 가장 단순하게 이해하는 방법은 다음과 같습니다: 컴파일된 프로그램 바이트코드를 받아 일련의 계정에 대해 실행하고, 그 결과로 발생하는 상태 변화를 결정하는 샌드박스 런타임 환경입니다. Solana의 모든 트랜잭션은 SVM을 거쳐 흐릅니다.
SVM을 EVM과 다르게 만드는 것은 구현 세부사항만이 아니라 근본적인 설계입니다. SVM은 처음부터 병렬 실행을 중심으로 만들어졌습니다. 트랜잭션은 상태 종속성을 사전에 선언하며, 이를 통해 런타임은 충돌하지 않는 작업을 식별하고 여러 CPU 코어에서 동시에 처리할 수 있습니다. EVM은 트랜잭션을 순차적으로 처리하지만, SVM은 수천 개를 동시에 처리합니다.
용어에 대한 참고: "SVM"이라는 용어는 맥락에 따라 다른 의미를 가집니다. 좁은 정의는 프로그램 코드를 실행하는 바이트코드 인터프리터와 JIT 컴파일러만을 특정하여 가리킵니다(sBPF, 즉 바이트코드 형식에 대해서는 나중에 다룹니다). Anza(Solana의 코어 검증자 팀) 같은 팀이 공식적으로 사용하는 더 넓은 정의는 스케줄링, 컴퓨트 예산 책정, 프로그램 로딩, 실행, 상태 업데이트를 포함한 전체 트랜잭션 실행 파이프라인을 아우릅니다. 개발자들이 "SVM"이라고 말할 때는 보통 이 더 넓은 시스템을 의미합니다. 이 가이드는 두 가지 모두를 다루며, 진행하면서 어떤 의미인지 명확히 하겠습니다.
SVM 아키텍처 이해하기
SVM이 무엇인지, 다른 블록체인 VM과 어떻게 다른지 알았으니, 이제 이것이 실제로 어떻게 작동하는지 이해해 보겠습니다. 이 섹션에서는 트랜잭션이 도착하는 순간부터 최종 상태 변화까지 전체 아키텍처를 살펴봅니다.
서로 연결된 네 가지 부분을 다룰 것입니다:
- 트랜잭션이 시스템을 통과하는 흐름(파이프라인)
- 코드를 실행하는 실행 엔진(eBPF, 컴파일, VM 자체)
- 프로그램이 작동하는 데이터 모델(계정, PDA, rent, CPI)
- 병렬 실행과 Sealevel이 이를 가능하게 하는 방식
각 부분은 이전 내용을 기반으로 합니다. 끝까지 읽고 나면 개별 구성요소뿐만 아니라 이들이 어떻게 조합되어 Solana의 성능 특성을 만들어내는지 이해하게 될 것입니다.
Part 1: 트랜잭션이 SVM을 통과하는 흐름
SVM을 이해하는 첫 단계는 "전송" 버튼을 누르는 순간부터 블록 확정까지 트랜잭션의 여정을 추적하는 것입니다. 이 파이프라인은 Solana 프로그램이 왜 이런 식으로 구성되는지, 왜 계정을 사전에 선언해야 하는지, 그리고 병렬성이 실제로 어디서 발생하는지를 설명해줍니다.
Solana에 트랜잭션을 제출하면, 단순히 큐에 들어가서 차례를 기다리는 것이 아닙니다. 각각 특정 문제를 해결하는 일련의 전문화된 서브시스템을 거쳐 흐릅니다:
Transaction submitted
↓
Banking Stage
(conflict detection, parallel scheduling)
↓
The Bank
(state snapshot for this slot)
↓
BPF Loader
(provisions sBPF VM instance)
↓
Program executes
(reads/writes accounts within budget)
↓
State updates committed각 단계를 살펴보겠습니다:
Banking Stage: 병렬성이 발생하는 곳
이것은 교통 관제탑입니다. 검증된 트랜잭션이 도착하면, Banking Stage는 각각을 분석합니다: 어떤 계정을 읽어야 하는가? 어떤 계정에 써야 하는가?
이 정보를 바탕으로 어떤 트랜잭션이 동시에 안전하게 실행될 수 있는지 결정합니다:
- 완전히 다른 계정을 다루는 트랜잭션 → 병렬 실행
- 둘 다 같은 계정을 읽기만 하는 트랜잭션 → 병렬 실행(읽기는 충돌하지 않음)
- 둘 다 같은 계정에 쓰는 트랜잭션 → 순차적으로 실행해야 함
스케줄러는 이러한 규칙을 강제하기 위해 계정 수준의 잠금(locking)을 사용합니다. 워커 스레드는 충돌하지 않는 트랜잭션 묶음을 동시에 처리합니다. 이것이 Sealevel이라 불리는 Solana의 병렬 실행 모델의 핵심입니다(Sealevel에 대해서는 Part 4에서 더 깊이 다루겠습니다).
Bank: 특정 시점의 상태
Banking Stage가 _스케줄링_을 다룬다면, Bank는 _상태_를 다룹니다. Solana 전체 상태를 특정 슬롯(Solana의 시간 단위, 약 400ms)에 대해 스냅샷한 것이라고 생각하면 됩니다.
Bank는 계정 데이터를 관리하고, 실행을 조율하며, 어떤 버전의 상태가 정본인지 추적합니다. 각 Bank는 세 가지 생애주기 단계를 거칩니다:
Banking Stage가 트랜잭션을 실행할 때, 이는 특정 Bank, 즉 세계의 특정 버전에 대해 작동합니다. 이것이 Solana가 수천 개의 트랜잭션을 병렬로 처리하면서도 일관성을 유지하는 방법입니다.
BPF Loader: 프로그램 실행 준비하기
트랜잭션이 프로그램을 호출하면, 실제로 그 프로그램의 코드를 _실행_할 무언가가 필요합니다. 그것이 BPF Loader의 역할입니다.
BPF Loader는 프로그램의 전체 생애주기를 처리합니다:
- 배포: 새로운 프로그램 바이트코드를 네트워크에 업로드
- JIT 컴파일: 더 빠른 실행을 위해 바이트코드를 네이티브 머신 코드로 변환
- 업그레이드: 기존 프로그램의 새 버전을 배포
- 실행: 프로그램이 호출될 때 격리된 VM 인스턴스를 프로비저닝
각 프로그램 호출은 다음을 갖춘 자체 샌드박스 sBPF VM 인스턴스를 받습니다:
- 전용 메모리 영역
- 컴퓨트 예산(gas 한도와 유사)
- 다른 프로그램으로부터의 엄격한 격리
프로그램이 컴퓨트 예산을 초과하면? 실행이 중단됩니다. 접근하면 안 되는 메모리에 접근하려고 하면? 실행이 중단됩니다. 이 격리는 설계상 엄격합니다. 이것이 Solana가 수천 명의 개발자로부터 온 신뢰할 수 없는 코드를 안전하게 실행하는 방법입니다.
일반적인 트랜잭션 흐름
전형적인 트랜잭션의 전체 흐름은 다음과 같습니다:
- 어떤 프로그램을 호출할지, 그리고 어떤 계정이 필요한지를 명시한 트랜잭션을 제출합니다
- Banking Stage가 이를 수신하고, 다른 대기 중인 트랜잭션과의 충돌 여부를 확인한 후 적절히 스케줄링합니다
- Bank가 이 슬롯에 대한 현재 상태 스냅샷을 제공합니다
- BPF Loader가 대상 프로그램을 위한 sBPF VM 인스턴스를 프로비저닝합니다
- 프로그램이 실행되어 지정된 계정을 읽고 씁니다
- 상태 변화가 Bank에 커밋됩니다
- 결국 Bank가 frozen되고 rooted되어 변경사항이 영구적으로 확정됩니다
각 구성요소는 특정 문제를 해결합니다: Banking Stage는 병렬성을 가능하게 하고, Bank는 일관된 상태를 제공하며, BPF Loader는 안전한 실행을 보장합니다. 이들이 함께 넓은 의미에서의 "SVM"을 이룹니다.
트랜잭션에 대해 더 깊이 알아보고 싶다면 다음 자료를 확인하세요:
- Transaction lifecycle: 트랜잭션이 어떻게 구성되고 처리되는지
- Fees on Solana: 컴퓨트 유닛, 우선순위 수수료, 예산 책정
- Clusters & endpoints: Solana의 네트워크 아키텍처 이해하기
Part 2: 실행 엔진
BPF Loader는 프로그램 코드를 실행하기 위해 VM 인스턴스를 프로비저닝합니다. 그런데 그 VM 인스턴스 내부에서 실제로 무슨 일이 일어날까요?
대부분의 블록체인 VM은 처음부터 설계되었습니다. Solana는 다른 방향을 택했습니다. 원래 Linux 커널을 위해 만들어진 기술인 eBPF(extended Berkeley Packet Filter)를 채택한 것입니다.
BPF는 1992년 Lawrence Berkeley Laboratory에서 효율적인 네트워크 패킷 필터링을 위해 만들어졌습니다. 시간이 지나면서 Linux 커널 내부에서 안전하게 실행되는 범용 샌드박스 VM인 eBPF로 발전했습니다. bpftrace와 같은 관찰 도구를 사용해봤거나 eBPF 기반 네트워킹을 다뤄본 적이 있다면 이미 이 기술을 접한 것입니다. 대규모로 중요한 시스템을 구동하는 실전 검증된 인프라입니다.
Solana의 창립자인 Anatoly Yakovenko는 운영체제 분야의 경력(Qualcomm에서 13년 이상)을 바탕으로 핵심적인 통찰에 도달했습니다: 기존의 것이 이미 어려운 문제들을 해결했는데 왜 처음부터 새로운 VM을 만들어야 하는가?
eBPF는 Solana가 필요로 하던 것을 정확히 제공했습니다:
- 오버헤드 없는 안전성: eBPF 프로그램은 호스트를 크래시시키거나 메모리를 손상시킬 수 없는 제한된 환경에서 실행됩니다. 바이트코드는 로드되기 전 정적으로 검증됩니다. 잘못된 메모리 접근도, 범위를 벗어난 점프도, 승인되지 않은 연산도 없습니다. 이러한 안전성은 가비지 컬렉션이 필요한 관리형 런타임과 달리 런타임 오버헤드 없이 제공됩니다.
- 네이티브에 가까운 성능: (EVM의 스택 기반 설계와 달리) 레지스터 기반 아키텍처는 네이티브 머신 코드로의 JIT 컴파일을 가능하게 합니다. 프로그램은 네이티브에 가까운 속도로 실행됩니다.
- 성숙한 툴체인: LLVM은 이미 eBPF 백엔드를 포함하고 있습니다. Rust, C, C++ 및 기타 LLVM 지원 언어는 eBPF 바이트코드로 직접 컴파일됩니다. 여러분이 아는 언어로 작성하면 툴체인이 나머지를 처리합니다.
sBPF: Solana의 맞춤형 변형
Solana는 표준 eBPF를 그대로 사용하지 않습니다. 사용할 수도 없었는데, 표준 eBPF는 블록체인 실행에 맞지 않는 엄격한 제약이 있는 커널 공간 작업을 위해 설계되었기 때문입니다. 그래서 Solana는 이를 포크했습니다.
그 결과가 sBPF(Solana Bytecode Format)로, 온체인 프로그램 실행에 맞게 조정된 변형입니다:
커널 공간에서 eBPF를 안전하게 만드는 제약들, 즉 작은 스택, 루프 금지 등은 Solana에서 스마트 컨트랙트 개발을 불가능하게 만들었을 것입니다. sBPF는 컴퓨트 유닛 예산을 통해 안전성을 유지하면서 이러한 제약을 완화합니다: 루프를 돌 수는 있지만 결국 컴퓨트가 소진됩니다.
맞춤형 시스템콜도 중요합니다. 프로그램은 메시지를 로깅하고, 다른 프로그램을 호출(Cross-Program Invocation)하며, 암호화 연산을 수행해야 합니다. 표준 eBPF에는 이러한 개념이 없으며, sBPF는 이를 1급 프리미티브로 추가합니다.
Solana 프로그램을 컴파일한다면, 툴체인에서 타겟 트리플 sbf-solana-solana을 보게 될 것입니다. 이것이 이 Solana 전용 변형을 나타내는 식별자입니다.
Rust에서 바이트코드로: 컴파일 파이프라인
cargo build-sbf을 실행하면, Rust 코드는 다단계 컴파일 파이프라인을 거칩니다:
1. Rust 프론트엔드: 컴파일러는 코드를 파싱하고, 매크로를 확장하고, 타입 검사를 수행하고, 메모리 안전성을 검증하기 위해 borrow checker를 실행합니다. 이 단계를 벗어날 때쯤이면 Rust는 다른 시스템 언어들을 괴롭히는 여러 종류의 버그(use-after-free, 데이터 레이스, null 포인터)를 제거한 상태입니다. 이는 컴파일 타임에 메모리 안전성이 강제된다는, Solana의 저평가된 장점 중 하나입니다. 여러분의 프로그램이 체인에 닿기 전에 말이죠.
2. LLVM 최적화: 코드는 LLVM IR이라는 플랫폼 독립적인 표현으로 변환되며, 여기서 상수 폴딩, 함수 인라이닝, 죽은 코드 제거, 루프 언롤링 등 본격적인 최적화가 일어납니다. 컴퓨트 유닛은 비용이 들기 때문에 이러한 최적화가 중요합니다. 더 작고 촘촘한 바이트코드는 더 저렴한 트랜잭션을 의미합니다.
3. sBPF 백엔드: LLVM의 BPF 백엔드를 Solana가 맞춤형으로 포크한 이것이 최적화된 IR을 sBPF 바이트코드로 변환하고, ELF 파일(.so)로 패키징합니다. 이것이 네트워크에 배포하는 것이며, 프로그램이 호출될 때 BPF Loader가 VM 인스턴스에 프로비저닝하는 것입니다.
Rust source (.rs)
↓
Rust compiler (type checking, borrow checker)
↓
LLVM IR (optimizations)
↓
sBPF bytecode (.so)
↓
Deployed to SolanasBPF VM 내부
이제 가장 낮은 수준, 즉 실제로 바이트코드를 실행하는 가상 머신에 도달했습니다.
sBPF 명령어 세트는 RISC와 유사한 설계에 약 100개의 opcode를 가진 64비트 명령어(각 8바이트)를 사용합니다. 프로그램은 11개의 64비트 레지스터에 접근할 수 있습니다:
메모리 레이아웃
VM은 메모리를 각각 특정 주소에서 시작하는 고정된 영역으로 구성합니다:
이 엄격한 레이아웃 덕분에 VM은 경계를 엄격히 강제할 수 있어, 프로그램이 접근하면 안 되는 메모리에 실수로(또는 악의적으로) 접근할 수 없습니다.
JIT 컴파일과 보안
sBPF VM은 두 가지 실행 모드를 지원합니다:
- 인터프리터: 명령어를 하나씩 순회합니다. 시작은 빠르지만 실행은 느립니다. 로컬 테스트와 디버깅에 유용합니다.
- JIT 컴파일: 실행 전에 sBPF 바이트코드를 네이티브 x86_64 머신 코드로 변환합니다. 시작은 느리지만 런타임 속도는 극적으로 빠릅니다. 검증자가 프로덕션에서 사용하는 방식입니다.
Agave 검증자는 재사용을 위해 JIT 컴파일된 프로그램을 ProgramCacheForTxBatch에 캐시합니다. Token Program처럼 자주 사용되는 프로그램은 트랜잭션마다 재컴파일되지 않습니다. 이미 캐시에 있기 때문입니다.
보안 강제는 두 단계에서 이루어집니다:
- 정적 검증(실행 전):
- 형식이 잘못되었거나 유효하지 않은 명령어를 거부
- 모든 메모리 접근 패턴을 검증
- 점프 대상이 유효한 명령어 경계에 위치하는지 확인
- 도달 불가능한 코드 경로를 포착
프로그램이 검증에 실패하면 배포되지 않습니다. 예외는 없습니다.
- 런타임 계측(실행 중):
- 모든 명령어는 컴퓨트 유닛을 소모함
- VM은 각 단계 후 예산을 확인함
- 예산 초과 시 실행이 즉시 중단됨
이 2단계 접근 방식은 무한 루프, 리소스 고갈 공격, 폭주하는 프로그램을 방지합니다. 악의적인 바이트코드가 어떻게든 정적 검증을 통과하더라도 영원히 실행될 수는 없습니다. 컴퓨트 한도에 도달하면 중단됩니다.
실행 엔진에 대해 더 알아보고 싶다면 다음 자료를 확인하세요:
- Programs overview: Solana 프로그램의 작동 방식
- Developing programs in Rust: 공식 Rust 개발 가이드
Part 3: 데이터 모델
트랜잭션이 SVM을 흐르는 방식과 바이트코드가 sBPF VM 내부에서 실행되는 방식을 살펴봤으니, 이제 프로그램이 무엇을 대상으로 작동하는지 살펴보겠습니다.
대부분의 프로그래밍 환경에는 변수, 데이터베이스, 파일 시스템 등 데이터를 저장하고 조회하는 다양한 방법이 있습니다. 블록체인도 비슷한 것이 필요합니다: 트랜잭션 간에 상태를 유지하는 방법 말입니다. EVM은 각 컨트랙트에 자체 저장소, 즉 컨트랙트 자체에 내장된 key-value 저장소를 부여함으로써 이 문제를 해결했습니다.
Solana는 근본적으로 다른 접근 방식을 취하며, 이 차이를 이해하는 것은 필수적입니다. 이것이 플랫폼에서 구축하는 방식 전반을 형성하기 때문입니다.
Solana의 모든 것은 계정이다
Solana를 거대한 key-value 데이터베이스라고 생각해 보세요:
- Key: 32바이트 주소(일반적으로 공개키 또는 파생 주소)
- Value: 계정(바이트, 잔액, 메타데이터를 담고 있는 데이터 구조)
이러한 균일성은 처음에는 이상하게 보일 수 있지만, 이것이 Solana의 성능 특성을 가능하게 하는 요소입니다. 모든 상태 조각은 명시적인 주소, 명시적인 소유자, 그리고 누가 그것을 수정할 수 있는지에 대한 명시적인 규칙을 가집니다. 런타임은 어떤 상태가 변경될지 알아내기 위해 중첩된 컨트랙트 호출을 추적할 필요가 없습니다. 트랜잭션의 계정 목록으로부터 사전에 알 수 있기 때문입니다.
계정 내부에 실제로 무엇이 있는지 살펴보면, 각각 동일한 다섯 개의 필드를 포함합니다:
owner 필드가 중요합니다. 오직 소유 프로그램만이 계정의 data 필드를 수정하거나 lamports를 차감할 수 있습니다. 누구나 어떤 계정이든 읽을 수 있고(Solana의 모든 상태는 공개되어 있습니다), 누구나 어떤 계정에든 lamports를 입금할 수 있습니다. 하지만 쓰기는 소유권에 의해 제한됩니다.
이 소유권 모델이 병렬 실행을 가능하게 만드는 요소입니다. 런타임은 어떤 프로그램이 어떤 계정을 수정할 수 있는지 정확히 알기 때문에, 충돌하지 않는 트랜잭션을 안전하게 동시에 실행할 수 있습니다.
프로그램: 설계상 상태를 갖지 않음
Solana 프로그램은 컴파일된 sBPF 바이트코드를 담고 있는 실행 가능한 계정입니다. 하지만 핵심 통찰은 이것입니다: 프로그램은 내부적으로 상태를 저장할 수 없습니다. 이들은 명령어를 처리하고 전달받은 계정을 수정하는 순수 함수입니다.
모든 Solana 프로그램은 동일한 진입점 시그니처를 공유합니다:
pub fn process_instruction(
program_id: &Pubkey, // This program's address
accounts: &[AccountInfo], // All accounts passed to this instruction
instruction_data: &[u8], // Arbitrary data (parameters, method selectors, etc.)
) -> ProgramResult프로그램이 실행될 때 다음을 전달받습니다:
- 자신의 주소(자신이 파생한 PDA를 검증할 수 있도록)
- 읽기/쓰기가 허용된 계정 배열
- 호출자가 전달한 매개변수를 담은 명령어 데이터
프로그램은 로직을 수행하고, 수정이 허용된 계정을 수정한 다음, 성공 또는 오류를 반환합니다. 호출 사이에 내부적으로 아무것도 저장하지 않습니다.
왜 상태를 갖지 않을까요? 명확한 소유권 경계를 가능하게 하기 때문입니다. 프로그램이 자체 상태를 저장한다면, 어떤 프로그램이 어떤 저장소에 접근할 수 있는지에 대한 복잡한 규칙이 필요할 것입니다. 모든 상태를 명시적 소유자를 가진 계정으로 강제함으로써, 모델은 단순함을 유지하고 병렬화도 가능한 상태로 남습니다.
설계 참고사항: 기본적으로 불변인 EVM 컨트랙트와 달리, Solana 프로그램은 기본적으로 업그레이드 가능합니다. 업그레이드 권한을 가진 자는 언제든 새로운 바이트코드를 배포할 수 있습니다. 개발자는 프로그램을 불변으로 만들기 위해 업그레이드 권한을 철회할 수 있지만, 이는 명시적인 선택입니다. 이것은 Solana의 실용적인 접근 방식을 반영합니다. 대부분의 프로그램은 버그 수정과 기능 업데이트가 필요합니다.
Program Derived Addresses(PDAs)
프로그램이 상태를 갖지 않고 모든 데이터가 계정에 존재한다면, 프로그램은 자신의 계정을 어떻게 생성하고 관리할까요? 프로그램은 개인키를 가질 수 없습니다. 이때 Program Derived Addresses(PDAs)가 등장합니다.
PDA는 Ed25519 타원 곡선을 벗어나는 특수한 주소로, 이는 유효한 개인키가 존재하지 않음을 의미합니다. 이러한 암호학적 속성 덕분에 프로그램은 개인키를 보유하지 않고도 이러한 주소를 대신해 "서명"할 수 있으며, 런타임이 내부적으로 파생 과정을 검증합니다.
PDA 파생은 시드와 프로그램 ID, 그리고 "bump seed"를 해싱하는 방식으로 작동합니다:
// Find a PDA for storing a user's balance
let (user_balance_pda, bump) = Pubkey::find_program_address(
&[
b"balance", // Static seed
user.key().as_ref() // User's public key as seed
],
program_id
);이 알고리즘은 255부터 시작해 값을 내려가며 시도하다가 곡선을 벗어난 주소를 만들어내는 값을 찾습니다. 이 첫 번째 유효한 bump가 "canonical bump"입니다.
PDA가 중요한 이유
- 결정론적 주소 지정: 동일한 시드가 주어지면 항상 동일한 주소를 얻습니다. 주소를 별도로 저장할 필요가 없습니다.
- 프로그램이 제어하는 계정: 프로그램은 자신이 파생한 PDA에 계정을 생성할 수 있으며, 오직 그들만이 해당 PDA를 대신해 서명할 수 있습니다.
- Key-value 패턴: 시드는 관계를 인코딩할 수 있어(사용자 + 토큰 유형 → 잔액 계정), 매핑과 유사한 데이터 구조를 가능하게 합니다.
// Common PDA patterns
// User-specific data
let (user*profile, *) = Pubkey::find_program_address(
&[b"profile", user.key().as_ref()],
program_id
);
// Token account for a specific mint
let (token*vault, *) = Pubkey::find_program_address(
&[b"vault", mint.key().as_ref()],
program_id
);
// Unique item with incrementing ID
let (item, _) = Pubkey::find_program_address(
&[b"item", &item_id.to_le_bytes()],
program_id
);Rent: 상태에 대한 대가 지불
블록체인 상태는 공짜가 아닙니다. 모든 계정은 검증자의 디스크 공간을 차지하며, 그 공간에는 실질적인 비용이 듭니다. 체인마다 이를 다르게 처리합니다. Ethereum은 저장 연산에 gas를 부과하지만, 한번 기록된 상태는 영구히 유지되어 점점 커지는 상태 비대화 문제에 기여합니다.
Solana는 다른 접근 방식을 취합니다. "rent"라는 것이 있어, 네트워크는 데이터를 온체인에 유지하기 위해 바이트당 연간 약 3,480 lamports를 부과합니다. 실제로는 모든 메인넷 계정이 "rent 면제"이어야 하며, 최소 2년치 rent를 사전에 보유해야 합니다:
rent_exempt_minimum = (account_size + 128 bytes overhead) × 3,480 × 2일반적인 토큰 계정(165바이트)의 경우, 이는 대략 0.002 SOL에 해당합니다.
하지만 여기 다른 체인과의 핵심 차이가 있습니다: 계정을 닫으면 전체 rent 보증금이 반환됩니다. 이는 사용하지 않는 상태를 정리할 경제적 유인을 만들어내는데, 이는 저장소가 영구히 유지되는 모델에는 존재하지 않는 것입니다.
// Closing an account returns lamports to a recipient
ctx.accounts.account_to_close.close(ctx.accounts.recipient.to_account_info())?;Cross-Program Invocations(CPIs)
프로그램은 고립되어 존재하지 않습니다. DeFi 프로토콜은 토큰을 전송하기 위해 Token Program을 호출할 수 있고, 이는 다시 Associated Token Account Program을 호출할 수 있습니다. 이러한 Cross-Program Invocation이 Solana 생태계가 조합되는 방식입니다.
두 함수가 CPI를 가능하게 합니다:
// Standard CPI - passes existing signers through
invoke(
&instruction,
&[account1, account2, ...]
)?;
// CPI with PDA signing - program "signs" for a PDA it controls
invoke_signed(
&instruction,
&[account1, account2, ...],
&[&[b"seed", &[bump]]] // Seeds that derive the PDA
)?;PDA 시드와 함께 invoke\_signed을 호출하면, 런타임은 파생 결과가 예상 주소와 일치하는지 검증하고 해당 호출에 대한 서명 권한을 부여합니다. 이것이 프로그램이 개인키를 보유하지 않고도 자산을 제어할 수 있는 방법입니다.
중요한 제약사항:
- 최대 호출 깊이는 5(초기 트랜잭션으로부터 4단계의 중첩된 CPI)
- 서명자 권한은 호출 체인을 따라 이어짐
- 컴퓨트 예산은 트랜잭션 내 모든 CPI에 걸쳐 공유됨
계정에 대해 더 알아보려면 다음을 확인하세요:
- Accounts Overview: Solana 계정에 대한 완전한 가이드
- PDAs: Program Derived Addresses 설명
- CPIs: Cross-Program Invocations 가이드
Part 4: 병렬 실행(Sealevel)
이제 기초가 되는 모든 요소를 다뤘습니다: 트랜잭션이 파이프라인을 흐르는 방식, sBPF VM이 바이트코드를 실행하는 방식, 그리고 계정 모델이 명시적 소유권으로 상태를 저장하는 방식까지요.
이제 지금까지 쌓아온 질문에 마침내 답할 수 있습니다: Solana는 실제로 어떻게 병렬 실행을 달성할까요?
우리는 지금까지 이에 대한 힌트를 여러 번 언급했습니다: 충돌하지 않는 트랜잭션을 스케줄링하는 Banking Stage, 소유자를 사전에 선언하는 계정, 어떤 계정을 다룰지 명시하는 트랜잭션. 이것들은 별개의 기능이 아닙니다. 모두 Sealevel이라는 단일 시스템의 부분들입니다.
Sealevel은 Solana의 병렬 스마트 컨트랙트 런타임으로, SVM의 처리량을 가능하게 하는 핵심 혁신입니다. 지금까지 다룬 모든 것, 즉 계정 모델, 소유권 규칙, 사전 계정 선언은 모두 Sealevel을 가능하게 하기 위해 존재합니다.
근본적인 통찰은 겉보기와 다르게 단순합니다:
트랜잭션이 실행 시작 전에 어떤 계정을 읽고 쓰는지 선언하면, 런타임은 겹치지 않는 트랜잭션을 식별하여 동시에 실행할 수 있습니다.
그게 전부입니다. 그것이 전체 트릭입니다. 하지만 이것을 실제로 작동시키기 위해서는 시스템의 다른 모든 부분을 이 제약을 중심으로 설계해야 했습니다.
병렬 실행의 규칙
Sealevel의 스케줄링은 다음과 같은 간단한 규칙을 따릅니다:
그게 전부입니다. 읽기는 읽기와 충돌하지 않습니다. 쓰기는 모든 것과 충돌합니다.
TX1: [Account A (write), Account B (read)]
TX2: [Account C (write), Account D (read)] ──► PARALLEL
TX3: [Account B (read), Account E (write)]
TX4: [Account A (write), Account F (read)] ──► SEQUENTIAL with TX1
(conflicts with TX1 on Account A write)이것이 Solana 트랜잭션에서 모든 계정을 사전에 선언해야 하는 이유입니다. 이것은 관료적인 절차가 아니라, 런타임이 트랜잭션을 병렬화하는 데 필요한 정보입니다.
스케줄링 알고리즘
Banking Stage는 계정 수준의 잠금을 통해 Sealevel을 구현합니다:
- 읽기/쓰기 플래그와 함께 계정을 명시한 트랜잭션이 도착합니다
- 쓰기 가능한 각 계정에 대해: 배타적 잠금을 획득합니다
- 읽기 가능한 각 계정에 대해: 공유 잠금을 획득합니다(여러 명의 읽기 주체 가능)
- 모든 잠금이 획득되면: 실행을 위해 스케줄링합니다
- 어떤 잠금이든 막히면: 다시 큐에 넣고 나중에 시도합니다
현재 구현은 6개의 스레드를 사용합니다: 투표가 아닌 트랜잭션용 4개, 투표 트랜잭션용 2개. 각 스레드는 우선순위 수수료(컴퓨트 유닛당 수수료)와 도착 시간으로 정렬된 큐를 유지합니다.
더 새로운 Central Scheduler 아키텍처는 단일 스케줄링 스레드와 Prio-Graph 알고리즘을 사용하는데, 이는 미리보기 윈도우를 통해 충돌을 식별하는 지연 생성 종속성 그래프입니다. 이는 경쟁이 심한 워크로드의 스케줄링 효율을 개선합니다.
실전에서의 성능
실제 처리량은 트랜잭션 구성에 크게 좌우됩니다. 고유한 계정을 다루는 단순 전송은 완벽하게 병렬화됩니다. 모두 같은 유동성 풀을 건드리는 복잡한 DeFi 트랜잭션은 경합을 일으키고 직렬화됩니다.
이것은 사실 하나의 특징입니다: 경합이 국소화된다는 점입니다. 하나의 탈중앙화 거래소에서 거래량이 급증해도 다른 계정을 다루기 때문에 네오뱅크에서의 토큰 전송이 느려지지 않습니다. 이는 모든 트랜잭션이 동일한 전역 처리량을 두고 경쟁하는 체인과는 근본적으로 다릅니다.
왜 순차적 VM은 이것을 단순히 채택할 수 없는가
왜 EVM은 단순히 병렬 실행을 추가할 수 없는지 궁금할 수 있습니다.
근본적인 문제는 EVM의 상태 접근이 사전이 아니라 실행 시점에 결정된다는 것입니다. Solidity 컨트랙트를 호출할 때, 실제로 실행하기 전까지는 어떤 저장소 슬롯을 읽거나 쓸지 알 방법이 없습니다. 컨트랙트가 다른 컨트랙트를 호출할 수 있고, 그 컨트랙트가 또 다른 컨트랙트를 호출할 수 있으며, 각각이 예측할 수 없는 상태에 접근합니다.
이러한 "읽기-쓰기를 알 수 없는" 모델은 추측 없이는 안전한 병렬화를 불가능하게 만듭니다. 일부 최신 체인은 "낙관적 병렬 실행"을 구현합니다. 충돌이 없다고 가정하고 추측적으로 실행한 다음, 충돌을 감지하고 발생 시 순차적으로 재실행하는 방식입니다. 이는 작동하지만 복잡성과 오버헤드를 추가합니다.
Solana의 접근 방식은 다릅니다: 충돌은 해결되는 것이 아니라 회피됩니다. 사전 선언을 요구함으로써, 런타임은 실행이 시작되기 전에 각 트랜잭션이 정확히 무엇을 필요로 하는지 알고 있습니다. 이 제약이 최적화를 가능하게 합니다.
EIP-2930은 gas 할인을 위한 선택적 "access list"를 Ethereum에 도입했지만, 이는 필수가 아닙니다. Solana는 선언을 필수적이고 보편적으로 만듭니다. 이것이 핵심적인 차이입니다.
SVM 생태계: Solana 메인넷을 넘어서
SVM은 더 이상 Solana만의 것이 아닙니다. 2024년 6월, Anza는 SVM API를 도입하여 실행 엔진을 Solana의 검증자 클라이언트로부터 분리했습니다. 이 모듈화는 완전히 새로운 사용 사례를 가능하게 했습니다.
Eclipse: Ethereum 위의 SVM
Eclipse는 2024년 11월 Ethereum 위의 첫 프로덕션 SVM 롤업으로 출시되었습니다:
출시 시점에 Orca를 포함한 60개 이상의 앱이 배포되었습니다. Eclipse는 이 브리지를 구축하기 위해 6,500만 달러를 조달했으며, 이는 SVM이 Solana의 합의 계층과 독립적으로 가치를 지닌다는 것을 입증합니다.
SOON network
SOON(Solana Optimistic Network)은 2025년 초 첫 "분리형 SVM" 롤업으로 알파 메인넷을 달성했습니다. 단순한 포크와 달리, SOON은 실행을 합의로부터 깔끔하게 분리하며, 상태 관리를 위해(Solana의 AccountsDB와는 다른) Merkle Patricia Trie를 구현합니다. 목표: Firedancer 통합을 통해 5K–600K TPS.
Sonic SVM
Sonic은 2025년 1월 Solana 위에서 게이밍을 위한 첫 원자적 SVM Layer-2로 출시되었습니다. Mirror World Labs가 구축했으며, 게임별로 맞춤형 SVM 체인을 구동할 수 있는 HyperGrid Framework를 포함합니다. 테스트넷은 월간 활성 지갑 200만 개 이상으로부터 6억 건 이상의 트랜잭션을 처리했습니다.
MagicBlock: 임시 롤업
MagicBlock은 "ephemeral rollup", 즉 임시적이며 필요에 따라 생성되는 SVM 실행 환경을 도입했습니다. Solana에 컨트랙트를 평소처럼 배포한 후, 50ms 미만의 지연이 필요할 때 특정 계정을 MagicBlock에 위임합니다. 쓰기는 임시 세션에서 발생한 뒤 Solana로 다시 커밋됩니다.
400ms 블록도 여전히 느린 게임 및 실시간 애플리케이션에 완벽합니다.
Firedancer: 성능의 도약
Jump Crypto의 Firedancer 클라이언트는 가장 중요한 SVM 개발일 수 있습니다. Agave와 공유하는 구성요소 없이 전적으로 C로 작성되었으며, 각 함수가 커널 우회 네트워킹과 함께 전용 CPU 코어에서 실행되는 타일 기반 아키텍처를 사용합니다.
이는 합성 벤치마크이지만, 현재 메인넷 성능을 넘어서는 상당한 여유가 있음을 시사합니다.
타임라인:
- 2024년 9월: Frankendancer(하이브리드)가 메인넷에 적용
- Breakpoint 2024: 투표하지 않는 모드에서의 완전한 Firedancer
- 2025년: 완전한 프로덕션 출시 예정
SVM 위에서 구축하기
아키텍처를 다뤘으니 이제 실용적인 부분으로 가보겠습니다. Solana 위에서 구축을 시작하고 싶다면, 실제로 무엇이 필요할까요?
한눈에 보는 툴체인
대부분의 개발자에게 경로는 다음과 같습니다: Solana CLI + Anchor + Bankrun. 이 조합은 사용 사례의 90%를 커버합니다.
시작하기: 5분 설정
# Install Solana CLI
sh -c "$(curl -sSfL <https://release.anza.xyz/stable/install>)"
# Install anchor
cargo install --git <https://github.com/coral-xyz/anchor> anchor-cli
# Create a new project
anchor init my_project && cd my_project
# Build and test
anchor build
anchor test이게 전부입니다. 이제 작동하는 Solana 개발 환경, 스타터 프로그램, 테스트 스위트, 그리고 로컬 검증자 통합이 준비되었습니다.
여기서부터 Anchor Book은 첫 실제 프로그램을 구축하는 과정을 안내하며, Solana Cookbook은 여러분이 마주할 일반적인 패턴에 대한 레시피를 제공합니다.
더 깊이 알아보려면:
- Solana Developer Docs: 공식 문서
- Anchor Book: 완전한 프레임워크 가이드
- Solana Cookbook: 실용적인 레시피와 패턴
- Alchemy Solana APIs: RPC 인프라와 개발자 도구
결론: 아키텍처적 도박
SVM은 하나의 일관된 아키텍처적 비전을 나타냅니다: 병렬성, 처리량, 국소화된 수수료 시장을 얻기 위해 사전 제약(명시적 계정 선언, 상태 없는 프로그램, 복잡한 트랜잭션 구성)을 받아들이는 것입니다. 이러한 제약은 부수적인 것이 아니라, 그 성능을 가능하게 만드는 메커니즘 그 자체입니다.
가능성을 탐색하고 싶다면, Alchemy의 Solana APIs는 하나의 플랫폼에서 Solana 메인넷, devnet, 그리고 더 넓은 SVM 생태계에 대한 접근을 제공합니다. 지금 구축을 시작하고 직접 확인해 보세요.
자주 묻는 질문
Solana Virtual Machine(SVM)이란 무엇인가요?
SVM은 Solana의 실행 엔진으로, 모든 상태 종속성을 사전에 선언하도록 요구함으로써 트랜잭션을 병렬로 실행하는, eBPF 바이트코드 기반의 레지스터 방식 런타임입니다. 이를 통해 여러 CPU 코어에서 수천 개의 트랜잭션을 동시에 처리할 수 있습니다.
SVM은 Ethereum Virtual Machine(EVM)과 어떻게 다른가요?
스택 기반의 순차적인 아키텍처를 가진 EVM과 달리, SVM은 병렬 실행을 갖춘 레지스터 기반 설계를 사용하고, 계정을 통해 코드와 상태를 분리하며, 동시 처리를 가능하게 하기 위해 사전 계정 선언을 요구합니다.
Sealevel은 무엇이며 왜 중요한가요?
Sealevel은 충돌하지 않는 트랜잭션을 스케줄링하여 여러 CPU 코어에서 동시에 실행하는 Solana의 병렬 스마트 컨트랙트 런타임으로, 서로 다른 계정을 다루는 트랜잭션을 병렬로 처리함으로써 수천 TPS의 처리량을 가능하게 합니다.
SVM 위에서 구축하는 데 어떤 프로그래밍 언어를 사용할 수 있나요?
프로그램은 주로 Rust로 작성되어 LLVM을 통해 sBPF 바이트코드로 컴파일되지만, C, C++, Zig 같은 다른 LLVM 호환 언어도 지원됩니다.
Program Derived Addresses(PDAs)란 무엇인가요?
PDA는 유효한 개인키가 없는, Ed25519 곡선을 벗어난 특수한 주소로, 프로그램이 개인키를 보유하지 않고도 자신이 제어하는 주소를 결정론적으로 생성하고 "서명"할 수 있게 하여 프로그램이 자신의 계정을 관리할 수 있게 합니다.
SVM의 계정 모델은 어떻게 작동하나요?
Solana의 모든 것은 계정이며, 이는 lamports(잔액), 임의의 데이터 바이트, 소유자 프로그램 ID, 메타데이터를 담고 있는 데이터 구조입니다. 프로그램은 상태를 갖지 않으며 자신이 소유한 계정만 수정할 수 있어, 병렬 실행을 위한 명확한 소유권 경계를 가능하게 합니다.
sBPF란 무엇이며 eBPF와 어떤 관계인가요?
sBPF(Solana Bytecode Format)는 Solana가 커스터마이징한 eBPF 변형으로, 더 큰 스택 크기(512바이트 대신 4KB), 컴퓨트 유닛으로 제한된 루프 지원, 로깅·CPI·암호화 연산을 위한 맞춤형 시스템콜을 통해 블록체인 사용에 맞게 수정되었습니다.
Cross-Program Invocations(CPIs)란 무엇인가요?
CPI는 Solana 프로그램이 실행 중 다른 프로그램을 호출할 수 있게 하며, 최대 호출 깊이는 5입니다. 이는 공유된 컴퓨트 예산과 이어지는 서명자 권한을 유지하면서 생태계 전반의 조합성을 가능하게 합니다.
SVM을 Solana 메인넷 외부에서 사용할 수 있나요?
네, 모듈화된 SVM API는 Solana를 넘어선 사용을 가능하게 합니다. Eclipse는 Ethereum 롤업으로 SVM을 실행하고, SOON Network는 분리형 SVM 롤업으로 운영되며, Sonic과 MagicBlock 같은 프로젝트는 특화된 SVM 실행 환경을 구축합니다.
SVM 위에서 구축을 시작하려면 어떻게 해야 하나요?
Solana CLI와 Anchor 프레임워크를 설치한 다음, anchor init을 사용해 스타터 프로그램, 테스트 스위트, 로컬 검증자 통합이 포함된 프로젝트를 생성하세요. Anchor Book과 Solana Cookbook은 포괄적인 개발 가이드를 제공합니다.
관련 개요
Solana2026년 7월 27일
Solana 노드: 밸리데이터, RPC 노드, 셀프 호스팅
Solana 노드란 무엇인지, 밸리데이터와 RPC 노드, 보조 데이터 시스템은 어떻게 다른지, 그리고 언제 셀프 호스팅을 하고 언제 프로바이더를 써야 하는지 설명합니다.
Solana2026년 7월 22일
Solana 아카이브 데이터: 전체 블록 및 트랜잭션 기록을 조회하는 방법
Solana 아카이브 데이터 설명: 노드가 기록을 정리(prune)하는 이유, 아카이브 액세스가 필요한 RPC 메서드, 그리고 전체 블록 및 트랜잭션 기록을 대규모로 조회하는 방법.
Solana2026년 5월 28일
Solana Agent Kit vs GOAT vs ElizaOS: 어떤 프레임워크를 사용해야 할까?
Solana Agent Kit, GOAT, ElizaOS 비교: Solana 네이티브 심층 지원, 멀티체인 확장성, 완전한 에이전트 런타임 중 선택. 코드 예제와 결정 프레임워크 제공.

블록체인 매직을 만드세요
Alchemy는 가장 강력한 Web3 개발자 제품 및 도구를 리소스, 커뮤니티, 그리고 전설적인 지원과 결합합니다.