Solidity

Solidity Library 알아보기_(All you should know about libraries in solidity 번역)

Aile_I'll 2020. 7. 6. 18:21

Solidity Library에 대해 알고가기!

아래 링크에 있는 글을 번역한 내용이다. 오역 있을 수 있음!

 

reference : https://medium.com/coinmonks/all-you-should-know-about-libraries-in-solidity-dd8bc953eae7

 

 

Dapps를 개발할 때 Solidity 의 library(이하 라이브러리)를 아는 것은 매우 중요하다.

간단히 말해서, 라이브러리는 한번 배포된 후 계속해서 공유되는 재사용 가능한 코드 조각이다.
그치만 라이브러리는 재사용성을 위해서만 쓰이는 것이 아니고, ethereum 개발자들이 라이브러리 특징을 이용하는 몇몇 영역들이 있다.

이 게시물은 기본적인 것부터 시작해서 모든 주제를 다루는 것을 목표로 한다.

 

수학 연산을 위한 간단한 라이브러리부터 보자. 아래에 설명된 SafeMath 라이브러리는 2개의 unsigned int를 입력으로 사용하고 산술 연산 결과를 리턴하는 기본 산술 연산을 한다.

library SafeMath {

    function mul(uint256 num1, uint256 num2) internal pure returns (uint256) {
        uint256 result = num1 * num2;
        return result;
    }


    function div(uint256 num1, uint256 num2) internal pure returns (uint256) {
        uint256 result = num1 / num2;
        return result;
    }


    function sub(uint256 num1, uint256 num2) internal pure returns (uint256) {
        uint256 result = num1 - num2;
        return result;
    }


    function add(uint256 num1, uint256 num2) internal pure returns (uint256) {
        uint256 result = num1 + num2;
        return result;
    }
}

 

"이론적으로 라이브러리는 계약 상태를 변경하기 위한 것이 아니라 입력 및 반환 결과에 따라 단순 작업을 수행하는 데만 사용해야 한다."

자세히 알아보기 전에, 몇가지 배경 지식에 대해 알아보자.

 

1. Solidity 의 Contract 는 무엇??

기술적으로 Smart Contract는 Dapp의 기본 구성 요소다.

이더리움에서 Smart Contract는 외부 사용자 계정 (external user account) 과 같은 주소를 가지고 있는데,

이 주소는 method호출, ether 전송 등 Contract와 상호 작용하는 데에 이용될 수 있다.

각 계약에는 다음과 같은 네 가지 속성이 있다:

  • Nonce : 계정에서 발생한 거래의 수
  • Balance : 해당 주소가 보유하고 있는 ether의 양
  • Storage root : Contract는 데이터를 저장할 수 있는데 이때 Contract의 데이터를 저장하는 tree자료구조의 root
  • Code hash : Contract code의 hash값

 

2. Function 타입 

Solidity에는 아래와 같은 function 타입이 있다.

  • Internal : Contract 내부에서만 호출 가능한 함수
  • External : Contract 외부에서만 호출 가능한 함수
  • Public : Contract의 외부와 내부에서 둘다 호출 가능한 함수
  • Pure : Contract의 storage를 read하거나 write하지 않는 함수
  • View : Contract의 storage를 read는 할수 있지만 write는 할 수 없는 함수
  • Payable : payable로 선언되어야만 ether를 수신할 수 있음

How library works? (라이브러리 동작 방식)

 

출처에서 가져온 그림

블록 체인에서 transaction은 Smart Contract의 상태(state)를 변경할 수 있다. Contract에서 발생할 수있는 다양한 종류의 상태 변경은 아래와 같다.

  • Ether 전송(Sending ether) : Contract의 잔액을 업데이트
  • Contract의 데이터 변경(Changing data in contract) : storage root가 변경됨
"사용자가 내부적으로 라이브러리 Contract를 사용하는 Smart Contract에게 transaction을 보낼 때마다 라이브러리 Contract가 아니라 Smart contract의 상태가 변경된다. 이 때, EVM의 Delegate call 기능을 이용한다."

Delegate Call???

Solidity 문서에서의 정의:

"Delegate Call은 1) target address의 코드가 Calling Contract에서 실행되고 2) msg.sender 및 msg.value가 값을 변경하지 않는다는 점을 제외하고는 message call과 동일하다.

즉, contract가 런타임에 다른 address의 코드를 동적으로 load할 수 있다는 것이다.

storage, 현재 address, 잔액은 Calling Contract의 것을 참조하고, code만 호출된(called address) address에서 가져온다."

 

이 low-level 함수(delegate call)는 라이브러리 구현에서 중요한 역할을 한다.

 

 

라이브러리의 배포(Deployment of libraries) :

