[USCF 시리즈 (1/4)] 왜 우리는 업그레이드 가능한 스마트 컨트랙트가 필요한가?

Why do we need an Upgradeable Smart Contract?

Geon-gi Moon | Henesis
HAECHI AUDIT
11 min readAug 6, 2018

--

블록체인 기술 전문 기업 ‘해치랩스(HAECHI LABS)’에서 업그레이드 가능한 스마트 컨트랙트 프레임워크에 대한 글을 연재합니다.

  1. 왜 우리는 업그레이드 가능한 스마트 컨트랙트가 필요한가?
  2. 업그레이드 가능한 스마트 컨트랙트를 위한 필요 조건과 배경지식
  3. 어떻게 스마트 컨트랙트를 업그레이드 가능하도록 바꿀 수 있을까?
  4. vvisp을 통해 DApp 업그레이드하기

블록체인은 검열 저항성, 투명성 등의 특성들로 인하여 세상을 변화시킬 잠재력을 지닌 기술로 주목받고 있습니다. 그 중에서 검열 저항성(censorship resistance)이란 블록체인에 적힌 내용이 정부, 기업, 개인, 심지어는 그 내용의 주인을 포함하여 어느 누구에 의해서도 변경되거나 지워지지 않는다는 특성을 말합니다. 다시 말해 블록체인에 한 번 올라간 데이터는 위변조 불가능합니다. 블록체인은 기록들이 체인처럼 연결되어 있기 때문에 이미 기록된 데이터를 수정하려면 해당 기록부터 체인을 분기하여 새로운 체인을 형성해야 합니다. 이 체인을 만들었다고 하여 기록이 수정되지는 않습니다. 비트코인이나 이더리움의 경우 가장 긴 체인을 택하는 규칙을 따르기 때문에, 새롭게 형성된 체인을 기존에 가장 길던 체인보다 더 길게 만들어야만 기록을 수정하는 효과를 얻을 수 있습니다. 그러려면 새로운 체인을 지지하는 집단이 전체 네트워크가 가진 해시 파워의 50% 이상만큼의 해시 파워를 지니고 있어야 합니다. 이를 통해, 네트워크를 압도할 만한 해시 파워를 지닌 채굴자가 나타나지 않는 이상 전체 네트워크의 절반 이상이 선량하다면 데이터가 위변조될 일은 없을 것이라는 것을 알 수 있습니다.

이러한 특성으로 인해 블록체인에 올라가는 데이터 중 하나인 스마트 컨트랙트 코드 역시 위변조 불가능합니다. 부분적으로 스마트 컨트랙트가 접근하는 메모리, 스토리지에 대해서는 수정할 수 있지만, 코드 자체에 대한 수정은 할 수 없습니다. 쉽게 말하면, 스마트 컨트랙트가 한 번 배포되면 코드에 적힌 function에는 접근할 수 있지만 새로운 function을 추가할 수는 없습니다. 예를 들어 아래와 같은 코드의 스마트 컨트랙트를 배포했다면, setNumber()를 통해 number의 값은 수정할 수 있지만 getNumber()와 같은 function은 추가할 수 없습니다.

pragma solidity ^0.4.23;

contract Haechi {
uint number = 8;

function setNumber(uint newNumber) public {
number = newNumber;
}
}

이렇듯 스마트 컨트랙트 코드를 업데이트할 수 없는 것은 블록체인의 특성으로부터 파생되는 자연스러운 현상이지만, 이는 현실에서 블록체인을 활용하는 데에 있어 크고 작은 불편함을 야기합니다. 이 글에서는 크게 2가지의 문제점을 통해 왜 우리는 업그레이드 가능한 스마트 컨트랙트가 필요한지에 대해 이야기해보려 합니다.

본격적으로 글을 시작하기에 앞서, 코드를 업데이트할 수 있는 권한에 대한 논의는 해당 글의 범위를 벗어나므로 다루지 않겠습니다.

왜 업그레이드 가능한 스마트 컨트랙트가 필요한가?

배포 후에 버그를 발견해도 수정할 수 없다

첫 번째, 배포 후에 버그를 발견해도 수정할 수 없습니다.

