🐷

EthereumのStorage Slotを理解する①

2023/06/18に公開

Solidityを学習していてStorage Slotsという概念について備忘録として学んだ内容をアウトプットしていきます。

Storage Slotsとは?

Storage Slotsとはイーサリアムのスマートコントラクトが自分のデータを保存する場所のこと。
1つのSlotあたりの大きさは256bitで、キーバリューストアとして機能します。
Storage slotsの重要な特性として

  • 保存されたデータは永続的であること
  • データの読み書きにはガス代がかかるということ

があります。
つまり状態変数を保存する場所ということですね。

Storage Slotsの仕組み

Storage Slotsはキーバリューストアとして機能しています。
例えば以下のようなコントラクトがあるとします。

Storage.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

contract Storage {
    uint256 x = 22;
    uint256 y = 23;
}

Storage.solに保存されている状態変数はxとyの2つです。
この時EVM上では以下のような形で保存されています。

// 0x0 => 22
// 0x1 => 23

このように状態変数はそのコントラクト内に0からインデックスされて保存されているのです。

実際に検証してみる

百聞は一見にしかず。実際に検証していきましょう。

まずはhardhatでプロジェクトを立ち上げましょう。

 npm init -y
 npm i hardhat
 npx hardhat init

hardhat.config.jsを以下のように書き換えましょう

harhat.config
require("@nomicfoundation/hardhat-toolbox");

/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
  solidity: "0.8.18",
  defaultNetwork: "localhost"
};

ローカルでブロックチェーンを起動しましょう

npx hardhat node

Storage.solというファイルを作って以下のコードを貼り付けます。

Storage
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

contract Storage {
    uint256 x = 22;
    uint256 y = 23;
}

シンプルですね。
ただ2つの状態変数が保存されているだけのコントラクトです。

続いてデプロイ用のscriptを書きます

deploy
const hre = require("hardhat");

async function main() {

  const Storage = await hre.ethers.getContractFactory("Storage");
  const storage = await Storage.deploy();

  console.log(
    `Storage deployed to ${storage.target}`
  );
}
main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

ローカルにデプロイしましょう。

npx hardhat run scripts/deploy.js        

これで準備完了です。
それでは続いて検証用のコードを書いていきましょう。

lookup.jsというファイルをscripts/直下に作って以下を貼り付けて下さい。

lookup
const hre = require("hardhat");

const addr = "0x5fbdb2315678afecb367f032d93f642f64180aa3"; // ローカルにデプロイしたコントラクトのアドレスを入れる

async function lookup() {
    const value = await hre.ethers.provider.getStorage(addr, 0);

    console.log(parseInt(value)); // 16進数を10進数にする
}

lookup()

コードを軽く解説するとethers.jsのgetStorageという関数で特定のアドレスにデプロイされているスマートコントラクト上の指定したslotに存在するデータを取得しています。
Storage.solでx=22を定義しているのでlookup.jsを実行するとコンソールには22表示されるはずです。

結果を見ていきましょう。

npx hardhat run scripts/lookup.js
22

うまくいきましたね。
念の為getStorageの第二引数を1にして実行してみましょう。
この場合はyの値が取得できるはずなので、コンソールには23が表示されるはずです。

npx hardhat run scripts/lookup.js
23

これもうまくいきました。

終わりに

これが超基本的なStorage Slotsの仕組みです。
今回は変数のデータ型がuint256型の時のみ試してみましたが、次回はより複雑なmapping型について考えてみます。

もっと詳しく知りたい方は以下をご覧ださい。
https://docs.alchemy.com/docs/smart-contract-storage-layout

Discussion