【GCP】無料トライアル登録手順

Google Map のAPIを使用して地図を表示していますが、特定の環境下で「Googleマップが正しく読み込まれませんでした」となります。

ググってみると請求先アカウントが登録されていない場合に表示される(ことがある?)とありましたので早速登録してみます。

今回はGCPの無料トライアル登録で請求先アカウントも登録する手順を紹介します。

Google Cloud Platform の無料トライアル登録手順

右上の有効化ボタンをクリック

f:id:takuyafujita:20190116232312p:plain

国を選択、利用規約に同意して実行

f:id:takuyafujita:20190116232358p:plain

アカウントの種類、名前と住所を入力

f:id:takuyafujita:20190116232410p:plain

メインの連絡先、クレジットカード情報を入力して無料トライアルを開始

f:id:takuyafujita:20190116232424p:plain

完了

f:id:takuyafujita:20190116232434p:plain

以上です!

Truffleを使ってERC20の独自トークンを発行する

こんにちは。休みの日はDapps開発をしている 藤田拓弥 です。

今回はERC20の独自トークン作成からローカル環境にデプロイまでを行います。
Truffle(Ethereumのスマートコントラクト開発フレームワーク)を使うので、何それ?という方は下記の記事を参考にして環境構築をお願いします。

takuyafujita.hatenablog.com

それでは早速作っていきましょう。

Truffleでプロジェクトを作成する

今回は自分の名前(takuya)でトークンを発行しますので「takuya_token」という名前のディレクトリを作成します。

mkdir takuya_token

作成したディレクトリに移動します。

cd takuya_token

Truffleを初期化してプロジェクトに必要なファイル一式を作成します。

truffle init

OpenZepplinをインストールする

続いて独自トークンとなるコントラクトを作成しますが、その前にOpenZepplinをインストールします。
OpenZepplinはEthereum上で安全なコントラクトを実装するためのフレームワークです。
その中にERC20も含まれており、トークンに必要な機能が一通り揃っています。

まずは「package.json」を作成します。

npm init -f

続いてOpenZeppelinをインストールします。

npm install zeppelin-solidity

インストールすると以下の警告が出ました。

This package has been renamed to openzeppelin-solidity. Please update your dependency, or you will no longer receive updates.

OpenZeppelinのバージョンが上がり、パッケージ名が変わっているようです。

新:openzeppelin-solidity
旧:zeppelin-solidity

今回は旧の方を使用します。

コントラクトを実装する

プロジェクト(takuya_token)配下の「contracts」ファルダ内に、「TakuyaToken.sol」という名前でファイルを新規作成します。

「TakuyaToken.sol」の内容は下記の通りです。


マイグレーションファイルを作成する

デプロイを行うので、マイグレーションファイルを作成します。

プロジェクト(takuya_token)配下の「migrations」ファルダ内に、「2_deploy_takuya_token.js」という名前でファイルを新規作成します。

「2_deploy_takuya_token.js」の内容は下記の通りです。


テストコードを作成する

プロジェクト(takuya_token)配下の「test」ファルダ内に、「TestTakuyaToken.js」という名前でファイルを新規作成します。

「TestTakuyaToken.js」の内容は下記の通りです。


テストを実施する

今回はローカル環境を使用するので、以下のコマンドでEthereumブロックチェーンエミュレータを起動します。

truffle develop

truffle consoleに入りますので、そのままテストを実行します。

truffle(develop)> test

テスト結果が表示されます。想定通りの結果になればデプロイに進みます。

Compiling .\contracts\Migrations.sol...
Compiling .\contracts\TakuyaToken.sol...
Compiling zeppelin-solidity/contracts/token/ERC20/StandardToken.sol...
Compiling zeppelin-solidity\contracts\math\SafeMath.sol...
Compiling zeppelin-solidity\contracts\token\ERC20\BasicToken.sol...
Compiling zeppelin-solidity\contracts\token\ERC20\ERC20.sol...
Compiling zeppelin-solidity\contracts\token\ERC20\ERC20Basic.sol...

  Contract: TakuyaToken
    √ should put 1000 TAKUYA in the first account

  1 passing (65ms)

