하얗게 불태웠어… 고크립토봇 PvP 스마트 컨트랙 개발기

JinGyeong Jeong
GoCryptobot
Published in
9 min readMay 11, 2018

확률형 아이템을 구매해 본 사람은 누구나 운영사를 한 번쯤 의심해본 적이 있을 것이다. 물론 회사는 아이템 확률도 공시하고 실제로 좋은 아이템을 뽑은 사람도 있다고 열심히 홍보하고 있다. 하지만 당장 나에게 돌아오는 아이템은 형편없는 경우가 대부분이라 확률이 제대로 지켜지고 있는지 궁금할 수밖에 없다. 통계적 검증을 통해 조작이 드러난 경우도 셀 수 없이 많고, 최근에는 이런 기사까지 나왔으니 유저들이 게임사를 의심할 수밖에 없는 것이 현실이다.

하지만 운영사 측에서도 불만이 없는 것은 아니다. 정직하게 랜덤한 확률로 아이템을 판매하는 회사도 많고, 조작이 없다는 것을 홍보하기 위해 마케팅에도 적지 않은 비용을 쓰고 있다. 게다가 가끔 한 번씩 나오는 “정말로 운이 없었던” 사람들의 불평을 없애기 위한 장치도 마련해야 한다. 덕분에 공시된 확률보다 더 높은 확률로 아이템을 제공해야 할 때도 있다. 확률에 대한 불신은 유저와 게임사 모두에게 손해일 수 밖에 없다.

코드박스는 블록체인을 이용해 이런 불신을 해소하고자 노력해왔다. 블록체인과 게임을 결합한 사례로 CryptoKitties가 자주 언급되는데, CryptoKitties는 화려하고 복잡한 게임과는 거리가 멀다. 모두가 검증할 수 있는 확률을 만들어낸 점은 높이 사지만, 온라인 게임의 정수인 유저간 상호작용은 아쉬운 점이 많다.

코드박스는 블록체인도 복잡한 상호작용, 특히 확률적 요소가 들어가는 상호작용도 충분히 구현할 수 있다는 것을 보여주고 싶어 GoCryptobot을 출시하였다. 처음 시도하는 구현 방식이다보니, 개발 과정에서도 많은 시행착오를 겪었다. 앞으로 블록체인 게임을 개발할 개발자들에게도 도움이 되길 바라는 마음으로 코드박스가 크립토 게임을 개발하면서 겪었던 문제 해결 과정을 공유하고자 한다.

고크립토봇은 어떤 게임?