모든 프로그램 코드에는 개발자가 생각하지 못한 버그 또는 보안 취약점이 있을 수 있습니다. 이를 발견하기 위해 배포 전에 테스트 케이스를 작성하여 예상 가능한 시나리오들에서 코드가 잘 구동되는지 확인하거나 다른 개발자에게 검토를 요청하기도 합니다. 일반적인 앱, 웹, 서버 프로그래밍에서는 만약 이 과정에서 놓친 버그가 있다고 하더라도 사후에 업데이트하여 다시금 배포함으로써 손쉽게 버그를 수정할 수 있습니다.

스마트 컨트랙트는 어떨까요? 대다수의 스마트 컨트랙트는 경제적 가치를 지니는 암호화폐를 매개하기 때문에 사소한 버그가 엄청난 경제적 손실을 초래함을 이미 수 차례의 사건들을 통해 뼈저리게 경험하였습니다. 이더리움 전체 발행량의 15%를 해킹당한 The DAO 사건, 약 50만 ETH를 허공에 잠가버린 Parity의 Multisig Wallet 동결 사건[1] 등을 통해 말입니다. 게다가 코드가 대중에게 투명하게 공개되기 때문에 해커들에게 버그가 발견되기 더욱 쉽습니다. 그럼에도 불구하고 한 번 배포하고 나면 이 버그를 발견하더라도 수정할 기회가 없습니다. 이로 인해 배포하기 이전에 보안 감사나 정적 분석(static analysis) 등을 통해 코드의 보안 취약성을 발견하고자 하지만, 복잡한 컨트랙트의 경우 이러한 분석 방법을 거쳐도 보안 취약점을 놓칠 수 있습니다. 특히 이더리움의 Solidity와 같은 튜링 완전한(turing complete) 언어로 짜여진 코드의 경우 복잡도가 높아지면 보안 취약성을 분석하기가 더욱 어렵습니다. (최근에는 Zilliqa와 같이 튜링 완전성(turing completeness)을 포기한 프로그래밍 언어를 스마트 컨트랙트에 채택하고 형식 검증(formal verification)을 돕는 툴을 함께 제공함으로써 이러한 문제를 한정적으로 해결하려는 시도도 있습니다.[2]) 따라서 스마트 컨트랙트를 배포하기 전 충분한 보안 감사와 더불어, 배포 이후 보안 취약성이 발견되더라도 업데이트할 수 있는 장치가 마련되어야만 보다 근본적인 해결에 가까워질 수 있습니다.

DApp이 비즈니스 로직을 업데이트할 수 없다

두 번째, 스마트 컨트랙트를 활용하는 DApp이 비즈니스 로직을 업데이트할 수 없습니다.

대표적으로 크립토키티(CryptoKitties)의 사례를 살펴보도록 하겠습니다.