デプロイする

以下のコマンドでローカル環境にデプロイを行います。

truffle(develop)> migrate

デプロイされた内容を確認する

以下のコマンドでデプロイしたTakuyaTokenのオブジェクトを変数(TakuyaToken)に格納します。

truffle(develop)> TakuyaToken = TakuyaToken.at(TakuyaToken.address)

コントラクトを作成する際に設定した情報を確認します。

トークンの名称

truffle(develop)> TakuyaToken.name()
'TAKUYA'

トークンの単位

truffle(develop)> TakuyaToken.symbol()
'TAKUYA'

トークンの総発行量

truffle(develop)> TakuyaToken.totalSupply()
BigNumber { s: 1, e: 21, c: [ 10000000 ] }

独自トークンを送金する

1つ目のアカウントはトークンの発行者なので作成した全てのトークンが入っていることを確認します。

truffle(develop)> TakuyaToken.balanceOf(web3.eth.accounts[0])
BigNumber { s: 1, e: 21, c: [ 10000000 ] }

2つ目のアカウントはトークンの残高が0であることを確認します。

truffle(develop)> TakuyaToken.balanceOf(web3.eth.accounts[1])
BigNumber { s: 1, e: 0, c: [ 0 ] }

1つ目のアカウントから2つ目のアカウントに 100 TAKUYA を送金します。

truffle(develop)> TakuyaToken.transfer(web3.eth.accounts[1], 100)

2つ目のアカウントの残高が100であることを確認します。

truffle(develop)> TakuyaToken.balanceOf(web3.eth.accounts[1])
BigNumber { s: 1, e: 2, c: [ 100 ] }

これで独自トークンを発行し、送金できることが確認できました!

本当はRopstenにデプロイしたかったのですがエラーが出て解決に時間がかかりそうだったので断念しました。

次はRopstenへのデプロイに挑戦しようかな。

【CryptoZombiesを触ってみた】Lesson6で学んだこと

【CryptoZombiesとは】

Solidityでスマートコントラクトの構築を学習できるサイトです。日本語で丁寧に説明してくれるので、プログラミング未経験の人でも学習できます。

cryptozombies.io

【はじめに】

Solidityは未経験ですが、JavaScriptは触ったことがあります。そんな人が自分用の学習メモとして書いています。

【学んだこと】

Web3.js

イーサリアムのノードにアクセスできるJavaScriptライブラリです。フロントエンド(Webページ)からスマートコントラクトの関数を呼び出す場合に使用します。

まずは、Web3.jsをダウンロードして、htmlのheadタグ内にscriptタグを追加します。

<script language="javascript" type="text/javascript" src="web3.min.js"></script>

Web3プロバイダとMetamask

続いて、Web3プロバイダの設定(どのノードを使用すれば良いか教えてくれる)が必要になります。また、ブロックチェーンに書き込みを行う場合は秘密鍵を使って署名するので、秘密鍵の安全な管理も必要になります。これら全てを自前で実装することも可能ですが、今はMetamaskを使用するのがデファクトスタンダードになっています。MetamaskがインストールされていればMetamaskで使用しているWeb3プロバイダをそのまま使用することができ、イーサリアムのアカウントと秘密鍵も安全に管理してくれます。
Metamaskのインストール方法や使い方は他の方々がブログで紹介しているので、そちらを参考にしてください。

window.addEventListener('load', function() {
  // MetamaskがJavaScriptのグローバルオブジェクト web3 にWeb3プロバイダを設定するので
  // web3が設定されているかを確認すればMetamaskのインストール状況を判断できます。
  if (typeof web3 !== 'undefined') {
    // Web3が設定されていればMetamaskで使用しているWeb3プロバイダを設定
    web3js = new Web3(web3.currentProvider);
  } else {
    // web3が設定されていなければMetamaskをインストールするメッセージを表示
  }
  // 処理開始
  startApp()
})

コントラクトアドレスとABI

Web3.jsを使用してスマートコントラクトにアクセスするには
・スマートコントラクトをデプロイする際に付与されるコントラクトアドレス
・スマートコントラクトをコンパイルする際に作成されるABI(Application Binary Interface)
 ※ABIは関数の定義(関数名や引数など)がJSON形式で記載されています。
