Ethereum
solidity
SmartContract
ブロックチェーン
DApps

CryptoKittiesとは

logo.png
https://www.cryptokitties.co/

イーサリアム・ブロックチェーン上の猫育成ゲーム・CryptoKitties。
2017年末にリリースされるや否や、たちまちイーサリアム・ネットワークを大混雑させるほどの人気を獲得しました。
子猫の売買、繁殖を行いますが、レアな特徴を持つ猫や繁殖させやすい猫、世代が古い猫は高値で取引される傾向にあります。

CryptoKittiesソースコード

CryptoKittiesソースコード(EthFiddle)

Снимок экрана 2018-02-27 в 0.26.36.png

↑まずは全て見てみましょう!

概要

CryptoKittiesのコードは、いくつものコントラクトに分けられています。
KittyCoreはそれまでのコントラクトの内容を全て継承しているのがわかります。

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

それでは各コントラクトを一つずつ見ていきましょう。

1. contract KittyAccessControl

このコントラクトは、マネージメントに関するものであり、ゲーム内容と直接的な関係はありません。セッターメソッドを含んでおり、CEO、CFO、COOという特定のイーサリアムのアドレスにコントラクトの特定の関数に特別な権限を持たせるようにしています。

このコントラクトは、例えばCEOアドレスのみが関数を実行できるよう制限するonlyCEOという関数修飾詞の定義を持ち、コントラクトや資金引き出しの停止を可能にするpause関数を含んでいます。

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()関数はおそらく、予期せぬバグなどあった場合に開発者がコントラクトをアップデートできるよう加えられています。
ですがLoom networkのメンバー・Lukeによるとこの関数を使って開発者は完全にコントラクトをフリーズできてしまうそうです・・・!大丈夫だとは思いますが、万一そうなってしまうと猫の売買やブリードができなくなってしまいます。
イーサリアム上にあるというだけで、DAppsは完全に分散化されていると思われがちですが、そうとも限らないことが見て取れます。

2. contract 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— もし猫が妊娠中であれば、父親となる相手の猫のIDを設定する。妊娠していない場合は0。
  • cooldownIndex— 現在のクールダウン時間のインデックス。ブリーディング後、再度ブリーディングするまでにどのくらい待つか、インデックスごとに時間が決められている。
  • generation — 猫の「ジェネレーション数」。親のジェネレーション数にプラス1されたものになる。最もはじめの猫達はジェネレーション0。

ちなみにゲーム中では、猫は性別を持たず、どの猫同士であっても交配可能です。

猫の構造体を定義したら、次にこれら猫構造体の配列を宣言します。

Kitty[] kitties;

この配列は存在する全ての猫のデータを含んでいるので、いわばマスターの猫データベースのようなものです。新たな猫が生まれるたびにこの配列に追加され、そのインデックスが猫のIDとなります。例として、こちらのGenesis猫のIDは1です。


Снимок экрана 2018-02-27 в 20.01.23.png

またこのコントラクトは猫のIDから猫の所有者を参照するマッピングを含んでいます。
元の所有者から新しい所有者に猫を移動するたびに、このkittyIndexToOwnerマッピングは新たな所有者を反映するようアップデートされ、誰が猫の所有者か常に追跡しています。

mapping (uint256 => address) public kittyIndexToOwner;

↓6行目でマッピングを新しい所有者に更新(クリックでテキストとして開きます。)
Снимок экрана 2018-02-27 в 23.28.48.png

次に、猫が生まれるとき何が起こっているか見ていきましょう。
_createKittyという関数が呼び出されますが、まずは以下にて関数の内容をご覧ください。(クリックでテキストとして開きます。)
kittycode.png

_createKitty関数は、母猫及び父猫のID、猫の世代数、256ビットの遺伝子コード、所有者のアドレスをパラメーターとして持っています。
この関数では猫を生成してマスターのKitty配列に格納した後(25行目〜)、_transfer()関数を呼び出して(52行目〜)、猫を所有者の元へ割り当てます。

少し長かったのでまとめると、このコントラクトで以下のことがわかりました。

  • 猫が整数の集まりであること
  • 猫が配列としてブロックチェーン上に保存されること
  • 猫の所有者をどのようにトラッキングしているか

3. contract KittyOwnership

CryptoKittiesのトークン仕様はERC721に準拠しており、このコントラクトではベーシックなERC721準拠のNFT(Non-fungible token:非代替トークン)のトランザクションに必要なメソッドが記述されています

