CryptoKitties проделали отличную работу по демонстрации того, какие блокчейны можно использовать, помимо простых финансовых транзакций.

Я надеюсь, что в будущем мы начнем видеть гораздо более инновационные способы использования блокчейна для подобных игр, поэтому я хотел написать краткое пошаговое руководство по коду CryptoKitties, чтобы показать, как это реализовано на поверхности.

Эта статья написана для разработчиков, и хотя она не является введением в Solidity для новичков, я попытался включить ссылки на документацию, чтобы сделать ее максимально доступной для разработчиков всех уровней.

Давайте погрузимся в…

Исходный код CryptoKitties

Почти весь код CryptoKitties имеет открытый исходный код, поэтому лучший способ понять, как он работает, - это прочитать исходный код.

Всего около 2000 строк, поэтому в этой статье я собираюсь пройти только по тем разделам, которые я считаю наиболее важными. Но вот копия полного кода контракта на EthFiddle, если вы хотите прочитать ее самостоятельно:



Обзор высокого уровня

Если вы не знакомы с тем, что такое CryptoKitties, это, по сути, игра для покупки, продажи и разведения цифровых кошек. Каждая кошка имеет уникальный внешний вид, который определяется ее генами, и когда вы разводите двух кошек вместе, их гены объединяются уникальным образом, чтобы произвести потомство, которое затем можно развести или продать.

Код для CryptoKitties разделен на несколько более мелких контрактов , чтобы связать связанный код вместе, не создавая единого гигантского файла со всем в нем.

Субподряд наследование по основному договору котенка выглядит так:

contract KittyAccessControl
contract KittyBase is KittyAccessControl
contract KittyOwnership is KittyBase, ERC721
contract KittyBreeding is KittyOwnership
contract KittyAuction is KittyBreeding
contract KittyMinting is KittyAuction
contract KittyCore is KittyMinting

Таким образом, KittyCore - это, в конечном счете, адрес контракта, на который указывает приложение, и он наследует все данные и методы из предыдущих контрактов.

Давайте рассмотрим эти контракты один за другим.

1. KittyAccessControl: Кто контролирует контракт?

Этот контракт управляет различными адресами и ограничениями для операций, которые могут выполняться только определенными ролями. А именно генеральный директор, финансовый директор и главный операционный директор.

Этот контракт предназначен для управления контрактом и никак не связан с игровой механикой. Он в основном имеет методы «установщика» для «CEO», «COO» и «CFO», которые представляют собой адреса Ethereum, которые имеют особую собственность и контроль над конкретными функциями контракта.

KittyAccessControl определяет некоторые модификаторы функции, такие как onlyCEO (который ограничивает функцию так, чтобы ее мог выполнять только генеральный директор), и добавляет методы для выполнения таких действий, как приостановка / возобновление контракта или снятие средств:

modifier onlyCLevel() {
    require(
        msg.sender == cooAddress ||
        msg.sender == ceoAddress ||
        msg.sender == cfoAddress
    );
    _;
}
//...some other stuff
// Only the CEO, COO, and CFO can execute this function:
function pause() external onlyCLevel whenNotPaused {
    paused = true;
}

Функция pause(), вероятно, была добавлена ​​для того, чтобы разработчики могли обновить ее до более новой версии в случае каких-либо непредвиденных ошибок ... Но, как указал мой коллега Люк, это фактически позволило бы разработчикам полностью заморозить контракт, сделав его таким никто не может передавать, продавать или разводить своих котят! Не то, чтобы они когда-либо захотели это сделать, но это интересно отметить, поскольку большинство людей полагают, что DApp полностью децентрализован только потому, что он находится на Ethereum.

Двигаемся дальше…

2. KittyBase: Что такое Китти на самом деле?

Здесь мы определяем самый фундаментальный код, который используется во всех основных функциях. Это включает в себя наше основное хранилище данных, константы и типы данных, а также внутренние функции для управления этими элементами.

KittyBase определяет множество основных данных приложения. Во-первых, он определяет Китти как структуру:

struct Kitty {
    uint256 genes;
    uint64 birthTime;
    uint64 cooldownEndBlock;
    uint32 matronId;
    uint32 sireId;
    uint32 siringWithId;
    uint16 cooldownIndex;
    uint16 generation;
}

