cryptozombiesのコードと詳解

solidityのコード無料ソフトcryptozombiesの詳解をしていきます。

少し古いですが多分今でも通用すると思います。

ぼくはプログラミング言語が初めてなので、不正確な部分もあると思いますので、

この記事は参考程度にご覧ください。

Making the Zombie Factory

全体コードの確認

全体のコードを見てみます。

1  pragma solidity >=0.5.0 <0.6.0;
2
3  contract ZombieFactory {
4
5     event NewZombie(uint zombieId, string name, uint dna);
6
7     uint dnaDigits = 16;
8     uint dnaModulus = 10 ** dnaDigits;
9
10    struct Zombie {
11        string name;
12        uint dna;
13    }
14
15    Zombie[] public zombies;
16
17    function _createZombie(string memory _name, uint _dna) private {
18        uint id = zombies.push(Zombie(_name, _dna)) - 1;
19        emit NewZombie(id, _name, _dna);
20    }
21
22    function _generateRandomDna(string memory _str) private view returns (uint) {
23        uint rand = uint(keccak256(abi.encodePacked(_str)));
24        return rand % dnaModulus;
25    }
26
27    function createRandomZombie(string memory _name) public {
28        uint randDna = _generateRandomDna(_name);
29        _createZombie(_name, randDna);
30    }
31
32 }

コードの流れを追った説明

外部からテキスト(具体的にはゾンビの名前)を入力することで、ゾンビが自動的に生成される仕組みになっています。

ユーザーからの入力
27 function createRandomZombie(string memory _name) public {
28     uint randDna = _generateRandomDna(_name);
29     _createZombie(_name, randDna);
30 }

このプロセスは、ユーザーが createRandomZombie 関数を呼び出すことから始まります。

ユーザーはこの関数にゾンビに付けたい名前(_name)を文字列として渡します。

ランダムなDNAの生成
22 function _generateRandomDna(string memory _str) private view returns (uint) {
23     uint rand = uint(keccak256(abi.encodePacked(_str)));
24     return rand % dnaModulus;
25 }

_generateRandomDna 関数が内部的に呼び出されます。

この関数は、入力された名前からランダムなDNA(数値)を生成します。

これは、入力文字列に基づいて計算されたハッシュから数値を生成し、dnaModulus(ここでは 10 の 16 乗)で割った剰余を取ることで行われます。

ゾンビの作成
17 function _createZombie(string memory _name, uint _dna) private {
18     uint id = zombies.push(Zombie(_name, _dna)) - 1;
19     emit NewZombie(id, _name, _dna);
20 }

生成されたDNAとユーザーが入力した名前を使用して、_createZombie 関数が呼び出されます。

この関数は、新しい Zombie 構造体を作成し、zombies 配列に追加します。

そして、配列内の新しいゾンビのインデックス(ID)を計算します。

※pragma solidity ^0.8.0;の場合

18   uint id = zombies.push(Zombie(_name, _dna)) - 1;

というところが

zombies.push(Zombie(_name, _dna));
        uint id = zombies.length - 1;

が正しい記載になります。

イベントの発火
19     emit NewZombie(id, _name, _dna);

NewZombie という名前のイベントが発火されます。

そのイベントに関連するデータがブロックチェーンのトランザクションログに記録されます。

コードの詳細

1 pragma solidity >=0.5.0 <0.6.0;

Solidityコンパイラのバージョンを指定します。

ここでは、バージョン0.5.0以上かつ0.6.0未満であることを要求しています。

コンパイラ:プログラミング言語で書かれたコードをコンピュータが直接実行可能な形式に変換するプログラムやソフトウェアのこと

ーーー

