플라네타리움 엔지니어링 스낵

Libplanet 0.11–0.19 업데이트 요약

(한국어English)

안녕하세요. 오랜만에 소식 전합니다. Libplanet1은 지난 몇 달 동안, 여러 마이너 버전을 릴리스했습니다. 그렇지만 저희의 릴리스 정책과 주기가 바뀜에 따라, 그리고 Libplanet으로 만들어진 첫 게임 〈나인 크로니클〉 메인넷의 여러 문제들에 대응하느라 차분히 그간의 업데이트를 정리된 글로 쓸 여유가 없었습니다. 그래서 이번 글에서 그 사이의 변화 중 큰 것들을 중심으로 소개해 볼까 합니다.

달라진 릴리스 주기

이전까지 Libplanet은 릴리스 주기에 뚜렷한 규칙이 없었습니다. 주로 큰 API 변경이 있거나 마지막 릴리스 이후로 시간이 많이 지났을 때 그 동안의 변경을 모아서 새 버전 번호를 부여하는 것에 가까웠습니다.

그러나 지난해 〈나인 크로니클〉 메인넷 (이하 메인넷) 출범 이후, 메인넷의 크고 작은 문제들을 해결해 나가기 위해 Libplanet도 그에 발맞춘 잦은 릴리스가 이뤄져야 했습니다. 현재 플라네타리움의 Libplanet 팀과 〈나인 크로니클〉 팀은 긴밀히 협력하며 릴리스 주기를 맞추고 있습니다. 이러한 기조는 한동안 바뀌지 않을 것으로 보입니다.

그러한 방침 아래, 지난 몇 달 동안 릴리스된 Libplanet 버전으로는 올해 3월에 나온 0.11.0부터 금주에 나온 0.19.0까지 총 9번의 마이너 업데이트가 있습니다.

프로토콜 버전

0.11.0 버전에서 추가됨.

프로토콜 버전은 블록에 붙는 속성으로, 해당 블록이 어떤 Libplanet 버전을 써서 마이닝됐는지 기록합니다. 프로토콜 버전은 Libplanet을 이용해 만들어진 게임이 Libplanet 버전을 쉽게 업그레이드할 수 있도록 도우며, 한편으로는 Libplanet 쪽에서 기존의 네트워크를 유지하면서도 기능을 추가할 수 있게 합니다.

API 측면에서는 Block<T>.ProtocolVersion 속성으로 확인할 수 있으며, 32비트 정수형으로 표현됩니다. 표현되는 프로토콜 버전은 Libplanet의 패키지 버전과는 별개의 네트워크 프로토콜의 버전인데, 패키지 버전의 패치 릴리스는 프로토콜 버전이 올라갈 수 없고 반드시 마이너 및 메이저 릴리스할 때만 프로토콜 버전도 함께 증가됩니다.2

0.19.0 버전 현재 프로토콜 버전은 2이고, 프로토콜 버전이 도입된 0.11.0 버전 미만에서 생성된 블록은 모두 프로토콜 버전 0으로 취급됩니다.

네트워크 트랜스포트 레이어

0.11.0 버전에서 추가됨.

오랫동안 Libplanet은 네트워크 통신에 있어 많은 저수준 처리를 ZeroMQ의 .NET 구현인 NetMQ에 맡겨 왔습니다. 하지만 모바일이나 웹 등 여러 플랫폼에서도 Libplanet을 쓸 수 있도록, NetMQ에 의존하지 않고도 네트워크 통신이 가능하게 바뀔 필요가 있었습니다.

네트워크 트랜스포트 레이어는 저수준 통신 방식을 다양화하고, 특수한 요구사항이 있을 경우 게임 개발자도 직접 저수준 통신 방식을 정의하여 쓸 수 있도록 추가된 실험적인 추상화 계층입니다.

API 측면에서는 ITransport 인터페이스로 표현되며, 이를 구현한 NetMQTransport 클래스가 기본 제공됩니다.

시범 단계이기에 인터페이스는 현재 여러 마이너 릴리스에 걸쳐 조정되고 있으며, 아직 게임 개발자가 직접 정의한 트랜스포트 구현을 사용할 수는 없습니다. 연내에는 NetMQTransport를 대체할 새로운 TCP 기반 트랜스포트 구현과 함께 Swarm<T> 객체가 사용자 정의 트랜스포트를 쓰도록 설정 가능해질 예정입니다.

교체 가능한 작업 증명 해시 알고리즘

0.12.0 버전에서 추가됨.

이전까지 Libplanet은 작업 증명에 SHA-256 해시 알고리즘을 써 왔습니다. 그러나 0.12.0 버전부터는 네트워크마다 IBlockPolicy<T>.GetHashAlgorithm() 메서드를 정의하여 해시 알고리즘을 선택할 수 있게 됐습니다. 네트워크마다 다르게 할 수 있을 뿐만 아니라 블록 인덱스에 따라 다른 해시 알고리즘을 쓸 수도 있기 때문에, 네트워크 출범 이후에도 다른 해시 알고리즘으로 쉽게 이행할 수 있습니다.

.NET 런타임에 정의된 HashAlgorithm 추상 클래스의 서브클래스라면 모두 해시 알고리즘으로 사용할 수 있습니다. 서브클래스는 꼭 .NET 런타임에서 제공하는 것으로 국한되지 않으며, 사용자가 직접 상속 받아 구현하거나 NuGet 등으로 제공되는 서드파티 라이브러리에서 정의한 것도 쓸 수 있습니다. 이를테면 플라네타리움에서 직접 만든 RandomX의 .NET 바인딩 라이브러리인 RandomXSharp 역시 HashAlgorithm의 서브클래스를 제공합니다.