が必要になります。

var myContract;
function startApp() {
  // デプロイする際に付与されたコントラクトアドレス
  var myContractAddress = "YOUR_CONTRACT_ADDRESS";
  // コンパイルする際に作成されたABI
  var myContractABI = "YOUR_CONTRACT_ABI";
  // コントラクトアドレスとABIを使用してコントラクトを初期化
  myContract = new web3js.eth.Contract(myContractABI, myContractAddress);
}

call

Web3.jsを使用してスマートコントラクトのview関数、pure関数を呼び出します。読み取り専用なのでブロックチェーンへのトランザクションは発生しません。

myContract.methods.myMethod(argument1, argument2, argument3).call()

send

Web3.jsを使用してスマートコントラクトのview関数、pure関数以外の関数を呼び出します。ブロックチェーンのデータを更新するのでトランザクションが発生します。当然、ガス(Gas)の支払いや署名が必要になりますが、Metamaskがインストールされていれば全てMetamaskが行ってくれます。

myContract.methods.myMethod(argument1, argument2, argument3).send()

アカウント取得

Web3プロバイダを設定したグローバルオブジェクト web3 からユーザーのアカウントを取得することができます。Metamaskを使用している場合、Metamaskでアクティブになっているユーザーのアカウントを取得します。

var userAccount = web3.eth.accounts[0]

ユーザーのアカウントが変更されているかチェックしたい場合は、setInterval(JavaScriptのループ関数)を使います。

var accountInterval = setInterval(function() {
  // アカウントが変更されているかチェック
  if (web3.eth.accounts[0] !== userAccount) {
    userAccount = web3.eth.accounts[0];
    // 変更後のアカウントで行いたい処理
  }
}, 100);

トランザクションの送信

トランザクションが大量に保留されていたり、設定したガス代が安すぎると数ブロック待つ必要があるため、非同期処理で記述する必要があります。

function createRandomZombie(name) {
  // しばらく時間がかかるので、ユーザーにトランザクションが送信されたことを知らせる
  $("#txStatus").text("Creating new zombie on the blockchain. This may take a while...");
  // トランザクションをコントラクトに送信する
  return cryptoZombies.methods.createRandomZombie(name)
  .send({ from: userAccount })
  // トランザクションがブロックに含まれるとreceiptが発行される
  .on("receipt", function(receipt) {
    // トランザクションがブロックチェーンに取り込まれたことを知らせる
    $("#txStatus").text("Successfully created " + name + "!");
    getZombiesByOwner(userAccount).then(displayZombies);
  })
  .on("error", function(error) {
    // トランザクションが失敗したことをユーザーに知らせる
    $("#txStatus").text(error);
  });
}

Wei

イーサ(イーサリアムの通貨)の最小単位
1 wei = 0.000000000000000001 ether

// payable関数を呼び出す際、etherではなくweiで指定する必要があるので
// toWeiを使用してetherをweiに変換する
cryptoZombies.methods.levelUp(zombieId)
.send({ from: userAccount, value: web3js.utils.toWei("0.001", "ether") })

eventをトリガーにする

Web3.jsではスマートコントラクトのイベントをトリガーにすることができます。

// スマートコントラクト側(Solidity)
// eventを設定
event NewZombie(uint zombieId, string name, uint dna);

// フロントエンド側(javascript)
// eventをトリガーとして処理を行います。
cryptoZombies.events.NewZombie()
.on("data", function(event) {
  let zombie = event.returnValues;
  console.log("A new zombie was born!", zombie.zombieId, zombie.name, zombie.dna);
}).on("error", console.error);

indexedを使用すればイベントのフィルタリングができます。

// スマートコントラクト側(Solidity)
// indexedで引数を設定しておきます
event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);

// フロントエンド側(javascript)
// '_to'が'userAccount'と同じ場合のみ処理が行われます。
cryptoZombies.events.Transfer({ filter: { _to: userAccount } })
.on("data", function(event) {
  let data = event.returnValues;
}).on("error", console.error);

【できたもの】

