イーサリアムでのスマートコントラクトを始めるためのガイド

将来のプログラマーがイーサリアムのスマートコントラクトを開発するのを簡単にするための手短なガイドをまとめました。このガイドは大きく2つの項目からなります:イーサリアムでのスマートコントラクト作成の始め方と、スマートコントラクトセキュリティーにおける注意点です。

イーサリアムでスマートコントラクトを始める

0.基本的コンセプト

このガイドは、読者がどのように仮想通貨とブロックチェーンが働くか、基本的な技術的理解があることを前提にしています。先に進むためには、公開鍵と秘密鍵とは何で、どうしてブロックチェーンにマイナーが必要で、どのように非中央化コンセンサスが達成されているか、トランザクションとはなんであるか、そしてトランザクションスクリプティングとスマートコントラクトのコンセプトをまず理解してほしいと思います。

イーサリアムに取り組む前に理解すべき2つの重要なコンセプトは、イーサリアム仮想マシン(EVM)とgasです。
イーサリアムはスマートコントラクトのプラットホームとしてデザインされています。その発端はビタリック・ブテリンによる「ビットコインはスマートコントラクトのプラットホームとして非常に限定的だ」という批判でした。
イーサリアム仮想マシン(EVM)はイーサリアムでスマートコントラクトが実行される場所となります。スクリプティングにおいてビットコインよりも、表現力があり完璧な言語が使われます。事実、これはターニング・コンプリートのプログラム言語です。EVMはすべてのスマートコントラクトが実行される世界規模のコンピューター群に分散されているようなものです。

スマートコントラクトがEVMで実行されていることを踏まえると、各々のコントラクトに使用されるリソースを制限するメカニズムが必須です。EVM内で実行される一つ一つの演算は、実際に同時にネットワーク内のすべてのノードで実行されています。これがgasの存在する理由です。イーサリアムのトランザクションコントラクトコードはデータの読み書きや、暗号化プリミティブのような高コストな計算や、ほかのコントラクトへのコール(メッセージ)の送信といったもののきっかけとなる事ができます。それぞれの演算のコストはgasで計算され、処理によって消費される各々のgasは、ダイナミックに変化するgas/イーサ価格に基づいて、イーサで支払われなければなりません。この値はトランザクションを送信するイーサリアムのアカウントから差し引かれます。
またトランザクションにはgas制限パラーメーターがあり、それはトランザクションがどれだけgasを消費できるかの上限で、アカウントの資金を枯渇しうるプログラムエラーに対するセーフガードとして使用されます。
ここでさらにgasについて学べます。

1.環境設定

それでは基本を理解したら、コードに向けてセッティングしましょう。イーサリアムのアプリの開発を始めるために、(通称DApps/非集中化アプリ)、ネットワークにつなげるためのクライアントが必要になります。これは分散したネットワークへの覗き窓となり、すべてのEVM状態が表象されるブロックチェーンを一望できるようにします。
このプロトコルには様々な互換性のあるクライアントがあり、もっともポピュラーなものはgethで、Go言語の実装物です。しかしながら、これは開発者が最も使いやすい物というわけではありません。私の思うベストな選択肢はtestrpcノードです。(ええ、名前はいけてないですけども。)信じてください、多くの時間が節約できます。これをインストールして走らせましょう。(設定に応じて先頭にsudoをつける必要があるかもしれません。)

$ npm install -g ethereumjs-testrpc
$ testrpc

新しいターミナルでtestrpcを走らせ、開発中はそれを走らせ続けた方がいいでしょう。tsetpcを走らせる度、それは使用のためのシミュレートされたテスト資金と共に10の新しいアドレスを生成します。これは本物の金銭ではないので、資金を失うリスクなしに何でも安全に試すことができます。
イーサリアムでスマートコントラクトを書くための最もポピュラーな言語はソリディティなので、それを使います。また、Truffle開発フレームワークを使います。これはスマートコントラクトの作成と、コンパイル、開発とテストを助けてくれます。さあ、始めましょう。(ここもう一度、設定によってsudoを先頭につける必要があるかもしれません。)

# First, let’s install truffle
$ npm install -g truffle
# let’s setup our project
$ mkdir solidity-experiments
$ cd solidity-experiments/
$ truffle init