NFTとは、代替不可能なトークン、つまりそれぞれのトークンがそれ特有の特徴を持つトークンのことです。例えば、EtherはNFTではありません。なぜなら、ある1Etherと別の1Etherは全く同じであり、それぞれを入れ替えることが可能です。

NFTはデジタルなコレクション資産に向いており、トークンが個性や所有者情報を持つことができます。例えばNFTをデジタルなトレーディングカード、ゲームのレアアイテムのようなものとすれば、その所有者情報をトラックすることが可能です。

NFTの詳細に関しては、こちらの記事をご参照ください。

『仮想子猫経済を支える ERC721』
https://m0t0k1ch1st0ry.com/blog/2017/12/19/erc721/

ではコントラクトを見ていきます。
以下のように、KittyOwnershipERC721コントラクトを継承しています。

contract KittyOwnership is KittyBase, ERC721 {

ERC721のトークンは全て同じ基準に従うこととなりますので、KittyOwnership関数も以下の関数を実装しています。(クリックでテキストとして開きます。)
Снимок экрана 2018-02-28 в 14.00.12.png

これらのメソッドはパブリックであるため、他のERC721トークンと同じようにCryptoKittiesトークンが利用できるようスタンダードな方法を提供します。
自分のトークンを他の人に転送する際、Webインターフェイスを経由せずにイーサリアム上のCryptoKittiesコントラクトと直接対話することになります。
つまりあなたはクリプトキティを直接的に所有しているということになりますね。

これら全メソッドの実装についてはここでは扱いませんが、こちらのEthFiddleで"KittyOwnership"を探してチェックしてみてください。

4. contract KittyBreeding

ここでは、猫をブリーディングするのに必要なメソッドが記述されています
このコントラクト外に、猫同士の遺伝子を組み合わせるgeneScienceコントラクトというものがあるんですが、これは残念ながらオープンソースではありません。

それを踏まえて以下KittyBreedingコントラクト内容を見ていきます。
(クリックでテキストとして開きます。)
Снимок экрана 2018-02-28 в 19.20.48.png

externalな関数setGeneScienceAddressはonlyCEOの修飾詞を持ち、CEOだけが引数にアドレスを設定して子猫の遺伝子を決定する関数を呼び出すことができます。

このロジックをみんなが見れてしまうと、どんな猫同士を掛け合わせればレアな猫が生まれるかわかってしまい面白くないですからね。

外部のgeneScienceコントラクトは、新しく生まれる猫の遺伝子を決めるために後ほどgiveBirth()関数でも出てきます。

ではブリードするとき何が起こるのか見ていきましょう。(クリックでテキストとして開きます。)
Снимок экрана 2018-03-01 в 16.25.14.png

breedWith関数は、引数として受け取った母猫と父猫のIDをマスターのKitty配列で探し、母猫にsiringWithIdをセットします。
siringWithIdは上記の2.KittyBaseコントラクトで説明したように、母猫に父猫のIDを紐付け妊娠中とする変数です。0の場合は妊娠していません。

またbreedWith関数内でtriggerCooldown関数を呼び出し、親猫両方がクールダウン中になるよう設定しています。triggerCooldown関数もこのコントラクト内に定義されていますが、ここでの説明は省略します。

次に、新たな猫を生成するpublicのgiveBirth()関数を見ていきます。
(クリックでテキストとして開きます。)
givebirth.png
この関数内では、まず初めに母猫が子猫を生める状態にあるかをチェックします。
そのあと、34行目以降geneScience.mixGenes()関数を用いて生まれる子猫の遺伝子を決定し、子猫の所有権を母猫の所有者に割り当てます。そしてKittyBaseコントラクト内で扱った_createKitty()関数を呼び出し、猫データを生成します。

ちなみにgeneScience.mixGenes()関数は、CryptoKittiesをワクワクするゲームにしてくれているとても大事なものです。そのため仕様の詳細はクローズドですが、引数を見ると両親の猫の遺伝子、母親のcooldownEndBlockを利用する関数だとわかります。
Снимок экрана 2018-03-02 в 4.29.39.png

5. contract KittyAuctions

このコントラクトでは、猫の売買及び貸し出しに関するメソッドを扱います
CryptoKittiesは、通常の猫の販売、そしてブリーディングのために猫を貸し出す2つのオークション機能を持ちます。CryotiKittiesの開発者曰く、それぞれの機能を別のコントラクトとすることで所有者が追跡できなくなるといったバグのリスクを回避しつつ、アップグレードを可能にしているとのことです。

そのためこのKittyAuctionsコントラクトは、setSaleAuctionAddress()setSiringAuctionAddress()の2つの関数を持っています。これらは前出のsetGeneScienceAddress()のようにCEOのみが呼び出せ、外部コントラクトアドレスを利用できる関数です

こういった仕様は、オークションのルールを記したコントラクトのアドレスを容易に変更できることを表します。バグの修正の際など開発者にとっては便利なのかもしれませんが、ユーザーとしては注意を払うべき点です。

非常に長くなってしまいますので、オークションについてはここまでにしておきます。
関心がある方はこちらのEthFiddleで"KittyAuctions"を探してチェックしてみてください。

6. contract KittyMinting

このコントラクトは、Gen0の猫を生成するためのメソッドを持っています。Gen0はプロモーション配布用の猫は5000匹まで、その他のGen0猫は45000匹までの作成と制限されています。
通常のGen0猫は生成後すぐに、あるアルゴリズムによって決められた値段で売りに出されます。

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

以下、COOがプロモーション用の猫と通常のGen0猫を作るためのメソッドです。
(クリックでテキストとして開きます。)
Снимок экрана 2018-03-02 в 1.07.45.png
4行目createPromoKitty()関数はonlyCOO修飾詞を持ち、COOアドレスが自由に好きな遺伝子の猫を生成して任意の相手に送ることができるようになっています。ですがこれはおそらく初期のベータ版でプロモーションなどの目的で使うためのものでしょう。

17行目createGen0Auction()関数にも、COOが新たなGen0猫を生成する遺伝子コードを渡します。 ただし、ここでは任意の所有者アドレスに送るのではなく、オークションに出すようになっています。

7. contract KittyCore

これはCryptoKittiesでのメインのコントラクトとなります。ブロックチェーン上でコンパイルされ動いているもので、これまで扱ってきたコントラクトを継承しまとめています。

この構造のおかげで、KittyCoreはこれまで見てきたコントラクトの内容全てを継承しており、さらに最終的にメソッドを付け加えています。例として、以下のgetKitty関数を見て見ましょう。(クリックでテキストとして開きます。)
Снимок экрана 2018-03-02 в 2.00.05.png

これは特定の猫のデータをブロックチェーン上から取得するパブリックなメソッドです。このメソッドでウェブサーバーから猫データを参照し、サイトに猫を表示しているのでしょう。

Solidityのコントラクトは、猫の画像や自己紹介文(自動で生成されます)を含みません。上のコードでわかるように、猫は遺伝子情報を表すuint256からできていて、それがCryptoKittiesのウェブサーバーで猫の姿に変換されているのです。

CryptoKittiesは、イーサリアム上にあるゲームとして素晴らしい実例だということができます。ですがブロックチェーン上にあるのはあくまで猫の遺伝子コードだけで、可愛らしい姿の画像はサーバーにあるのですかra,100%ブロックチェーン上に構築されたものではありません。

実はコントラクトコード中にERC721Metadataというコントラクトがあるのですが、これはどこにも使われていません。あくまで憶測になりマウが、当初はブロックチェーン上に全てを乗せようとしていたけれど、あまりにコストがかかるので途中でウェブサーバーも利用することにしたのかもしれません。

まとめ

今回の記事では次のことを扱いました。

  • 猫はデータで表されていること
  • 存在する猫は一つのコントラクトに格納されており、所有者とも紐づけられていること
  • Gen0猫の生成
  • 猫のブリーディング/子猫の生成

説明を省略した部分もありますが、少しでもご参考になりましたら幸いです!
長い記事となりましたが、最後までお読みいただきありがとうございます!
より深くDAppsゲームについて理解したい方は、ぜひ私たちのコードレッスンもチェックしてください!

CryptoZombies(日本語ver.もあります!もちろん全て無料です!)

CryptoZombies.png

当記事は、How to Code Your Own CryptoKitties-Style Game on Ethereum(James Martin Duffy)をベースに作成しています。 Thank you, James!


フォローをお願いします!

Github | Telegram | Twitter | Medium
Visit us at: https://loomx.io
Contact us: team@loomx.io
logo.png