今回のLessonはフロントエンド(javascript)がメインだったので比較的分かりやすかったです。Metamaskのお面カワイイ!
f:id:takuyafujita:20181014194805j:plain

現在はLesson6で終了ですが、もうすぐseason2が登場しそうなので楽しみです!

Gethのコンパイル環境構築とコンパイル方法

こんにちは。休みの日はDapp開発の勉強をしている 藤田拓弥@ディズニー好きのSE です。

今日はイーサリアムが提供しているクライアントソフトのGethを触ってみようと思い、公式サイトにアクセスしましたが「Retrieving packages from release server...」のダイアログが表示され続け何もできませんでした。インストール用の実行ファイルもダウンロードできませんでした。(2018年9月30日時点)

f:id:takuyafujita:20180930160257j:plain

ブラウザを変えてみても状況が変わらなかったのでダウンロードは諦めて、Gitに公開されているGethのソースコードを自分でコンパイルする方法を試してみました。

試した環境はwindows10です。

Gethのコンパイル方法は以下のサイトを参考にしました。

Git:Geth公式のインストール手順(Windows

github.com

Qiita:gethをwindows10にインストールする

qiita.com

両方参考にしましたが、内容は同じです。

Gethのコンパイル環境構築

Go言語のインストール

公式サイトからwindows用のMSIファイルをダウンロードしてインストールします。

コマンドプロンプトでバージョンが表示されればOKです。

C:\>go version
go version go1.11 windows/amd64

chocolatey(パッケージ管理ソフト)のインストール

コマンドプロンプトまたはWindows PowerShellのどちらかを使用してインストールします。
インストールに必要な要件等は公式サイトを確認してください。

コマンドプロンプトを使用する場合

管理者として以下のコマンドを実行します。

@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"
Windows PowerShellを使用する場合

管理者として以下のコマンドを実行します。

Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

コマンドプロンプトでバージョンが表示されればOKです。

C:\>choco --version
0.10.11

chocolateyを使用して必要なソフトをインストール

既にインストール済みの場合は対応不要です。インストール時にスクリプトを実行するか?と聞かれるので「y」を選んで進めます。オプション -y をつけると実行確認が表示されないので楽です。

C:\Windows\system32> choco install git
C:\Windows\system32> choco install golang
C:\Windows\system32> choco install mingw

インストール後にsuccessfullyが表示されていればOKです。

環境変数の設定

C:\Users\xxx> set "GOPATH=%USERPROFILE%"
C:\Users\xxx> set "Path=%USERPROFILE%\bin;%Path%"
C:\Users\xxx> setx GOPATH "%GOPATH%"
C:\Users\xxx> setx Path "%Path%"

Gethのコンパイル手順

githubからGethのソースをclone

C:\Users\xxx> mkdir src\github.com\ethereum
C:\Users\xxx> git clone https://github.com/ethereum/go-ethereum src\github.com\ethereum\go-ethereum

goで各種外部パッケージを取得

C:\Users\xxx> cd src\github.com\ethereum\go-ethereum
C:\Users\xxx> go get -u -v golang.org/x/net/context

goでGethの実行ファイルを作成

C:\Users\xxx\src\github.com\ethereum\go-ethereum> go install -v ./cmd/...

Gethが正常にインストールされたか確認

コマンドプロンプトで「geth help」を実行し、Gethの情報(NAME、USAGE、VERSIONなど)が表示されればOKです。

C:\>geth help

NAME:
   geth - the go-ethereum command line interface

   Copyright 2013-2018 The go-ethereum Authors

USAGE:
   geth [options] command [command options] [arguments...]

VERSION:
   1.8.17-unstable

【CryptoZombiesを触ってみた】Lesson5で学んだこと

【CryptoZombiesとは】

Solidityでスマートコントラクトの構築を学習できるサイト
日本語で丁寧に説明してくれるので、プログラミングやったことない人でも学習できる。

cryptozombies.io

【はじめに】

Solidityは未経験ですが、JavaScriptは触ったことがあります。
そんな人が自分用の学習メモとして書いています。

【学んだこと】

ERC20とERC721

ERC(Ethereum Request for Comments)はイーサリアムトークン規格。ERC20はトークンの送金、残高照会、アドレス毎の残高記録など、トークンを発行するのに必要な機能について定められている。ERC20で作成されたトークン同士は互換性があるので連携しやすい(実装が容易になる)。ERC721は同じトークンでも、それぞれがユニークであると仮定され異なる特徴を持たせることができる。ERC721であれば、同じトークン(ゾンビ)でもレベルが異なれば別物として扱うことができる。

ERCについてはこちらの説明が分かりやすいです。
dappsmarket.net

複数継承

Solidityではカンマ区切りで複数の継承ができる。

contract newContract is Contract1, Contract2 {
}

ERC721の実装

ERC721を継承し各関数をオーバーライドして使用する。

import "./erc721.sol";

// ERC721を継承
contract newContract is ERC721 {

  // balanceOf:addressを受け取り、そのaddressのトークン保有量を返す。
  function balanceOf(address _owner) public view returns (uint256 _balance);

  // ownerOf:トークンIDを受け取り、その所有者のaddressを返す。
  function ownerOf(uint256 _tokenId) public view returns (address _owner);

  // transfer:トークン所有者が送り先(address)、送るトークン(トークンID)を指定し所有権を移転する。
  // 処理の最後にTransferイベントを呼び出す必要がある。
  function transfer(address _to, uint256 _tokenId) public;

  // approve:トークン所有者が送り先(address)、送るトークン(トークンID)を指定し、コントラクトのmappingに記録する。
  // transferと異なり、approveを実行しただけで所有権の移転はしない。takeOwnershipを実行した際に移転する。
  // 処理の最後にApprovalイベントを呼び出す必要がある。
  function approve(address _to, uint256 _tokenId) public;

  // takeOwnership:トークンの受取人が呼び出す。approveで記録したmappingから受取人のアドレスを検索し、該当のトークンの所有権を移転する。
  function takeOwnership(uint256 _tokenId) public;

}

オーバーフローとアンダーフロー

オーバーフローとは四則演算の結果が許容範囲を上回ること。

uint8 number = 255;
// uint8の最大値である255を上回るのでオーバーフローが発生し、結果は0となる。
number++;

アンダーフローとは四則演算の結果が許容範囲を下回ること。

uint8 number = 0;
// uint8の最小値である0を下回るのでアンダーフローが発生し、結果は255となる。
number--;

SafeMath

SafeMathはOpenZeppelinのライブラリ。OpenZeppelinについてはこちらの記事でも紹介しています。

takuyafujita.hatenablog.com

SafeMathはadd(加算)、sub(減算)、mul(乗算)、div(除算)の4つの関数を持ち、オーバーフローやアンダーフローの脆弱性に対応している。SafeMathを使用して四則演算を行えばオーバーフローやアンダーフローが発生する演算を行う前にエラーで返してくれる。基本的に四則演算を行う場合はSafeMathを使用した方が安全。

library SafeMath {

  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0) {
      return 0;
    }
    uint256 c = a * b;
    assert(c / a == b);
    return c;
  }

  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return c;
  }

  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b <= a);
    return a - b;
  }

  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}