Truffleは仮想のプロジェクトのためにすべてのファイルを作ります。これはサンプルのトークンコントラクトのMetaCoinのためのコントラクトを含みます。
truffle compileを走らせることで仮想コントラクトをコンパイルできるようにしておきましょう。
そうしたら、コントラクトをtestrpcノードを使ったシミュレートされたネットワークへ展開するために、truffle migrateを走らせる必要があります。

$ truffle compile
Compiling ConvertLib.sol…
Compiling MetaCoin.sol…
Compiling Migrations.sol…
Writing artifacts to ./build/contracts

$ truffle migrate
Using network ‘development’.

Running migration: 1_initial_migration.js
Deploying Migrations…

0x686ed32f73afdf4a84298642c60e2002a6d0d736a5478cc8cb22a655ac018a67
Migrations: 0xa7edbac1156f98907a24d18df8104b5b1bd7027c
Saving successful migration to network…

0xe3bf1e50d2262d9ffb015091e5f2974c8ebe0d6fd0df97a7dbcde8a0e51c694a
Saving artifacts…
Running migration: 2_deploy_contracts.js
Deploying ConvertLib…

0x2e0e6718f01d0da6da2ada13d6e4ad662c5a20e784e04c404e9d4ef1d392bdae
ConvertLib: 0xf4388ce4d4ce8a443228d65ecfa5149205db049f
Linking ConvertLib to MetaCoin
Deploying MetaCoin…

0xb03a3cde0672a2bd4dda6c01dd31641d95bd680c4e21162b3370ed6db7a5620d
MetaCoin: 0x4fc68713f7ac86bb84ac1ef1a09881a9b8d4100f
Saving successful migration to network…

0xb9a2245c27ff1c6506c0bc6349caf86a31bc9f700388defe04566b6d237b54b6
Saving artifacts…

マックOS Xユーザーへの注意: TruffleはDS_Store fileとたまに取り違えられます。もしそういったファイルのひとつでエラーが出たら、単純に削除しましょう。

サンプルコントラクトをtestrpcノードに展開しました。簡単ですよね?さて、今度は自分のコントラクトを作りましょう!

2.初めてのイーサリアムのスマートコントラクトを書く

このガイドでは、シンプルなProof of Existenceのスマートコントラクトを書きます。考え方としては、デジタル公証人を作ることで、これはその存在の証明としてドキュメントのハッシュを保存します。
truffle create contractを使って始めましょう。

$ truffle create contract ProofOfExistence1

そして適当なテキストエディタにcontracts/ProofOfExistence1.solを開いて (私はソリディティ・シンタックス・ハイライティングでvimを使います。) 、そしてこの最初のバージョンのコードをペーストします。

pragma solidity ^0.4.15;

// Proof of Existence contract, version 1
contract ProofOfExistence1 {
// state
bytes32 public proof;
// calculate and store the proof for a document
// *transactional function*
function notarize(string document) {
proof = proofFor(document);
}
// helper function to get a document’s sha256
// *read-only function*
function proofFor(string document) constant returns (bytes32) {
return sha256(document);
}
}

まずはシンプルですが間違っている物から始め、より良いソリューションへと進んでいきます。これがソリディティコントラクトの定義で、それは他のプログラム言語内の一種のような物です。コントラクトは状態と機能があります。コントラクト内に現れる2種類の機能を見分ける事は重要です。

・読み出し専用(定数)機能:なんの状態変化も行わない機能で、ただ状態を読み出し、計算をし、値を返します。
これらの機能が各々のノードにローカルで解決されるとき、gasは消費しません。キーワードconstantで示されます。
・トランザクション的機能:コントラクト内で状態変化を実行したり、資金を動かしたりする機能。ブロックチェーン内にこれらの変化が反映される必要があるときは、トランザクション的機能の実行はトランザクションをネットワークへ送り、gasを消費する必要があります。

上記のコントラクトではそれぞれどちらも含んでいるのがわかると思います。次のセクションでは、これらの機能がスマートコントラクトとの情報交換の方法を変えるかを見ていきます。

このシンプルなバージョンは一度に一つだけプルーフを保存し、bytes32か32 bytesのデータタイプを使い、そのサイズはsha256 hashです。トランザクション的機能notarizeは、スマートコントラクトの状態変数proofにドキュメントのハッシュを保存することを可能にします。もしドキュメントが認証されているなら、当該変数が公開で、それがコントラクトのユーザーが確かめなくてはならない唯一の方法です。
まもなくそれに取り掛かりますが、まずは…

ProofOfExistence1をネットワークに展開しましょう!今度は、マイグレーションファイル(migrations/2_deploy_contracts.js)を、Truffleに新しいコントラクトを展開させるために、編集する必要があります。内容を以下のように置き換えましょう。

var ProofOfExistence1 =
artifacts.require(“./ProofOfExistence1.sol”);

module.exports = function(deployer) {
deployer.deploy(ProofOfExistence1);
};

このマイグレーションをまた走らせ、もう一度走るのを確認するためにリセットフラグを使う必要があります。

truffle migrate –reset

3.スマートコントラクトと情報交換する

コントラクトが展開されたので、遊んでみましょう!機能での呼び出しを介してメッセージを送ったり、公開状態を読んだりすることができます。そのためにはTruffleコンソールを使います。

$ truffle console
// get the deployed version of our contract
truffle(default)> var poe = ProofOfExistence1.at(ProofOfExistence1.address)

// and print its address
truffle(default)> poe.address
0x3d3bce79cccc331e9e095e8985def13651a86004

// let’s register our first “document”
truffle(default)> poe.notarize(‘An amazing idea’)
{ tx: ‘0x18ac…cb1a’,
receipt:
{ transactionHash: ‘0x18ac…cb1a’,

},
logs: [] }

// let’s now get the proof for that document
truffle(default)> poe.proofFor(‘An amazing idea’)
0xa3287ff8d1abde95498962c4e1dd2f50a9f75bd8810bd591a64a387b93580ee7

// To check if the contract’s state was correctly changed:
truffle(default)> poe.proof()
0xa3287ff8d1abde95498962c4e1dd2f50a9f75bd8810bd591a64a387b93580ee7
// The hash matches the one we previously calculated

初めにすることは、展開されているコントラクトの表象を得ることで、そしてpoeと呼ばれる変数にそれを保存します。
そうしたら状態変化を伴うトランザクション的機能notarizeを呼び出します。トランザクション機能を呼び出すと、実際の機能が返す物ではなくトランザクションオブジェクトに変わるプロミスが得られます。EVM状態を変えるためには、gasを消費しネットワークにトランザクションを送る必要があることを覚えておいてください。
これがトランザクション情報オブジェクトを、この状態変化を行うトランザクションを参照するプロミスの結果として得る理由です。この場合、トランザクションidには興味はないので、単純にプロミスを廃棄します。本物のアプリを書くときは、結果として生じるトランザクションをチェックし、エラーを見つけるためにそれを保存します。
次は、読み出し専用(定数)機能proofForを呼び出します。読み出し専用機能をキーワードconstantで目印をつける事を覚えておかないと、Truffleはそれらを実行するためにトランザクションを作成しようとするでしょう。これがTruffleにブロックチェーンと情報交換せず、ただそれを読むことを伝える方法です。この読み出し専用機能を使うことで、‘An amazing idea’ “document”のsha256ハッシュを得ます。

そして、これをスマートコントラクトの状態と対照する必要があります。状態が適切に変化したかチェックするために、proof公開状態変数を読む必要があります。公開状態変数の値を得るために、その値のプロミスを返す同名の機能を呼び出せます。この場合、出力ハッシュは同じですから、すべては予想通りに働きます。

4.コントラクトコードを繰り返す

コントラクトを複数のドキュメントのプルーフをサポートするように変更しましょう。元ファイルをcontracts/ProofOfExistence2.solの名前でコピーして、これらの変更を加えましょう。主な変更点としては、proof変数をbytes32配列に変え、これをproofs呼び、これを秘密にし、そしてその配列を繰り返す事によってドキュメントがすでに認証されているかどうかチェックする機能を加えます。

pragma solidity ^0.4.15;
// Proof of Existence contract, version 2
contract ProofOfExistence2 {
// state
bytes32[] private proofs;
// store a proof of existence in the contract state
// *transactional function*
function storeProof(bytes32 proof) {
proofs.push(proof);
}
// calculate and store the proof for a document
// *transactional function*
function notarize(string document) {
bytes32 proof = proofFor(document);
storeProof(proof);
}
// helper function to get a document’s sha256
// *read-only function*
function proofFor(string document) constant returns (bytes32) {
return sha256(document);
}
// check if a document has been notarized
// *read-only function*
function checkDocument(string document) constant returns (bool) {
bytes32 proof = proofFor(document);
return hasProof(proof);
}
// returns true if proof is stored
// *read-only function*
function hasProof(bytes32 proof) constant returns (bool) {
for (uint256 i = 0; i < proofs.length; i++) { if (proofs[i] == proof) { return true; } } return false; } }