라이브러리의 배포는 일반 Smart contract의 배포와 약간 다르다. 라이브러리를 배포할 때 두 가지 시나리오가 있다.

  • Embedded Library(내장 라이브러리) : Smart contract가 internal 함수만 가지고 있는 라이브러리를 쓴다면, EVM은  라이브러리를 Contract에 내장시킨다. 그러면 함수를 호출할때 Delegate Call을 사용하는 대신 JUMP 문 (일반 메소드 호출)을 사용할 수 있다. 이 시나리오에서는 따로 라이브러리를 배포 할 필요가 없다.
  • Linked Library(연결된 라이브러리) : 반대로 라이브러리에 public 또는 external 함수가 포함 된 경우, 라이브러리를 배포해야한다. 라이브러리 배포는 블록 체인에서 고유 한 주소를 생성한다. 이 address는 calling contract와 연결되어 있어야한다.

(2020.07.08 이어서 작성)

 

 linked library를 이해하기위한 간단한 예를 살펴보자.

아래 코드는 tranfer라는 함수를 가진 ERC20 Contract의 일부다.

 

external 로 선언된 transfer함수에서 SafeMath library의 sub함수와 add함수가 사용된다.

pragma solidity ^0.4.23;

import "./SafeMath.sol";

contract ERC20 {

    using SafeMath for uint256;
    mapping(address => uint256) balances;

    function transfer(address _to, uint256 _value) public returns (bool success) {
        balances[msg.sender] = balances[msg.sender].sub(_value);
        balances[_to] = balances[_to].add(_value);
        return true;
    }
}

library SafeMath {

    function mul(uint256 a, uint256 b) external pure returns (uint256) {
        uint256 c = a * b;
        assert(a == 0 || c / a == b);
        return c;
    }


    function div(uint256 a, uint256 b) external pure returns (uint256) {
        uint256 c = a / b;
        return c;
    }


    function sub(uint256 a, uint256 b) external pure returns (uint256) {
        assert(b <= a);
        return a - b;
    }


    function add(uint256 a, uint256 b) external pure returns (uint256) {
        uint256 c = a + b;
        assert(c >= a);
        return c;
    }
}

 

이때 흥미로운 점이 2가지 있다.

  1. SafeMath 라이브러리에는 external로 선언된 함수가 있다.
  2. 아래 문자열은 ERC20 Contract를 컴파일한 후 생성된 bytecode의 일부이다. 이 바이트 코드는 SafeMath의 reference를 포함한다.(__SafeMath______________________________) 이는 라이브러리 deploy를 수행하기 전에 ERC20의 bytecode를 배포 할 수 없다는 것을 의미한다. Linking은 bytecode의 라이브러리 참조를 address로 바꾸는 것을 의미한다.

0x608060405234801561001057600080fd5b50610343806100206000396000f300608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a9059cbb14610046575b600080fd5b34801561005257600080fd5b50610091600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506100ab565b604051808215151515815260200191505060405180910390f35b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205473__SafeMath______________________________63b67d77c59091846040518363ffffffff167c0100000000000000000000000000000000000

 

배포할때 라이브러리와 link 하는 방법은? (How to link library contract during deployment?)

  1. 라이브러리 배포 : ropsten에 SafeMath 라이브러리를 배포해서 라이브러리의 주소로0x40189fb71f54a3ad0370620dfb095382859eb095 를 얻음
  2. 배포된 라이브러이와 Contract를 연결 : 아래 명령어를 사용해서 SafeMath 라이브러리와 ERC20 Contract를 연결할 수 있음 (solc ERC20.sol — libraries “SafeMath:0x40189fb71f54a3ad0370620dfb095382859eb095” — bin)

제대로 연결되면 SafeMath의 reference가 bytecode에서 사라지고 배포할 준비가 된 상태이다.

 

‘Using for’ in library:

Solidity에서 'using X for Y'의 의미는 라이브러리의 함수 X를 타입 Y로 사용한다는 것이다.

예를 들어 Using SafeMath for uint256 라고 하면,

add, sub, mul, div같은 SafeMath 의 함수의 bound는 uint256타입인 것이다.

 

"라이브러리 함수는 첫 번째 매개 변수와 같은 오브젝트를 받는다는 것에 주의해야한다."

 

예시: 위에서 언급한 ERC20에서  Using for는 SafeMath 을 type uint256로 쓰겠다의 형태로 나타났다. 

using SafeMath for uint256;

uint256 a = 10;
uint256 b= 10;

uint256 = a.add(b);

여기서 add 함수는 SafeMath에서 가져온 함수다. 이 함수는 uint256과 바인딩 된다.

 


번역 끝!

의문점

=>내가 Solc로 컴파일하면 라이브러리 String이 비어서 나오는게 아니라 다 바이트 코드로 나오는데 이미 reference돼서 나오는건가?? Solc내부 찾아볼 필요가 있을 듯