티스토리 뷰

https://programtheblockchain.com/posts/2018/03/09/understanding-ethereum-smart-contract-storage/

를 번역해보았다.

 

이더리움 스마트컨트랙트는 독특한 스토리지 모델을 사용하고, 이는 뉴비 개발자들을 혼란시킵니다.

이 포스트에서는 스마트컨트랙트 스토리지 모델을 설명하고, 솔리디티 프로그래밍에서 어떻게 사용하는지를 설명합니다.

 

목차

1. 1개의 천문학적으로 큰 어레이

2. 고정 크기값 위치하기

3. 다이나믹 사이즈 값들 위치하기

(1)다이나믹 사이즈 어레이

(2)매핑

(3)여러타입들의 조합

 

1. 1개의 천문학적으로 큰 어레이

EVM 에서 작동하는 각각의 스마트컨트랙트는 각각의 영구적인 스토리지를 가진다. (storage hash)

이 스토리지는 하나의 거대한 어레이이며, 초기값은 0이라고 생각될수있다.

어레이의 하나의 값은 32바이트 크기이며, 이러한 32바이트가 2^256개 있다. 

스마트 컨트랙트는 어떤위치의 값이라도 읽거나 쓸수있다. 

이게 스토리지 인터페이스의 범위이다.

 

이런식의 거대한 하나의 어레이라고 상상해보자.

사실 이더리움의 스토리지는 이렇게 생기지 않았지만, 이렇게 하나의 거대한 어레이라고 생각하는 편이 이해하기 쉽다.

실제 스토리지는 극단적으로 희박하여 0까지 저장할 이유가 없다.

키/밸류 스토어 매핑으로 충분하다.(키,밸류 모두 32바이드 밸류) 키가 없는 경우에는 0값을 돌려주면 되기 때문이다.

0은 아무런 자리도 차지하지않아서, 값을 0으로 지정한다면 스토리지는 되돌려진다. 이게 스마트컨트랙트에서 "가스 리펀" 을 받는 경우이다.

 

 

2. 고정된 크기의 값 위치하기

이 스토리지 모델에서 값들은 어디로 가는가? 고정된 크기의 알려진 변수들은, 스토리지의 지정된 장소로 주면 된다. 솔리디티언어가 그걸한다.

contract StorageTest {
    uint256 a;
    uint256[2] b;

    struct Entry {
        uint256 id;
        uint256 value;
    }
    Entry c;
}

이런 코드가 있다고 치자.

  • a는 슬랏 0 에 저장된다
  • b는 슬랏 1, 2에 저장된다
  • c는 슬랏 3,4에 저장된다. Entry 내에 32바이트 값이 두개 있기 때문이다. 

이 슬랏들은 컴파일될때 결정되고, 컨트랙트에 쓰여진 순서대로 할당된다.

 

3. 다이나믹 사이즈 값들 위치하기

다이나믹사이즈 어레이와 매핑의 경우엔 몇개의 슬랏을 사용하게 될지 모르기때문에 선지정할수 없다.

램이나 하드를 예시로 생각해보면, 빈 공간을 사용하기 위해 할당하는 단계와 사용중인 공간을 릴리즈하는 단계가 있을것이다.

그러나 스마트컨트랙트 스토리지경우엔 천문학적 규모때문에 그럴필요가없다.

스토리지에는 2^256 개의 위치가있는데, 이게 얼마나 큰 수냐면 관찰 가능한 우주의 원자의 수와 비슷할 정도다. 아무 위치를 랜덤으로 찍어도 충돌할 확률이 몹시 작다는 뜻이다. 심지어 이렇게 찍은 위치간에 멀리 떨어져있어서 다이나믹한 데이터를 얼마나 넣던 충돌할 가능성도 적다.

물론 위치를 진짜로 랜덤으로 설정하지는 않는다. 이러면 나중에 데이터를 찾을수가 없기때문이다. 솔리디티는 해시 펑션을 이용해 다이나믹 사이즈의 값의 위치를 통일성있게, 반복적으로 정한다.

 

