Exclamate EOS! : Immutable contract

Jeeyong Um
GameXCoin
Published in
9 min readSep 3, 2018

EOS와 Ethereum의 스마트 컨트랙트는 작성 언어(C++ vs Solidity), 런타임 환경(WASM vs EVM) 등 기술적인 면에서 여러 다른 점이 있지만 설계상의 가장 큰 차이는 변경가능성에 있다. 즉, 스마트 컨트랙트를 배포한 이후 수정할 수 있는가 인데 EOS는 이를 허용하고, Ethereum에서는 (원칙적으로) 불가능하다.

이는 어느 한 쪽이 절대적으로 옳은가 보다는 어떤 가치를 우선할 것인가의 문제로 EOS는 코드로 작성된 스마트 컨트랙트의 업그레이드를 허용함으로써 사용 편의를 우선하고, Ethereum은 불변성(immutability)을 통해 한 번 배포한 컨트랙트는 최초 배포한 내용 그대로 실행될 것에 대한 신뢰를 중시한다고 볼 수 있다.

물론 양자 모두 한계가 있으므로 스마트 컨트랙트 내에 포함된 리카디언 계약(ricardian contract)을 통해 코드 변경에 따른 위험성을 사후적인 법률 수단으로 보완(EOS)하거나 프록시 패턴 등 스마트 컨트랙트 내용을 우회적으로 변경하기 위한 연구(Ethereum)가 이루어지고 있다.

EOS의 가장 큰 장점은 사용자의 목적에 따라 다양한 기능을 직접 구현하여 사용할 수 있다는 것인데 이 글은 EOS에서 Ethereum 같이 변경 불가능한(immutable) 컨트랙트를 작성하는 방법에 대해 소개하고 있다.

변경 불가능한 컨트랙트

배포한 컨트랙트 코드를 변경하는 setcode 액션은 스마트 컨트랙트를 배포한 계정의 active 권한을 요구하는데, activeowner 권한을 포기¹하여 코드를 변경할 수 없게 만들 수 있다.

권한 비활성화를 통한 계정 잠금

EOS는 특정 레벨의 권한(permission level) 실행에 필요한 키(key) 또는 임의의 계정 권한을 지정할 수 있다. 계정을 생성하면 owneractive권한에 처음 입력했던 공개키가 설정된다. (로컬 노드에 testaccount 란 이름으로 계정을 생성하였다)

$ cleos create account eosio testaccount EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV$ cleos get account testaccount
permissions:
owner 1: 1 EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
active 1: 1 EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV

testaccountactive 권한에서 공개키를 삭제하고 testaccount@active 권한을 지정하면 실행 권한에 자기 자신을 다시 참조하게 되어 권한을 획득할 수 없게 된다.

$ cleos set account permission testaccount active '{"threshold": 1, "accounts": [{"permission": {"actor": "testaccount", "permission": "active"}, "weight": 1}]}'$ cleos get account testaccount
permissions:
owner 1: 1 EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
active 1: 1 testaccount@active,

마찬가지 방법으로 owner 권한도 제한한다. active 권한 변경에는 active 권한만 있으면 되지만 owner 권한 변경에는 owner 권한을 사용할 것을 명시해야 한다.²

$ cleos set account permission testaccount owner '{"threshold": 1, "accounts": [{"permission": {"actor": "testaccount", "permission": "owner"}, "weight": 1}]}' -p testaccount@owner$ cleos get account testaccount
permissions:
owner 1: 1 testaccount@owner,
active 1: 1 testaccount@active,

이제 testaccount 계정으로 배포한 컨트랙트는 변경할 수 없게 된다. 다만 이와 같은 계정 잠금(lock up)이 의도한 것이 아니라면 영구적으로 계정을 잃을 수 있으므로 --force 옵션을 사용한 경우만 적용할 수 있도록 제한하는 패치가 검토중이다.

블록 생성자에게 권한 이전

계정 잠금 방식으로 변경 불가능한 컨트랙트를 작성하면 차후에 코드에서 심각한 문제를 발견하더라도 이를 수정할 수 없다. 권한을 제거하는 대신 블록 생성자(block producer)에게 이전하면 자의적인 코드 변경에 대한 위험성은 줄이면서도 문제가 생겼을 때 대처할 수 있다.

eosio.prods 계정은 블록 생성자 그룹을 가리키는데 권한에 따라 블록 생성자 중 몇 명이 동의해야 사용 가능한지 여부가 달라진다.

eosio.prods@active // 21개 중 15개 이상 동의
eosio.prods@prod.major // 21개 중 11개 이상 동의
eosio.prods@prod.minor // 21개 중 8개 이상 동의