SafeMathの使い方

// uint256にSafeMathの関数を追加する(使用できるようにする)。
using SafeMath for uint256;

// aがSafeMathの関数の1つ目の引数として渡される。
uint256 a = 5;
uint256 b = a.add(3); // 5 + 3 = 8
uint256 c = a.mul(2); // 5 * 2 = 10

※uint16やuint32の場合、ライブラリ内でuint256に変換されるので脆弱性に対応出来ていない。この場合、uint16やuint32用のSafeMathライブラリを作成する必要がある。

assert

偽(false)の場合、エラーを発生させる。関数呼び出しが失敗した場合、ユーザーにガスの残りを返却しない。

require

真(true)の場合、エラーを発生させる。関数呼び出しが失敗した場合、ユーザーにガスの残りを返却する。

コメント

JavaScriptに似ている

// 1行コメントの場合

/*
  複数行
  コメント
  の場合
*/

// natspec
/// @title contractのタイトル
/// @author contractの作成者
/// @notice contractが何を行うのか説明
contract Math {
  /// @notice 関数が何を行うのか説明
  /// @param x 1つ目の引数の説明
  /// @param y 2つ目の引数の説明
  /// @return z 戻り値の説明
  /// @dev 開発者向けの詳細な説明
  function multiply(uint x, uint y) returns (uint z) {
    z = x * y;
  }
}