(1) 다이나믹 사이즈 어레이

contract StorageTest {
    uint256 a;     // slot 0
    uint256[2] b;  // slots 1-2

    struct Entry {
        uint256 id;
        uint256 value;
    }
    Entry c;       // slots 3-4
    Entry[] d;
}

다이나믹 사이즈 어레이 d는 5번째 슬롯에 저장되지만, 정확히 5번째 슬롯에는 d의 크기만 저장된다.

어레이의 값은 슬롯의 해시 (hash(5)) 슬롯부터 순서대로 저장된다.

솔리디티에서는 다음과 같이 위치를찾는다

function arrLocation(uint256 slot, uint256 index, uint256 elementSize)
    public
    pure
    returns (uint256)
{
    return uint256(keccak256(slot)) + (index * elementSize);
}

(2) Mappings

매핑은 주어진 키에 대응하는 위치를 찾을 효율적인 방법을 요구한다. 키를 해싱하는것은 좋은 시작이지만, 다른 매핑이 다른 위치를 생성하도록 신경써야한다.

contract StorageTest {
    uint256 a;     // slot 0
    uint256[2] b;  // slots 1-2

    struct Entry {
        uint256 id;
        uint256 value;
    }
    Entry c;       // slots 3-4
    Entry[] d;     // slot 5 for length, keccak256(5)+ for data

    mapping(uint256 => uint256) e;
    mapping(uint256 => uint256) f;
}

e 슬롯의 위치는 6, f슬롯의 위치는 7이다. 그러나 6,7에 실제 데이터가 저장되지않는다. 이번엔 저장될 길이도 없고, 각개 데이터는 다른 어딘가에 저장되어야한다.

매핑의 경우에는 키와 매핑의 슬롯이 함께 해시된다.

매핑의 위치와 키가 함께 해싱되기때문에 충돌을 방지할수있다.

솔리디티에서는 다음과 같이 위치를찾는다.

function mapLocation(uint256 slot, uint256 key) public pure returns (uint256) {
    return uint256(keccak256(key, slot));
}

 

(3) 복잡한 타입들의 컴비네이션

다이나믹사이즈 어레이와 매핑은 서로 재귀적 중첩이 가능하다. 이게 발생하면 위의 계산이 재귀적으로 발생한다. 

contract StorageTest {
    uint256 a;     // slot 0
    uint256[2] b;  // slots 1-2

    struct Entry {
        uint256 id;
        uint256 value;
    }
    Entry c;       // slots 3-4
    Entry[] d;     // slot 5 for length, keccak256(5)+ for data

    mapping(uint256 => uint256) e;    // slot 6, data at h(k . 6)
    mapping(uint256 => uint256) f;    // slot 7, data at h(k . 7)

    mapping(uint256 => uint256[]) g;  // slot 8
    mapping(uint256 => uint256)[] h;  // slot 9
}

이런게있으면 g[123][0]을 찾고자하면

g[123]을 먼저 찾고 -> g의 슬롯인 8과 키값으로 위치를 찾는다

그 후 arr[0]을 찾게된다. -> g[123]값을 해싱하면 첫 위치가 나온다. g[123]에는 어레이의 길이가 들어있으므로 길이만큼 값을 가져오면 된다.

 

 

h[2][456]을 찾고자하면

h[2] 는 슬롯9번을 해싱한 위치에 있고, 그중 2번째인 값을 가져온다.

 

 

요약

-각 스마트컨트랙트는 2^256개의- 한 슬랏은 32바이트가 들어가는- 형태의 어레이이며 모두 0으로 초기화된 셈이다.

-0은 명시적으로 저장되어있지않으므로 값을 0으로 세팅하는것은 그 스토리지를 요구하는 것이다.

-솔리디티는 고정된 사이즈의 값을 "슬롯"이라는 지정된위치에 지정시킨다. 이 슬랏은 0부터 시작한다.

-솔리디티는 다이나믹 사이즈 값들을 균일하고 안전히 저장하기 위해 해시 결과값을 쓴다.

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함