L1からL2への移行手順|「EVM互換」でも本番で崩れる6つの違いと切り戻し

コラム

/約14分で読めます

コラム

/約14分

L1からL2への移行手順|「EVM互換」でも本番で崩れる6つの違いと切り戻し
目次(タップで折りたたみ)

    Ethereum L1で動いているアプリを、手数料の安いL2へ移す。候補のL2は「EVM互換」とうたっていて、テストネットでも問題なく動いた。ところが本番に切り替えると、崩れます。費用が見積もりと合わない。送金先のアドレスが違っていた。L1とL2の間の処理が、片側だけ成功したまま止まっている。

    「EVM互換」という表示だけで、同じ動きをすると考えるのは危険です。移行では、コードだけでなく次のものを確かめます。

    • 実行の違い、アドレス
    • 残高などの状態、資産
    • L1とL2の間のメッセージ

    確かめた結果と、切り替えの条件を満たしたのを見てから、書き込み先を移します。

    以下では、ロールアップ型のL2へ移す計画を、互換性の確認、状態の移し方、段階的な切り替え、本番前の試験、監視、切り戻しの順に組み立てます。どのL2が優れているかではなく、候補ごとの違いを同じ証拠で比べる方法です。L2そのものの全体像はL2(Layer 2)完全マップ2026で整理しています。

    この記事で使う言葉

    • ロールアップ(L2):取引をまとめて処理し、データをL1に預ける別の処理の場
    • シーケンサー:L2で取引を受け付け、順番を決める役
    • 公式ブリッジ:L1とL2の間で資産を移す正式な通り道
    • 強制取引:シーケンサーを通さず、L1から直接L2へ取引を入れる手段
    • opcode/precompile:EVMの命令/あらかじめ組み込まれた計算機能

    「EVM互換」を6つに分けて確かめる

    「互換」の一語で移せるかを判定すると、冒頭の例のように、本番で費用・アドレス・非同期の処理が崩れます。最低でも次の6つを台帳にします。各項目には「同一」「差分あり」「不明」の判定と、根拠のURL、検証のコード、責任者を付けます。

    互換性確認対象見落とした場合
    実行opcode、precompile、ガス計算、ブロック情報、コンパイラ、プロキシ特定の関数だけrevertする、想定外のガス不足
    アドレスCREATE/CREATE2、デプロイ用アカウントのnonce、外部の許可リスト別アドレスへ送金、署名ドメインや権限参照の破損
    状態残高、所有者、ロール、nonce、ポジション、処理中の操作、履歴二重計上、取りこぼし、再実行
    資産公式ブリッジ(canonical bridge)、トークンの表現、decimals、発行・焼却の権限、流動性異なるトークンを同一視、資産のロック
    通信入金、出金、確定性(finality)、再送・再生、順序、失敗時の補償片側だけ成功、二重実行、長時間の保留
    運用シーケンサー、RPC、強制取引(forced transaction)、アップグレード、監視、鍵、エクスプローラー停止時に状態確認も退出もできない

    それぞれの合格の証拠は、後半の「実装する人向けの詳細」にまとめています。

    Optimistic rollupはEVM互換で、既存のツールを使いやすい方式です。一方で、L1とL2の資産の移動は、ブリッジのコントラクトと非同期のメッセージを通ります。Ethereum.orgのOptimistic rollup解説も、入金ではL1側の資産をロックし、L2側で対応する資産を発行する構造だと説明しています。シーケンサーを通らない送信の道も説明しています。「コントラクトが動く」と「業務全体が同じように動く」は、別の合格条件です。

    何をL2へ移し、何をL1に残すか

    L2と相性がよいのは、頻繁な注文、ゲームの操作、少額の決済など、安く何度も処理したいものです。一方で、次のものまで無条件に移すと、障害のときに立て直す道を失います。

    • L2が止まっても必要な、退出する権利
    • 最終的な決済の根拠
    • L2から参照される発行の権限

    同じ画面の中にも、L2に向く処理と、L1に残すべき権限が混ざることがあります。そのため移す範囲は、画面の単位では決めません。どのシステムの記録を正とするか(状態の正本)と、失敗したときの責任で分けます。

    置き場所の候補と判断の基準は、次のとおりです。

    機能・状態置き場所の候補判断基準
    高頻度の業務処理L2遅延、処理量、手数料の目標をL2が満たすか
    資産の発行・最終保全L1または明示したL2ブリッジ、アップグレード、退出の信頼の前提を利用者へ説明できるか
    緊急停止・アップグレード権限責任主体ごとに分離L2の障害中にも実行でき、単一の鍵に集中しないか
    検索・分析用データオフチェーンのインデクサー作り直しができ、正本と誤認されないか
    L1との連携非同期のメッセージ処理重複、順序の逆転、期限切れ、再送を状態機械で扱えるか

    「全部L2」か「全部L1」かの二択にする必要はありません。ただし、同じ残高や権限を両方で書き換えられる期間は短くします。どちらが正本かは、区切りの期間(epoch)か切り替えのブロックで、1つに決めます。

    L1の古いコントラクトを止められない場合は、注意が要ります。画面を切り替えるだけでは、古い道から書き込みが続くからです。古い状態を凍結するか、両方の更新を調整する設計が必要です。

    移行は5つのステップで少しずつ進める

    1. 基準になる状態を確定する:対象のコントラクト、プロキシの実装、code hash、chain ID、ブロック番号とhash、残高・ロール・処理中の操作を保存します。ブロック番号だけでは、チェーンの巻き戻り(再編)の後に同じ状態を特定できません。
    2. L2に再現する:コントラクト、設定、権限をデプロイし、スナップショットを決まった手順で取り込みます。分けた塊ごとに件数・範囲・hashを付け、途中から再開しても二重に反映しないようにします。
    3. 読み取りを並行で突き合わせる(shadow read):利用者への応答はL1のまま返します。同じ問い合わせをL2にも流し、結果の違いを記録します。時刻やブロックに依存する値は、比べる前にそろえます。
    4. 書き込みを限定して始める(canary write):社内のアカウント、少額、限られた機能から、L2への書き込みを始めます。成功率だけでなく、event、インデクサー、会計、L1との連携、問い合わせ対応まで追います。
    5. 切り替えて、様子を見る期間を終える:事前に決めたサービス目標(SLO)と、常に成り立つべき条件(不変条件)を満たしたら、対象を広げます。古いL1の道はすぐには消しません。立て直しに必要な期間だけ、読み取りと緊急操作を残します。廃止の条件も決めておきます。

    各ステップの判定は、1つの記録(移行マニフェスト)にまとめます。例は後半に載せています。

    スナップショットのブロックを決めた後もL1への書き込みを許すなら、選び方は2つです。その差分を記録(journal)としてL2へ適用するか、短い書き込み停止の時間を設けるか。止まる時間をゼロにしたいなら、その代わりに実装の費用がかかります。二重書き込みの順番、片側だけの失敗、再送、埋め合わせの処理です。

    コントラクトと状態は、別々に確かめる

    同じSolidityのソースがコンパイルできても、L2の上で同じように動くとは限りません。コンパイルできるのは、入り口にすぎません。コンパイラ、最適化の設定、ライブラリのアドレスを固定してbytecodeを再現し、L1とL2で関数ごとの結果を比べます。確かめ方の細部は後半にまとめています。

    移し方にも2通りあります。Ethereum.orgのコントラクトのアップグレード解説が示すように、古いインスタンスから新しいインスタンスへ状態を移す方式と、プロキシの中身(ロジック)を差し替える方式です。責任も、失敗の条件も違います。

    L2どうしでも、互換の範囲は同じではありません。たとえばZKsyncのEVM Bytecode Interpreterは、標準のEVM bytecodeと、普段使うFoundry・Hardhatを使えます。一方で、公式資料は違いをはっきり書いています(概要、Ethereumとの差分)。

    • 取引に署名するガスの値は、EVMではなくEraVMのガスとして扱われる。そのため、事前に署名しておいた取引が通らない場合がある
    • CALLCODE・SELFDESTRUCT・BLOBHASH・BLOBBASEFEEが使えない
    • RIPEMD-160やblake2fなど、一部のprecompileが使えない
    • EVMとEraVMのコントラクトの間のDELEGATECALLがrevertする

    デバッグの手段の違いも含め、候補のL2の最新版で実際に動かして確かめます。使うopcode、precompile、factory、署名済みの取引、ガスの上限です。

    状態の突き合わせは、行数が一致するだけでは足りません。少なくとも次のものを、それぞれ独立に計算し直します。

    • 総供給量、利用者ごとの残高、所有権、ロールの集合
    • ポジションの合計、処理が終わっていないメッセージ
    • 会計上の総資産・総負債

    巨大な状態は、全件を出力したhashだけで済ませません。検査し直せる塊ごとのrootと、例外の一覧を残します。個人情報や業務上の秘密を、そのままチェーン上へ写してはいけません。必要性と公開の範囲を見直します。

    L1とL2の間のメッセージを、普通の関数呼び出しとして扱わない

    L1とL2の通信では、送る側の取引が成功したことと、受け取る側で実行が成功したことは、同時には起きません。そこで、メッセージごとに状態を記録します。同じメッセージが二度届いても結果が増えないようにし、送った取引のhashだけで完了とはしません。受け取る側のeventと、業務上の状態まで突き合わせます。状態の移り方は後半にまとめています。

    出金には待ち時間があります。Optimistic rollupからL1への通常の出金は、不正の証明(fault proof)のための待機が関わり、最終化の条件もL2ごとに違います。

    高速ブリッジや流動性の提供者を使えば、利用者の待ち時間は短くできます。ただし、公式ブリッジでの決済とは別に、流動性と取引相手のリスクが加わります。入出金のサービス目標は、次の4つに分けて表示・監視します。

    • 画面で受け付けた
    • L2で実行した
    • L1で最終化した
    • 使える残高へ反映した

    利用者への見せ方はL2出金の待ち時間とUX設計で詳しく扱っています。

    障害の試験では、RPCのタイムアウトだけでは足りません。シーケンサーの停止、L1の混雑、メッセージの重複・順番の逆転・期限切れ、L1の再編、中継者(relayer)の停止も起こします。

    Ethereum Foundationは2026年3月23日のL1とL2の関係に関する記事で、「walkaway test」を示しています。悪意ある運営者や、セキュリティカウンシル(緊急時に権限を持つ委員会)に障害があっても、利用者が安全にL1へ退出できるか、という試験です。信頼をできるだけ小さくする方向のL2に、これを求めています。

    採用する候補について、普段の画面が使えない状態から必要なデータを取り、L1経由の強制操作を実際にできるかを練習します。シーケンサーが止まったときの縮退と強制取引の待機条件はシーケンサー停止時のサービス継続設計、データ可用性の障害時に状態を作り直して退出する条件はロールアップのデータ可用性障害で扱っています。

    切り替えてよいかを、何で判定するか

    「全テスト成功」だけでは、テストに書かなかった会計上の違いを見つけられません。移行の前に、常に成り立つべき条件(不変条件)と、許せる差を、業務の責任者と合意しておきます。

    • L1で凍結した総供給量と、L2へ割り当てた残高・未移行の残高・焼却済みの残高の合計が一致する。
    • 各メッセージは業務上の効果を最大1回だけ生み、失敗中のメッセージを一覧にできる。
    • 管理ロール、アップグレード権限、一時停止(pause)の権限を持つ主体とタイムロックが、デプロイの記録(manifest)と一致する。
    • 代表的な取引のp50、p95、p99の費用と確定までの時間が目標内で、混雑時の上限を超えない。
    • RPCかシーケンサーが止まったとき、誤って「成功」と表示せず、復旧後に安全に追いつける。

    費用にも注意が要ります。L2では、実行の費用と、L1へデータを公開する費用が、別々の理由で動きます。そのため、L1のガス価格を一定の比率で割っただけの見積もりは使えません。

    費用の試験は、平均値ではなく、代表的な操作ごとに行います。calldataの量、ストレージへの書き込み、コントラクトのデプロイ、L1データ手数料(L1 data fee)を含めます。費用のモデルと流量の制限は、本番に近い取引の分布で測ります。移行後の費用の分け方と監視はL2取引コストの可視化と予算管理を参照してください。

    切り戻せる範囲を、切り替えの前に決める

    画面や接続先は元に戻せても、L2で一度確定した取引は消せません。だから「切り戻す」と言っても、中身は3種類に分かれます。

    1. 道を戻す:L2への新しい書き込みを止め、通信をL1か、安全な読み取り専用の状態へ戻す。
    2. 状態を埋め合わせる:切り替え後にL2で成立した操作を記録から集計し、合意したルールでL1か次のL2へ反映する。取引を消すのではありません。
    3. 資産を引き揚げる:公式ブリッジか強制退出の道を使い、待ち時間とガスを含めて利用者の資産を取り戻す。

    始める前に、手順書にしておくことがあります。誰が停止を宣言するか。どの鍵でどの機能を止めるか。処理中のメッセージをどう扱うか。利用者へ何を知らせるか。

    再開するのは、原因と影響の範囲が分かり、L1とL2の状態の突き合わせが済み、再発防止策が入ってからです。同じ障害を隠すための再起動はしません。いきなり全開にせず、少しずつ戻します。運用設計の詳細はスマートコントラクト本番運用で整理しています。

    本番切り替え前の受入チェックリスト

    • 候補L2の公式差分表を、使うopcode、precompile、開発ツール、ガス、アドレス生成へ対応付けた。
    • 移行元・移行先のchain ID、コントラクトアドレス、code hash、ブロック番号・hash、設定、ロールをマニフェストへ保存した。
    • 同じ略称やチェーンの表示名だけで資産を識別せず、chain IDとコントラクトアドレスで識別している。
    • スナップショット、差分の記録、取込スクリプトが冪等で、中断後の再開と件数・rootの照合ができる。
    • 読み取りの並行照合と書き込みの限定開始で、機能、event、インデクサー、会計、サポート対応を確認した。
    • 入金・出金の重複、遅延、失敗、再送、再編を試験した。
    • シーケンサー、RPC、中継者、インデクサー、Oracleの停止を検知し、代替経路または安全な停止を実行した。
    • 切替・停止・補償・再開の権限者と二者承認、連絡先、証拠の保管先を決めた。
    • 旧L1経路の読み取り、書き込み停止、廃止日時と利用者への案内を決めた。
    • 本番と同等の負荷・資産上限で不変条件を監視し、観察期間を通過した。

    移行を見送るのは、どんなときか

    移行しない条件も、先に決めておきます。次のような場合は、L1での最適化や、別のL2と比べます。

    • 必要なopcodeやprecompileに対応していない
    • 強制退出を運用できない
    • 流動性が分かれてしまい、事業の要件を満たさない
    • 既存の連携先が、チェーンを見分けられない
    • 管理権限の信頼の前提を受け入れられない

    手数料が安いというだけで、立て直せない移行を正当化しません。

    実装する人向けの詳細

    ここからは、移行の仕組みを実際に作る設計者向けに、合格の証拠、マニフェスト、確かめ方の細部をまとめます。

    互換性ごとの合格の証拠

    • 実行:同じテストベクトルで戻り値・event・ストレージの差分が許容内
    • アドレス:予定アドレスと実際のデプロイ先、参照設定の一致
    • 状態:基準ブロックのスナップショットとL2取込後の集計・Merkle root(データ全体から計算する要約値)の照合
    • 資産:L1の預け入れ残高とL2の供給量をメッセージ単位で照合
    • 通信:重複・遅延・再編・失敗を注入した端から端までの試験
    • 運用:障害演習と承認済みの手順書、代替経路の実行記録

    移行マニフェストの例

    関門ごとの判定を1つの記録にまとめる例です。

    {
      "migration_id": "l1-l2-2026-01",
      "source": {
        "chain_id": 1,
        "block_number": 0,
        "block_hash": "0x..."
      },
      "target": {
        "chain_id": 0,
        "deploy_manifest_hash": "0x..."
      },
      "state_root": "0x...",
      "counts": {
        "accounts": 0,
        "positions": 0,
        "pending_msgs": 0
      },
      "gates": {
        "execution": "PASS",
        "state": "PASS",
        "operations": "PENDING"
      }
    }

    コントラクトの比べ方

    L1とL2で、関数ごとの戻り値、revert、event、ストレージのスロットを比べます。プロキシを使う場合は、実装コントラクトだけでなく、管理者、beacon、初期化済みフラグ、ストレージの配置も対象です。

    メッセージの状態

    メッセージIDごとに CREATED → RELAYABLE → RELAYED、または FAILED → RETRY/REFUND の状態を保存し、同じメッセージが二度届いても結果が増えない冪等性を持たせます。

    XTELAができること

    XTELAは、L1で動いているアプリの互換性台帳づくりから、候補L2での再現と差分試験、スナップショットの取込と照合の仕組み、読み取りの並行照合・書き込みの限定開始の実装、障害演習と切り戻し手順の設計までを行います。貴社の移行を「動いた」ではなく不変条件で判定できる状態にするのが私たちの仕事です。L2への移行について相談する

    参考資料

    資料の確認日と注意

    公式仕様の主要な資料は2026年9月24日に再確認しました(ZKsyncの差分も2026年9月24日確認)。最終確認日は2026年9月24日です。採用時は対象チェーンの最新仕様、アップグレード権限、障害情報、監査結果、利用規約をあらためて確かめてください。

    お問い合わせ

    どんなフェーズからでも、お持ちのアイデアや企画をもとにご提案可能です。
    まずはお気軽にご相談下さい!