CryptoZombiesを触ってみる

巷を賑わせているCryptoZombiesを触ってみました。
感想としては、まだレッスン3までしか終わっていないですが、かなり良いです。
今まで、コントラクトコードを読んで少し疑問に思っていたことが解決されていきます。
以下は勉強になったなぁと感じたことを備忘のためにも記載していきます。

レッスン1:ゾンビファクトリーの作成

CtyptoZombiesレッスン1

まずDApps上ではblockchain = databaseです。
これがwebアプリケーションとは異なる点。

状態変数はコントラクト内に永遠に保管され続けるものだ。要するにイーサリアムブロックチェーン上に記載されるということだ。まぁDB(データベース)に書き込むようなものだと思って良い。

contract Example {
  // この部分がブロックチェーン上に記載される
  uint myUnsignedInteger = 100;
}

状態変数がブロックチェーンに記載されていきます。
これが結構重要です。

状態変数は永久にブロックチェーン上に格納されると話したことを覚えているか?こういう構造体の可変長配列は、データベースのように使えるから、コントラクトの構造データを格納する時に便利だ。

function

注:グローバル変数と区別をつけるために、関数パラメーター変数名はアンダースコア(_)をつけるのが通例(必須ではありません)です。このチュートリアルでは通例に従います。

function eatHamburgers(string _name, uint _amount) {

}

そうなのか…

public

配列をpublicで宣言すれば、Solidityが自動的にgetterメソッドを作成するぞ。

他のコントラクトもこの配列を読める(但し、書き込めない)ぞ。こういう性質を持っているから、コントラクトの公開データを格納するときに便利に使えるパターンとして覚えておくように。

私は自分のアプリにゾンビの軍隊を格納したいのだ。そして格納したゾンビを他のアプリに見せてやるために、公開したい。

関数をpublicで宣言しておけば他のコントラクトから読み取ることができます。

private

uint[] numbers;

function _addToArray(uint _number) private {
  numbers.push(_number);
}

このように書くと、この関数はコントラクト内の他の関数からだけ呼び出せて、numbers配列に格納できるようになります。

見ればわかる通り、関数名の後に privateとつけるのだ。関数のパラメーターと同様に、アンダースコア(_)で始めるのが通例だから覚えておくように。

pure/view

このケースではview関数を宣言できる。これはつまりデータの読み取り専用で編集できないということだ:

Solidityにはpure関数がある。これを使うとアプリ内のデータにすらアクセスできない。次のコードを考えてみよう:
この関数はアプリから読み込むことすらできない。つまり戻り値が関数のパラメーターのみに依存することになる。この場合pure関数として宣言することができる。

今まで、viewpureに関して、曖昧だったのでよく理解できました。

uint8 a = 5;
uint b = 6;
// a * b はuint8ではなくuintで返すから、エラーになる:
uint8 c = a * b; 
// 正しく動作させるために、bをuint8に型キャストさせる:
uint8 c = a * uint8(b);

この例ではa * bはuintを返すが、uint8で格納しようとしているから、問題が発生することになります。
uint8にキャストすることで、正常に動作する上にコンパイラもエラーを吐き出すことがなくなります。

struct

struct Person {
  uint age;
  string name;
}

Person[] public people;
// 新しいPersonを作る:
Person satoshi = Person(172, "Satoshi");

// それを配列に格納する:
people.push(satoshi);

structでグループの状態変数を宣言できる。

レッスン2

CryptoZombiesレッスン2

Solidityには全ての関数で利用できるグローバル変数が用意してある。msg.senderもその一つだ。これを使用すると、その関数を呼び出したユーザー(またはスマートコントラクト)の addressを参照できるのだ。

Storageはブロックチェーン上に永久に格納される変数だ。それとは対照的にMemoryは一時的な変数で、外部関数をコントラクトに呼び出す際に消去されるものだ。まぁ、コンピューターのハードディスクとRAMみたいなイメージでいい。

Solidityにはpublicとprivateの他に、internalとexternalという関数用のビジビリティが用意されているのだ。

うーん、かなり勉強になりました…

interface

contract NumberInterface {
  function getNum(address _myAddress) public view returns (uint);
}

function内の定義はしていないとinterfaceという分類になります。

クリプトキティーズのコントラクトのアドレスへアクセスすることでinterfaceを使ってクリプトキティーズのコントラクトにある情報を取得することができます。

