Ethereum Hello World Contract
この記事では、実際のスマートコントラクト (DApps) を Hello World Contract チュートリアルに沿って動かしています。
事前に Ethereum プライベートネットを構築しておくと、ブロック同期や Gas 支払いのために使われる Ether を採掘する待ち時間が短くなり、ストレスを溜めずに進められます。
コントラクトを定義
まず最初に Greeter というコントラクトを Greeter.sol
ファイルに定義していきます。
Greeter は、他の誰かに挨拶するためのコントラクトです。予め決めたメッセージで初期化したオブジェクトを、誰かが greet
関数を呼び出すことでメッセージを取得できます。
cat << EOF > Greeter.sol
pragma solidity ^0.4.24;
/* 自己破棄可能なコントラクト */
contract Mortal {
/* コントラクト所有者のアドレス */
address owner;
/* 初期化時に呼ばれる関数 */
constructor() public {
owner = msg.sender; // 所有者を設定
}
/* 自己破棄する関数 */
function kill() public {
if (msg.sender == owner) {
// コントラクトに格納された Ether を回収した後、
// ストレージとコードを削除する。
selfdestruct(owner);
}
}
}
/* 挨拶コントラクト */
contract Greeter is Mortal {
/* メッセージ */
bytes32 greeting;
/* 初期化時に呼ばれる関数 */
constructor(bytes32 _greeting) public {
greeting = _greeting; // メッセージを設定
}
/* メッセージを取得する関数 */
function greet() public view returns (bytes32) {
return greeting;
}
}
EOF
Mortal は、 kill
関数による自己破棄可能なコントラクトで、この特性は Greeter に継承されます。所有者だけが kill
関数を呼び出すことが出来ます。コントラクトが必要なくなった時にブロックチェーンを掃除し、資金を回収する目的があります。これを定義しないと展開した後に破棄することが出来ないので、実装を検討してください。
コンパイル
次の二つの方法があります。
- Solidity コンパイラを使用する
- Web ベースの Solidity IDE である Remix を使用する
Solidity コンパイラを使用する
Solidity コンパイラの solc
を使用するため、ドキュメントに従いビルドします。
次のシェルスクリプトは、ドキュメントのリンク先にある、ソースコードからのビルド手順をまとめたものです。
git clone --recursive https://github.com/ethereum/solidity.git
cd solidity
git checkout v0.4.24 # Select from `git tag -l`
./scripts/install_deps.sh
./scripts/build.sh
solc # Show help message
homebrew
の入っていない macOS の場合は、次のようにビルドします。
Installing Boost on macOS
curl -OL https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.gz
tar xzf boost_1_66_0.tar.gz
cd boost_1_66_0
./bootstrap.sh
sudo ./b2 install --prefix=/usr/local/boost
Installing Solidity on macOS
git clone --recursive https://github.com/ethereum/solidity.git
cd solidity
git checkout v0.4.24 # Select from `git tag -l`
sudo BOOST_ROOT=/usr/local/boost scripts/build.sh
solc # Show help message
Greeter.sol
をコンパイルします。
solc -o target --bin --abi Greeter.sol
次のように target というディレクトリに .abi (Application Binary Interface) と .bin が作成されます。
tree
.
├── Greeter.sol
└── target
├── Greeter.abi
├── Greeter.bin
├── Mortal.abi
└── Mortal.bin
実際に Geth コンソールを起動し、コントラクトを作成してみます。Greeter には Mortal が含まれているため、 Greeter を展開するために Mortal を作成する必要はありません。
var greeterFactory = eth.contract(...); // Greeter.abi の内容を渡す
var greeterCompiled = "0x" + "..."; // Greeter.bin の内容を渡す
展開する前にアカウントをアンロックします。
personal.unlockAccount(eth.accounts[0], '');
作成したコントラクトをネットワークへ展開します。 Contract mined! Address
と表示されれば成功です。
var _greeting = "Hello World!"
var greeter = greeterFactory.new(_greeting, {from: eth.accounts[0], data: greeterCompiled, gas: 4700000}, function(e, contract) {
if (e) {
console.error(e); // If something goes wrong, at least we'll know.
return;
}
if (!contract.address) {
console.log("Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined...");
} else {
console.log("Contract mined! Address: " + contract.address);
console.log(contract);
}
});
Remix を使用する
solc
をインストールしていない場合は、 Remix を使用します。
コントラクトの作成・展開の手順は次の通りです。
- ソースコード
Greeter.sol
を Remix にコピーして、コンパイルされることを確認 - 右ペインのドロップダウンメニューで Greeter が選択されていることを確認
- ドロップダウンの右にある Details ボタンをクリック
- ポップアップを下にスクロールして WEB3DEPLOY の内容をコピー
yourFilename.js
を作成し、コピーしたコードをペースト- ローカル開発環境での作業
Remix での作業
selfdestruct
に関する警告が出ると思いますが、呼び出し元チェックにより安全とみなし、無視しています。
ローカル開発環境での作業
yourFilename.js
の最初の行を次のように変更してください。
var _greeting = "Hello World!";
geth
コンソールを起動して、アカウントをアンロックします。
personal.unlockAccount(eth.accounts[0], '');
スクリプトを読み込んでコントラクトを作成・展開します。
loadScript("yourFilename.js");
マイニングが完了すると、次のようなメッセージが表示されるはずです。
Contract mined! address: 0xdaa24d02bad7e9d6a80106db164bad9399a0423e
コントラクトが正常に展開できたかどうかを確認するには、次のコードを実行します。
eth.getCode(greeter.address);
0x
以外の値を返せば成功です!
実行
挨拶してみます。チェーンに変更を加えないので Gas コストなしで実行できます。
greeter.greet();
コントラクト作成時に予め決めたメッセージが表示されるはずです。
"Hello World!"
同じコントラクトを再度実行するには、Address
と ABI
が必要になります。次のようにすることで、同じコントラクトの JavaScript オブジェクトをインスタンス化できます。
var greeter2 = eth.contract(greeter.abi).at(greeter.address);
コントラクトを破棄
将来的にはスケーラビリティを高めるためにブロックチェーンのレンタル機能が実装されるかもしれないとのことですが、現時点では、不要になったコントラクトは、ブロックチェーン上に放棄されます。
次のコードを実行すると、ブロックチェーンに加えられた変更に対して支払う手数料が発生します。ただし、自己破壊はネットワークによって助成されるので、通常の取引よりもはるかに安くなります。
greeter.kill.sendTransaction({from: eth.accounts[0]});
Greeter.sol
で定義した通り、所有者 (from: owner) の呼び出しに限定しているため、それ以外のアドレスからは実行できません。次のコードを実行して 0x
を返せば破棄が完了しています。
eth.getCode(greeter.address);
おわりに
基本的にチュートリアル通りの内容ですが、最新バージョンで廃止になっているコードを置き換えたり、コンパイルが通らない箇所など、部分的に書き換えているところがあります。
この記事について、何か気になるところがあれば、お気軽にご連絡ください!