3 contract ZombieFactory {

ZombieFactory という名前の新しいスマートコントラクトを宣言しています。

スマートコントラクト:特定の条件が満たされた時に、自動的に特定のアクションを行うコードのセットのこと

ーーー

5 event NewZombie(uint zombieId, string name, uint dna);

新しいゾンビが作成されたときに発動するイベントNewZombieを定義しています。

このイベントは、ゾンビのID、名前、DNAをパラメータとして持っています。

event:特定のアクションが発生したことを外部に通知するために使われる。

外部:例えばフロントエンドアプリケーションやサーバー側のアプリケーション

uint:符号なし整数のこと

string:主にASCII文字やUTF-8エンコードされた文字列を表すために使用される。

ーーー

7 uint dnaDigits = 16;

dnaDigits という名前の状態変数を宣言し、16という値を代入しています。

これは、後で使用されるゾンビのDNAが16桁であることを示しています。

状態変数:プログラムがブロックチェーン上に存在する限り、その値が維持されます。

ーーー

8 uint dnaModulus = 10 ** dnaDigits;

dnaModulus という状態変数を宣言し、10の dnaDigits 乗(この場合は 10の16乗)の値を代入しています。

これは、後でDNAの値を計算する際の上限として使用されます。

ーーー

10 struct Zombie {
11         string name;
12         uint dna;
13 }

Zombie という構造体を宣言し、name(文字列型)と dna(符号なし整数型)という2つのプロパティを持たせています。

構造体:異なる型のデータを一つの単位でまとめるために使用されるプログラミングの構造

具体例Zombie という構造体name(文字列型)と dna(符号なし整数型)の2つのフィールドがあります。
これにより、各 Zombie インスタンスに名前と年齢のデータを関連付けて保存できます。

ーーー

15 Zombie[] public zombies;

Zombie 構造体のインスタンスを格納する公開(public)動的配列 zombies を宣言しています。

インスタンス:ここではゾンビの個体情報のこと。

動的配列:サイズが実行時に変更可能な配列のこと。
“[]”を使用すると動的配列を宣言することになる。

ーーー

17 function _createZombie(string memory _name, uint _dna) private { ... }

_createZombie という名前のプライベート関数を宣言しています。

この関数は string 型の _nameuint 型の _dna の2つのパラメータを取り、新しいゾンビを zombies 配列に追加します。

function:関数を宣言

プライベート関数:その定義されたコンテキスト内でのみアクセス可能な関数のこと

配列:同じデータ型の複数の要素を連続的に格納するためのデータ構造のこと。

Solidityで関数を宣言する際には、関数の可視性(publicprivateinternalexternal)、状態変更の可否(pureview)、およびその他の修飾子(payable など)を指定することが重要です。

ーーー

18 uint id = zombies.push(Zombie(_name, _dna)) - 1;

新しい Zombie インスタンスを zombies 配列に追加し、追加されたゾンビのIDを計算しています。

zombies.push(Zombie(_name, _dna)) は配列にゾンビを追加し、配列の新しい長さを返します。

新しいゾンビのインデックス(ID)は、この長さから1を引くことで得られます。

push:動的配列の末尾に新しい要素を追加し、配列の長さを増加させる。

zombiesという配列に新しいZombie個体を追加(push)する操作を行なっている。

例えば配列の長さを5とした場合、配列のインデックス(ID)は0から始まるので、最後の要素のインデックスは4になる。このため”-1”をしている

ーーー

19 emit NewZombie(id, _name, _dna);

NewZombieのイベントを発火し、この情報をスマートコントラクトの外部に通知します。

emit:イベントを発行または外部に通知すること

ーーー

22 function _generateRandomDna(string memory _str) private view returns (uint) { ... }

_generateRandomDna という名前のプライベート関数を宣言しています。

この関数は文字列 _str を入力として受け取ります。

memory:一時的なデータの保管場所
変数が関数の実行中のみ存在し、関数の実行が終了すると消去されることを意味する。

view:プログラムの状態に影響を与えず、データを読み取ることができる。

ーーー

23 uint rand = uint(keccak256(abi.encodePacked(_str)));

_str をエンコードし、keccak256 ハッシュ関数を適用します。

その結果を uint 型にキャストし、rand という変数に代入しています。

keccak256:イーサリアムのスマートコントラクト開発において使用されるハッシュ関数の一つ。
任意の長さのデータを取り、一定の長さ(256ビット)のハッシュ値を生成する。

abi.encodePacked:異なるデータ型の変数を一つのバイト列にまとめる(パックする)こと

エンコード:データを特定の形式やコードに変換するプロセスのこと

ハッシュ関数:特定の入力から固定長のハッシュ値を生成する。

ハッシュ値:ハッシュ関数によって生成される固定長の値

キャスト:あるデータ型の変数や値を別のデータ型に変換するプロセスのこと

ーーー

24 return rand % dnaModulus;

randdnaModulus で割った剰余を返しています。

これにより、DNAの値は指定された桁数内に収まります。

return:何らかのデータを処理し、その結果を戻り値として返す。

ーーー

27 function createRandomZombie(string memory _name) public { ... }

createRandomZombie という名前の公開関数を宣言しています。

この関数は _name を入力として受け取り、ランダムなDNAを持つ新しいゾンビを作成します。

ーーー

28 uint randDna = _generateRandomDna(_name);

_generateRandomDna 関数を呼び出し、得られたランダムなDNAを randDna に代入します。

ーーー

29 _createZombie(_name, randDna);

_createZombie 関数を呼び出し、_namerandDna を使って新しいゾンビを作成します。

コメントを残す

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