【Ethereum】Contractをネットワークにデプロイする
Ethereumの勉強を引き続きしています。
Contractをネットワークへデプロイする場合、
今までは、Ethereum WalletやRemix経由で行っていたのですが、ソースをコンパイルしていデプロイする方法がよくわからなかったので調べてまとめてみました。
古いバージョンのgethでは、コンソール上でコンパイルができるようなのですが、最新のgethではできないようです。
なので今回は、javascriptのAPIであるweb3
を使ってSollidityのソースをコンパイルします。
Solidityのインストール
npm install solc
- SolidityのコンパイルをJavascript上で行うためにSolidityのパッケージをインストールします
web3のインストール
npm install web3@0.20.0
- JavaScriptAPI環境であるweb3をインストールします。
- 現状のnpmの最新バージョンは、ベータ版の
1.0.0-beta.13
でしたが、想定のAPIが上手く動かなかったりとハマったためStable版の0.20.0
をインストールしました。
ノード起動
geth --datadir <ネットワークのrootディレクトリ> --mine --nodiscover --maxpeers 0 --networkid <ネットワークID> --rpc --rpcport 8545 --rpcaddr "0.0.0.0" --rpcapi="db,eth,net,web3,personal,web3" --rpccorsdomain "*"
- プライベートネットワークのノードを起動します。
datadir
はプライベートネットワークを作成したディレクトリです。networkid
は任意のIDで大丈夫です。- web3はRPC経由でアクセスするため、RPCを許可します。
- プライベートネットワークの構築方法は以下を参照いただければ幸いです。
Contract
pragma solidity ^0.4.0; contract TestContract { uint data; function set(uint x) { data = x; } function get() constant returns (uint) { return data; } }
- 今回は、このテスト用のContractをコンパイルしてノード上にデプロイしてみます。
- Javascriptを実行するディレクトリ上に上記ファイルを配置しておきます。
Javascript
// 必要なパッケージをインポート const fs = require("fs"); const solc = require('solc'); const Web3 = require('web3'); // web3の初期化 web3 = new Web3(); // プライベートネットワークと接続 if (!web3.currentProvider) { web3.setProvider(new web3.providers.HttpProvider("http://localhost:8545")); } // contractソースをファイルから読み込み // ここは、ソースを文字列として読み込んでいるだけです。 let source = fs.readFileSync('test_contract.sol', 'utf8'); // コンパイル let compiledContract = solc.compile(source, 1); // ABIを取得(配列のキーはなぜか頭に:が必要でした) let abi = compiledContract.contracts[':TestContract'].interface; // コントラクトのバイトコードの取得(頭に0xを付けないと後述のAPIで弾かれる) let bytecode = "0x" + compiledContract.contracts[':TestContract'].bytecode; // デプロイに必要なGasを問い合わせる let gasEstimate = web3.eth.estimateGas({data: bytecode}); // コントラクトオブジェクトの生成 let TestContract = web3.eth.contract(JSON.parse(abi)); // デプロイアカウントのLockを外す web3.personal.unlockAccount(web3.eth.accounts[0], "<アカウントのパス>"); // ネットワークにデプロイ // コンストラクタがある場合は、ハッシュの前の引数にコンストラクタのパラメタを渡すことで初期化可能 TestContract.new({from: web3.eth.accounts[0], data:bytecode, gas:gasEstimate });
- このJavascriptを実行します
node deploy.js
デプロイの確認
INFO [08-02|22:49:38] Submitted contract creation fullhash=0x7605a5560f0d729f89f5b1e4ea632d84b4ebd038f930d53620c521adc8f90f0d contract=0xd06c3fce760aa1ab550b0cde8fe4792a1e4a3e11
- 上記のようなログがgethに出力されていればデプロイに成功しています。
デプロイしたコントラクトを使う場合
const Web3 = require('web3'); web3 = new Web3(); // providerとの接続 if (!web3.currentProvider) { web3.setProvider(new web3.providers.HttpProvider("http://localhost:8545")); } let abi = [{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"}]; let address = "0xd06c3fce760aa1ab550b0cde8fe4792a1e4a3e11"; let TestContract = web3.eth.contract(abi); let contract = TestContract.at(address); let num = contract.get.call(); console.log(num.toPrecision());
- 一度ネットワークにデプロイされたコントラクトは
ABI
とコントラクトのアドレス
からアクセスすることが可能です
0
- 現状は、値のセットがされていないため0が返ります。
参考リンク
https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethcontract