問題が何であるかがすぐに明らかになりました-CryptoKittiesプロジェクトのせいでした。 これはイーサリアムブロックチェーン上で実行される楽しいおもちゃで、ユーザーが「子猫」を繁殖させ、それらを交差させ、通常の暗号通貨トークンのように販売することを可能にします。 ある時点で、イーサリアムのすべてのトランザクションの15%が暗号子猫でした! そして、この記事が書かれた頃には、プレイヤーはすでに子猫に2300万ドルを費やしていた !
それで、私はそのような興味深いトピックを通り抜けることができなかったので、この種のゲームの作り方を伝えることにしました。 この記事(およびその続き)では、主に元のCryptoKittiesコントラクトのコードを解析することにより、Ethereumで同様のプロジェクトを作成する方法について詳しく説明します。
CryptoKittiesゲームのソースコード
CryptoKittiesのゲームコードのほとんどはオープンソースなので、その動作を理解する最良の方法はソースを読むことです。
コードには約2,000行あるため、この記事では最も重要な部分のみを説明します。 ただし、ソースコードを自分で読みたい場合は、EthFiddleオンラインIDEですぐにコピーできます。
一般的なレビュー
CryptoKittiesというゲームについて初めて耳にする場合は、その中でプレイヤーがデジタル猫を販売、購入、繁殖させることを知ってください。 それぞれの猫はユニークで、その外観は遺伝子によって決まります。 2匹の猫を交配すると、それらの遺伝子がユニークな方法で結合し、非常に特別な子猫を得ることができます。
CryptoKittiesコードは、相互接続されたいくつかの小さなコントラクトに分割されているため、すべての情報を含む1つの巨大なファイルを保存する必要はありません。
Solidityを使用すると 、 コントラクトを継承できます。子猫の場合、継承チェーンは次のようになります。
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、CFO、COOと呼びましょう。
この契約は管理に必要であり、ゲームの仕組みには適用されません。 基本的に、彼はメソッドを、契約の特定の機能を所有および制御するイーサリアムベースのアドレスである「CEO」、「COO」、および「CFO」のユーザーに帰属します。
KittyAccessControlは、たとえば、 onlyCEO
(CEOユーザーのみが実行できるように機能を制限する)などの関数修飾子を定義し、ゲームの一時停止/再開やお金の引き出しなどのアクションのメソッドも追加します。
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
ママとパパの猫のアカウント
それに応じて。 -
siringWithId
妊娠中の母親を参照するこのインジケーター
お父さんのアカウントに追加されました。 それ以外の場合、指数はゼロです。 -
cooldownIndex
猫の現在の休息時間(猫が交配してから再び繁殖できるようになるまでの時間)。 -
generation
猫の「世代番号」。 ゲームの最初の猫
ゼロ世代に属し、アザラシの後続の各世代は、親の世代よりも優れた番号1を持っています。
ゲームCryptoKittiesでは、猫は無性であり、任意の2匹の猫を交配できることに注意してください。
次に、 KittyBaseコントラクトは、ネコ科の構造の配列を定義します。
Kitty[] kitties;
この配列には、既存のすべてのシールのデータが含まれているため、これは一種の一般的なデータベースです。
新しい猫を作成すると、それが配列に追加され、配列内のそのインデックスが猫のアカウントになります。 次の例では、Genesis catアカウントは1です。
この猫の配列のインデックスは「1」です!
この契約には辞書も含まれており(Solidityではこれはマッピングと呼ばれますが、お互いを理解していると思います)、シールのアカウントと所有者の住所をリンクして、誰がこの猫を所有しているかを追跡できるようにします
mapping (uint256 => address) public kittyIndexToOwner;
契約書には他の辞書も含まれています。複雑なことは何もありません。
飼い主が猫を別の人に転送すると、 kittyIndexToOwner
辞書kittyIndexToOwner
更新され、猫と新しい飼い主の関連付けが開始されます。
/// @dev Assigns ownership of a specific Kitty to an address. function _transfer(address _from, address _to, uint256 _tokenId) internal { // Since the number of kittens is capped to 2^32 we can't overflow this ownershipTokenCount[_to]++; // transfer ownership kittyIndexToOwner[_tokenId] = _to; // When creating new kittens _from is 0x0, but we can't account that address. if (_from != address(0)) { ownershipTokenCount[_from]--; // once the kitten is transferred also clear sire allowances delete sireAllowedToAddress[_tokenId]; // clear any previously approved ownership exchange delete kittyIndexToApproved[_tokenId]; } // Emit the transfer event. Transfer(_from, _to, _tokenId);
シールを転送する kittyIndexToOwner
シールのアカウントと新しい所有者のアドレス kittyIndexToOwner
接続 kittyIndexToOwner
確立され ます 。
新しい猫を作成するとどうなるか見てみましょう。
function _createKitty( uint256 _matronId, uint256 _sireId, uint256 _generation, uint256 _genes, address _owner ) internal returns (uint) { // These requires are not strictly necessary, our calling code should make // sure that these conditions are never broken. However! _createKitty() is already // an expensive call (for storage), and it doesn't hurt to be especially careful // to ensure our data structures are always valid. require(_matronId == uint256(uint32(_matronId))); require(_sireId == uint256(uint32(_sireId))); require(_generation == uint256(uint16(_generation))); // New kitty starts with the same cooldown as parent gen/2 uint16 cooldownIndex = uint16(_generation / 2); if (cooldownIndex > 13) { cooldownIndex = 13; } Kitty memory _kitty = Kitty({ genes: _genes, birthTime: uint64(now), cooldownEndBlock: 0, matronId: uint32(_matronId), sireId: uint32(_sireId), siringWithId: 0, cooldownIndex: cooldownIndex, generation: uint16(_generation) }); uint256 newKittenId = kitties.push(_kitty) - 1; // It's probably never going to happen, 4 billion cats is A LOT, but // let's just be 100% sure we never let this happen. require(newKittenId == uint256(uint32(newKittenId))); // emit the birth event Birth( _owner, newKittenId, uint256(_kitty.matronId), uint256(_kitty.sireId), _kitty.genes ); // This will assign ownership, and also emit the Transfer event as // per ERC721 draft _transfer(0, _owner, newKittenId); return newKittenId; }
この関数は、 母親と父親のアカウント、猫の世代 、 256ビットの遺伝コード 、および所有者の住所を 「受け入れ」ます。 次に、彼女はKitty
を作成し、それをメインの猫の配列に_transfer()
、 _transfer()
コマンドを呼び出して猫を新しい所有者にバインドします。
クール-CryptoKittiesがデータタイプの形でシールを定義する方法、ブロックチェーンにシールを保存する方法、およびこの猫の所有者を追跡する方法を確認できます。
3. KittyOwnership:トークンとしての猫
このコントラクトには、ERC-721標準に準拠した基本的な交換不可能なトークン操作に必要なメソッドが含まれています。
CryptoKittiesは、ERC721トークン標準に従います 。 これは、デジタルトランプやロールプレイングゲームのレアアイテムなど、デジタルコレクションの所有権を追跡することが実証されている交換可能なトークンです。
互換性に関する 注意 :イーサリアム暗号通貨は、5つのイーサリアムが他の5つのイーサリアムと等しいため交換可能です。 しかし、CryptoKittiesのようなトークンについて話している場合、1つの猫は別の猫と同等ではないため、 交換できません 。
この契約の定義から、 KittyOwnership
がERC721
契約を継承していることがわかります。
contract KittyOwnership is KittyBase, ERC721
すべてのERC721トークンは1つの標準に準拠しているため、継承の結果として、KittyOwnership契約は次の機能を担当します。
/// @title Interface for contracts conforming to ERC-721: Non-Fungible Tokens /// @author Dieter Shirley <dete@axiomzen.co> (https://github.com/dete) contract ERC721 { // Required methods function totalSupply() public view returns (uint256 total); function balanceOf(address _owner) public view returns (uint256 balance); function ownerOf(uint256 _tokenId) external view returns (address owner); function approve(address \_to, uint256 \_tokenId) external; function transfer(address \_to, uint256 \_tokenId) external; function transferFrom(address \_from, address \_to, uint256 _tokenId) external; // Events event Transfer(address from, address to, uint256 tokenId); event Approval(address owner, address approved, uint256 tokenId); // Optional // function name() public view returns (string name); // function symbol() public view returns (string symbol); // function tokensOfOwner(address _owner) external view returns (uint256\[\] tokenIds); // function tokenMetadata(uint256 \_tokenId, string \_preferredTransport) public view returns (string infoUrl); // ERC-165 Compatibility (https://github.com/ethereum/EIPs/issues/165) function supportsInterface(bytes4 _interfaceID) external view returns (bool); }
これらのメソッドはすべて公開されているため、ユーザーはCryptoKittiesトークンとやり取りする標準的な方法があります。同様に、他のERC721トークンともやり取りできます。 Webインターフェースを使用せずに、EthereumプラットフォームでCryptoKitties契約と直接やり取りすることにより、トークンを別のユーザーに転送できるため、この意味であなたは実際にシールの所有者です。 (CEOが契約を停止しない限り)。
Ethereumでゲームを作成することに興味がある場合は、 CryptoZombiesで練習できます。Solidityでプログラミングを教えるためのインタラクティブな学校で、 ロシア語のローカライズ版があります。
サーシャ・イワノワの翻訳を手伝ってくれてありがとう!
継続する。