[Slot] 마스터링 슬롯 배치

드림보이즈·2025년 3월 26일
0

Smart Contract

목록 보기
4/11

학습 목표 : 변수들이 어떻게 슬롯에 배치되는지 마스터하자.

학습 배경 : 면접에서 애매하게 알아서 틀림

1. Storage & Slot

컨트랙트에서 저장되는 다양한 전역변수들은 Storage에 저장된다.
이 때 Slot(256비트) 단위로 주소를 가지어 저장한다.
뭔 개소리냐고? 예시를 보면 ㅈㄴ 쉽다.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract StorageLayoutExample {
    uint256 public a = 42;       // 슬롯 0
    uint8 public b = 1;          // 슬롯 1 (uint8 + uint16과 같은 작은 타입들은 같은 슬롯에 패킹될 수도 있음)
    uint16 public c = 256;       // 슬롯 1 (b와 함께 패킹될 가능성 있음)
    uint256 public d;            // 슬롯 2 (명시적 할당 없음, 기본값 0)
    
    address public owner = msg.sender;  // 슬롯 3
    bool public flag = true;    // 슬롯 3 (bool은 1바이트만 차지)
    bytes32 public hash = keccak256("Hello"); // 슬롯 4

    struct User {
        uint256 id;
        address userAddress;
    }

    User public user = User(123, msg.sender); // 슬롯 5,6(구조체는 여러 슬롯 차지)

    mapping(uint256 => address) public users; // 슬롯 7 (매핑 자체는 슬롯을 차지하지 않음, 키 해시를 통해 위치 계산)

    uint256[3] public fixedArray = [10, 20, 30]; // 슬롯 8,9,10(고정 배열)

    string public myString = "Ethereum";  // 문자열은 동적 데이터로 별도 슬롯 사용 (슬롯 11에 길이 저장, 실제 값은 Keccak256(11) 위치)
    
    bytes public myBytes = hex"123456";  // bytes도 동적 데이터 (슬롯 13에 길이 저장, 실제 값은 Keccak256(12) 위치)
}

EVM은 컨트랙트에 선언한 순서대로 슬롯에 저장한다.
즉 위부터 슬롯 0부터 차례대로 저장한다.

대충 감이 오는가?

먼저 데이터 타입을 나누어서 생각하자.

2. Primitive : bool, int, address (고정)

고정 길이 타입이면 최대한 모여잇~ 그것이 Packing

이들은 고정 길이 타입의 데이터다.
길이가 고정되어 있으니 32바이트 슬롯을 함께 사용할 수도 잇다.

위 예시 : uint8,uint16 / address,bool

b,c는 작은 정수형으로, 256비트 짜리 슬롯에, 8 + 16 합쳐도 24비트 짜리라 한 슬롯에 같이 들어갈 수 있다는 점이다.

아마 솔리디티를 배우면서, 작은 정수형들은 선언할 때 모아서 선언하라는 팁을 배웠을 것인데,
그 이유가 바로 이것이다.

마찬가지로 owner는 address 타입, 20바이트, bool은 1비트다. 한 슬롯에 함께 묶인다.

3. Dynmaic : struct, string, bytes, array, mapping

정적 길이 타입이면 최대한 안 겹치게 해시 사용해서 따로 저장해잇~

dynamic은 해당 슬롯에, "길이가 저장되고" 실제 값은 별도의 슬롯에 저장된다.

위 예시 : strings, bytes

만약 0-31바이트라면, 한 개의 슬롯에 저장되고
32바이트 이상이라면 슬롯에는 길이 정보만 저장하고, 실제는 keccack256(slotNum)에 저장.

동적인 데이터에 특정 공간만 주면, 길어지면 남의 슬롯이랑 충돌이 발생할 것 아닌가?
가뜩이나 순서대로 슬롯을 배정하고 있는데? 맞잖아?

그래서 이런 길이가 동적인 데이터들은, 단순히 Slot 12가 아니라,
Slot keccak256(12) 위치에 저장이 된다.
즉 실제 슬롯 12는 비워두고, 해시를 한 슬롯에 실제 데이터를 저장하는 것이다.

구조체 : struct

구조체 각각 필드가 각각의 슬롯을 사용한다.

매핑 : mapping

위를 보면, 매핑의 선언만 했지 값을 할당은 안했다.
앞으로 누군가 채워넣겠지? 그러므로 동적이다.
매핑 선언은 그 자체로 슬롯에 값이 들어가진 않지만, 슬롯 번호 8은 사용을 한다.
만약 누군가 값을 넣는다면,
그 값은 Keccak(key,8)인 Slot에 저장된다.

마무리

결론, 데이터 타입을 정적이냐, 동적이냐로 나눠서,
정적이면 최대한 모아서 한 슬롯에 넣고,
동적이면 최대한 안 겹치게, 해시를 사용해서 널리널리 뿌려서 저장한다. 너무 쉽죠?

profile
시리즈 클릭하셔서 카테고리 별로 편하게 보세용

0개의 댓글