83
59

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Blockchain(ブロックチェーン)/ TokenEconomy(トークンエコノミー)Advent Calendar 2020

Day 5

【Solidity入門】まず最初にSolidityで覚えるべき基本構文まとめ

Last updated at Posted at 2020-05-18

前提知識

・Blockchain、Ethereum、Smart Contract 等の概念的理解
・基本的なプログラミングスキル

▼Solidity環境構築はこちらを参考にしました!▼
Ethereum スマートコントラクト入門:geth のインストールから Hello World まで

Solidityとは

スマートコントラクトを開発するために生まれたJavaScriptライクな静的型付け言語。
スマートコントラクトの開発では、現在最も利用されている言語でデファクトスタンダードと言える。

・大文字小文字は区別する
・文(Statement)最後にはセミコロン

基本記法

以下は、「Hello World!」と表示させるだけの簡単なプログラム。
このプログラムを例に簡単に説明していきます。

.js
// 冒頭でsolidityのバージョンを指定する。
pragma solidity ^0.6.7;

// contractという大きな入れ物を定義。ここに関数や変数を指定する。
contract Hello {

    string public productname='Hello World';

    // 関数定義
    function setname (string memory name1) public {
        productname = name1;
    }

    // 関数定義
    function getname () public view returns (string memory) {
        return productname;
    }
}

ここでは、バージョン「0.6.7」を指定することで,Solidityのバージョン番号が0.6.7未満ではコンパイルせず、^で0.6.7以上でも動作しないことを宣言している。

  • contractでコントラクトを定義

( Solidityで作成するコントラクトは、ブロックチェーン上のコントラクトアドレスが保持するコードとデータの集合からできている。)

contract Contract名 {
   //スマート・コントラクトで行う処理をここに記述
} 
  • functionで関数定義
  • 戻り値がある場合→明示にデータ型を定義する必要がある
  • 戻り値がない場合→定義なし

ちなみにコメントアウトはJavaScriptと同じで、
// 一行コメントはこんな感じ

/* 複数行コメントはこういう感じ */

データ型

カテゴリ    定義 意味
値型 bool     論理型
int 符号付き整数
uint 符合なし整数
string 文字列型
address       アドレス専用のデータ型
bytes バイト配列
enum         列挙
function 関数
参照型 array 配列(固定・可変)
structs 構造体
その他 mapping マッピング

値型

Solidityの値型では、変数に指定した値が直接メモリ領域に確保され、値そのものが変数に代入される。

参照型

「値を格納するメモリ上のアドレス」が変数に代入される。

また、参照型は、データの保存場所(Data location) という概念がある。

データの保存場所(Data location)

・memoryとstorage

明示しない場合は、デフォルトのデータ保存場所が使用されるが、明示することでオーバーライドできる。関数の戻り値のデフォルトはmemory、ローカル変数として宣言した場合はstorage

memoryの場合は、処理中だけ保持され、終わったら保持されない
storageの場合は、処理後、ブロックチェーンに保持される

下記はstorageとmemoryを使ったサンプルコード。ここの内容が理解できればstorageとmemoryは理解したと言って大丈夫かと思う。

.js
contract BookFactory {
  struct Book {
    string name;
    string status;
  }
 
  Book[] books;
 
  function getBook(uint _index) public {
    // この場合、コンパイラがstorageかmemoryをつけてと注意してくれる
    // Book book1 = books[_index];
 
    // ブロックチェーンに書き込む場合
    // 要素への参照を渡しているのでブロックチェーンを更新できる
    Book storage book1 = books[_index];
    book1.status = "Read!";
 
    // 値のコピーにはmemoryを使う
    // memoryの値を変更してもブロックチェーンには書き込まれない
    Book memory book2 = books[_index + 1];
    book2.status = "Read!";
 
    // memoryを使ってブロックチェーンに書き込む
    books[_index] = book2;
  }
}

・第3のデータ位置、calldata

実はまた3個目の場所 calldata がある。外部に公開する関数の場合、そのパラメータに渡される値はこれに該当する。ほとんど memory と同じ動作になる。違うのは、値の変更は不可なところ。

なお、保存先を明示しない場合にstorageに保存されるか、memoryに一時的に保存されるかの判断は、下記の通り。

強制されるデータの場合

・外部関数のパラメータ(戻り値ではない):calldata
・状態変数:storage

デフォルトデータの場合

・関数のパラメータ(戻り値):memory
・その他すべてのローカル変数:storage

基本構文まとめ

・演算

演算は基本的にJSなどと変わらない
加算(足し算): x + y
減算(引き算): x - y,
乗算(掛け算): x * y
除算(割り算): x / y
剰余(余り): x % y
累乗:x ** y

・構造体

複雑なデータ型を作成できるように構造体が用意されている。

.js

struct Person {
  uint age;
  string name;
}

・配列

固定長配列:配列の長さが決まっている

User [2] users;

可変長配列:配列の長さが決まっていない

User [] users;

構造体の配列も作れる

.js
Person[] people;

//publicで宣言することによって、コントラクト内だけでなく、外部からも呼び出しが可能になる。裏を返せば、外部からの攻撃に晒される可能性が高い。
Person[] public people;

・関数の宣言

ex).stringとuintの2つのパラメータをもつ関数

.js
function eatApples(string _impressions, uint _amount) {
//関数内の引数には、型指定をした後に「_hoge」のように頭にアンダースコア(_)を入力。
}

//関数を呼び出すときはこのように。
eatApples("yammy!", 10);

・関数はデフォルトでpublicとなっているためprivateにしたい場合は追記する
その際に関数を_(アンダースコア)から始めるようにする