Так что на самом деле котенок - это просто набор беззнаковых целых чисел… я полагаю.

Разбивая каждую часть этого:

  • genes - 256-битное целое число, представляющее генетический код кошки, основной фрагмент данных, который определяет, как кошка выглядит.
  • birthTime - метка времени блока, когда родился кот
  • cooldownEndBlock - минимальная отметка времени, по истечении которой кошка может снова заниматься разведением
  • matronId & sireId - ID матери и отца кошки соответственно
  • siringWithId - устанавливается идентификатор отца, если кошка в настоящее время беременна, в противном случае - ноль.
  • cooldownIndex - текущая продолжительность восстановления для этой кошки (сколько времени кошка должна ждать после размножения, прежде чем она сможет снова размножаться)
  • generation - «номер поколения» этого кота. Первые кошки, отчеканенные по контракту, имеют поколение 0; поколение новых кошек - это большее из поколений их родителей плюс 1.

Обратите внимание, что в CryptoKitties кошки бесполые, и любые 2 кошки могут воспроизводиться вместе - таким образом, кошка не имеет пола.

Затем контракт KittyBase объявляет массив из этихKitty структур:

Kitty[] kitties;

В этом массиве хранятся данные обо всех существующих котятах, так что он похож на основную базу данных Kitty. Всякий раз, когда создается новый кот, он добавляется в этот массив, и его индекс в массиве становится идентификатором кошки, например, Genesis здесь имеет идентификатор 1:

Этот контракт также содержит сопоставление идентификатора кошки с адресом ее владельца, чтобы отслеживать, кому принадлежит котенок:

mapping (uint256 => address) public kittyIndexToOwner;

Определены и некоторые другие сопоставления, но для того, чтобы статья была достаточно длинной, я не буду вдаваться в подробности.

Когда котенок передается от одного человека к другому, это kittyIndexToOwner отображение обновляется, чтобы отразить нового владельца:

Теперь давайте посмотрим, что происходит, когда создается новый котенок:

Таким образом, этой функции передаются идентификаторы матери и отца, номер поколения котенка, 256-битный генетический код и адрес владельца. Затем он создает котенка, помещает его в главный массив Kitty, а затем вызывает _transfer(), чтобы назначить его новому владельцу.

Круто - теперь мы можем увидеть, как CryptoKitties определяет котенка как тип данных, как он хранит всех котят в блокчейне и как он отслеживает, кому принадлежат котята.

3. KittyOwnership: котята как жетоны

Это обеспечивает методы, необходимые для основных транзакций с невзаимозаменяемыми токенами, в соответствии с проектом спецификации ERC721.

CryptoKitties соответствует спецификации токена ERC721, невзаимозаменяемому типу токенов, который отлично подходит для отслеживания владения цифровыми коллекционными предметами, такими как цифровые игральные карты или редкие предметы в MMORPG.

Примечание о взаимозаменяемости. Эфир взаимозаменяемый, потому что любые 5 ETH так же хороши, как и любые другие 5 ETH. Но с помощью невзаимозаменяемых токенов, таких как CryptoKitties, не все кошки созданы равными, поэтому они не взаимозаменяемы друг с другом.

Из определения контракта видно, что KittyOwnership наследуется от контракта ERC721:

