跳至內容
0%

EVM vs SVM:開發者指南

發布於 2026年9月25日閱讀時間 4 分鐘

EVM vs SVM:開發者指南

每條區塊鏈都運行在一個虛擬機之上,也就是負責執行鏈上程式並套用其狀態變化的引擎。Ethereum 的引擎是 EVM(Ethereum Virtual Machine),它同時也驅動了 Ethereum 大多數的 Layer 2。Solana 的引擎是 SVM(Solana Virtual Machine),其設計目的是平行執行交易。兩者在架構上的核心差異在於:EVM 將合約的程式碼與狀態儲存在一起,而 SVM 則將兩者存放在不同的帳戶中。這項差異決定了鏈上程式如何儲存資料、交易如何執行,以及費用如何因應網路壅塞。

本指南從帳戶模型、執行方式、費用、program 設計與工具等面向比較兩者,附上簡短的程式碼範例,最後提供一套決策框架,協助你決定要在哪裡建構或移植應用。如果你偏好影片,我們的 SVM vs EVM 建構者指南 涵蓋了相同的比較內容。

什麼是 EVM 與 SVM?

EVM 是一種堆疊式虛擬機,它會逐筆處理交易,並更新單一的共享狀態樹。它的主要優勢是相容性。同一份 Solidity 合約不需修改,即可部署到 Ethereum、其 Layer 2(Arbitrum、Base、Optimism、Unichain、World Chain、Ink),以及獨立的 EVM 鏈(BNB Chain、Avalanche、Polygon、Monad、Berachain),而周邊工具在該位元碼能執行的任何地方都能使用。如果你剛接觸 EVM,我們的 Ethereum Virtual Machine 說明文章 介紹了基礎知識。

SVM 是圍繞平行執行來設計的。Program 會編譯成 sBPF 位元碼,這是一種衍生自 eBPF(Linux kernel 所使用的同一種位元碼設計)的暫存器式格式,而且每筆交易都會預先宣告它將讀取與寫入哪些帳戶。這項宣告讓 Sealevel,也就是 Solana 的平行執行環境,能在多個 CPU 核心上同時執行彼此不衝突的交易。我們的 Solana Virtual Machine 說明文章 深入介紹了其執行 pipeline。

下表整理了主要差異。

面向
EVM
SVM

帳戶模型

程式碼與儲存空間綁定在合約帳戶中

一切皆是帳戶;program 是無狀態的

執行

區塊內循序執行

不衝突的交易平行執行

虛擬機

堆疊式,256 位元字組

暫存器式,衍生自 eBPF

費用市場

單一全域基本費用,加上小費

每個簽章的基本費用,加上僅限於受爭用帳戶的優先費

主要語言

Solidity

Rust 搭配 Anchor

代幣

每種代幣一份合約

共用的 Token Program,每種代幣一個 mint 帳戶

升級

預設不可變,透過代理合約升級

預設可升級,撤銷權限即可凍結

兩者的帳戶模型有何不同?

Ethereum 有兩種帳戶類型:由私鑰控制的外部擁有帳戶(externally-owned account),以及由程式碼控制的合約帳戶。合約帳戶除了保存位元碼,也持有自己的儲存空間,也就是一個由 32 位元組槽位組成的鍵值儲存區。當你對某個 ERC-20 代幣呼叫 balanceOf 時,合約會從自身儲存空間中的一個 mapping 讀取你的餘額。程式碼與狀態共用同一個位址,無法分開。

Solana 對所有東西都使用單一帳戶模型。Solana 上的每一份狀態都是一個帳戶,且結構相同:以 lamports(Solana 的最小單位,類似 wei)計價的餘額、一個資料欄位、一個 owner,以及一個 executable 旗標。Program 是一種資料內容為 sBPF 位元碼、且 executable 旗標設為 true 的帳戶。Program 所管理的狀態則存放在獨立的資料帳戶中。執行環境會直接強制執行 ownership,因為只有擁有某個帳戶的 program 才能修改其資料,這省去了 Solidity 合約必須自行實作的大量存取控制邏輯。我們的 Solana 資料帳戶 vs. program 帳戶指南 詳細說明了這種區分。

對 EVM 開發者來說,Program derived address(PDA)通常是最陌生的概念。Solidity 合約會把每位使用者的資料存放在 mapping 中,而 Solana program 則是根據 program ID 與一組 seed(通常是使用者的公鑰)為每位使用者衍生出專屬的帳戶位址。這種衍生是確定性的,產生的位址落在 Ed25519 曲線之外,因此不存在對應的私鑰。只有該 program 能代表這個位址簽署。實務上,Solidity mapping 中的每一筆項目,在 Solana 上都會成為獨立的帳戶。