新しい機能と情報交換してみましょう。:(migrations/2_deploy_contracts.jsに新しいコントラクトを含め、truffle migrate –resetを走らせることを憶えておきましょう。)

// deploy contracts
truffle(default)> migrate –reset
// Get the new version of the contract
truffle(default)> var poe = ProofOfExistence2.at(ProofOfExistence2.address)
// let’s check for some new document, and it shouldn’t be there.
truffle(default)> poe.

checkDocument(‘hello’)
false
// let’s now add that document to the proof store
truffle(default)> poe.notarize(‘hello’)
{ tx: ‘0x1d2d…
413f’,
receipt: { … },
logs: []
}
// let’s now check again if the document has been notarized!
truffle(default)> poe.checkDocument(‘hello’)
true
// success!
// we can also store other documents and they are recorded too
truffle(default)> poe.notarize(‘some other document’);
truffle(default)> poe.checkDocument(‘some other document’)
true

このバージョンは初めの物より良いですが、まだいくつか問題があります。ドキュメントが認証されたかどうかチェックしたいときはいつも、すべての存在するプルーフを繰り返す必要があることに注意しましょう。これによって追加のドキュメントがあるたびにチェックするために、コントラクトはさらに多くのgasを消費します。プルーフを保存するより良い構造は、マップです。幸いにも、ソリディティはマップをサポートしていて、マッピングと呼んでいます。
このバージョンでのもう一つの改善点は、読み取り専用やトランザクション的機能を示す余計なコメントをすべて削除することです。これはもう分かると思います。

下記が最終バージョンで、これは前のバージョンを追えばいいので、理解するのは難しくないでしょう。

pragma solidity ^0.4.15;

// Proof of Existence contract, version 3
contract ProofOfExistence3 {
mapping (bytes32 => bool) private proofs;
// store a proof of existence in the contract state
function storeProof(bytes32 proof) {
proofs[proof] = true;
}
// calculate and store the proof for a document
function notarize(string document) {
var proof = proofFor(document);
storeProof(proof);
}
// helper function to get a document’s sha256
function proofFor(string document) constant returns (bytes32) {
return sha256(document);
}
// check if a document has been notarized
function checkDocument(string document) constant returns (bool) {
var proof = proofFor(document);
return hasProof(proof);
}
// returns true if proof is stored
function hasProof(bytes32 proof) constant returns(bool) {
return proofs[proof];
}
}

良さそうですね。これが第2バージョンとして働きます。これを試すためには、マイグレーションファイルを更新して、truffle migrate –resetをまた走らせるのを覚えておきましょう。このチュートリアルのすべてのコードはGitHub repoで見つけられます。

5.本物のテストネットネットワークを展開する

いったんシミュレートされたネットワークでtestrpcを使ってコントラクトを広範にテストしたら、本物のネットワークで試す準備ができています!そのためには、本物のtestnet/livenetのイーサリアムのクライアントが必要です。これらの手順を踏んでgethをインストールしましょう。 

開発中は本物の資金を危険にさらさずにすべてをテストできるように、ノードをテストネットモードで走らせるといいでしょう。テストネットモードは(イーサリアムではMordenとしても知られ)、基本的に本物のイーサリアムと同じですが、そこのイーサトークンに貨幣価値はありません。さぼらずに、いつもテストネットモードで開発することを覚えておきましょう。プログラムエラーで本物のイーサを失えばきっと後悔します。

RPCサーバーを有効にして、テストネットモードでgethを走らせましょう。

geth –testnet –rpc console 2>> geth.log

これがnode/clientを操作するための基本コマンドを打ち込めるコンソールを開きます。ノードはテストネットのブロックチェーンのダウンロードを始め、eth. blockNumber.をチェックすることで、進行状況をチェックできます。ブロックチェーンをダウンロードしている間も、コマンドを走らせることができます。
例としてアカウントを作ってみましょう。(パスワードは忘れないように!)

> personal.newAccount()
Passphrase:
Repeat passphrase:

“0xa88614166227d83c93f4c50be37150b9500d51fc”

