데이터 - 로직 분리 컨트랙트

_Block·2022년 5월 19일
0

SmartContract

목록 보기
2/5
post-thumbnail

스마트 컨트랙트는 한번 기록이 되면 수정이 불가능 합니다.

Proxy와 같은 특별한 형태도 있지만 일반적으로는 불가능하고 새로운 컨트랙트를 배포해야한 새로운 버전의 컨트랙트를 활용 가능합니다.

앞서 말했던 것처럼 Proxy를 활용하면 컨트랙트를 업그레이드 가능하지만..

제가 스스로 테스트 해본 결과, Proxy를 통해서 작동 시킬수 있지만 안타깝게도 데이터는 보존이 되지 않았습니다.

  • 제가 잘 못 한걸 수도 있지만.. 다양한 방면으로 시도해 봤고.. 거의 대부분 비슷한 코드였지만 이상하게 만치 데이터 보존이 되지 않았습니다.

그래서 저는 다른 방식의 컨트랙트 데이터를 보존하면서, 업그레이드 가능한 컨트랙트를 구현 해 볼수 있는지 고민을 해보앗고

답은 데이터와 로직을 분리한 형태의 컨트랙트를 활용 하였습니다.

  • 실제 서비스 될 프로젝트에 직접 적용하여 사용해볼 예정입니다.

🐾 데이터 - 로직 분리??

데이터와 로직을 분리한다는 말을 처음 들었으면 어떤 소리인지 의문이 들 수 있습니다.

저 같은 경우에는 처음에 변수명은 다른 컨트랙트에 적고, 함수를 통해서 해당 변수에 접근한다는 소리인가?? 정도로 간단하게 생각을 해보았는데.

이러한 방식은 그냥 같이 적는것과 차이가 없습니다.

그럼 어떻게 활용이 가능한지 간단한 코드를 통해서 살펴 보겠습니다.

👆 V1

contract V1{
 uint256[] num;
 
 function pushNum() public {
 	num.push(3);
 }
 
 function getNum() public view returns(uint256[] memory) {
 	return num;
 }
}

간단한 컨트랙트가 있습니다.

  • 어려운 로직은 없기 떄문에 넘어가도록 하겠습니다.

👆 V2

import "./V1.sol";

contract V2 {
	V1 private V1Contract;
    
    function setV1(V1 _V1) public {
    	V1Contract = _V1;
    }
    
    funtion pushNum() public {
		V1Contract.pushNum();  
    }
    
    function getNum() public view returns(uint256[] memory){
    	V1Contract.getNum();
    }
}

이와 V2의 컨트랙트도 있습니다.

V2같은 경우에는 V1의 컨트랙트 주소를 받아서 활용을 합니다.

  • 이때 V1에 들어가는 msg.sender는 V2의 컨트랙트 주소가 됩니다.
  • 현재는 중요한 문제가 아니니 넘어가겠습니다.


즉 이러한 구조로 작동을 하고 있습니다.

실질적으로 V2에서 실행을 시키면 V1의 값을 바꾸고 잇는 구조 입니다.

그럼 이떄 V2에 다른 함수를 추가하여 배포 하고 싶다면 어떻게 하면 될까요

간단합니다. 다른 컨트랙트를 배포하고 마찬가지로 V1을 실행시킬수 있는 환경을 조성 하면 됩니다.

👆 V3

import "./V1.sol";

contract V3 {
	V1 private V1Contract;
    
    function setV1(V1 _V1) public {
    	V1Contract = _V1;
    }
    
    funtion pushNum() public {
		V1Contract.pushNum();  
    }
    
    function getNum() public view returns(uint256[] memory){
    	V1Contract.getNum();
    }
    
    function getString() public pure returns(string memory){
    	return "string";
    }
}

이러한 V3컨트랙트를 배포한다면 V2와는 다른 컨트랙트 이지만 마찬가지로 V1에 접근을 하고 있으며 데이터에 대한 정보는 V1에 있기 떄문에 이전 값을 잃어버지 않는 상태로 활용이 가능 합니다.

  • 이떄 주의해야 하는 점은 V2는 없애 주어야 한다는 점 입니다.
  • 누군가 이후에 활용을 할 수 있기 떄문에 반드시 삭제해 주도록 합니다.
  • 이 부분은 solidity selfdestruct를 참고하면 좋을 꺼 같습니다.

자 그러면 우리는 여기까지 진행을 하면 간단하게 데이터와 로직이 분리된 형태의 컨트랙트가 무엇인지 알 수가 있습니다.

👆 보통 컨트랙트를 import하는 것은 많이 부담이 되는 행위 입니다. 그러기 때문에 인터페이스를 구성하여 해당 인터페이스를 활용하는 것도 좋은 방법 입니다.

🐾 Proxy + 데이터 && 로직 분리 컨트랙트

자 그러면 이제 어떻게 하면 Proxy를 활용 가능할지 확인해볼 시간 입니다.

일단 처음에 들 수 있는 생각은 굳이 Proxy를 활용 해야해?? 일 껍니다.

저도 사실 지금도 그런 생각을 하고 있습니다.

실제로 서비스를 할 떄에는 Owner계정이 존재하고 해당 Owner계정이 컨트랙트를 Paused걸고 그후 새로운 컨트랙트를 배포 하고, 그다음 다시 재 실행 시키면 되지 않나??

라는 생각을 하고 있습니다.

하지만 굳이 Proxy까지 추가를 했을떄의 이점을 뽑자면 방금전의 상황을 없앨 수 있습니다.

Paused할 필요 없이 Proxy에 적용되어잇는 주소값을 변경만 해주면 되기 떄문에 좀더 편하다?? 라는 점이 있는 것 같습니다.

  • 그래도 뭐 굳이..??

서론이 길었으니 바로 적용을 해보겠습니다.

Proxy를 어디에 연결하여 전송을 해야 할까요??

기본적으로 Proxy는 fallback을 활용하여 로직을 실행을 시킵니다.

그러기 떄문에 실질적으로 로직이 실행이 되는 로직 컨트랙트에 연결이 되어야 합니다.

  • V2, V3 컨트랙트가 이에 해당됩니다.
  • Proxy에 대한 코드는 제 블로그의 다른 글을 참고하면 나와 있습니다.

아니면 KlaySwap에서도 Factory형태를 위해서 Proxy를 활용하고 있는데 이 부분을 참고 해도 됩니다.

  • 굳이 형태를 그려보자면 이런식으로 동작이 될 것입니다.
profile
Block_Chain 개발자 입니다. 해당 블로그는 네트워크에 관한 내용을 다루고 있습니다.

0개의 댓글