contract KittyOwnership is KittyBase, ERC721 {

И все токены ERC721 соответствуют одному стандарту, поэтому контракт KittyOwnership выполняет следующие функции:

Поскольку эти методы являются общедоступными, это предоставляет пользователям стандартный способ взаимодействия с токенами CryptoKitties так же, как они взаимодействуют с любым другим токеном ERC721. Вы можете передать свои токены кому-то другому, напрямую взаимодействуя с контрактом CryptoKitties в блокчейне Ethereum, без необходимости проходить через их веб-интерфейс, так что в этом смысле вы действительно владеете своими котятами. (Если только генеральный директор не приостановит контракт 😉).

Я не буду вдаваться в подробности реализации всех этих методов, но вы можете проверить их на EthFiddle (ищите KittyOwnership).

Антракт: хотите создать свою собственную игру Ethereum?

Эта статья получила массу положительных отзывов, когда была впервые опубликована, поэтому мы создали CryptoZombies: интерактивное руководство по созданию ваших собственных игр на Ethereum. Он шаг за шагом проведет вас через обучение программированию Solidity и создание собственной игры Ethereum. Если вам нравится статья, зацените!

4. KittyBreeding: кошки падают и пачкаются

Этот файл содержит методы, необходимые для совместного разведения кошек, включая отслеживание предложений по производству, и полагается на внешний контракт генетической комбинации.

«Контракт внешней генетической комбинации» (geneScience) хранится в отдельном контракте, который не является открытым исходным кодом.

Контракт KittyBreeding содержит метод, позволяющий генеральному директору установить адрес этого внешнего контракта:

Они сделали это таким образом, чтобы игра не была слишком простой - если бы вы могли просто прочитать, как определяется ДНК котенка, было бы намного легче узнать, каких кошек разводить, чтобы получить «модного кота».

Этот внешний geneScience контракт позже используется в giveBirth() функции (которую мы немного увидим) для определения ДНК новой кошки.

А теперь давайте посмотрим, что происходит, когда двух кошек разводят вместе:

Таким образом, эта функция берет идентификаторы матери и отца, находит их в главном массиве kitties и устанавливает siringWithId на матери равным идентификатору отца. (Когда siringWithId ненулевое значение, это означает, что мать беременна).

Он также выполняет triggerCooldown на обоих родителях, поэтому они не могут снова размножаться в течение определенного периода времени.

Затем у нас есть общедоступная функция giveBirth(), которая создает нового кота:

Встроенные комментарии к коду говорят сами за себя. Обычно код сначала выполняет некоторые проверки, чтобы увидеть, готова ли мать к родам. Затем он определяет гены ребенка с помощью geneScience.mixGenes(), присваивает право собственности на нового котенка владельцу матери, а затем вызывает функцию _createKitty(), которую мы рассмотрели в KittyBase.

Обратите внимание, что функция geneScience.mixGenes() - это черный ящик, поскольку этот контракт является закрытым. Таким образом, мы на самом деле не знаем, как определяются гены ребенка, но мы знаем, что это какая-то функция генов матери, генов отца и cooldownEndBlock матери.

5. KittyAuctions: покупка, продажа и прокачка кошек

Здесь у нас есть общедоступные методы аукционов или ставок на кошек или услуг по разведению. Фактическая функциональность аукциона обрабатывается в двух родственных контрактах (один для продажи и один для производителей), в то время как создание аукциона и торги в основном опосредуются через этот аспект основного контракта.

По словам разработчиков, они разделили эту функцию аукциона на «родственные» контракты, потому что «их логика довольно сложна и всегда есть риск незначительных ошибок. Сохраняя их в своих собственных контрактах, мы можем модернизировать их, не нарушая основной контракт, который отслеживает владение котенком ».

Таким образом, этот контракт KittyAuctions содержит функции setSaleAuctionAddress() и setSiringAuctionAddress(), которые, как и setGeneScienceAddress(), могут быть вызваны только генеральным директором, и устанавливает адрес внешнего контракта, который обрабатывает эти функции.

Примечание. «Отцовство» относится к сутенерству вашей кошки - выставлению ее на аукцион, где другой пользователь может заплатить вам эфир за то, чтобы ваша кошка спаривалась с их кошкой. Lols.

Это означает, что даже если бы сам контракт CryptoKitties был неизменным, генеральный директор имел возможность изменить адрес этих аукционных контрактов в дальнейшем, что изменило бы правила аукционов. Опять же, это не обязательно плохо, поскольку иногда разработчикам нужно исправлять ошибки, но кое-что, о чем следует знать.

Я не собираюсь вдаваться в подробности того, как именно обрабатывается логика аукциона и торгов, чтобы эта статья не стала слишком длинной (она уже достаточно длинная!), Но вы можете проверить код в EthFiddle (поиск по KittyAuctions ).

6. KittyMinting: фабрика кошек Gen0

Этот последний аспект содержит функции, которые мы используем для создания новых кошек gen0. Мы можем сделать до 5000 «промо» кошек, которые можно раздать (особенно важно, когда сообщество новое), а всех остальных можно только создать, а затем сразу же выставить на аукцион по начальной цене, определенной алгоритмом. Независимо от того, как они созданы, существует жесткий предел в 50 тысяч кошек gen0. После этого вся ответственность сообщества - разводить, разводить, разводить!

Количество промо-кошек и кошек gen0, которые может создать контракт, жестко запрограммировано здесь:

uint256 public constant PROMO_CREATION_LIMIT = 5000;
uint256 public constant GEN0_CREATION_LIMIT = 45000;

А вот код, в котором «главный операционный директор» может создавать промо-котят и котят gen0:

Итак, с createPromoKitty() похоже, что главный операционный директор может создать нового котенка с любыми генами, которые он хочет, и отправить его кому захочет (максимум до 5000 котят). Я предполагаю, что они используют это для первых бета-тестеров, друзей и родственников, чтобы раздавать бесплатных котят в рекламных целях и т. Д.

Но это также означает, что ваш кот может быть не таким уникальным, как вы думаете, поскольку он потенциально может напечатать 5000 его идентичных копий!

Для createGen0Auction() главный операционный директор также предоставляет генетический код нового котенка. Но вместо того, чтобы связывать его с адресом конкретного человека, он создает аукцион, на котором пользователи будут предлагать Ether, чтобы купить котенка.

7. KittyCore: генеральный контракт

Это основной контракт CryptoKitties, который компилируется и запускается в блокчейне Ethereum. Этот контракт связывает все воедино.

Из-за структуры наследования он наследуется от всех контрактов, которые мы рассматривали до этого, и добавляет еще несколько финальных методов, таких как эта функция для получения всех данных Китти с использованием его идентификатора:

Это общедоступный метод, который вернет все данные для конкретного котенка из блокчейна. Я предполагаю, что это то, что запрашивает их веб-сервер для отображения кошек на веб-сайте.

Подождите ... Я не вижу данных об изображении. От чего зависит, как выглядит котенок?

Как видно из приведенного выше кода, «котенок» в основном сводится к 256-битному целому числу без знака, которое представляет его генетический код.

В коде контракта Solidity нет ничего, что могло бы хранить изображение или описание кошки или определять, что на самом деле означает это 256-битное целое число. Интерпретация этого генетического кода происходит на веб-сервере CryptoKitty.

Таким образом, хотя это действительно умная демонстрация игры на блокчейне, на самом деле она не на 100% основана на блокчейне. Если их веб-сайт будет отключен в будущем, если кто-то не сделает резервную копию всех изображений, у вас останется только бессмысленное 256-битное целое число.

В коде контракта я нашел контракт под названием ERC721Metadata, но он никогда ни к чему не привык. Итак, я предполагаю, что они изначально планировали хранить все в блокчейне, но позже отказались от этого (слишком дорого хранить много данных в Ethereum?), И поэтому им пришлось вместо этого хранить их на своем веб-сервере.

Связывая все вместе

Хорошо ... Итак, чтобы подвести итог, мы рассмотрели:

  • Как котята представлены в виде данных
  • Как все существующие котята хранятся в едином смарт-контракте и как он отслеживает, кто чем владеет
  • Как производятся котята gen0
  • Как котят разводят вместе, чтобы образовались новые котята

Это был всего лишь обзор верхнего уровня. Если вам нужно более подробное руководство по созданию собственной игры, возможно, вас заинтересует интерактивная школа кода, которую мы выпустим в течение следующих нескольких недель.

ОБНОВЛЕНИЕ: мы выпустили интерактивную школу кода. Проверьте это на CryptoZombies.io!

Loom Network - это платформа взаимодействия с несколькими цепями для масштабирования высокопроизводительных децентрализованных приложений - уже запущенная в производство, проверенная и испытанная в боевых условиях.

Разверните свое децентрализованное приложение в Loom's Basechain один раз и охватите как можно более широкую базу пользователей во всех основных блокчейнах сегодня.

Впервые в Loom? Начните здесь.

Хотите поставить свои токены LOOM и помочь защитить Basechain? Узнайте, как.

Нравится то, что мы здесь делаем? Оставайтесь в курсе, подписавшись на нашу частную рассылку.