兩種模型對儲存空間的計價方式也不同。在 Ethereum 上,你只在寫入時以 gas 支付一次儲存費用。在 Solana 上,每個帳戶都必須持有一筆與其大小成正比的可退還押金,稱為免租(rent exemption)。帳戶關閉時會退還這筆押金,讓開發者有直接的誘因清除不再使用的狀態。

SVM 上的平行執行如何運作?

EVM 會循序執行區塊中的交易。一筆交易可以讀寫任何儲存槽,而這些存取在交易實際執行前無從得知,因此 EVM 無法安全地同時執行兩筆交易。

Solana 消除了這種不確定性,要求每筆交易在執行前列出它將讀取與寫入的每個帳戶。排程器會平行執行只讀取共享帳戶的交易,並將寫入同一帳戶的交易序列化。寫入鎖一次只允許一個執行緒持有。需要同一個鎖的交易會排入佇列並依序處理,不會因為衝突而失敗。

這個模型會影響 program 設計。許多使用者會同時更新的狀態,應該分散到多個帳戶中,這正是 SPL 代幣(Solana 的代幣標準)的結構方式。兩筆發生在無關錢包之間的 USDC 轉帳會寫入四個不同的代幣帳戶,因此可以同時執行。在 Ethereum 上,同樣的兩筆轉帳都會更新同一份 ERC-20 合約的儲存空間,只能一筆接著一筆執行。

平行執行也正在進入 EVM 生態系統。Monad 運行一條具備完整位元碼相容性的平行執行 EVM L1,而 MegaETH 則以 Ethereum L2 的形式採用類似技術。這些鏈在執行期偵測衝突,而不是要求交易宣告其帳戶,因此在提升吞吐量的同時保留了 EVM 相容性。

兩者的費用有何不同?

Ethereum 使用單一的全域費用市場。每筆交易都支付相同的基本費用(base fee),由協定在每個區塊調整並銷毀,另外可再選擇支付優先小費給驗證者。一筆標準的 ETH 轉帳花費 21,000 gas,區塊的目標為 3,000 萬 gas,gas limit 為 6,000 萬。由於基本費用適用於整條鏈,單一應用的需求會影響所有人。熱門的 NFT 鑄造或空投領取會推高所有使用者的基本費用,包括無關應用的使用者。

Solana 採用不同的費用結構。每筆交易都要支付每個簽章 5,000 lamports 的基本費用,其中一半銷毀,一半支付給驗證者。運算以 compute unit(CU)計量,每個 instruction 的預設 budget 為 200,000 CU,每筆交易的上限為 140 萬 CU。交易也可以附加優先費(prioritization fee),以每 compute unit 多少 micro-lamports 計價,藉此比其他交易更早被排程。

關鍵差異在於費用競爭的範圍。由於每筆交易都會指明它要寫入的帳戶,優先費的競爭會集中在爭用相同帳戶的交易之間。生態系統將這種行為稱為局部費用市場(local fee markets)。getRecentPrioritizationFees 這個 RPC 方法反映了這種設計:它會依交易將鎖定的可寫入帳戶來篩選費用樣本。在熱門的鑄造活動期間,寫入該鑄造相關帳戶的交易費用會上升,而無關的交易則大致不受影響。

這會影響容量規劃。在 Ethereum 上,無關應用的活動可能推高你的交易成本,而應用設計無法避免這一點。在 Solana 上,費用壓力主要來自你自身帳戶上的爭用,因此將頻繁寫入的狀態分散到更多帳戶,就能降低費用壓力。

Program 設計有哪些改變?

Solidity 合約是由程式碼與儲存空間組成的單一單元,而且在設計上是不可變的。部署後若要更改其邏輯,就需要以 delegatecall 為基礎的代理模式,將呼叫轉送到可替換的實作合約。一個最小化的 Solidity 計數器如下:

solidity
Copied
// 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; } }

以 Anchor(一個廣泛使用的 Solana program 框架)撰寫的等效 Solana program,本身不儲存任何狀態。計數值存放在一個獨立的帳戶中,每次呼叫時都會明確傳入:

rust
Copied
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,因此實際的 program 需要加上 signer 要求或衍生位址限制,以控制誰可以更新計數器。

預設的升級行為正好相反。以升級權限(upgrade authority)部署的 Solana program 原生即可升級,撤銷該權限則會使 program 變成不可變。因此 Solana program 不需要代理合約,也省去了 EVM 審計經常關注的一整類程式碼。