다음 코드는 1만번째 블록까지는 SHA-256을 쓰고 그 뒤부터는 SHA-512를 쓰도록 블록체인 정책을 설정하는 예입니다.

HashAlgorithmType GetHashAlgorithm(long index) =>
    index <= 10_000
        ? HashAlgorithmType.Of<SHA256>()
        : HashAlgorithmType.Of<SHA512>();

논블로킹 렌더러

0.14.0 버전에서 추가됨.

노드의 로컬 블록체인의 상태가 변화를 이벤트로 수신할 수 있는 IRenderer<T>IActionRenderer<T> 인터페이스는 별도의 스레드를 만들지 않는 대신 렌더링 로직이 블로킹으로 동작합니다. 이를테면, 렌더링 로직이 Thread.Sleep(60_000)을 호출한다면 블록체인의 다음 상태 변화는 60초의 렌더링을 기다린 뒤에 이뤄진다는 것입니다.

0.14.0 버전부터는 시간이 소요되는 렌더링 로직을 별도 스레드에서 논블로킹 방식으로 실행할 수 있게 해주는 NonblockRenderer<T>NonblockActionRenderer<T> 데코레이터 클래스가 도입됐습니다. 두 클래스는 생성자에서 다른 렌더러를 인자로 받아, 해당 렌더러의 이벤트 핸들러를 별도 스레드에서 호출합니다. 따라서 기존의 렌더러 구현을 한 번 감싸는 것만으로 논블로킹 방식으로 전환할 수 있습니다.

논블로킹 방식이지만 내부적으로는 대기열이 존재하며, 따라서 이벤트의 순서는 보장됩니다.

마이너가 설정 가능한 트랜잭션 선호 함수

0.17.0 버전에서 추가됨.

마이닝할 블록에 포함할 트랜잭션들은 IBlockPolicy<T>.ValidateNextBlockTx() 서술 메서드를 만족하기만 한다면, 프로토콜에서 정해진 우선순위는 없습니다.3 그렇지만 아직 블록에 포함되지 않는 트랜잭션이 너무 많을 때는 한 블록에 너무 많은 트랜잭션을 다 넣을 수 없기 때문에, 어떤 트랜잭션을 이번 블록에 포함시키고 어떤 트랜잭션을 나중 블록으로 미룰지 줄을 세워야 합니다.

0.17.0 버전부터는 어떤 트랜잭션부터 블록에 넣을지 그 기준을 Libplanet이 임의로 정하는 대신 마이너가 정할 수 있게 됐습니다. API 측면에서는 BlockChain<T>.MineBlock() 메서드IComparer<Transaction<T>> 타입의 옵션 txPriority가 생겼습니다.

블록 서명

0.18.0 버전에서 추가됨.

프로토콜 버전 2, Libplanet 버전 0.18.0부터 블록은 마이너의 비밀 키로 서명되며 블록에는 마이너의 주소 뿐만 아니라 공개 키가 포함됩니다.

API 측면에서는, 블록의 서명은 Block<T>.Signature 속성에 담기고 마이너의 공개 키는 Block<T>.PublicKey 속성에 담기게 됩니다. 프로토콜 버전 1 및 0의 블록에서는 두 속성이 모두 null로 비어 있습니다.

병렬 프로세스 마이닝

0.19.0 버전에서 추가됨.

Libplanet 0.19.0 버전부터는 블록 마이닝이 자동으로 해당 기기의 프로세서 코어 수에 따라 병렬로 수행됩니다. 마이너가 직접 활용할 프로세스 수를 조절하는 옵션은 추후 버전에서 추가될 예정입니다.

그 외

그 외에도 수많은 기능이 더해졌을 뿐만 아니라, 몇 달 동안의 메인넷 운영에서 발생한 문제를 해결하며 많은 영역에서 크게 안정화 됐습니다. 자세한 내용은 각 버전의 전체 변경 내역에서 확인해 주세요.

호기심이 생기신 분들은 설치해서 이용해 보시고, 궁금한 점이 있으시다면 저희 팀이 상주해 있는 디스코드에도 놀러오세요!


  1. Libplanet은 분산 P2P로 돌아가는 온라인 멀티플레이어 게임을 만들 때, 매번 구현해야 하는 P2P 통신이나 데이터 동기화 등의 문제를 푸는 공용 라이브러리입니다. ↩︎

  2. 모든 메이저 및 마이너 릴리스가 프로토콜 버전을 증가시키는 것은 아닙니다. 사실, 대부분의 릴리스는 프로토콜 버전을 증가시키지 않습니다. ↩︎

  3. 물론 같은 서명자의 트랜잭션들 사이에는 Transaction<T>.Nonce를 기준으로 정해지는 순서가 있습니다. ↩︎

플라네타리움은 게임에 특화된 오픈 소스 P2P 라이브러리 Libplanet과, 그 위에서 중앙 서버 없는 온라인 게임 〈나인 크로니클〉을 만들고 있습니다. 저희와 흥미로운 기술적 도전을 함께 하실 분들을 모시고 있습니다. 지금 인재 영입 페이지를 확인해주세요!