---
title: "EVM vs SVM：開発者向けガイド"
description: "EVMとSVMを、アカウントモデル、並列実行、手数料、プログラム設計、移行の観点からコード例とともに比較する開発者向けの解説。"
---

# EVM vs SVM：開発者向けガイド

<ImageBlock
  src="https://media.alchemy.com/overviews/evm-vs-svm-hero-20260924.png"
  alt="EVM vs SVM：開発者向けガイド"
  width={1920}
  height={900}
  priority
/>

すべてのブロックチェーンは仮想マシン上で動作している。仮想マシンとは、プログラムを実行し、その状態変化を適用するエンジンである。EthereumのエンジンはEVM（Ethereum Virtual Machine）であり、EthereumのLayer 2の大半もEVMで動いている。SolanaのエンジンはSVM（Solana Virtual Machine）であり、トランザクションを並列実行するために構築された。アーキテクチャ上の核心的な違いは、EVMがコントラクトのコードと状態をまとめて保存するのに対し、SVMはそれらを別々のアカウントに保持する点にある。この違いが、プログラムのデータ保存方法、トランザクションの実行方法、そして混雑時の手数料の挙動を左右する。

本ガイドでは、アカウントモデル、実行、手数料、プログラム設計、ツールの観点から両者を短いコード例とともに比較し、最後にどこで構築するか、あるいはどこへ移植するかを判断するためのフレームワークを示す。動画で確認したい場合は、当社の[SVM vs EVMビルダーガイド](https://www.youtube.com/watch?v=OsposMFk9Ro)で同じ比較を扱っている。

## EVMとSVMとは何か

EVMはスタックベースの仮想マシンであり、[トランザクションを1件ずつ](https://ethereum.org/en/developers/docs/evm/)処理し、単一の共有状態ツリーを更新する。主な利点は互換性だ。同じSolidityコントラクトを、Ethereum、そのLayer 2（Arbitrum、Base、Optimism、Unichain、World Chain、Ink）、独立したEVMチェーン（BNB Chain、Avalanche、Polygon、Monad、Berachain）に変更なしでデプロイでき、周辺ツールもバイトコードが動くあらゆる場所で機能する。EVMについて初めて知る場合は、当社の[Ethereum Virtual Machineの解説](https://www.alchemy.com/overviews/what-is-the-ethereum-virtual-machine-evm)で基礎を扱っている。

SVMは並列実行を中心に設計された。プログラムは[sBPFバイトコード](https://solana.com/docs/core/programs)にコンパイルされる。これはeBPF（Linuxカーネルが使用するのと同じバイトコード設計）から派生したレジスタベースの形式である。また、すべてのトランザクションは読み書きするアカウントを事前に宣言する。この宣言によって、[Solanaの並列ランタイム](https://solana.com/docs/references/terminology)であるSealevelは、競合しないトランザクションを複数のCPUコアで同時に実行できる。当社の[Solana Virtual Machineの解説](https://www.alchemy.com/overviews/what-is-the-solana-virtual-machine)では、実行パイプラインを詳しく扱っている。

主な違いを以下の表にまとめる。

<EmbeddedTable
  table={{
    columns: [
      { key: "1", width: 240, title: "観点", dataType: "object" },
      { key: "2", width: 240, title: "EVM", dataType: "object" },
      { key: "3", width: 240, title: "SVM", dataType: "object" },
    ],
    data: [
      {
        "1": {
          title: "<p>アカウントモデル</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title:
            "<p>コントラクトアカウントにコードとストレージをまとめて保持</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title: "<p>すべてがアカウント。プログラムはステートレス</p>",
          tooltip: "",
          icon: "",
        },
        id: 0,
      },
      {
        "1": {
          title: "<p>実行</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title: "<p>ブロック内で逐次実行</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title: "<p>競合しないトランザクション間で並列実行</p>",
          tooltip: "",
          icon: "",
        },
        id: 1,
      },
      {
        "1": {
          title: "<p>仮想マシン</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title: "<p>スタックベース、256ビットワード</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title: "<p>レジスタベース、eBPF派生</p>",
          tooltip: "",
          icon: "",
        },
        id: 2,
      },
      {
        "1": {
          title: "<p>手数料市場</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title: "<p>単一のグローバルな基本手数料とチップ</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title:
            "<p>署名ごとの基本手数料と、競合するアカウントに限定された優先手数料</p>",
          tooltip: "",
          icon: "",
        },
        id: 3,
      },
      {
        "1": {
          title: "<p>主要言語</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title: "<p>Solidity</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title: "<p>RustとAnchor</p>",
          tooltip: "",
          icon: "",
        },
        id: 4,
      },
      {
        "1": {
          title: "<p>トークン</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title: "<p>トークンごとに1つのコントラクト</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title:
            "<p>共有のToken Program、トークンごとに1つのミントアカウント</p>",
          tooltip: "",
          icon: "",
        },
        id: 5,
      },
      {
        "1": {
          title: "<p>アップグレード</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title:
            "<p>デフォルトでイミュータブル、アップグレードにはプロキシを使用</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title:
            "<p>デフォルトでアップグレード可能、権限を放棄すると固定される</p>",
          tooltip: "",
          icon: "",
        },
        id: 6,
      },
    ],
  }}
/>

## アカウントモデルはどう異なるか

Ethereumには[2種類のアカウント](https://ethereum.org/en/developers/docs/accounts/)がある。秘密鍵で管理される外部所有アカウントと、コードで管理されるコントラクトアカウントだ。コントラクトアカウントは、バイトコードとともに独自のストレージ（32バイトのスロットで構成されるキーバリューストア）を保持する。ERC-20トークンで`balanceOf`を呼び出すと、コントラクトは自身のストレージ内のマッピングから残高を読み取る。コードと状態は1つのアドレスを共有しており、分離できない。

Solanaはすべてに[単一のアカウントモデル](https://www.alchemy.com/overviews/solana-account-model)を使用する。[Solana上のすべての状態はアカウントであり](https://solana.com/docs/core/accounts)、同じ構造を持つ。lamports単位の残高（Solanaの最小単位で、weiに相当）、データフィールド、所有者、実行可能フラグである。プログラムとは、データがsBPFバイトコードであり、実行可能フラグがtrueに設定されたアカウントである。プログラムが管理する状態は、別のデータアカウントに存在する。ランタイムは所有権を直接強制する。アカウントのデータを変更できるのはそのアカウントを所有するプログラムだけであるため、Solidityコントラクトが自前で実装するアクセス制御ロジックの多くが不要になる。この分離については、当社の[Solanaのデータアカウントとプログラムアカウントの解説](https://www.alchemy.com/overviews/solana-data-vs-program-accounts)で詳しく扱っている。

Program Derived Addresses（PDA）は、EVM開発者にとって通常最もなじみの薄い概念だ。Solidityコントラクトがユーザーごとのデータをマッピングに保存するのに対し、Solanaプログラムは[プログラムIDと一連のseed](https://solana.com/docs/core/pda)（通常はユーザーの公開鍵）から、ユーザーごとに専用のアカウントアドレスを導出する。この導出は決定論的であり、Ed25519曲線から外れたアドレスを生成するため、それに対応する秘密鍵は存在しない。そのアドレスのために署名できるのはプログラムだけである。実際には、Solidityのマッピングの各エントリが、Solana上ではそれぞれ独立したアカウントになる。

2つのモデルはストレージの価格設定も異なる。Ethereumでは、ストレージは書き込み時にガスとして一度だけ支払う。Solanaでは、すべてのアカウントが[サイズに比例した返還可能なデポジット](https://solana.com/docs/core/accounts)を保持する必要があり、これは[rent免除](https://www.alchemy.com/overviews/how-to-calculate-rent-for-solana-programs)と呼ばれる。デポジットはアカウントを閉じると返還されるため、開発者には未使用の状態を削除する直接的なインセンティブが生まれる。

## SVMの並列実行はどのように機能するか

EVMはブロック内のトランザクションを逐次実行する。トランザクションは任意のストレージスロットを読み書きでき、そのアクセスは実行するまでわからない。そのためEVMは、2つのトランザクションを同時に安全に実行できない。

Solanaは、各トランザクションに読み書きするすべてのアカウントを実行前に列挙させることで、この不確実性を取り除いている。スケジューラは、[共有アカウントを読み取るだけのトランザクションを並列実行し、同じアカウントに書き込むトランザクションは逐次化する](https://docs.anza.xyz/validator/runtime)。書き込みロックを保持できるのは一度に1つのスレッドだけである。同じロックを必要とするトランザクションはキューに入れられて順番に処理され、競合によって失敗することはない。

このモデルはプログラム設計に影響する。多くのユーザーが同時に更新する状態は複数のアカウントに分割すべきであり、SPLトークン（Solanaのトークン標準）もこの形で構成されている。無関係なウォレット間の2件のUSDC転送は、4つの異なるトークンアカウントに書き込むため、同時に実行できる。Ethereumでは、同じ2件の転送はどちらも1つのERC-20コントラクトのストレージを更新するため、順番に実行される。

並列実行はEVMエコシステムにも広がりつつある。[Monad](https://docs.monad.xyz/introduction/why-monad)は完全なバイトコード互換性を持つ並列実行EVMのL1を運用しており、MegaETHはEthereumのL2として同様の手法を適用している。これらのチェーンは、トランザクションにアカウントの宣言を求めるのではなく実行時に競合を検出するため、EVM互換性を維持しながらスループットを高められる。

## 手数料はどう違うか

Ethereumは単一のグローバルな手数料市場を使用する。すべてのトランザクションは同じ[基本手数料](https://ethereum.org/en/developers/docs/gas/)を支払う。基本手数料はプロトコルがブロックごとに調整してバーンするもので、これにバリデータへの任意の優先チップが加わる。標準的なETH送金のコストは21,000 gasで、ブロックは3,000万gasを目標とし、[ガスリミットは6,000万gas](https://ethereum.org/en/developers/docs/blocks/)である。基本手数料はチェーン全体に適用されるため、あるアプリケーションの需要が全員に影響する。人気のNFTミントやエアドロップの請求は、無関係なアプリケーションのユーザーを含むすべてのユーザーの基本手数料を引き上げる。

Solanaは異なる手数料構造を採用している。すべてのトランザクションは[署名ごとに5,000 lamportsの基本手数料](https://solana.com/docs/core/fees)を支払い、その半分はバーンされ、半分はバリデータに支払われる。計算量はcompute unit（CU）で計測され、デフォルトの予算はinstructionあたり200,000 CU、トランザクションあたりの上限は140万CUである。トランザクションには、他より先にスケジューリングされるための優先手数料を含めることもでき、これはcompute unitあたりのmicro-lamportsで価格設定される。

重要な違いは、手数料競争の範囲にある。すべてのトランザクションは書き込むアカウントを明示するため、優先手数料の競争は同じアカウントを奪い合うトランザクションの間に集中する。エコシステムではこの挙動をローカル手数料市場と呼んでいる。[`getRecentPrioritizationFees`](https://solana.com/docs/rpc/http/getrecentprioritizationfees) RPCメソッドは、トランザクションがロックする書き込み可能なアカウントで手数料サンプルを絞り込むことで、この設計を反映している。人気のミント中には、ミントのアカウントに書き込むトランザクションの手数料が上昇する一方、無関係なトランザクションはほとんど影響を受けない。

これはキャパシティプランニングに影響する。Ethereumでは、無関係なアプリケーションの活動によってトランザクションコストが上昇することがあり、アプリケーション設計ではそれを防げない。Solanaでは、手数料の圧力は主に自身のアカウントでの競合から生じるため、頻繁に書き込まれる状態をより多くのアカウントに分散すれば圧力を下げられる。

## プログラム設計では何が変わるか

Solidityコントラクトはコードとストレージからなる単一のユニットであり、[設計上イミュータブル](https://ethereum.org/en/developers/docs/smart-contracts/upgrading/)である。デプロイ後にロジックを変更するには、`delegatecall`に基づくプロキシパターンが必要になる。これは、呼び出しを差し替え可能な実装コントラクトへルーティングする仕組みだ。最小限のSolidityカウンターは次のとおりである。

<CodeSnippet
  language="solidity"
  code={`// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract Counter {
    uint64 public count; // state lives inside the contract itself
    function increment() external {
        count += 1;
    }
}`}
/>

同等のSolanaプログラムを[Anchor](https://www.alchemy.com/overviews/solana-anchor)（広く使われているSolanaプログラムフレームワーク）で書くと、プログラム自体は状態を保存しない。カウンターの値は別のアカウントに存在し、各呼び出しで明示的に渡される。

<CodeSnippet
  language="rust"
  code={`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");
#[program]
mod counter {
    use super::*;
    pub fn increment(ctx: Context<Increment>) -> Result<()> {
        ctx.accounts.counter.count += 1;
        Ok(())
    }
}
#[derive(Accounts)]
pub struct Increment<'info> {
    #[account(mut)]
    pub counter: Account<'info, Counter>, // state account passed in explicitly
}
#[account]
pub struct Counter {
    pub count: u64,
}`}
/>

完全版では、カウンターアカウントを作成して資金を入れるinitialize instructionも必要になる。Anchorはハンドラの実行前にすべてのアカウントを`Increment`構造体に照らして検証し、アカウントの型とownerが想定どおりであることを確認する。ただし、この検証は誰がinstructionを呼び出せるかを制限しない。このままでは誰でも`increment`を呼び出せるため、実際のプログラムではsignerの要件や派生アドレスの制約を追加して、カウンターを更新できる者を制御する。

デフォルトのアップグレード挙動は逆になっている。アップグレード権限を指定してデプロイしたSolanaプログラムは[ネイティブにアップグレード可能](https://solana.com/docs/core/programs)であり、その権限を放棄するとプログラムはイミュータブルになる。そのためSolanaプログラムにはプロキシコントラクトが不要であり、EVMの監査でしばしば焦点となる種類のコードがなくなる。

トークンも同じパターンに従う。各ERC-20トークンは標準インターフェースを実装した[独立したコントラクト](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/)であるため、多くのトークンをサポートするアプリケーションは多数の独立したコードベースに依存することになる。Solanaでは、トークンは[共有のToken Program](https://solana.com/docs/tokens)を通じて発行され、Token-2022は転送手数料などのオプション機能をサポートする拡張版を提供している。各トークンは供給量と小数点以下の桁数を記録するミントアカウントであり、各保有者の残高はトークンアカウントに保存される。これらのプログラムを統合したアプリケーションは、トークンごとのコードなしで任意のSPLトークンをサポートできる。

イベント処理は、EVMが明確に優位な領域である。EVMコントラクトはインデックス付きイベントを発行し、`eth_getLogs`やインデクサーがそれをネイティブに利用する。Solanaには[ネイティブのイベントシステムがない](https://www.anchor-lang.com/docs/features/events)。プログラムはログメッセージを書き込み、Anchorのイベントマクロは構造化データをそのログにエンコードするが、ログは切り詰められることがある。そのため、Solanaでの本番環境のインデックス作成は、通常[Webhook](https://www.alchemy.com/webhooks)や[Solana gRPCストリーミング](https://www.alchemy.com/solana-grpc)などのストリーミングインフラに依存する。

## クライアントスタックはどうなるか

VMの選択は言語とツールも決定する。EVM開発ではSolidityと成熟したツールチェーン（Foundry、Hardhat）を使い、テスト、ファジング、デプロイを幅広くサポートしている。Solana開発ではRustとAnchorを使い、学習曲線はより急で、監査人の層は拡大しつつあるもののまだ小さい。言語の選択肢については、当社の[web3プログラミング言語の概要](https://www.alchemy.com/overviews/web3-programming-languages)で詳しく扱っている。

データモデルの違いはクライアントコードにも表れる。EVMでは、状態の読み取りとはコントラクトの関数を呼び出すことであり、コントラクトは自身のストレージからデータを返す。この例ではviemを使用する。

<CodeSnippet
  language="typescript"
  code={`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`を使用する。

<CodeSnippet
  language="typescript"
  code={`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](https://solana.com/docs/core/cpi)を使う。
- **マッピングはPDAになる**。Solidityのマッピングの各キーは導出アカウントになり、初回使用前に作成してrentの資金を入れる必要がある。クライアントはコントラクトストレージに問い合わせるのではなくアカウントを取得するため、データの読み取り方も変わる。
- **コントラクトストレージは、サイズが決まりrentの資金が入ったアカウントになる**。状態は既知のサイズで事前に割り当てる必要があり、デポジットはアカウントを閉じると返還される。
- **プロキシによるアップグレードパターンは不要になる**。プログラムのアップグレード権限がプロキシの仕組みに代わり、その権限を放棄するとプログラムはイミュータブルになる。
- **イベントはログとストリーミングになる**。`eth_getLogs`を利用していたシステムは、ログ解析、Webhook、gRPCストリームを中心に作り直す必要がある。
- **クライアントとテストのスタックが変わる**。クライアントコードはviemから`@solana/kit`に、テストはFoundryからAnchorのテストフレームワークに移り、CIにはローカルバリデータが必要になる。

逆方向、つまりSVMからEVMへ移行するチームは、一般にツールの充実、ネイティブのイベントインデックス作成、より大きな監査人市場を得る一方、並列実行、1秒未満の承認、アカウント単位の手数料の分離を手放すことになる。

どちらの方向でも、通常最大のコストはチームの学習曲線である。Solanaに移行するEVMエンジニアにとっては、当社の[Solana開発ロードマップ](https://www.alchemy.com/overviews/learn-solana-development)が良い出発点となる。

## EVMとSVMのどちらを選ぶか

<EmbeddedTable
  table={{
    columns: [
      { key: "1", width: 240, title: "構築するもの", dataType: "object" },
      {
        key: "2",
        width: 240,
        title: "推奨される出発点",
        dataType: "object",
      },
      { key: "3", width: 240, title: "理由", dataType: "object" },
    ],
    data: [
      {
        "1": {
          title:
            "<p>高スループットのコンシューマー向けアプリ（決済、トレーディング、ミント）</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title: "<p>SVM</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title:
            "<p>並列実行とアカウント単位の手数料分離により、自身の負荷が高まってもコストが安定する</p>",
          tooltip: "",
          icon: "",
        },
        id: 0,
      },
      {
        "1": {
          title: "<p>既存の流動性と組み合わせるDeFiプロトコル</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title: "<p>EVM</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title:
            "<p>実績のあるDeFiプロトコル、インテグレーション、監査人はEVMエコシステムに集中している</p>",
          tooltip: "",
          icon: "",
        },
        id: 1,
      },
      {
        "1": {
          title:
            "<p>Solidityの経験があり、レイテンシの影響を受けにくいプロダクトを持つチーム</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title: "<p>EVM、または並列EVMチェーン</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title:
            "<p>ワークロードがSVMのスループットを必要としない場合、既存のスタックにとどまれば書き直しを避けられる</p>",
          tooltip: "",
          icon: "",
        },
        id: 2,
      },
    ],
  }}
/>

<ExternalVideo
  url="https://www.youtube.com/watch?v=OsposMFk9Ro"
  provider="youtube"
  providerUid="OsposMFk9Ro"
/>

## AlchemyはEVMとSVMの開発をどのようにサポートしているか

当社は単一のプラットフォームで両方のエコシステムをサポートしている。当社の[RPCエンドポイント](https://www.alchemy.com/rpc-api)は、Ethereum、主要なL2、そしてより広範なEVMエコシステムをカバーする。当社の[Solanaインフラ](https://www.alchemy.com/blog/solana-infrastructure)はアーカイブ呼び出しを最大20倍高速に処理し、99.99%のアップタイムを実現している。また、[gRPCストリーミング](https://www.alchemy.com/solana-grpc)は、Solanaのインデックス作成に欠かせないリアルタイムのデータフィードを提供する。Solanaインフラを検討している場合は、当社の[Solana RPCガイド](https://www.alchemy.com/overviews/solana-rpc)でプロバイダー選びのポイントを扱っている。

無料のAPIキーで、EVMチェーンとSolanaのエンドポイントを1つのダッシュボードから利用できる。契約や最低利用額は不要で、エコシステムごとに別のプロバイダーを統合する必要もない。
