メインコンテンツまでスキップ

Storage Layout

Storage Layoutについて学習します

Storage Layoutとは、スマートコントラクトがstorage変数を保存するためのアドレス(保存場所)を指定するアルゴリズムの事です

slot

slotとはstorageの最小単位のことで、32bytes(256bit)のデータブロック

EVMにおいてはmapping(uint256 slotNumber => bytes32 slot)のようなKVS(Key-Value Store)の形で保存される

ヒント

後述の説明ではkeccak256関数をつかってスロットを指定するケースがあります

ハッシュ元の値が同じでない限りハッシュは衝突しないため、疑似的に32バイトの記憶空間を利用できているといえます

動的配列とマッピングは1スロット与えられ、他の型はデータブロックに収まる範囲でパッキングされる

contract Sample {
uint256 a;
uint128 b;
bool c;
mapping(address => uint) d;
bool e;
}

という変数が存在するとき

  • uint256 a
    • 第0スロットに格納
  • uint128 b
    • 第0スロットが埋まっているため第1スロットに格納
  • bool c
    • 第1スロットに空きがあるため格納
  • mapping(address => uint) d
    • 空きに関係なくスロットが割り当てられるため第2スロットに格納
  • bool e
    • 第2スロットが埋まっているため第3スロットに格納

となる

基本型

uintやboolなど占有するバイト数が確定しているものはその分のバイトが確保され、スロットに空きがある限りパッキングされる

bytes, string

可変長変数はデータ長が31バイト以下かどうかで格納方法が変わる

31バイト以下の場合

第pスロットにおいて要素は上位バイトに格納され(左揃え)、最下位バイトには長さ * 2の値が格納される。

32バイト以上の場合

第pスロットに要素数を格納したbytes1[]の動的配列に1文字ずつ格納されている状態と同義になる

静的配列

静的配列は第pスロットから要素がすべて収まるまでスロットを確保する

動的配列

動的配列が第pスロットに割り当てられたとき、第pスロットには要素数が格納される

要素は第uint256(keccak256(p))スロットから格納される

マッピング

マッピングが第pスロットに割り当てられたとき、第pスロットにはなにも格納されない

nというkeyの要素は第uint256(keccak256(abi.encode(n, p)))スロットに格納される

継承

複数のコントラクトが変数を持ち、それらが継承されている場合、各変数はC3_linearizationの制約にしたがってスロットが配置される

簡単に説明すると、親が優先、同列の場合は左が優先である

contract A {
uint a;
}

contract B is A {
uint b;
}

contract C {
uint c;
}

contract D is C, B {
uint d;
}

という関係が存在するとき、スロットは[c, a, b, d]の順番に配置される

forge inspect --pretty MyContract storage

を実行すると変数に対して何番のスロットが割り当てられているかを確認できる

Reference