ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [solidity] datalocation 에 대한 정리 calldata, memory, storage
    solidity 2023. 3. 22. 00:33
    반응형

    data-type 에는 두가지로 나눌수 있다.

    1. primitive type

    2. reference type

     

    기준은 데이터 크기가 유동적인지 아닌지에 따라서 구분하면 되고 이부분은 다른 언어와 크게 다를건 없다.

    string, bytes, mapping, array, structs 가 reference type 으로 나눌수 있고 크게 나누면 mapping, array, structs 로만 나눌수 있다. string, bytes 의 경우 special array로 array의 일부라고 볼수있다.

     

    reference type의 경우 선언시에 dataLocation 을 명시 해줘야 하는데 엄밀히 이야기 하면 함수 안에서 선언시에 명시 해줘야 한다는 이야기다 함수 외부인 경우에는 기본적으로 dataLocation 이 storage 이다.

     

    data location의 종류는 storage, memory, calldata 세가지 이다.

    storage 는 블록체인에 저장한다라고 생각하면 되서 어렵게 느껴지지는 않는 부분이다.

    memory 의 경우는 함수 호출시에 생성이 되는 저장공간이라고 생각하면 편하다. 그렇기 때문에 위에서 이야기한거처럼 함수 밖에서 기본적으로 datalocation이 storage 라는 점이 당연하게 느껴질것이다.

    그냥 저장공간은 storage 뿐이고 함수 호출시에 잠깐 있는 공간을 memory 라고 생각하면 된다.

     

    그러면 calldata는 뭐냐하면 이름 그대로 call data 이다ㅎㅎ

    먼저 다시 생각해보면 좋은부분이 함수호출은 트랜잭션중 하나이다.

    이더리움에서 트랜잭션은 이더전송(eoa) 혹은 함수호출(ca) 둘중하나다 트랜잭션 구조중에 data 라는 부분이 있다.

    아래코드는 트랜잭션 세부를 보기위해 etersjs의 gettransaction 을 통해서 가져온 데이터이다.

    {
      hash: '0x85acc6325abd55664d115eecdf8f518032be9dbf911476a77a49db35e2db28fa',
      type: 2,
      accessList: [],
      blockHash: '0xd555c5161c75276f587e17d2062dfc20f31f706ea964313544f7705ca572861a',
      blockNumber: 8507604,
      transactionIndex: 59,
      confirmations: 178890,
      from: '0xB93C3fA33c2A1837cf83DE70c69c7aAB6D7A52e4',
      gasPrice: BigNumber { _hex: '0x04e3b29200', _isBigNumber: true },
      maxPriorityFeePerGas: BigNumber { _hex: '0x04e3b29200', _isBigNumber: true },
      maxFeePerGas: BigNumber { _hex: '0x04e3b29200', _isBigNumber: true },
      gasLimit: BigNumber { _hex: '0x04baf0', _isBigNumber: true },
      to: '0xaEB01ebD5BD17ED365d975496a504B1F36C7D9Bf',
      value: BigNumber { _hex: '0x00', _isBigNumber: true },
      nonce: 181,
      data: '0x7048233a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000057365756e67000000000000000000000000000000000000000000000000000000',
      r: '0xc1323f3051465d6ca830e8654472642d1f2152474a36c56c6dab971dc0e3efd9',
      s: '0x2b6012ecf8941a31be8c79540e9b5052b023604ed8f17f442207e423887c23d1',
      v: 0,
      creates: null,
      chainId: 5,
      wait: [Function (anonymous)]
    }

    data 라는 부분을 보면 0x7048233a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000057365756e67000000000000000000000000000000000000000000000000000000

    이렇게 되어있다.

    이부분이 함수의 시그니쳐(함수의 이름과 파라미터의 타입의 해시값)중 앞 8자리가 data 앞에 위치하고 전달된 인자가 뒤에 위치한다 그니까 일단 여기서 이야기 하고 싶은 부분은 트랜잭션내의 data에는 호출한 함수와 인자(inputdata)를 보유 하고 있다라는 점이다.

    저 데이터가 call 할때 생성된 data 여서 저걸 그대로 사용한다~ 라는 의미로 calldata 구나 라고 생각하면 된다.

     

    그래서 calldata datalocation 을 명시할수 있는 부분은 함수의 인자 자리 일수 밖에 없는거다.

    함수의 실행부에서는 calldata로 명시해줄수가 없고(call할때 알수있는 부분이 아니였기 때문에) 인자 자리에 memory를 사용한다는 것은 이 calldata를 memory에 복사해두고 사용한다는 의미이기 때문에 cost가 calldata 보다 높다라는 점은 당연하게 받아드릴수 있다.

    다만 calldata의 특성상 함수내부에서 값을 mutable 하게 사용할수 없다는 점만 참고해서 사용하면된다.

     

     

     

     

     

     

     

Designed by Tistory.