【できたもの】

ゾンビが4体に増えた。ゾンビの名前が変更できるようになった。

f:id:takuyafujita:20180924194242j:plain

【CryptoZombiesを触ってみた】Lesson4で学んだこと

【CryptoZombiesとは】

Solidityでスマートコントラクトの構築を学習できるサイト
日本語で丁寧に説明してくれるので、プログラミングやったことない人でも学習できる。

cryptozombies.io

【はじめに】

Solidityは未経験ですが、JavaScriptは触ったことがあります。
そんな人が自分用の学習メモとして書いています。

【学んだこと】

payable修飾子

ブロックチェーン上にあるコントラクトを呼び出す際にETHを受け取ることができる。

contract OnlineStore {
  function buySomething() external payable {
    // 関数呼び出し時、0.001ETHが送られてきたか確認する
    require(msg.value == 0.001 ether);
    // 0.001ETHが送られてきた場合に実行する処理
    transferThing(msg.sender);
  }
}
// buySomething関数を呼び出す(web3.js)
// valueに0.001ETHを設定
OnlineStore.buySomething({from: web3.eth.defaultAccount, value: web3.utils.toWei(0.001)})

CryptoZombiesより引用

withdraws関数とtransfer関数

コントラクトに送られたETHはコントラクトのアカウントに貯められる。貯まったETHをコントラクト以外で使用するにはコントラクトから引き出す処理(withdraws関数)が必要になる。transfer関数を使用すると指定したイーサリアムのアドレスに送金できる。

contract GetPaid is Ownable {
  function withdraws() external onlyOwner {
    // transfer関数でownerにETHを送る
    // this.balanceでコントラクトに貯まっているETHの残高を取得する
    owner.transfer(this.balance);
  }
}

CryptoZombiesより引用

乱数

ハッシュ関数のkeccak256で乱数を生成する。ただし、この方法で作成した乱数を使用しランダムな結果にしても脆弱性(※)が含まれる。
※自分のノードに向けてトランザクションを発行し、自分の都合の良い結果になるまで繰り返し行うことができる脆弱性。対策としてはoracle(イーサリアムブロックチェーン外の乱数関数にアクセスする)を使う。

uint once = 0;
uint random = uint(keccak256(once));
once++;
uint random = uint(keccak256(once));

else

JavaScriptと同じ

if (age < 30) {
  // 30歳未満
} else {
  // 30歳以上
}

【できたもの】

ゾンビ同士のバトル機能を追加
バトルに勝つとゾンビのレベルが上がる。更に新たなゾンビを生み出し、自分のゾンビ軍団に加わる。

f:id:takuyafujita:20180917041746j:plain
f:id:takuyafujita:20180917041804j:plain

【CryptoZombiesを触ってみた】Lesson3で学んだこと

【CryptoZombiesとは】

Solidityでスマートコントラクトの構築を学習できるサイト
日本語で丁寧に説明してくれるので、プログラミングやったことない人でも学習できる。

cryptozombies.io

【はじめに】

Solidityは未経験ですが、JavaScriptは触ったことがあります。
そんな人が自分用の学習メモとして書いています。

【学んだこと】

イミュータブル(immutable)

コントラクトをイーサリアム上にデプロイするとイミュータブル(※)になる。改竄できないのでセキュリティが高くなる反面、不具合があっても修正できない。修正する場合は別途、修正版のコントラクトを新規で作成する。

※作成後にその状態を変えることのできないオブジェクト

外部依存関係

外部のコントラクトを呼び出す場合は、コントラクトのアドレスをハードコーディングせず関数にする。関数にしておくと呼び出し先のコントラクトで不具合が発生しても後から変更できる。ハードコーディングしているとイミュータブルなので修正できない。

Ownableコントラクト

