[aside type=”normal”]
本記事は、Solidityのサイトの Introduction to Smart Contractsを翻訳(適宜意訳)したものです。誤り等あればご指摘いただけたら幸いです。
[/aside]
シンプルなスマートコントラクトを作る
まずは最も基本的な例から始めてみましょう。
もし今すべてを理解していなくても大丈夫です。
pragma solidity ^0.4.0; contract SimpleStorage { uint storedData; function set(uint x) public { storedData = x; } function get() public constant returns (uint) { return storedData; } }
最初の行は、ソースコードのバージョンを記述しています。この場合は、Solidityバージョン0.4.0です。これは、新しいコンパイラバージョンでスマートコントラクトが突然異なる動作をしないようにするためのものです。キーワードpragma
は、ソースコードの処理方法についてのコンパイラへの命令のための記述になります。(pragma once)
Solinityにおいてのスマートコントラクトは、Ethereumブロックチェーンの特定のアドレスにあるコード(functions)とデータ(state)の集合です。uint storedData;
では、uint
(256ビットの符号なし整数)型のstoredData
と呼ばれる状態変数を宣言しています。データベースの管理をするための関数を呼び出して、データ照会と変更ができるようにしている、と考えてください。この場合、関数set
とget
を用意して、変数の値を変更または取得できるようにします。
変数にアクセスするには、接頭辞this
は必要ありません。他の言語ではthis
をつけることが一般的ですが、ここでは必要ありません。
ここで作ったスマートコントラクトは、世界中の誰からもアクセスできる単一の番号が格納されています。(Ethereumによって構築されているため)
そして、誰もが別の値でset
関数を呼び出して番号を上書きすることはできますが、その番号はブロックチェーンの履歴に保存されます。
後ほど、自分だけが番号を変更できるようにアクセス制限をつける方法を紹介します。
[aside type=”normal”]
NOTE:
すべての識別子(契約名、関数名、変数名)はASCII文字セットに制限されています。UTF-8でエンコードされたデータを文字列変数に格納することは可能です。
[/aside]
[aside type=”normal”]
WARNING:
同じように見える(または同じ文字さえも)文字が異なるコードポイントを持つ可能性があり、異なるバイト配列としてエンコードされるため、Unicodeテキストの使用には注意が必要です。
[/aside]
シンプルな仮想通貨を作ってみる
次のスマートコントラクトでは、最も単純な形式の暗号化を実装しています。
単純なコインを生成することも可能ですが、ここではコントラクトを作った人だけがそれを行うことができるようにします。さらに、誰でもユーザー名やパスワードを登録する必要なく、お互いにコインを送ることができます。あなたが必要とするのは、Ethereumの鍵ペア(キーペア)だけです。
pragma solidity ^0.4.20; // should actually be 0.4.21 contract Coin { // publicキーワードで外部からもアクセス可能にする address public minter; mapping (address => uint) public balances; // イベントを定義して、効率的に変更を検知する event Sent(address from, address to, uint amount); // このコンストラクタで、コントラクトの作成者だけが操作できるようにする function Coin() public { minter = msg.sender; } function mint(address receiver, uint amount) public { if (msg.sender != minter) return; balances[receiver] += amount; } function send(address receiver, uint amount) public { if (balances[msg.sender] < amount) return; balances[msg.sender] -= amount; balances[receiver] += amount; emit Sent(msg.sender, receiver, amount); } }
このスマートコントラクトでは、いくつかの新しいコンセプトがあります。
address public minter;
の行で、パブリックにアクセス可能なアドレス型の状態変数を宣言します。
address
のタイプは、算術演算を許可しない160ビットの値です。これは、スマートコントラクトや鍵ペア(キーペア)のアドレスを格納するのに適しています。public
キーワードは、外部からの変数へアクセスするための宣言です。このキーワードがなければ、他のコントラクトは変数にアクセスできません。コンパイラによって生成される関数のコードは、次のコードとほぼ同じです。
function minter() returns (address) { return minter; }
もちろん、まったく同じような関数を追加することはできません。なぜなら、同じ名前の関数と状態変数を持つことになるからです。
次は、mapping(address => uint)public balances;
という行です。パブリック変数も作成されますが、より複雑なデータ型です。
型は、アドレスを符号なし整数にマッピングします。マッピングは、すべての可能なキーが存在し、バイト表現がすべてゼロである値にマッピングされるように、初期化されるハッシュテーブルとして見ることができます。
ただし、マッピングのすべてのキーのリストやすべての値のリストを取得することはできません。
なので、マッピングに追加したもの、またはこれが必要でないコンテキストで使用することを念頭に置いてください(リストを保持するか、より高度なデータ型を使用するかなど)。
この場合、public
キーワードによって作成されるgetting functionは少し複雑です。だいたい次のようになります。
function balances(address _account) public view returns (uint) { return balances[_account]; }
この機能を利用すると、単一のアカウントの残高を簡単に照会することができます。
event Sent(address from, address to, uint amount);
で、いわゆる "イベント"を宣言します。 ユーザーインターフェイス(もちろんサーバーアプリケーション)は、あまりコストをかけずにブロックチェーン上で発行されたイベントを検知することができます。イベントが検知されるとすぐに、リスナーはfrom
、to
、およびamount
を受け取るので、トランザクションの追跡が容易になります。このイベントを検知するためには、以下のようなコードを用意します。
Coin.Sent().watch({}, '', function(error, result) { if (!error) { console.log("Coin transfer: " + result.args.amount + " coins were sent from " + result.args.from + " to " + result.args.to + "."); console.log("Balances now:\n" + "Sender: " + Coin.balances.call(result.args.from) + "Receiver: " + Coin.balances.call(result.args.to)); } })
balance
関数が、ユーザインタフェースからどのように呼び出されるかに注目してください。
関数Coin
は、スマートコントラクトの作成中に実行されるコンストラクタであり、後で呼び出すことはできません。
コントラクト作成者のアドレスを永久に保存します:msg
(tx
とblock
と一緒に)は、ブロックチェーンへのアクセスを可能にするいくつかのプロパティを含むグローバル変数です。msg.sender
によって、常に現在の(外部の)関数呼び出しがどこから来たかがわかります。
実際にコントラクトを結び、ユーザーと契約者が同じように呼び出すことができる機能は、mint
とsend
です。mint
がコントラクトを作成したアカウント以外の誰かによって呼び出された場合、何も起こりません。
一方、send
は、コインを他の誰かに送るために(すでにこれらのコインの一部を持っている)誰でも使うことができます。このコントラクトを使用してコインをあるアドレスに送信した場合、ブロックチェーンエクスプローラでそのアドレスを見ると何も表示されません。コインを送ったことと変更された残高がこの特定のコインのデータストレージにのみ保存されるためです。
イベントを利用することで、新しいコインの取引と残高を追跡する「ブロックチェーンエクスプローラ」を作成するのは比較的簡単です。