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はスタックベースの仮想マシンで、トランザクションを1つずつ処理し、単一の共有ステートツリーを更新していく。その主な利点は互換性である。同じ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には2種類のアカウントがある。秘密鍵によって制御されるExternally-owned account(EOA)と、コードによって制御されるコントラクトアカウントだ。コントラクトアカウントは、32バイトのスロットからなるキー・バリューストアであるストレージを、バイトコードと一緒に保持する。ERC-20トークンでbalanceOfを呼び出すと、コントラクトは自分のストレージ内のマッピングから残高を読み取る。コードとステートは同じアドレスを共有し、分離することはできない。
Solanaはすべてに対して単一のアカウントモデルを使う。Solana上のすべてのステートはアカウントであり、同じ構造を持つ。lamports(Solanaの最小単位で、weiに相当)建ての残高、データフィールド、オーナー、そしてexecutableフラグだ。プログラムとは、データがsBPFバイトコードで、executableフラグがtrueに設定されているアカウントのことである。プログラムが管理するステートは、別のデータアカウントに存在する。ランタイムはオーナーシップを直接強制し、あるアカウントを所有するプログラムだけがそのデータを変更できるため、Solidityコントラクトが自前で実装しなければならないアクセス制御ロジックの多くが不要になる。この分離についてはSolana data accounts vs. program accounts guideで詳しく解説している。
Program derived address(PDA)は、通常EVM開発者にとって最も馴染みのない概念だろう。Solidityコントラクトがユーザーごとのデータをマッピングに保存するのに対し、SolanaプログラムはプログラムのIDと一連のシード(通常はユーザーの公開鍵)から、ユーザーごとに専用のアカウントアドレスを導出する。この導出は決定的であり、Ed25519曲線外のアドレスを生成するため、そのアドレスに対応する秘密鍵は存在しない。プログラムだけがそのアドレスの代わりに署名できる。実務上、Solidityのマッピングの各エントリは、Solanaでは1つのアカウントになる。
この2つのモデルはストレージの課金方法も異なる。Ethereumでは、書き込み時に一度だけガスとしてストレージ料金を支払う。Solanaでは、すべてのアカウントがそのサイズに比例した返金可能なデポジットを保持しなければならず、これはrent exemptionと呼ばれる。このデポジットはアカウントが閉じられたときに返還されるため、開発者には未使用のステートを削除する直接的なインセンティブが生まれる。
SVMの並列実行はどう機能するのか
EVMは、あるブロック内のトランザクションを逐次実行する。トランザクションはどのストレージスロットでも読み書きできるが、そのアクセス内容は実行するまでわからないため、EVMは2つのトランザクションを同時に安全に実行できない。
Solanaは、各トランザクションに実行前に読み書きするすべてのアカウントをリストアップさせることで、この不確実性を排除している。スケジューラは共有アカウントを読み取るだけのトランザクションを並列実行し、同じアカウントに書き込むトランザクションを直列化する。書き込みロックは一度に1つのスレッドにしか許可されない。同じロックを必要とするトランザクションはキューに入れられ、順番に処理されるが、競合を理由に失敗することはない。
このモデルはプログラム設計にも影響を与える。多数のユーザーが同時に更新するステートは複数のアカウントに分割すべきであり、これはSPLトークン(Solanaのトークン標準)の構成方法そのものである。無関係なウォレット間の2件のUSDC送金は、4つの異なるトークンアカウントに書き込むため、同時に実行できる。Ethereumでは、同じ2件の送金は同じERC-20コントラクトのストレージを更新するため、1件ずつ順番に実行される。
並列実行はEVMエコシステムにも広がりつつある。Monadは完全なバイトコード互換性を持つ並列実行EVM L1として動作し、MegaETHはEthereum L2として同様の技術を適用している。これらのチェーンは、トランザクションにアカウントの宣言を求める代わりに実行時に競合を検出することで、EVM互換性を保ちながらスループットを高めている。
手数料はどう比較されるか
Ethereumは単一のグローバルな手数料市場を使う。すべてのトランザクションは、プロトコルがブロックごとに調整しバーンする同じbase feeを支払い、さらにバリデーターへの任意のpriority tipを加える。標準的なETH送金には21,000ガスがかかり、ブロックは3,000万ガスを目標に、6,000万ガスの上限を持つ。base feeはチェーン全体に適用されるため、1つのアプリケーションからの需要が全員に影響する。人気のNFTミントやエアドロップの受け取りは、無関係なアプリケーションのユーザーも含め、全ユーザーのbase feeを引き上げる。
Solanaは異なる手数料構造を使う。すべてのトランザクションは署名1つにつき5,000 lamportsのbase feeを支払い、その半分がバーンされ、残り半分がバリデーターに支払われる。計算量はcompute unit(CU)で計測され、デフォルトの予算は命令あたり200,000 CU、トランザクションあたりの上限は140万CUだ。トランザクションには、compute unitあたりmicro-lamports建てで価格が付くprioritization feeを含めることもでき、これにより他より優先的にスケジューリングされる。
決定的な違いは手数料競争の範囲にある。すべてのトランザクションが書き込むアカウントを名指しするため、priority feeの競争は同じアカウントを取り合うトランザクション間に集中する。エコシステムではこの挙動をlocal fee marketsと呼んでいる。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;
}
}一方、広く使われているSolanaプログラムフレームワークであるAnchorで書かれた同等の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はtransfer feeなどのオプション機能をサポートする拡張版を提供している。各トークンは供給量とdecimalsを記録するmintアカウントであり、各保有者の残高はトークンアカウントに保存される。これらのプログラムと統合するアプリケーションは、トークンごとのコードなしにあらゆるSPLトークンをサポートできる。
イベント処理は、EVMに明確な優位性がある領域だ。EVMコントラクトはインデックス付きイベントを発行し、それをeth_getLogsやインデクサーがネイティブに消費する。Solanaにはネイティブなイベントシステムがない。プログラムはログメッセージを書き出し、Anchorのイベントマクロが構造化データをそれらのログにエンコードするが、切り詰められることがある。その結果、Solana上のプロダクションレベルのインデックス作成は、webhooksやSolana gRPC streamingといったストリーミングインフラに依存するのが一般的だ。
クライアントスタックはどのようなものか
VMの選択は、言語とツーリングも決定する。EVM開発ではSolidityと、テスト、fuzzing、デプロイに対する広範なサポートを持つ成熟したツールチェーン(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がsignerアカウントになる。 Solana上の認可は、トランザクション上でsignerとしてマークされ、プログラムによってチェックされるアカウントから来る。加えて、プログラム自身が権限を持つ場合にはプログラムが代わりに署名するPDAを使う。- マッピングがPDAになる。 Solidityマッピングの各キーは、初回使用前に作成しrent資金を供給しなければならない導出アカウントになる。データの読み取り方法も変わり、クライアントはコントラクトストレージにクエリを投げる代わりにアカウントを取得する。
- コントラクトストレージがサイズ指定済みでrent資金供給されたアカウントになる。 ステートは既知のサイズで事前に割り当てる必要があり、デポジットはアカウントが閉じられたときに返還される。
- プロキシによるアップグレードパターンが不要になる。 プログラムのアップグレード権限がプロキシ構成に代わり、その権限を放棄するとプログラムはイミュータブルになる。
- イベントがログとストリーミングになる。
eth_getLogsを消費していたシステムは、ログのパース、webhooks、gRPCストリームを中心に再構築する必要がある。 - クライアントとテストスタックが変わる。 クライアントコードはviemから
@solana/kitに、テストはFoundryからAnchorのテストフレームワークに移行し、CIにはローカルバリデーターが必要になる。
逆方向、つまりSVMからEVMへ移行するチームは、通常ツールの成熟度、ネイティブなイベントインデックス作成、より大きな監査人市場を得る一方で、並列実行、サブセカンドの確定、アカウント単位の手数料分離を失う。
どちらの方向でも、チームの学習曲線が最大のコストになることが多い。SolanaへのEVMエンジニアの移行には、Solana development roadmapが良い出発点になる。
EVMとSVM、どちらを選ぶべきか
AlchemyはEVMとSVMの開発をどう支援しているのか
私たちは両エコシステムを単一のプラットフォームからサポートしている。RPCエンドポイントはEthereum、主要なL2、そしてより広いEVMエコシステムをカバーしている。Solanaインフラはアーカイブ呼び出しを最大20倍高速に、99.99%の稼働率で提供し、gRPC streamingはSolanaのインデックス作成が依存するリアルタイムデータフィードを提供する。Solanaインフラの検討に際しては、Solana RPC guideでプロバイダーに求めるべきポイントを解説している。
無料のAPIキー1つで、1つのダッシュボードからEVMチェーンとSolana向けのエンドポイントが利用でき、契約や最低利用量の縛りもなく、エコシステムごとに別のプロバイダーを統合する必要もない。
関連する概要

ブロックチェーンで魔法を生み出す
Alchemyは、最も強力なweb3開発者向けプロダクトとツールを、豊富なリソース、コミュニティ、そして卓越したサポートと組み合わせて提供します。


