web3.jsでgethにアクセスする

やっとできたぜゲスゲスゲス…

ゲスをつなげるとなんかやばみがあることがわかったところでWeb3.jsの1.0.0の情報がとても少ないので書いておきます。公式はこちら。
web3.js - Ethereum JavaScript API — web3.js 1.0.0 documentation

とりあえずweb3をインストールする

$ sudo npm install web3

すでにGethが入っているならこれだけで最新版のWeb3は入ります。Web3.jsの0.x.xと1.0.0はかなり違うみたいなのでふるいやつを使いたい場合は注意。

gethサーバーでrpcを有効にする

詳しくはこちらを参照。
qiita.com

開発モードでRPCを有効にします

$ geth --dev --datadir . --gasprice 1 --rpc --rpcapi "eth,net,web3,personal"

rpcapiはとりあえずpersonalも含めておいたがとりあえず動かすだけならいらないかも。

javaScriptを書く

1.0.0のドキュメントにもあるのだが、まずweb3のインスタンスを作ってプロバイダをセットし、そのごIPCプロバイダを設定してコネクションオープンにする。ここがよくわからなかった。なおgeth.ipcはスタートしているGethサーバーが使っているgeth.ipcを使おう(当たり前だね、、、

今回はdatadirをカレントディレクトリにしているがデフォルトにした場合は/home/user/.ethereum/geth.ipcかな

//モジュールごとに必要…というわけではないみたいなのだがgethのオプションで指定していない場合はつけておいたほうが良いのかもというかrpcapiオプションいらないのか?
var Eth = require("web3-eth");
var eth = new Eth("http://localhost:8545");
eth.setProvider("ws://localhost:8546");

var Web3 = require("web3");
//IPC providerを設定する場合は不要。
//var web3 = new Web3("http://localhost:8545");
//web3.setProvider("ws://localhost:8546");

var net = require("net");
var web3 = new Web3(new Web3.providers.IpcProvider("/home/users/test/geth.ipc", net));

web3.eth.defaultAccount = "0xアドレス";
console.log(web3.eth.defaultAccount);

//とりあえず標準出力で結果を出力するためにconsole.logをコールバックに指定
var accounts = web3.eth.getAccounts().then(console.log);
var isMining = web3.eth.isMining().then(console.log);

ぐっとUIが作りやすくなったけどJSよく知らんのよね…


ついでにスマートコントラクトを動かすところまで書くことにしました(というかようやくわかった

Solidityでスマートコントラクトの実装をする

とりあえずget/setの簡単なやつをサンプルにしてみる。

pragma solidity ^0.4.0;
contract Storage {
    uint storedData;

    function set(uint x) public {  
        storedData = x;
    }

    function get() public constant returns (uint) {
        return storedData;
    }
}

Solidityのコードをコンパイルする

これと書いたのと同じ
Ubuntu17でSolidityでスマートコントラクトをする - TOUS LES HOMMES

だがnpmでsolcをインストールしてnode上で使えるようにする方法もあるみたい。まぁこれでも読んどいてや
medium.com

とりあえずabiとbinaryを取得します。

web3jsのコードを書く

var Web3 = require("web3");
var net = require("net");
var web3 = new Web3(new Web3.providers.IpcProvider("/path/geth.iipc", net));

var bin = "0x...."; //コンパイルの結果を貼り付ける
var abi = [{"constnt":false, ...}]; //コピペした場合はこんな感じに。
//var abi = require("./storage.json"); //ファイルに書き出して読み込ませてもよい。
var contract = new web3.eth.Contract(abi);

var accounts = web3.eth.getAccounts().then(function(result, error)
{
    console.log(result[0]); //eth.accounts[0]のアドレス
    var from_address = result[0];
    contract.deploy({data:bin})   /*dataオプションは必須*/
    .send({from: from_address, gas:1000000, gasPrice: "1000000"})  /*sendTransactionでブロックチェーンに登録される*/
    .then(function(x)
    {
        console.log(x.options.address);  //成功していればアドレスが降ってくる
        contract.options.address = x.options.address;   //これをやらないと使えない
        contract.method.get().call({from: from_address}, function(error, y){ console.log(y); }); //Readする場合はcallを使う。戻り値が欲しい時はコールバック関数を指定。このときは初期値のままなのでgetした値は0
        contract.method.set(1).send({from: from_address}) /*Writeする場合はsendを使う。この場合getしたときの戻り値が1になるようにした*/
        .then(function(z)
        {
            contract.method.get().call({from: from_address}, function(error, y){ console.log(y); }); //実行すると戻り値が1になっていることを確認できる
        });
    });
});

こりゃひどい。JSのコーディングパターンとかないのか。あとEvent使えるようにならないとダメぽいですねぇ…