代幣也遵循相同的模式。每個 ERC-20 代幣都是實作標準介面的獨立合約,因此支援多種代幣的應用必須依賴許多各自獨立的程式碼庫。在 Solana 上,代幣是透過共用的 Token Program 發行,而 Token-2022 則提供擴充版本,支援轉帳手續費等選用功能。每種代幣都是一個記錄供給量與小數位數的 mint 帳戶,每位持有者的餘額則儲存在代幣帳戶中。整合這些 program 的應用,不需要為個別代幣撰寫程式碼,就能支援任何 SPL 代幣。

事件處理是 EVM 具有明顯優勢的領域。EVM 合約會發出帶索引的事件,eth_getLogs 與索引器可以原生使用這些事件。Solana 沒有原生的事件系統。Program 會寫入日誌訊息,而 Anchor 的事件巨集會將結構化資料編碼進這些日誌中,但日誌可能會被截斷。因此,Solana 上的正式環境索引通常依賴串流基礎設施,例如 webhook 與 Solana gRPC 串流。

用戶端技術堆疊是什麼樣子?

VM 的選擇也決定了語言與工具。EVM 開發使用 Solidity 與成熟的工具鏈(Foundry、Hardhat),在測試、模糊測試與部署方面都有廣泛支援。Solana 開發使用 Rust 與 Anchor,學習曲線較陡,審計人員也較少,不過人數正在成長。我們的 web3 程式語言總覽 更詳細地介紹了各種語言選項。

資料模型的差異在用戶端程式碼中也看得出來。在 EVM 上,讀取狀態意味著呼叫合約上的函式,由合約從自身儲存空間回傳資料。此範例使用 viem:

typescript
Copied
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:

typescript
Copied
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、並由你的 program 檢查的帳戶;當 program 本身持有權限時,則來自由 program 代為簽署的 PDA。
  • Mapping 變成 PDA。 Solidity mapping 中的每個 key 都會變成一個衍生帳戶,必須在首次使用前建立並存入 rent 所需的資金。讀取資料的方式也會改變,因為用戶端是取得帳戶,而不是查詢合約儲存空間。
  • 合約儲存空間變成有固定大小、需存入 rent 資金的帳戶。 狀態必須以已知大小預先配置,帳戶關閉時則會退還押金。
  • 不再需要代理升級模式。 Program 的升級權限取代了代理設定,撤銷該權限則會使 program 變成不可變。
  • 事件變成日誌與串流。 任何使用 eth_getLogs 的系統,都必須圍繞日誌解析、webhook 或 gRPC 串流重新建構。
  • 用戶端與測試技術堆疊隨之改變。 用戶端程式碼從 viem 改用 @solana/kit,測試從 Foundry 改用 Anchor 的測試框架,CI 也需要本地驗證者。

反方向移轉的團隊,也就是從 SVM 移到 EVM,通常會獲得更完整的工具、原生事件索引與更大的審計市場,但會失去平行執行、次秒級確認,以及以帳戶為單位的費用隔離。

無論哪個方向,團隊的學習曲線通常都是最大的成本。對於轉向 Solana 的 EVM 工程師,我們的 Solana 開發路線圖 是很好的起點。

如何在 EVM 與 SVM 之間做選擇?

你正在建構
建議起點
原因

高吞吐量的消費級應用(支付、交易、鑄造)

SVM

平行執行與以帳戶為單位的費用隔離,能讓成本在你自身的負載下保持穩定

需要與既有流動性組合的 DeFi 協定

EVM

成熟的 DeFi 協定、整合與審計人員都集中在 EVM 生態系統

熟悉 Solidity、產品可容忍延遲的團隊

EVM,或平行 EVM 鏈

當工作負載不需要 SVM 的吞吐量時,沿用既有技術堆疊可避免重寫

Alchemy 如何支援 EVM 與 SVM 開發?

我們透過單一平台支援兩個生態系統。我們的 RPC 端點 涵蓋 Ethereum、主要的 L2 以及更廣泛的 EVM 生態系統。我們的 Solana 基礎設施 提供快達 20 倍的 archive 呼叫與 99.99% 的正常運作時間,而 gRPC 串流 則提供 Solana 索引所仰賴的即時資料饋送。如果你正在評估 Solana 基礎設施,我們的 Solana RPC 指南 說明了挑選供應商時應注意的事項。

一組免費的 API 金鑰,就能讓你從同一個儀表板取得 EVM 鏈與 Solana 的端點,無需簽約,也沒有最低用量承諾,更不必為每個生態系統分別整合不同的供應商。

Background gradient

打造區塊鏈魔法

Alchemy 結合最強大的 Web3 開發者產品與工具,並提供資源、社群與卓越的支援。