[TIL] 2023-05-03

Melon Coder·2023년 5월 3일
0

TIL

목록 보기
27/50
post-thumbnail

Today I Learned


[BlockChain]

오늘은 Solidity에서 자료형(문자열, 바이트형) 에 대해 배웠고 get, set함수를 작성해보았다.


Solidity code

// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.18;

contract UintandString {
    uint a; // 숫자형 변수 a 선언
    string b; // 문자형 변수 b 선언

    function setA(uint _a) public {
        a = _a;
    }

    function setAasFive() public {
        a = 5;
    }

    function getA() public view returns(uint) {
        return a;
    }

    function setB(string memory _b) public {
        b = _b;
    }

    function getB() public view returns(string memory) {
        return b;
    }

    function setBasC() public {
        b = "c";
    }

    function setBasC2() public {
        b = "C";
    }

    function setBasABC() public {
        b = "abc";
    }

    function setAB(uint _a, string memory _b) public {
        a = _a;
        b = _b;
    }

    function getAB() public view returns(uint, string memory) {
        return (a, b);
    }
}

위 코드를 보고 큰 차이점은 uint 타입의 변수를 선언하고 사용할 때에는 상태변수든 지역변수든 타입 다음에 변수명 외에 작성할 필요가 없었지만, string 타입의 변수를 선언할 때에는 상태변수에선 적을 필요가 없지만 지역변수에서는 memory를 적은 것을 볼 수 있다.
그 이유는 데이터의 크기 차이인데 숫자형보다 문자열의 데이터 크기가 크기 때문에 지역변수에서 memory혹은 calldata를 적어줘야 오류가 뜨지 않는다.(숫자형은 storage에 저장)

여기서 중요한 것은 변수와 데이터를 스마트 컨트랙트에서 작성할 때 EVM에선 어떻게 처리될지에 대해 항상 생각해야 한다는 것이다.
그러면 storagecalldata, memory의 각각 차이점은 무엇일까?

Storage vs Calldata vs Memory

Storage

Storage는 모든 상태변수가 저장되는 곳이다.
왜냐하면 상태는 컨트랙트 안(또는 함수 안)에서 변경될 수 있다.
따라서 storage의 변수는 변경이 가능해야 된다.
그러나 위치는 영구적이며, 그 변수들은 블록체인에 저장된다.

또한 storage의 상태변수는 압축 방식으로 배열된다.
가능하면 여러 값이 동일한 storage 슬롯을 채운다.
동적 크기의 배열 및 구조체의 특수한 경우 외에도 다른 변수는 32바이트 블록으로 함께 채워진다.

만일 이러한 변수들이 32바이트 미만이면 이 변수들이 결합되어 동일한 슬롯을 채운다.
그렇지 않으면 다음 슬롯에 채워진다.
데이터는 contract에서 선언된 순서대로 0 슬롯부터 1,2,3 ... 차례로 채워진다.

동적 배열과 구조체는 항상 새로운 슬롯을 사용하며, 이를 따르는 변수들도 새 슬롯을 시작하도록 초기화된다.

동적 배열과 구조체의 크기 모두 사전엔 알 수 없기 때문에(contract에서 나중에 할당할 때까지) 다른 상태 변수 사이에 데이터를 저장할 수 없다. 대신 32바이트라 가정하고 그안의 요소는 해시함수(Keccak-256)를 사용하여 계산되는 별도 슬롯에서 시작하여 저장된다.

그러나 상수 상태 변수는 슬롯에 저장되지 않는다.
대신 이러한 변수는 contract bytecode에 직접 주입된다.
또한 변수를 읽을 때마다 contract는 할당된 상수 값으로 자동으로 전환한다.

Memory

Memory는 함수의 범위 내에 정의된 변수를 위해 예약된다.
이러한 변수는 함수가 호출되는 동안에만 유지되므로 이 범위 바깥에서는 접근할 수 없는 임시 변수이다.(즉, 해당 함수 안이 아닌 이외의 contract의 다른 위치)
그러나 해당 함수 내에서는 변경을 할 수 있다.

Calldata

Calldata는 함수 인수가 저장되는 변경이 불가능한 임시 위치이며 대부분 memory처럼 동작한다.

Calldata는 불필요한 복사를 방지하고 데이터가 변경되지 않도록 하기 위해 사용하는 것이 좋다.
Calldata 위치가 있는 배열 및 구조체도 함수에서 반환할 수 있다.

0개의 댓글