いくつかコインを送ってみて、残高をチェックしてみましょう。フリーのテストネットのイーサをここで取得できます。here. 生成したアドレスをコピーアンドペーストすると、いくつかのテストネットイーサが送られてきます。残高をチェックするためには、以下を走らせましょう。:

> eth.getBalance(eth.accounts[0])
0

ノードはまだ残りのネットワークと同期していないので、何の残高も表示しないでしょう。それを待っている間、テストネット・ブロック・エキスプローラの残高をチェックしましょう。ここでは、現在の最高のブロックナンバーを見ることができます。(これを書いている時点では#1819865です。)これはいつノードが完全に同期したか知るためにeth. blockNumberと合わせて使うことができます。

ノードがいったん同期したら、Truffleを使ってテストネットへコントラクトを展開する準備ができています。初めにTruffleがそれを使えるように、メインのgethのアカウントをアンロックしましょう。多少なりとも残高があることを確認しておかないと、新しいコントラクトをネットワークに送ることができません。
gethが走ったところで:

> personal.unlockAccount(eth.accounts[0], “mypassword”, 24*3600)
true
> eth.getBalance(eth.accounts[0])
1000000000000000000

準備は整いました!もしこの二つが働いていないなら、上記のステップをチェックして、正確にできているか確認しましょう。それでは以下を走らせましょう。:

$ truffle migrate –reset

ここでの注意としては、testrpcによるシミュレートされたものではなく、実際のネットワークに接続しているので、これには長い時間がかかるというところです。いったん完了したら、以前と同じアプローチを使ってコントラクトと情報交換できます。

ライブネットワークへの展開方法の詳細は読者に任せておきます。シミュレートされたネットワークとテストネットワークでいったん広範にテストしておけば、これを実行するだけです。ライブネット内では、どんなプログラムエラーも金銭の喪失につながりうることを覚えておきましょう。

イーサリアムでのスマートコントラクトのセキュリティは困難

スマートコントラクトはどのように資金が動くかを定義するコンピューターコードですが、セキュリティに関する手短な注意も無しにこのガイドを終える事はできません。

気を付けておくべき(そして避けるべき)問題

・再入可能性:コントラクト内で外部呼出しをしない。もしするなら一番最後にするように確認する。
・送信は失敗しうる:資金を送るときは、コードはいつも送信機能が失敗することに備えておく。
・ループはgas制限を引き起こしうる:状態変数をループするときは注意する。これはサイズが大きくなってgasを限界まで消費しうる。
・スタック深度制限を呼ぶ:再帰を使わず、スタック深度制限に達しているときはどんな呼び出しも失敗しうることに気を付ける。(追記:これは現在では問題にはなりません。
・タイムスタンプ依存性:マイナーが変更することできるので、コードの重要な部分でタイムスタンプを使わない。

これらは単に、スマートコントラクト内の資金の窃盗や破壊を引き起こしうる予想外の挙動の例です。重要な事は、もしスマートコントラクトを書いているなら、本物のお金を扱うコードを書いているという事です。慎重にやりましょう!テストを書いて、コードのレビューをして、コードの検査をしましょう。明らかなセキュリティの問題を避ける最良の方法は、言語に対するしっかりとした理解を持つことです。もし時間があれば、  the Solidity documentationを読むことをお勧めします。

以上です!このガイドを楽しんでイーサリアムでスマートコントラクトをプログラムする初めの一歩を学んでいただけたのなら嬉しいです! まだ新しい産業なので、新たなアプリとツールのための多くの余地があります。

まずはおためし!
ビットコインが買えるのはココ!

bitFlyer ビットコインを始めるなら安心・安全な取引所で
ビットコイン取引高日本一の仮想通貨取引所 coincheck bitcoin

  • このエントリーをはてなブックマークに追加

関連記事

  1. 【ビットコイン】ETFの承認はされる?されない?

  2. 【ビットコイン】受け入れの進む次の国々はここ!

  3. 【オーストラリア】仮想通貨規制法案を導入

  4. 【SAAVcoin】ICO:サーヴコインの概要&WhitePaper

  5. 【韓国】”ビットコイン投資”を謳った詐欺を警察が捜査

  6. 【ビットコイン】次の主要な市場はロシアとなるか?

  7. 【ベネズエラ】インフレにつきビットコインのブーム到来!?

  8. 【ビットコイン】逆境を乗り越え活況&各国政府が仮想通貨発行?

  9. KYCブロックチェーンスタートアップが160万ドル調達

PAGE TOP