고크립토봇(https://gocryptobot.io/)은 로봇의 머리, 몸통, 다리, 부스터 4개 파츠를 이용하여 런게임 혹은 PvP를 하는 모바일 게임이다. PvP의 승패 결과는 로봇 파츠로 결정되는데, PvP 모드에서 우승을 하게 되면 ERC20 토큰인 GCC(고크립토봇 코인)로 교환 가능한 게임 내 재화인 가루를 얻을 수 있다. 승패 로직은 이더리움 스마트 컨트랙으로 구현되어 있어 PvP 결과를 투명하게 확인할 수 있다.

PvP 방식

PvP는 한 팀에 32명씩 참가하여 총 128개의 로봇이 참여한다. 유저가 PvP에 참여할 때에는 어떤 조합의 로봇을 내보낼 것인지 결정해야 한다. 경기에서 이기려면 PvP의 점수가 어떻게 계산되는지 이해해야 한다.

PvP는 4개 라운드로 구성되어 있고, 각 라운드에 대응되는 파츠가 있다. 라운드의 개인 점수는 대응되는 파츠 의 레벨, 색상, 테마 효과 여부, 스킬에 의해 결정된다. 테마 효과는 4개 파츠의 테마가 일치하면 나타나는 효과다. 팀 내의 로봇들이 받은 점수를 합산하여 팀 점수를 계산하고 팀 점수가 가장 높은 팀이 우승하게 된다. 우승한 팀 내에서 개인 점수가 가장 높은 사람이 가장 많은 보상을 받게 된다.

라운드에는 2개 행운 색상이 지정되어 있다. 대응되는 파츠가 행운 색상과 맞으면 행운 색상 보너스를 받는다. PvP 스마트 컨트랙은 2개 색 중 랜덤으로 1개를 선택하는데, 선택된 색상은 행운 색상 보너스가 증가한다. 라운드가 총 4개이므로 행운 색상 선택에 따른 경우의 수가 16가지가 된다. 4개 파츠가 같은 테마로 이루어져 테마 효과가 나타나면 행운 색상 보너스가 더 높아진다. 따라서 유저는 가지고 있는 파츠 내에서 라운드의 행운 색상을 보고 최적의 조합을 찾는 것이 중요하다.

스마트 컨트랙 PvP의 장점

앞서 언급했듯 PvP는 이더리움 스마트 컨트랙(https://github.com/gocryptobot/gocryptobot-pvp-contract)으로 구현하였다. PvP가 시작할 때마다 게임 서버는 이더리움 트랜잭션을 보내고 그 결과에 따라 보상을 배분한다. 유저는 이더스캔(https://etherscan.io/)을 통해 트랜잭션 내역을 확인할 수 있다. 만약 PvP 로직에 의심이 가면 스마트 컨트랙을 직접 분석해볼 수 있다. 예를 들어, 행운 색상이 실제로 랜덤하게 선택되었는지, 내가 참여시킨 로봇의 레벨, 색상 등이 제대로 반영되어 정상적으로 계산한 결과인지를 확인해볼 수 있다.

그런데 PvP 스마트 컨트랙이 이런 장점을 살리기 위해서는 두 가지 문제를 풀어야 한다. 첫 번째 문제는 128개 로봇의 4개 파츠, 색상, 스킬을 인자로 받아 개인 점수를 계산하고 팀 점수를 합산해야 하는 것이고, 두 번째 문제는 행운 색상을 랜덤하게 결정해야 하는 것이다.

스마트 컨트랙 PvP: 가스 사용량 줄이기

우선 첫 번째를 구현할 때 가장 큰 문제가 되는 점은 가스 사용량이다. 128개 로봇을 파츠 수로 따지면 512개가 된다. 여기에 각각 파츠 레벨, 스킬 3개의 레벨, 색상, 테마 효과를 더하면 변수가 수천 개가 된다. 개발 초기 버전에서는 하나의 트랜잭션이 약 400만 가스를 사용했다. 현재 이더리움의 블록 가스 제한이 800만인 점을 생각해보면 트랜잭션 하나가 블록의 절반을 차지한 셈이다.

가스비를 계산할 때 주의해야 할 점 중 하나는 트랜잭션의 가스 제한이 마이닝 우선순위에 영향을 준다는 점이다. 이더리움 클라이언트는 몇 가지 마이닝 우선순위 옵션을 제공한다. Parity의 경우 Gas factor를 계산하는 것이 기본 설정이다. Gas factor는 가스 가격이 높을수록, 가스 제한이 낮을수록 우선순위가 높아진다. 따라서 가스를 많이 소모하는 트랜잭션은 더 비싼 가스 가격을 설정해야 같은 우선순위를 가진다. 즉, 400만 가스를 소모하는 트랜잭션은 200만 가스를 소모하는 트랜잭션보다 2배 이상 비싼 가스비를 지불해야 한다.

가스 사용량을 줄이기 위해 처음으로 한 일은 전체 데이터 크기를 줄이는 일이었다. 우선 불필요한 데이터를 없앴고, 하나의 배열 안에서 오프셋을 계산하는 방식으로 불필요한 복사 연산을 피했다. 행운 색상과 상관없이 미리 계산할 수 있는 요소는 서버에서 계산해서 인자로 넘겨주는 최적화도 했다. 연산에서도 가스 사용을 줄이기 위해 byte 타입을 정수나 enum 타입으로 변환하기도 하였다.

컨트랙 코드 내 오프셋 계산을 위한 주석

이런 식으로 400만 가스를 사용하던 트랜잭션을 약 120만 가스만 사용하도록 최적화하였다. 가스 사용량을 거의 3분의 1 수준으로 줄였기 때문에, 실제 지불하는 가스비는 3배 이상 줄었다.

스마트 컨트랙 PvP: 랜덤 선택

두 번째는 행운 색상의 랜덤 선택이다. 모든 노드가 똑같은 계산을 해서 결과를 상호 검증해야 하는 블록체인에서 랜덤을 구현하는 일은 쉽지 않다. 고크립토봇의 PvP 컨트랙은 Commitment Scheme을 사용하여 블록 해시를 얻어온다. 이 블록 해시를 랜덤 시드로 사용해서 Keccak 해시를 반복하면 랜덤한 바이트 값을 계속 얻어올 수 있다.

랜덤 선택은 GoCryptobotRandom 컨트랙에 있는 commitment()와 _initRandom(), _random256() 함수가 핵심이다. _random256()은 uint256을 반환하는 internal 함수인데, 랜덤한 uint256 값이 필요한 경우 호출해서 반환되는 값을 사용하면 된다. 내부에서는 Keccak-256 해시 함수를 사용한다. 블록체인에서 사용하는 해시함수는 Cryptographic Hash Function이어서 해시값이 Uniformly Distributed Random 특징을 가진다고 볼 수 있다. 간단히 말해 해시값이 32비트라고 가정하면 0x00000000 ~ 0xFFFFFFFF 값이 나올 확률이 모두 같다.

_random256()을 호출하기 전에 randomBytes 변수를 랜덤한 값으로 미리 설정해 두어야 하는데, 이는 _initRandom()에서 수행한다. 즉, _random256()을 사용하는 트랜잭션의 시작 부분에서 _initRandom()을 미리 호출해야 한다. _initRandom()은 어떤 블록의 블록 해시를 랜덤한 바이트로 본다. commitmentNumber가 설정이 되어 있지 않을 때에는 이전 블록의 해시를 사용한다. 문제는 이전 블록의 해시는 이미 알려진 값이기 때문에 랜덤으로 사용할 수 없다. 결과를 미리 예측할 수 있기 때문이다.

따라서 결과를 예측할 수 없도록 하기 위해 랜덤을 쓰기 전 commitment() 트랜잭션을 해야 한다. commitment()는 아직 계산되지 않은 미래의 블록 해시를 쓴다고 선언하는 역할이다. PvP를 진행하기 위해선 commitment() 트랜잭션을 보낸 뒤 해당 트랜잭션이 블록에 포함되는 것을 기다린 다음에 PvP를 진행해야 한다. 물론 PvP 트랜잭션을 보내는 시점에는 결과가 예측 가능하지만, commitmentNumber가 남아있는 한 그 결과를 임의대로 바꿀 수는 없다.

결론

현재 이더리움 게임은 명확한 한계를 가지고 있다. 유저가 수수료를 부담해야 하는 문제, 느린 트랜잭션 확정 속도, 스마트 컨트랙 구현의 높은 난이도는 게임 개발에 큰 장애물이다. 크립토키티로 대표되는 초기 블록체인 게임은 이러한 기술적 한계 때문에 게임성을 포기하였다. 하지만 쏟아지는 크립토키티의 아류 속에서 단순히 블록체인 게임을 출시했다는 것만으로는 유저의 주목을 받기 어렵게 되었다. 이제는 블록체인 게임도 기존 모바일 게임에 견주어도 부족하지 않은 게임성이 필요하다. 고크립토봇이 블록체인 게임이 지향해야 할 방향의 작은 이정표가 되길 기대한다.

고크립토봇 Android/iOS 앱은 아래 링크를 통해 다운로드 할 수 있다.

- App Store: https://apple.co/2KbMipn
- Google Play:
https://bit.ly/2K5tYhx

--

--