【本文】
Ethereumのスマートコントラクトを開発する際、別のコントラクトを呼び出し実行するケースが出てくると思います。
今回は、シンプルなコードで呼び出し事例を紹介します。内容は初心者向けです。
RemixでSolidityベースのスマートコントラクトを開発し、MetaMaskを使い、Ropsten(テストネットワーク)にデプロイしています。本格的にやる場合は別ですが、少し触ってみたいとか、社内向け勉強会で使用する場合等は、特に環境構築で頑張らなくても、Google Chrome上でスマートコントラクトの開発・デプロイ・実行が簡単にできるので、このやり方は覚えておくと良いです。
なお、MetaMaskの導入方法やRemixとRopsten Test Netとの連携方法等は【参考資料】で掲載しているリンクもご参考ください。
【スマートコントラクト】
今回のサンプル
testCalc
- calcNumメソッド: input値(uint)を与え、加算。
- getNumメソッド: Storageからxに格納された値(計算結果)を参照。
testCalc.sol
pragma solidity ^0.4.24;
contract testCalc {
uint x;
//計算
function calcNum(uint _x) external{
x = x + _x;
}
//計算結果取得
function getNum() public view returns(uint){
return x;
}
}
testCalcCaller
- 参照先のContract(今回は「testCalc」)をimport。
- コンストラクタで、参照先のContractアドレスを取得しオブジェクトにする。
- CntParcalcValueメソッド: 参照先contractの計算メソッド(calcNum)を呼び出す。
testCalcCall.sol
pragma solidity ^0.4.24;
// 参照先のコントラクトをimport
import './testCalc.sol';
contract testCalcCaller {
testCalc public cntAddr;
//コンストラクタ
constructor(address _cntAddr) public {
require(_cntAddr != 0x0);
//オブジェクト
cntAddr = testCalc(_cntAddr);
}
function CntParcalcValue(uint a) external {
// cntAddrからcalcNumを実行する
cntAddr.calcNum(a);
}
}
【デプロイ】
- (図1)Remix (https://remix.ethereum.org/) をGoogle Chrome上で開き、上記のコントラクトをそれぞれ別ファイルとして作成する。(ファイル名:「xxx.sol」)
- この時、Remixの右上タブで「Compile」を選択し、エラーになっていないことを確認しておく。(図は割愛。)
- (図2-3)MetaMaskでテストネットワーク(今回はRopsten)を選択しておく。MetaMaskの左上にあるキツネの絵の右隣のプルダウンメニューでMain Ethereum Networkも含め自由に選択可能。(Mainは本番用のネットワーク。)
- Remix上で「Run」より「Environment: injected Web3」(これでRopstenとRemixが連携される。)を選択し、「コントラクト名: testCalc」を選び、「Deploy」ボタンを押下。
- (図4)MetaMaskが勝手に立ち上がるので、Gas Price(1~4辺り)を設定し、「SUBMIT」ボタンを押下。
- (図5)Remixのコンソール画面上に「creation of testCalc pending...」と言うメッセージが表示され、Etherscanへのリンクが表示される。(TxをEtherscan上で確認できる。)
- 参考として今回デプロイしたTxへのリンクを貼っておく。:「 https://ropsten.etherscan.io/tx/0x31f6e8e8855d7ab58b78e15cb6e7e9549129578c38d121802e6440bf07acddf4 」
- (図6)Remixのコンソール上にデプロイ内容が表示され、右枠にデプロイしたContractアドレス(0x66cc348dee962a7203f5ad72f4e761b059bc09fd)とメソッド等の実行ボタンが表示される。(図例では、「calcNum」と「getNum」)このボタンを通じて、Contractを実行することが可能となる。
- (図7)「getNum」実行結果、「uint256: 0」となっており、まだ計算されていないことを確認。
- (図8)Remix上で今度は「testCalcCall」コントラクトをデプロイする。やり方は、「testCalc」と同じだが、「testCalc」を参照する必要があるので、デプロイ時に「testCalc」のContractアドレス(0x66cc348dee962a7203f5ad72f4e761b059bc09fd)を指定する必要がある。指定したら、「transact」ボタンを押下し実行。
- MetaMaskが自動的に立ち上がるが、やり方は「testCalc」と同じなので図は割愛。
- (図9)Remixのコンソール上にデプロイ内容が表示され、「testCalc」と同様に、右枠にデプロイしたContractアドレス(0x323d96b422e8420fba56cc95d26229e7bc645293)とメソッド等の実行ボタンが表示される。(図例では、「CntParcalcValue」と「cntAddr」)このボタンを通じて、Contractを実行することが可能となる。
- 参考として今回デプロイしたTxへのリンクを貼っておく。:「 https://ropsten.etherscan.io/tx/0x2418485429ce880a37cb6cd9f91ebaea7f7fe8e999d000a37838e28442390962 」
【コントラクト実行】
- 今回は、「testCalcCall」から「testCalc」コントラクトの「calcNum」メソッドを実行するので、Remix上で「testCalcCall」の「CntParcalcValue」メソッドに適当な正数を入力し、コントラクトを実行する。実行の度にMetaMaskが立ち上がるが、図は割愛する。(要は適当なGas Price」を入力し、「SUBMIT」ボタンを押下すればよい。)
- (図10)始めに、「CntParcalcValue」に引数「10」を入力し、コントラクト実行。
- 参考Tx:「 https://ropsten.etherscan.io/tx/0x572472f975b428ec5edfd117777d419438515eb56a637903d6c423685fdfdc62 」
- Remix上で、「testCalc」の「getNum」メソッドを実行すると、「uint256: 10」となり、「testCalcCall」コントラクトから「testCall」コントラクトの「calcNum」メソッドが実行されたことがわかる。
- (図11)続いて、「CntParcalcValue」に引数「5」を入力し、コントラクト実行。
- 参考Tx:「 https://ropsten.etherscan.io/tx/0x61af48306271f9fbca3a77a7f9d4c2ee5d1ac210c3773d9b598438a71f23be78 」
- Remix上で、「testCalc」の「getNum」メソッドを実行すると、「uint256: 15」となり、「testCalcCall」コントラクトから「testCall」コントラクトの「calcNum」メソッドを通じて加算処理が実行されたことがわかる。
- ポイントの一つとして、今回のコントラクトで「getNum」は「view」修飾子を使用している。この「view」を使用することで、トランザクションを発行せずに(つまりgasをかけずに)、直接ストレージに格納された値を参照することが出来る。gasの使用はコントラクト実行者にとっても、またEthereumネットワークにとってもコストや負荷を軽減することになるので、ストレージへの書き込みが不要で読込だけで済む場合は、「view」を使用することが推奨される。
【参考資料】
MetaMask,Remix関連
・「Learning Solidity Part 1: Contract Dev with MetaMask」(Karl Floersch さん)
・「RemixとMetaMaskを使って、Smart Contractの開発環境を整えてみた」(Qiita投稿 by @shiki_tak さん)
Ethereumのブロックチェーン構造
・「Basics of the Ethereum Blockchain」(GitHub: [Japanese] Ethereum Development Tutorial)
requireとgasとの関係について
・「Solidityのassertとrequireとrevertの違い(アルゴリズムとかオーダーとか)」(なかじょ さん)