It’s now or never

IT系の技術ブログです。気になったこと、勉強したことを備忘録的にまとめて行きます。

【Ethereum】Contractをネットワークにデプロイする

Ethereumの勉強を引き続きしています。
Contractをネットワークへデプロイする場合、 今までは、Ethereum WalletRemix経由で行っていたのですが、ソースをコンパイルしていデプロイする方法がよくわからなかったので調べてまとめてみました。

古いバージョンのgethでは、コンソール上でコンパイルができるようなのですが、最新のgethではできないようです。
なので今回は、javascriptAPIであるweb3を使ってSollidityのソースをコンパイルします。

Solidityのインストール

npm install solc

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を許可します。
  • プライベートネットワークの構築方法は以下を参照いただければ幸いです。

inon29.hateblo.jp

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 });
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