CryptoKittiesのコードから配合ロジックを探る


#はじめに
CryptoKittiesというEthereum上で行う猫育成ゲームが2017年の末頃に流行りました。
https://www.cryptokitties.co/

ERC721を採用する事で、猫をNon-Fungible Tokenとし、猫1匹ずつにアイデンティティを持たせて、どの猫も世界に一つしかいない代替不可なものとしています。

猫は配合する事で、新しい猫が産むことが出来、レアな猫はなんと数百万円で取引されています。
CryptoKittiesのコードは公開されているため、そのコードから配合ロジックを探りたいと思います。
<img width="1114" alt="スクリーンショット 2018-03-19 13.24.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/200669/dd9e0218-2cc6-999e-3ba0-88196daf4378.png">



[コードはこちらから参照できます](https://etherscan.io/address/0x06012c8cf97bead5deae237070f9587f8e7a266d#code)


#配合ロジックを探る
コードはいくつかのコントラクトから成り立ち、最終的に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
```

配合についてはKittyBreedingのcontractに記載されてます。


```
    function setGeneScienceAddress(address _address) external onlyCEO {
        GeneScienceInterface candidateContract = GeneScienceInterface(_address);

        // NOTE: verify that a contract is what we expect - https://github.com/Lunyr/crowdsale-contracts/blob/cfadd15986c30521d8ba7d5b6f57b4fefcc7ac38/contracts/LunyrToken.sol#L117
        require(candidateContract.isGeneScience());

        // Set the new contract address
        geneScience = candidateContract;
    }
```


```
function giveBirth(uint256 _matronId)
        external
        whenNotPaused
        returns(uint256)
    {
        // Grab a reference to the matron in storage.
        Kitty storage matron = kitties[_matronId];

        // Check that the matron is a valid cat.
        require(matron.birthTime != 0);

        // Check that the matron is pregnant, and that its time has come!
        require(_isReadyToGiveBirth(matron));

        // Grab a reference to the sire in storage.
        uint256 sireId = matron.siringWithId;
        Kitty storage sire = kitties[sireId];

        // Determine the higher generation number of the two parents
        uint16 parentGen = matron.generation;
        if (sire.generation > matron.generation) {
            parentGen = sire.generation;
        }

        // Call the sooper-sekret gene mixing operation.
        uint256 childGenes = geneScience.mixGenes(matron.genes, sire.genes, matron.cooldownEndBlock - 1);

        // Make the new kitten!
        address owner = kittyIndexToOwner[_matronId];
        uint256 kittenId = _createKitty(_matronId, matron.siringWithId, parentGen + 1, childGenes, owner);

        // Clear the reference to sire from the matron (REQUIRED! Having siringWithId
        // set is what marks a matron as being pregnant.)
        delete matron.siringWithId;

        // Every time a kitty gives birth counter is decremented.
        pregnantKitties--;

        // Send the balance fee to the person who made birth happen.
        msg.sender.send(autoBirthFee);

        // return the new kitten's ID
        return kittenId;
    }
}
```

注目するのはここ

```
uint256 childGenes = geneScience.mixGenes(matron.genes, sire.genes, matron.cooldownEndBlock - 1);
```

ここで子供の遺伝子が決定されますが、geneScienceが外部のコントラクトを参照し、コードが公開されていないため、残念ながらmixGenesの内容までは分かりません。(分かってしまったらゲーム性が無くなりますよね^^；)
ただし引数として父、母の遺伝子、母の`cooldownEndBlock`が利用される事が分かります。
geneScienceはCEOしかコントラクトアドレスを設定出来ないようにしてます。


ちなみにgeneScienceのコントラクトアドレスまでは分かりますので興味ある方はこちらから。
https://etherscan.io/address/0xf97e0a5b616dffc913e72455fde9ea8bbe946a2b#code

海外では猫の配合サンプルから解析したり、bytecodeから解析してるツワモノもいるみたいです。
https://medium.com/@kaigani/the-cryptokitties-genome-project-68582016f687
https://medium.com/@alexhegyi/cryptokitties-genescience-1f5b41963b0d
https://medium.com/@sean.soria/cryptokitties-mixgenes-function-69207883fc80

配合ロジックは分かりませんでしたが、Dappを作る上で、クローズにしたい実装が学べました。

#参考にさせて頂きました。
[CryptoKittiesコード解説](https://qiita.com/LoomNetworkJP/items/0ee486b6e01892840d7a)
[仮想仔猫ゲーム CryptoKitties のコントラクト解読その２](https://qiita.com/blueplanet/items/e257450834a5a32f0f10)