크립토키티 서비스 추이 (출처: https://dappradar.com)

크립토키티는 2017년 11월 말에 런칭된 직후 일일 사용자 14,000명을 돌파하는 등 선풍적인 인기를 끌었습니다. 이 수치가 크립토키티 스마트 컨트랙트와 통신한 이더리움 주소의 개수를 뜻하므로 크립토키티 웹사이트 방문자 기준으로 측정한다면 훨씬 많은 사용자에게 관심받던 서비스라고 할 수 있습니다. [3] 하지만 크립토키티의 급증하는 인기를 이더리움 네트워크가 감당하지 못하였고, 이더리움 가격 증가와 트랜잭션 처리 속도 저하 등으로 인해 서비스의 사용성이 저해 되었습니다. 결국 이 추세를 한 달을 채 유지하지 못하고 급락하였고, 현재는 당시 대비 95% 이상 낮아진 수치인 300여 명의 사용자만이 크립토키티를 사용하고 있습니다.

초기의 사용자 이탈은 메인 네트워크의 탓이 크지만, 네트워크가 안정된 이후에 단 한 번도 회복세를 보이지 못하고 있는 것은 비단 네트워크 성능의 문제는 아닌 듯합니다. 왜 크립토키티는 인기를 되찾지 못하였을까요?

필자는 이것이 크립토키티가 단 한 번도 게임 로직을 수정하고 발전하지 못했기 때문이라고 생각합니다. 오늘날 서비스의 발전을 위해서는 사용자의 피드백을 재빠르게 반영하고 시장 상황을 주의 깊게 살펴보면서 지속적으로 업데이트하는 것이 필수적입니다. 2017년 7월 기준 앱스토어 상위 200개 무료 앱 서비스의 경우 업데이트 간격의 중위값이 18일이며, 2018년 7월 기준 Facebook은 한 달 동안 무려 4번의 업데이트를 진행했습니다.[4][5] 버그 수정이 되었건 사용자 경험을 위한 기능 개선이 되었건 서비스는 생존하기 위해 지속적으로 변모해나가야 합니다. 블록체인 기반 서비스라고 한들 서비스의 공급과 수요 측면에서 시장 원리에서 벗어날 수 없기에 이러한 생존 법칙이 동일하게 적용될 것입니다.

물론 크립토키티 게임이 스마트 컨트랙트 업데이트로만 발전할 수 있는 것은 아닙니다. 블록체인에 담긴 데이터와 게임 로직은 그대로 두고 웹 클라이언트를 변경함으로써 게임을 발전시킬 수 있습니다. 실제 크립토키티의 업데이트 노트를 보면 꾸준히 클라이언트를 업데이트하고 있습니다.[6] 하지만 키티의 임신 주기와 같은 파라미터는 스마트 컨트랙트를 통해서 하드코딩되어 있기 때문에, 스마트 컨트랙트를 업데이트하지 못한다면 보다 대대적인 업데이트는 이루어지기 힘듭니다.[7]

크립토키티를 만든 팀 역시 코드 업그레이드를 고민하지 않았던 것은 아닙니다. 크립토키티 코어 스마트 컨트랙트 코드를 살펴보면 업그레이드를 위한 기능을 발견할 수 있습니다.[8] 하지만 이것은 단순히 현재 스마트 컨트랙트의 스토리지에 저장된 모든 기록을 버리고, 해당 스마트 컨트랙트를 영원히 잠가 버리는 기능에 불과합니다. 아래의 코드를 보면서 좀 더 자세히 설명해드리도록 하겠습니다. 만약 크립토키티 스마트 컨트랙트 코드에 치명적인 결함이 발견된다면, 전체 스마트 컨트랙트를 pause()하고 난 뒤에 새로운 컨트랙트를 배포합니다. setNewAddress() function을 호출하여 새로운 컨트랙트의 주소를 newContractAddress에 저장하고 나면, 이후로 영영 unpause() 할 수 없습니다. 이러한 형태는 당시의 고민 끝에 택한 최선의 방법이었을 수 있지만, 업그레이드를 수행한다고 보기는 어렵습니다.

function pause() external onlyCLevel whenNotPaused {
paused = true;
}

function setNewAddress(address _v2Address) external onlyCEO whenPaused {
newContractAddress = _v2Address;
ContractUpgrade(_v2Address);
}

function unpause() public onlyCEO whenPaused {
require(saleAuction != address(0));
require(siringAuction != address(0));
require(geneScience != address(0));
require(newContractAddress == address(0));

// Actually unpause the contract.
super.unpause();
}

스마트 컨트랙트를 업그레이드할 수 있는 방법은 없을까?

지금까지 스마트 컨트랙트 코드가 변경 불가능하다는 사실이 초래하는 문제점들과 이를 통해 업그레이드 가능한 스마트 컨트랙트의 필요성을 살펴보았습니다.

정말 스마트 컨트랙트 코드를 업그레이드하는 방법은 없는 것일까요?

결론부터 말씀드리자면, 이미 배포된 코드를 수정하는 것은 불가능하지만 비즈니스 로직 자체를 업데이트하는 것이 불가능한 것은 아닙니다. 전체 프로그램이 처음부터 비즈니스 로직이 업데이트 가능한 구조를 갖춘 채로 배포된다면 지속적인 업데이트가 가능합니다.

앞으로 이어지는 글들을 통해 업데이트 가능한 스마트 컨트랙트가 어떤 구조인지, 어떻게 작동하는지에 대해 구체적으로 알아보도록 하겠습니다. 해치랩스가 앞선 질문에 답하기 위해 제시했던 여러 아이디어들과 최종적으로 가장 편리하고 효율적인 구조를 찾아내기까지의 과정을 상세히 공유해드릴 예정입니다. ‘업그레이드 가능한 스마트 컨트랙트 프레임워크 시리즈’는 총 4편으로 연재될 예정입니다. 감사합니다.

해당 연구는 서울대학교 블록체인 학회 디사이퍼(Decipher)와 협력하여 진행하였음을 밝힙니다.

--

--