外部のコントラクトを呼び出す関数の場合、誰でも呼び出しできる状態(External)だとクラッキングされる。そんな時はOwnableを使い、権限を持った人しか呼び出しできないようにする。OpenZeppelinのOwnableコントラクトを使うのが一般的。

OpenZeppelinのOwnableコントラクト

OpenZeppelinはイーサリアム上で安全なスマートコントラクトを実装するためのフレームワーク。そのうちの1つにOwnableコントラクトがあり、コントラクトの実行権限を限定することができる。

詳細は下記にまとめています。

takuyafujita.hatenablog.com

関数修飾子

functionの代わりにmodifierを使う。

/**
  * @dev Throws if called by any account other than the owner.
  */
  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }

下記の場合、transferOwnershipの処理が実行される前に関数修飾子のonlyOwnerが実行される。onlyOwnerの[_;]が実行されると呼び出し元のtransferOwnershipの処理が実行される。関数修飾子はrequireで処理前のチェックを行う使い方が一般的。

/**
  * @dev Allows the current owner to transfer control of the contract to a newOwner.
  * @param _newOwner The address to transfer ownership to.
  */
  function transferOwnership(address _newOwner) public onlyOwner {
    _transferOwnership(_newOwner);
  }

関数修飾子に引数を渡す

関数修飾子には関数同様、引数を渡すことが可能です。

mapping (uint => uint) public age;

// ユーザの年齢が一定の年齢を超えていること
modifier olderThan(uint _age, uint _userId) {
  require (age[_userId] >= _age);
  _;
}

// 基準となる年齢(20)とユーザIDを関数修飾子の引数として渡す
function drinking(uint _userId) public olderThan(20, _userId) {
  // 処理
}

ガス(Gas)

Solidityでは関数を実行する度にガス(Gas)と呼ばれる手数料が必要になる。必要なガスの量は関数のロジックで決まり、複雑なロジックになるほど多くのガスが必要になる。関数を実行する度にお金が必要になるのでコードの最適化(ガス代を抑える)が重要になる。

ガスが必要な理由

分散型のイーサリアムはいくつものノードが関数の実行結果が正しいことを検証しているが、無駄にネットワークに負荷をかける処理が多くなると検証時間も遅くなる。手数料を設定することでネットワークの負荷を軽減している。

ガスを節約する方法(struct構造)

structの中に複数のuintを宣言する場合、小さい単位で宣言すると変数がまとめられてストレージが小さくなりガス代が安くなる。下記の場合、NormalよりMinの方がガス代が安い。更に同じデータ型を隣同士にしておく([uint32 a]と[uint32 b])ことでもストレージを抑えることができ、ガス代も安くなる。
※struct以外でuintを宣言する場合は全て256Bitでストレージを確保するのでガス代が安くなる効果はない。

struct Normal {
  uint a;   // 256Bit
  uint b;   // 256Bit
  uint c;   // 256Bit
}

struct Min {
  uint32 a; // 32Bit
  uint32 b; // 32Bit
  uint c;   // 256Bit
}
ガスを節約する方法(View関数)

View関数はブロックチェーンの変更を行わないので外部から呼び出す場合のみガス代がいらない。

ガスを節約する方法(Memory)

Storageのデータを操作するとブロックチェーンに書き込まれ、全てのノードに取り込まれる必要があるのでガス代が高くなる。一時的に必要なデータであればStorageよりもMemoryを使用してガス代を抑える。Memoryの使い方は以下の通りです。

function getMemory() external pure returns(uint) {
  uint memory value = 10;
  return value;
}

時間

now変数は現在のunixタイムスタンプを返す。

seconds、minutes、hours、days、weeks、years

uintの秒数に変換されて使用できる。

1 minutes : 60
1 hours   : 3600 (60分×60秒)
1 days    : 86400(24時間×60分×60秒)
uint lastUpdated;

// lastUpdatedに5分加算する
function addFiveMin() public view returns (uint) {
  return lastUpdated + 5 minutes;
}

For

JavaScriptと同じ

【できたもの】

レベルが上がるとゾンビの名前を変更できる機能を追加したよ。

f:id:takuyafujita:20180902143837j:plain