eosio.prods 로 권한 변경 후 문제가 발생하면 블록 생성자 그룹의 동의를 받아 계정의 소유권을 되찾거나 코드를 업데이트 할 수 있다. 단, eosio.prodsowner 권한은 없으므로 설정하지 않도록 주의해야 한다.

일정 시간 동안 변경 불가능한 컨트랙트

Jonathan Lei는 일정 시간 동안 변경이 불가능한 컨트랙트를 만드는 Temporary Immutable Contract 패턴을 제안하였다. 가상 권한인 eosio.code 를 사용하는데 eosio.code 는 배포된 컨트랙트 코드 자체가 갖는 권한이다.

컨트랙트 배포자는 설정된 시간 동안 권한을 잃었다가 regain 액션을 사용하여 이를 되찾을 수 있다. owner 권한에 키를 추가하거나 특정 권한을 설정하는 액션은 owner 레벨로 실행해야 하는데 eosio.code 권한을 owner 에 추가하여 코드 스스로 owner 를 수정할 수 있게 한다 .

다음은 제안된 eosyield 컨트랙트의 코드이다.

setowner , yieldcontrol , extend , regain 4가지 액션으로 구성되어 있다.

  • setowner : 변경 제한 시간 종료 후 권한을 돌려받을 계정 이름
  • yieldcontrol : 변경 제한 시간 설정
  • extend : 변경 제한 시간 연장
  • regain : 변경 제한 시간 종료 후 호출하면 setowner 로 설정된 계정의 active 권한을 컨트랙트의 owner 권한에 추가 (권한 복구)

자신의 컨트랙트에 위 코드를 포함하여 배포한 후 다음 순서를 거쳐 변경 불가능한 시간을 설정할 수 있다. yield 라는 이름의 계정에 컨트랙트를 배포했다고 가정하자.

// yield 계정의 owner 권한에 yield@eosio.code 권한 추가
$ cleos set account permission yield owner '{"threshold": 1, "keys": [{"key": "YOUR_PUBLIC_KEY", "weight": 1}], "accounts": [{"permission": {"actor": "yield", "permission": "eosio.code"}, "weight": 1}]}' -p yield@owner
// 권한을 돌려받을 계정 지정 (testaccount 사용)
$ cleos push action yield setowner '["testaccount"]' -p yield@owner
// 변경 제한 시간 설정 (60초 지정)
$ cleos push action yield yieldcontrol '[60]' -p testaccount
// (optional) 변경 제한 시간 연장 (120초 연장)
$ cleos push action yield extend '[120]' -p testaccount
// 변경 제한 시간 종료 후 권한 복구
$ cleos push action yield regain '' -p testaccount

yieldcontrol 로 제한 시간을 설정하고 계정 정보를 조회하면 eosio.code 권한만 갖고 있는 것을 확인할 수 있다.

$ cleos push action yield yieldcontrol '[60]' -p testaccount$ cleos get account yield
permission:
owner 1: 1 yield@eosio.code,
active 1: 1 yield@eosio.code,

regain 호출 후 다시 조회하면 setowner 액션으로 사전에 설정한 계정이 owner 에 추가된다.

$ cleos push action yield regain '' -p testaccount$ cleos get account yield
permission:
owner 1: 1 testaccount@active, 1 yield@eosio.code,
active 1: 1 testaccount@active, 1 yield@eosio.code,

컨트랙트 배포자가 코드를 수정하여 이득을 얻을 수 있는 경우 사용자는 컨트랙트 사용 전에 변경 내용이 없는지 매번 검토해야 하는 부담이 있다. 이 패턴을 사용하면 사용자가 겪는 코드 변경의 위험성은 줄이되 일정 시간이 경과할 때마다 업그레이드 할 수 있는 유연한 방식의 컨트랙트를 작성할 수 있다.

결론

스마트 컨트랙트는 계약 사용의 당사자 간에 구속력을 가지는 점에서 전통적인 계약의 속성을 지니면서 취약점 수정이나 기능 업그레이드의 필요 등 컴퓨터 프로그램으로서의 성질도 동시에 지니고 있다. 계약의 불변성만이 최우선적으로 준수되어야 하는 가치라면 우회적으로라도 이를 변경, 업그레이드 하기 위한 노력은 없었을 것이다. 신뢰 없는 신뢰(trustless trust)라는 블록체인의 기본적인 동작 방식을 유지하면서 스마트 컨트랙트가 제공하는 풍부한 기능을 어떻게 활용할 수 있을지 고민이 필요하다.

[1] owner 권한이 있으면 active 권한을 복구할 수 있다.

[2] 권한이 생략되어 있으면 기본적으로 active 권한을 사용한다.

--

--