[Proxy Contract] 업그레이드가 가능한 스마트 컨트랙트

Seokhun Yoon·2022년 5월 24일
3
post-thumbnail

1. Proxy Contract가 필요한 이유

블록체인의 불변성이라는 특성 때문에 한 번 저장된 데이터는 변경이나 삭제가 불가능하며 오로지 추가만 가능하다. 이는 스마트 컨트랙트를 작성할 때도 마찬가지다. 한 번 배포가 된 스마트 컨트랙트는 버그가 발견되더라도 변경이 불가능하다. 만약 수정된 새로운 컨트랙트를 배포하더라도 사용자에게 새로운 컨트랙트 주소를 전달해야 하며, 이전 데이터를 옮겨오는데 상당한 시간과 비용이 발생할 수 있다.

이런 문제를 해결할 수 있는 방식이 Proxy Pattern이다. 로직과 데이터를 분리하여 각각 다른 Contract를 만들고 Proxy contract는 이 컨트랙트의 주소를 저장한다. 사용자는 오로지 Proxy contract에만 상호작용하기 때문에, 새로운 컨트랙트가 배포 되더라도 Proxy contract에 저장된 주소만 변경한다면 사용자는 아무런 변경 사항 없이 업그레이드 된 컨트랙트를 사용할 수 있다.

여기서 fallback 함수와 delegate call을 활용하기 때문에 이 개념에 대해서 알아둘 필요가 있다.

2. fallback function

사용자가 컨트랙트의 특정 함수를 호출했는데, 만약 그 함수가 컨트랙트에 없다면 fallback 함수를 호출하게 된다. Proxy Contract를 구현할 때 fallback 함수를 적극 활용한다. 특징은 아래와 같다.

  • 하나의 컨트랙트에는 단 하나의 fallback 함수만 가질 수 있다.
  • 무조건 external로 선언되어야 한다.
  • modifier를 가질 수 있고 virtual, override 모두 가능하다.
  • 가스비는 2300으로 제한되어 있어 컨트랙트를 생성하거나 이더를 전송하는 등, 복잡한 로직이나 가스비가 많이 소모되는 코드를 실행할 수 없다.

이런 특징 외에도 컴파일 버전 0.6.0을 기점으로 선언 방법 등이 다르다.

~0.5.17

function () external
또는
function () external payable
  • 함수의 이름이 없이 함수가 선언된다.
  • payable를 선언하면, transfer 함수나 send 함수를 사용하지 않고 이더를 전송받을 수 있다.

0.6.0~

  • function 키워드 없이 선언된다.
    1) receive 함수
receive () external payable
  • receive 함수가 이더를 전송받는 기능을 담당한다.
  • 무조건 externalpayable을 함께 선언해야 한다.
  • 만약 receive 함수가 없다면 payable을 포함하는 fallback 함수에서 이더를 전송 받을 수 있다.

2) fallback 함수

fallback () external [payable]
또는
fallback () external [payable] or fallback (bytes calldata input) external [payable] returns (bytes memory output)
  • fallback 함수와 receive 함수로 분리하여 담당한다.
  • 만약 매개변수가 존재한다면, msg.data와 같은 full data를 컨트랙트에 보내야 output을 반환한다. 반환 값은 abi로 인코딩되어 있지 않으며, 아무런 수정없이 반환된다.

3. delegate call

delegate call은 다른 외부 컨트랙트의 함수를 사용하면서 데이터는 호출한 컨트랙트에 저장한다.

  • 외부 컨트랙트와 호출한 컨트랙트 모두 같은 state 변수를 갖고 있어야 정상 작동한다.
  • msg.sendermsg.value는 호출될 당시의 값이 사용되며 변경되지 않는다.
  • delegate call은 boolean 타입의 값과 호출한 함수의 리턴 값을 반환한다. (boolena타입은 호출 성공 시 true를, 호출 실패 시 false를 반환)
  • 보통 upgradable contract를 구현할 때 많이 사용된다.

사용예시

4. Proxy Contract

proxy contract는 다른 컨트랙트를 대신 호출해주는 컨트랙트로, 이를 이용해서 upgradable contract를 구현한다. 따라서 실제 로직을 가지고 있지는 않지만, 로직을 갖고 있는 컨트랙트, 즉 implementation contract의 주소를 담고 있다.

사용자는 proxy contract를 이용하여 함수를 호출하지만, 실제로 함수는 implementation contract에 있기 때문에 fallback함수를 활용한다. 또한, 업그레이드 될 때마다 데이터가 변하면 안되기 때문에 delegate call로 함수를 호출하게 된다.

아래 그림은 proxy contract의 코드를 분석한 내용입니다.
혹시나 더 자세한 내용이 필요하신 분은 아래 Reference에 기재된 링크를 참고해주세요.

5. Reference

profile
블록체인 개발자를 꿈꾸다

0개의 댓글