EVM vs SVM: 개발자를 위한 가이드
작성자 Uttam Singh

모든 블록체인은 가상 머신, 즉 프로그램을 실행하고 상태 변화를 적용하는 엔진 위에서 동작합니다. Ethereum의 엔진은 EVM(Ethereum Virtual Machine)이며, 대부분의 Layer 2도 이 엔진으로 동작합니다. Solana의 엔진은 SVM(Solana Virtual Machine)으로, 트랜잭션을 병렬로 실행하도록 설계되었습니다. 두 엔진의 핵심적인 아키텍처 차이는 EVM이 컨트랙트의 코드와 상태를 함께 저장하는 반면, SVM은 이를 별도의 계정에 분리해서 보관한다는 점입니다. 이 차이는 프로그램이 데이터를 저장하는 방식, 트랜잭션이 실행되는 방식, 그리고 수수료가 혼잡도에 반응하는 방식을 결정합니다.
이 가이드는 계정 모델, 실행, 수수료, 프로그램 설계, 툴링 측면에서 두 엔진을 비교하며, 짧은 코드 예제를 함께 제시하고, 마지막으로 어디에 구축하거나 이식할지 결정하기 위한 프레임워크로 마무리합니다. 영상을 선호한다면, SVM vs EVM builders guide에서 동일한 비교를 다루고 있습니다.
EVM과 SVM이란 무엇인가?
EVM은 스택 기반 가상 머신으로, 트랜잭션을 하나씩 순차적으로 처리하며 단일한 공유 상태 트리를 업데이트합니다. EVM의 주요 장점은 호환성입니다. 동일한 Solidity 컨트랙트가 Ethereum, 그 Layer 2들(Arbitrum, Base, Optimism, Unichain, World Chain, Ink), 그리고 독립적인 EVM 체인(BNB Chain, Avalanche, Polygon, Monad, Berachain)에 변경 없이 배포되며, 주변 툴링도 바이트코드가 동작하는 모든 곳에서 작동합니다. EVM이 처음이라면, Ethereum Virtual Machine explainer에서 기본 개념을 다루고 있습니다.
SVM은 병렬 실행을 중심으로 설계되었습니다. 프로그램은 sBPF 바이트코드로 컴파일되는데, 이는 eBPF(Linux 커널이 사용하는 것과 동일한 바이트코드 설계)에서 파생된 레지스터 기반 포맷이며, 모든 트랜잭션은 실행 전에 자신이 읽고 쓸 계정을 미리 선언합니다. 이 선언 덕분에 Solana의 병렬 런타임인 Sealevel은 충돌하지 않는 트랜잭션들을 여러 CPU 코어에서 동시에 실행할 수 있습니다. Solana Virtual Machine explainer에서 실행 파이프라인을 자세히 다루고 있습니다.
아래 표는 주요 차이점을 요약한 것입니다.
계정 모델은 어떻게 다른가?
Ethereum에는 두 가지 계정 유형이 있습니다. 개인 키로 제어되는 외부 소유 계정(EOA)과, 코드로 제어되는 컨트랙트 계정입니다. 컨트랙트 계정은 자신의 바이트코드와 함께, 32바이트 슬롯으로 구성된 키-값 저장소인 자체 스토리지를 가집니다. ERC-20 토큰에서 balanceOf을 호출하면, 컨트랙트는 자신의 스토리지 안에 있는 매핑에서 잔액을 읽어옵니다. 코드와 상태는 하나의 주소를 공유하며 분리할 수 없습니다.
Solana는 모든 것에 대해 단일 계정 모델을 사용합니다. Solana의 모든 상태는 계정이며, 동일한 구조를 가집니다: lamports(wei와 같은 Solana의 최소 단위) 단위의 잔액, 데이터 필드, 소유자, 그리고 실행 가능 플래그입니다. 프로그램은 데이터가 sBPF 바이트코드이고 실행 가능 플래그가 true로 설정된 계정입니다. 프로그램이 관리하는 상태는 별도의 데이터 계정에 존재합니다. 런타임은 소유권을 직접 강제하는데, 해당 계정을 소유한 프로그램만이 그 데이터를 수정할 수 있으므로, Solidity 컨트랙트가 자체적으로 구현해야 하는 접근 제어 로직의 상당 부분이 필요 없어집니다. Solana data accounts vs. program accounts guide에서 이 분리 구조를 자세히 다루고 있습니다.
프로그램 파생 주소(PDA)는 EVM 개발자에게 가장 낯선 개념일 것입니다. Solidity 컨트랙트가 매핑을 사용해 사용자별 데이터를 저장하는 곳에서, Solana 프로그램은 프로그램의 ID와 시드 집합(보통 사용자의 공개 키)으로부터 각 사용자를 위한 전용 계정 주소를 파생시킵니다. 이 파생은 결정적이며 Ed25519 곡선 밖에 있는 주소를 생성하므로, 이 주소에 대응하는 개인 키는 존재하지 않습니다. 오직 해당 프로그램만이 그 주소를 대신해 서명할 수 있습니다. 실제로 Solidity 매핑의 각 항목은 Solana에서 각각 별도의 계정이 됩니다.
두 모델은 스토리지 가격 책정 방식도 다릅니다. Ethereum에서는 스토리지를 작성할 때 가스로 한 번 비용을 지불합니다. Solana에서는 모든 계정이 크기에 비례하는 환불 가능한 예치금을 보유해야 하며, 이를 rent exemption이라고 부릅니다. 이 예치금은 계정이 닫힐 때 반환되므로, 개발자에게 사용하지 않는 상태를 제거하려는 직접적인 유인을 제공합니다.
SVM에서 병렬 실행은 어떻게 동작하는가?
EVM은 블록 내 트랜잭션을 순차적으로 실행합니다. 트랜잭션은 어떤 스토리지 슬롯이든 읽거나 쓸 수 있으며, 그 접근 내역은 실행되기 전까지는 알 수 없으므로, EVM은 두 트랜잭션을 안전하게 동시에 실행할 수 없습니다.
Solana는 각 트랜잭션이 실행 전에 읽고 쓸 모든 계정을 나열하도록 요구함으로써 이러한 불확실성을 제거합니다. 스케줄러는 공유 계정을 읽기만 하는 트랜잭션은 병렬로 실행하고, 동일한 계정에 쓰는 트랜잭션은 순차 처리합니다. 쓰기 락은 한 번에 하나의 스레드만 허용합니다. 동일한 락이 필요한 트랜잭션들은 대기열에 들어가 순서대로 처리되며, 충돌 때문에 실패하지 않습니다.
이 모델은 프로그램 설계에 영향을 줍니다. 많은 사용자가 동시에 업데이트하는 상태는 여러 계정에 나눠야 하며, 이는 Solana의 토큰 표준인 SPL 토큰이 구성된 방식이기도 합니다. 관련 없는 두 지갑 사이의 USDC 전송 두 건은 서로 다른 네 개의 토큰 계정에 쓰기 작업을 하므로 동시에 실행될 수 있습니다. Ethereum에서는 동일한 두 건의 전송이 모두 하나의 ERC-20 컨트랙트 스토리지를 업데이트하므로 순차적으로 실행됩니다.
병렬 실행은 EVM 생태계에도 도입되고 있습니다. Monad는 완전한 바이트코드 호환성을 갖춘 병렬 실행 EVM L1을 운영하며, MegaETH는 Ethereum L2로서 유사한 기법을 적용합니다. 이 체인들은 트랜잭션이 계정을 미리 선언하도록 요구하는 대신 런타임에 충돌을 감지하며, 이를 통해 EVM 호환성을 유지하면서 처리량을 높입니다.
수수료는 어떻게 비교되는가?
Ethereum은 하나의 전역 수수료 시장을 사용합니다. 모든 트랜잭션은 프로토콜이 블록마다 조정하고 소각하는 동일한 기본 수수료와, 검증자에게 지불하는 선택적인 우선순위 팁을 지불합니다. 표준 ETH 전송은 21,000 가스를 소비하며, 블록은 6천만 가스라는 가스 한도 안에서 3천만 가스를 목표로 합니다. 기본 수수료가 체인 전체에 적용되므로, 한 애플리케이션의 수요가 모두에게 영향을 미칩니다. 인기 있는 NFT 민팅이나 에어드랍 청구는 관련 없는 애플리케이션의 사용자를 포함한 모든 사용자의 기본 수수료를 올립니다.
Solana는 다른 수수료 구조를 사용합니다. 모든 트랜잭션은 서명당 5,000 lamports의 기본 수수료를 지불하며, 이 중 절반은 소각되고 절반은 검증자에게 지급됩니다. 컴퓨팅은 compute units(CU)로 측정되며, 명령어당 기본 예산은 200,000 CU이고 트랜잭션당 최대치는 1.4백만 CU입니다. 트랜잭션은 또한 compute unit당 마이크로 lamports 단위로 가격이 매겨지는 우선순위 수수료를 포함해 다른 트랜잭션보다 먼저 스케줄될 수 있습니다.
핵심 차이는 수수료 경쟁의 범위입니다. 모든 트랜잭션이 자신이 쓸 계정을 명시하므로, 우선순위 수수료 경쟁은 동일한 계정을 두고 경쟁하는 트랜잭션들 사이로 국한됩니다. 생태계에서는 이 동작을 로컬 수수료 시장이라고 부릅니다. getRecentPrioritizationFees RPC 메서드는 트랜잭션이 잠글 쓰기 가능 계정을 기준으로 수수료 샘플을 필터링함으로써 이 설계를 반영합니다. 인기 있는 민팅이 진행되는 동안, 해당 민트의 계정에 쓰기 작업을 하는 트랜잭션들의 수수료는 오르지만, 관련 없는 트랜잭션들은 대체로 영향을 받지 않습니다.
이는 용량 계획에 영향을 미칩니다. Ethereum에서는 관련 없는 애플리케이션의 활동이 자신의 트랜잭션 비용을 올릴 수 있으며, 애플리케이션 설계로 이를 막을 수 없습니다. Solana에서는 수수료 압박이 주로 자신의 계정에 대한 경쟁에서 비롯되므로, 자주 쓰이는 상태를 더 많은 계정에 분산시키면 이를 줄일 수 있습니다.
프로그램 설계에서 무엇이 달라지는가?
Solidity 컨트랙트는 코드와 스토리지가 단일 단위로 묶여 있으며, 설계상 불변합니다. 배포 후 로직을 변경하려면 delegatecall를 기반으로 한 프록시 패턴이 필요하며, 이는 호출을 교체 가능한 구현 컨트랙트로 라우팅합니다. 최소한의 Solidity 카운터는 다음과 같습니다:
// SPDX-License-Identifier: MIT
contract Counter {
uint64 public count; // state lives inside the contract itself
function increment() external {
count += 1;
}
}Anchor(널리 쓰이는 Solana 프로그램 프레임워크)로 작성한 동등한 Solana 프로그램은 그 자체로는 상태를 저장하지 않습니다. 카운터 값은 각 호출이 명시적으로 전달하는 별도의 계정에 존재합니다:
use anchor_lang::prelude::*;
// Run anchor keys sync to set your program ID here and in Anchor.toml.
declare_id!("REPLACE_WITH_YOUR_PROGRAM_ID");
mod counter {
use super::*;
pub fn increment(ctx: Context<Increment>) -> Result<()> {
ctx.accounts.counter.count += 1;
Ok(())
}
}
pub struct Increment<'info> {
pub counter: Account<'info, Counter>, // state account passed in explicitly
}
pub struct Counter {
pub count: u64,
}완전한 버전에는 카운터 계정을 생성하고 자금을 넣는 initialize 명령어도 포함될 것입니다. 핸들러가 실행되기 전, Anchor는 각 계정을 Increment 구조체와 대조해 해당 계정이 예상한 타입과 소유자를 가지고 있는지 확인합니다. 이 검사는 누가 그 명령어를 호출할 수 있는지를 제한하지 않습니다. 작성된 그대로라면 누구나 increment를 호출할 수 있으므로, 실제 프로그램이라면 누가 카운터를 업데이트할 수 있는지 제어하기 위해 서명자 요구사항이나 파생 주소 제약 조건을 추가해야 합니다.
기본 업그레이드 동작은 반대로 뒤집혀 있습니다. 업그레이드 권한을 가지고 배포된 Solana 프로그램은 기본적으로 업그레이드 가능하며, 그 권한을 취소하면 프로그램이 불변으로 변합니다. 따라서 Solana 프로그램은 프록시 컨트랙트가 필요 없으며, 이는 EVM 감사에서 흔히 초점이 되는 코드 범주 하나를 제거합니다.
토큰도 같은 패턴을 따릅니다. 각 ERC-20 토큰은 표준 인터페이스를 구현하는 자체 컨트랙트이므로, 많은 토큰을 지원하는 애플리케이션은 여러 독립적인 코드베이스에 의존하게 됩니다. Solana에서는 토큰이 공유된 Token Program을 통해 발행되며, Token-2022는 전송 수수료와 같은 선택적 기능을 지원하는 확장 버전을 제공합니다. 각 토큰은 공급량과 소수점 자릿수를 기록하는 mint 계정이며, 각 보유자의 잔액은 토큰 계정에 저장됩니다. 이 프로그램들을 통합하는 애플리케이션은 토큰별 코드 없이도 어떤 SPL 토큰이든 지원할 수 있습니다.
이벤트 처리는 EVM이 명확한 우위를 가지는 영역입니다. EVM 컨트랙트는 인덱싱된 이벤트를 발생시키며, eth_getLogs와 인덱서들은 이를 네이티브로 소비합니다. Solana에는 네이티브 이벤트 시스템이 없습니다. 프로그램은 로그 메시지를 작성하고, Anchor의 이벤트 매크로가 구조화된 데이터를 그 로그에 인코딩하는데, 이 로그는 잘릴 수 있습니다. 결과적으로 Solana에서의 프로덕션 인덱싱은 보통 webhooks나 Solana gRPC streaming 같은 스트리밍 인프라에 의존합니다.
클라이언트 스택은 어떤 모습인가?
VM의 선택은 언어와 툴링도 결정합니다. EVM 개발은 Solidity와 테스트, 퍼징, 배포를 폭넓게 지원하는 성숙한 툴체인(Foundry, Hardhat)을 사용합니다. Solana 개발은 Rust와 Anchor를 사용하는데, 학습 곡선이 더 가파르고 감사자 풀도 더 작지만 성장하고 있습니다. web3 programming languages overview에서 언어 선택지를 더 자세히 다루고 있습니다.
데이터 모델의 차이는 클라이언트 코드에서도 드러납니다. EVM에서 상태를 읽는다는 것은 컨트랙트의 함수를 호출하는 것을 의미하며, 그 함수는 자신의 스토리지에서 데이터를 반환합니다. 다음 예제는 viem을 사용합니다:
import { createPublicClient, http, parseAbi, formatUnits } from "viem";
import { mainnet } from "viem/chains";
const client = createPublicClient({
chain: mainnet,
transport: http("https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY"),
});
const balance = await client.readContract({
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC contract
abi: parseAbi(["function balanceOf(address) view returns (uint256)"]),
functionName: "balanceOf",
args: ["0x47ac0Fb4F2D84898e4D9E7b4DaB3C24507a6D503"],
});
console.log(formatUnits(balance, 6));Solana에서 상태를 읽는다는 것은 데이터를 담고 있는 계정을 가져오는 것을 의미합니다. 토큰 잔액은 Token Program이 아니라 토큰 계정에 저장되므로, 클라이언트는 그 계정을 직접 읽습니다. 다음 예제는 @solana/kit을 사용합니다:
import { createSolanaRpc, address } from "@solana/kit";
const rpc = createSolanaRpc("https://solana-mainnet.g.alchemy.com/v2/YOUR_API_KEY");
// SOL balance: fetch the account's lamports by its address
const { value: lamports } = await rpc
.getBalance(address("83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri"))
.send();
// SPL balance: read the token account directly
const { value: tokenBalance } = await rpc
.getTokenAccountBalance(address("2ocS3orPq3jyszjsJ4NozKWyhdotr3csDjAizmkj65aH"))
.send();
console.log(lamports, tokenBalance.uiAmountString);이 패턴은 클라이언트 레이어 전반에 걸쳐 적용됩니다. EVM 클라이언트는 컨트랙트에 쿼리를 보내지만, Solana 클라이언트는 각 데이터가 어느 계정에 있는지 알아야 하므로 계정 레이아웃이 애플리케이션 설계의 일부가 됩니다.
EVM 앱을 Solana로 이식할 때 무엇이 깨지는가?
애플리케이션을 EVM에서 Solana로 옮기려면 온체인 코드를 다시 작성해야 합니다. 계정 모델과 실행 모델이 다르기 때문입니다. 주요 변경 사항은 다음과 같습니다:
msg.sender이 서명자 계정으로 바뀝니다. Solana에서의 권한 부여는 트랜잭션에서 서명자로 표시되고 프로그램이 검사하는 계정, 그리고 프로그램 자체가 권한을 가질 때 프로그램이 대신 서명하는 PDA에서 비롯됩니다.- 매핑이 PDA로 바뀝니다. Solidity 매핑의 각 키는 최초 사용 전에 생성하고 rent 자금을 넣어야 하는 파생 계정이 됩니다. 클라이언트가 컨트랙트 스토리지를 쿼리하는 대신 계정을 가져오므로, 데이터를 읽는 방식도 달라집니다.
- 컨트랙트 스토리지가 크기가 정해지고 rent 자금이 들어간 계정으로 바뀝니다. 상태는 알려진 크기로 미리 할당되어야 하며, 계정이 닫힐 때 예치금이 반환됩니다.
- 프록시 업그레이드 패턴이 더 이상 필요 없습니다. 프로그램의 업그레이드 권한이 프록시 설정을 대체하며, 그 권한을 취소하면 프로그램이 불변으로 변합니다.
- 이벤트가 로그와 스트리밍으로 바뀝니다.
eth_getLogs을 소비하던 어떤 시스템이든 로그 파싱, webhooks, 또는 gRPC 스트림을 중심으로 다시 구축해야 합니다. - 클라이언트와 테스트 스택이 바뀝니다. 클라이언트 코드는 viem에서
@solana/kit로 옮겨가고, 테스트는 Foundry에서 Anchor의 테스트 프레임워크로 옮겨가며, CI에는 로컬 밸리데이터가 필요합니다.
반대 방향, 즉 SVM에서 EVM으로 이동하는 팀은 보통 더 깊은 툴링, 네이티브 이벤트 인덱싱, 더 큰 감사자 시장을 얻는 대신, 병렬 실행, 1초 미만의 확정, 계정별 수수료 격리를 포기하게 됩니다.
어느 방향이든, 팀의 학습 곡선이 보통 가장 큰 비용입니다. Solana로 이동하는 EVM 엔지니어에게는 Solana development roadmap이 좋은 출발점입니다.
EVM과 SVM 중 어떻게 선택하는가?
Alchemy는 EVM과 SVM 개발을 어떻게 지원하는가?
저희는 단일 플랫폼에서 두 생태계를 모두 지원합니다. RPC endpoints는 Ethereum, 주요 L2들, 그리고 더 넓은 EVM 생태계를 아우릅니다. Solana infrastructure는 아카이브 호출을 최대 20배 더 빠르게 처리하며 99.99%의 가동 시간을 제공하고, gRPC streaming은 Solana 인덱싱이 의존하는 실시간 데이터 피드를 제공합니다. Solana 인프라를 검토 중이라면, Solana RPC guide에서 공급자를 선택할 때 확인해야 할 사항을 다루고 있습니다.
무료 API 키 하나로 하나의 대시보드에서 EVM 체인과 Solana용 엔드포인트를 모두 사용할 수 있으며, 계약이나 최소 약정이 필요 없고, 생태계마다 별도의 공급자를 통합할 필요도 없습니다.
관련 개요

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