指定桁数の取得方法

16 ** 10 で % すると16桁になる
途中まで意味がわかっていなかったんですが、どんな大きな数字でも10,000,000,000,000,000で割れば、余りの数は16桁になります。

レッスン3

CryptoZombiesレッスン3

まず、イーサリアムのコントラクトを実行すると、イミュータブルになる。つまり編集も更新もできなくなるということだ。

コントラクトで実行した初期のコードは永久にブロックチェーン上に残ることになる。これはSolidityにとってセキュリティが極めて重要だからだ。コントラクトに何か欠陥があっても、それをあとで修正する方法はない。その場合は、問題点を直した別のスマートコントラクトを使用してほしいと、他のユーザーに伝えるしかないのだ。

こうした理由で、大切な部分に関してはDAppを更新できる機能があったほうがいいのだ。

今回も勉強になりました…

ownerble

ではどうすれば良いかというと、一般的にはOwnable(所有権)というコントラクトを作成するのだ。これはオーナー(所有者)が特別な権限を持つことを意味するものだ。

OpenZeppelinOwnableコントラクトを使います!
ここで出てきました!OpenZeppelin

このレッスンの後で、OpenZeppelinのサイトをチェックしておくように。今後非常に役に立つだろう!

コンストラクタ: function Ownable()はコントラクタだ。これは特別な関数で、コントラクトと同じ名前だ。コントラクトが最初に作成された時に、1度だけ実行されるぞ。

関数修飾子

関数修飾子は一見関数のように見えるが、functionの代わりにmodifierを使うのでわかりやすいだろう。また、関数のように直接呼び出すことはできないから、修飾子の名前を関数定義の最後につけて、関数の動きを変更するのだ。

contract MyContract is Ownable {
  event LaughManiacally(string laughter);

  //`onlyOwner`の使い方を確認せよ:
  function likeABoss() external onlyOwner {
    LaughManiacally("Muahahahaha");
  }
}

likeABoss関数のonlyOwner修飾子を見るのだ。likeABossを呼び出すと onlyOwnerの中のコードが最初に実行されるのがわかるだろう。それからonlyOwnerの_;ステートメントをヒットした時に、likeABossに戻ってコードを実行するようになっているのだ。

オーナーに特別な力がないことを確認する必要があります。

これで権限の付与ができます!

gas

Solidityでは、ユーザーが関数を使用するたびに、ガスと呼ばれる通貨を支払うことになっている。ユーザーはEther(イーサ呼ぶ。イーサリアムの通貨だ)でガスを買い、アプリの関数を実行するのだ。

関数を実行するために必要なガスの量は、関数のロジックの複雑さによるのだ。個々の操作には、その操作を実行するためにどれくらいの計算資源が必要になるのかを計算したものに基づいて、ガスのコストが決まっている(例えば、storageは他の2つのintegerに比べて価格が高いぞ)

World of Warcraftのようなゲームをイーサリアムのメインのネットワーク上で直接動かすことは、ガスのコストが高額になることから、ありえない話です。しかし、別のアルゴリズムを使うコンセンサスのもとで、サイドチェーン上で実行することは十分考えられることです。

structの中に複数の uintがある場合、できる限り小さい単位の uintを使うことで、Solidityが変数を一つにまとめることができ、ストレージを小さくすることが可能だ。

どれだけgasを削れるかの戦いですね!

view関数にはガスが一切かからない。どれだけだくさんユーザーが呼び出しても、だ。

注:view関数は同じコントラクトの、view関数ではない別の関数から呼び出されるため、その呼び出しにガスのコストがかかります。別の関数はイーサリアム上にトランザクションを生成することから、各ノードの検証が必要になるためです。view関数は外部から呼び出す時のみ、無料になります。

Solidityで一番コストの高いのはstorageだ。特に書き込みはとても高い。

そこで、コストを抑えるために、絶対に必要な場合を除いてデータをstorageに書き込まないようにするのだ。そのため、一見非効率的なロジックを作ることもある。例えば、単純に配列を変数に保存せずに、関数を呼び出す毎にmemoryの配列を再構築するとか、だ。

うーん、gasの削減周りは奥が深そうですね…

ひとまず、レッスン3まで終わりました!
個人的にはかなり勉強になるので引き続きレッスンやっていきます!

「CryptoZombiesを触ってみる」への1件のフィードバック

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です