・view関数とpure関数

.js
function sayHello() public view returns (string) {
//view関数ではアプリ内のデータは読み取り専用になる。
}
function _greet(string _str) private pure returns (string) {
//pure関数ではアプリ内のデータそのものにアクセスできない。

・イベント

イベントとは、ブロックチェーンに何かが生じたときに、コントラクトとフロントエンドを接続するもの。

.js
// イベントの宣言
event IntegersAdded(uint x, uint y, uint result);

function add(uint _x, uint _y) public {
  uint result = _x + _y;
  // 関数が呼ばれたことをアプリに伝えるためにイベントを発生させる:
  IntegersAdded(_x, _y, result);
  return result;
}

・マッピング(mapping)

Mappings(マッピング) データを格納する時に使う、配列のような機能。

.js
// 金融系のアプリの場合、ユーザーのアカウントの残高にuintを格納する
mapping (address => uint) public accountBalance;
// もしくは、ユーザーIdを基にユーザー名を参照・格納するために使用する
mapping (uint => string) userIdToName;

マッピングは本質的にはデータの保管と参照のためのキーバリューストア。最初の例で言えば、キーはaddress で、バリュー(値)はuint。2番目の例だと、キーは uint で、バリューは string

・msg.sender 

全ての関数で利用できるグローバル変数の1つ。関数を呼び出したユーザーのaddressを参照できる。

.js
function getApple(uint _myApple) public {
  // mappingにデータを格納する。
  favoriteApple[msg.sender] = _myApple;
}

・require

require 条件を満たさない場合はエラーを投げて実行を止める。

.js
function sayName(string _name) public returns (string) {
  // _nameが"Test"と同じかどうか比較する。真でなければエラーを吐いて終了させる。
  // Solidityはネイティブで文字列比較ができないため、文字列の比較をする際はkeccak256 を使ってハッシュ同士を比較する方法を使う。
  require(keccak256(_name) == keccak256("Test"));
  return "Hi!";
}
// sayName("Test")でこの関数を呼び出せた時のみ、"Hi!"と返ってくる。

・継承

contractの継承。クラスの継承とイメージは近い

contract 新しいコントラクト is 継承されるコントラクト {    
}

・import

別のファイルからの呼び出しを行いたい場合に利用

.js
import "./hoge.sol";
// 同じ階層から呼び出す時は、ファイル名の冒頭に「./」をつける

・Interface

他人のコントラクトから関数を宣言することができる。
使うときは関数宣言の最後に;(セミコロン)を使う。(括弧などは利用しない)

.js
contract KittyInterface  {
    function getKitty(uint256 _id) external view returns (

    bool isGestating,
    bool isReady,
    uint256 cooldownIndex,
    uint256 nextActionAt,
    uint256 siringWithId,
    uint256 birthTime,
    uint256 matronId,
    uint256 sireId,
    uint256 generation,
    uint256 genes
    );       
}

・条件分岐(if-else文)

JavaScriptの条件分岐(if-else文)の記述方法と類似した構成になる。

if (条件式a) { //条件式aがtrueならば命令aを実行
  命令a;
} else if(条件式b) { //条件式bがtrueならば命令bを実行
  命令b;
} else { //すべての条件式がfalseの時命令cを実行
  命令c;
}

solidityでは条件演算子は「? : 」を使って記述することが出来る。

条件式 ? 条件がtrueの場合に行なう処理 : 条件がfalseの場合に行なう処理

・繰り返し処理(while文・do-while文・for文)

while(条件式a) { //条件式aが満たされている場合、繰り返し処理が続く。
  命令a;
}


do { //少なくとも1度は必ず処理が実行される
命令b;
} while(条件式b); //ここで条件式の検証が行われる


for (初期値;条件式;増減式) {
  繰り返し処理
}

関数とステート変数のアクセス範囲定義

external・・・コントラクトのインタフェースであり、他のコントラクトやトランザクションから呼び出せる。内部で直接に呼び出せない。 f()はだめで this.f() はOK

public・・・コントラクトのインタフェースであり、内部か、メッセージ経由で呼び出せる。パブリックなステート変数の場合、自動的にgetter関数が生成される

internal・・・現在のコントラクトまたは派生コントラクトから呼び出せる

private・・・現在のコントラクトのみ呼び出せ、派生コントラクトから呼び出せない

単位とグローバル値

・1 ether == 10^8 wei
・時刻単位: 1 hour == 60 minutes

ブロックチェーン周りのよく使うもの抜粋

・block.gaslimit (uint): 当該ブロックの gas limit
・block.number (uint): 当該ブロックの番号
・block.timestamp (uint): 当該ブロックのタイムスタンプ、秒数
・msg.sender (address): 当該呼び出しの呼び出し元アドレス
・now (uint): block.timestamp と同じ
・tx.gasprice (uint): 当該トランザクションの gas price

参考

▼圧倒的におすすめする著書
【Solidity】ブロックチェーン・スマートコントラクト開発入門
ブロックチェーン dapp&ゲーム開発入門
Ethereum+Solidity入門 Web3.0を切り拓く

▼Qiita記事
スマートコントラクト開発の基本
何も分からないところからスタートするSolidity学習
Solidity 言語仕様 基本編
Solidityの条件分岐(if-elseb文)、繰り返し処理(while文等)、イベントを紹介

最後に

以上、Solidityの基礎を簡単にまとめてみました。

CryptZombies」と呼ばれる、ゾンビバトルゲームでSolidityの基礎を無料で学べます。実際に使ってみましょう。

少しでも参考になれば、LGTMお願いします!

83
59
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
83
59

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?