web3.jsでEthereumのwallet作成 (with Nuxt.js)

はじめに

web3.jsを使ってEthereumの送金処理を作成してみました。 フレームワークには、Nuxt.jsを使いました。

f:id:loosefingers:20180419145003p:plain

GitHub

今回作成したサンプルはこちらから

github.com

ひとまず、実装したのは以下の基本的な機能のみ。 web3.jsからプライベートネットのAPIを叩いていきます。

  • nodeの状態確認
  • addressの新規作成
  • addressの一覧(及びbalance)
  • 送金機能

事前準備 PrivateNet

前提として、EthereumのPrivateNetを起動する必要があります。 以下のようなコマンドになりますが、この部分の詳しい説明はここでは省きます。 PrivateNetを起動する事によりweb3.jsから利用できるAPIが用意されます。

geth --networkid "10"  \
     --nodiscover  \
     --datadir `pwd`   \
     --rpc   \
     --rpcaddr "localhost"   \
     --rpcport "8545"   \
     --rpccorsdomain "*"  \
     --rpcapi "eth,net,web3,personal,accounts" \
     console 2>> `pwd`/geth_err.log
--rpcapi "eth,net,web3,personal,accounts" 

rpcapiのオプションで、web3を許可しておく必要があります。 rpcapiAPIで受け付けるHTTP-RPCインターフェースの種類の指定になります。

アカウント新規作成

personal.newAccount("password")

coinbaseの設定

miner.setEtherbase(eth.accounts[0])

マイニングを開始

> miner.start() 

マイニングを開始する事で、送金時のトランザクションが処理されます。

web3.js (Ethereum JavaScript API)

Generic JSON RPC仕様を実装したEthereum互換のJavaScript APIとの事。 https://github.com/ethereum/web3.js

npm install web3

web3.jsを経由してNuxt内部でEthereumのAPIを利用していきます。

CoinBase

bakanceを取得する簡単な例。

import Web3 from 'web3';

const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
const address = "0x5d8cd11ab2867895a3ce1b38f04569716ccec273"

web3.eth.getBalance(address).then( balance => {
   console.log(balance)
});

=> 27638999999998999999700

JSON-RPC

web3.jsのAPIは、JSON-RPCから取得する方法もあります。 以下、初歩的な呼び出し方法。

 curl -H "Content-type: application/json" -H "Accept: application/json" -X POST http://localhost:8545  --data '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":1}'

=> {"jsonrpc":"2.0","id":1,"result":"Geth/v1.8.3-stable/darwin-amd64/go1.10.1"}

Node情報の取得

web3.jsから情報を取得して、Vue.jsのdataに格納しています。

 this.Host = web3.currentProvider.host;
 web3.eth.isMining().then(val=>this.IsMining=val);
 web3.eth.getHashrate().then(val=>this.HashRate=val);
 web3.eth.getGasPrice().then(val=>this.GasPrice=val);
 web3.eth.getBlockNumber().then(val=>this.BlockNumber=val);
 web3.eth.net.getId().then(val=>this.NetId=val);
 web3.eth.net.getPeerCount().then(val=>this.PeerCount=val);

Addressの新規作成

 web3.eth.personal.newAccount(this.Password).then(()=>{
    this.Password = "";
    web3.eth.getAccounts().then(val=>this.Accounts=val);
 });

Addressの一覧の取得

 web3.eth.getAccounts().then(val=>this.Accounts=val);

送金処理

  web3.eth.personal.unlockAccount(this.CoinBase, this.PassWord).then(()=> {
          web3.eth.sendTransaction({
            from: this.CoinBase,
            to: this.To,
            value: this.SendValue
          }, (error, txHash) => {
            console.log("Transaction Hash:", txHash, error);
            this.TransactionHash = txHash;
            this.SendValue = 0;
            this.To = this.Accounts[0];
            if (!error) {
              web3.eth.getBalance(this.CoinBase).then(val => this.Balance = val);
            } else {
              alert("Ether Transfer Failed");
            }
  });

Command

web3.jsを利用せずに直接ethを送金するコマンド

eth.sendTransaction({from: eth.accounts[1], to: eth.accounts[0], value: web3.toWei(3, "ether")})

バランスの確認

eth.getBalance(eth.accounts[0])

ブロックナンバーの確認

eth.blockNumber

ハッシュレートの確認

eth.hashrate

coinBase指定

miner.setEtherbase(eth.accounts[1])

現在のcoinBase確認

eth.coinbase
=>"0x4338f1861bca03160caa6986fe6b816411c74807"

参考サイト

Web3.js document https://web3js.readthedocs.io/en/1.0/index.html

ReactNative Native UI Components

github.com

ReactNativeとNative機能のBridgeのサンプル。 このサンプルはIOSのみですが気軽にNative機能にアクセスできるのは素晴らしい。

単純なUI部分はReactNativeで実装して、react-native-router-fluxなどのRouter機能と合わせて使っていくと、作業の効率は向上するんじゃないかと思う。 2回めのReactNativeの実装のチャレンジをしていますが、ホットリロードでWebの感覚でUIを組み立てていけるのは、やはり気持ちいい。

最初に触った0.18のバージョンに比べると、0.49はかなりこなれた感じ。もう少しサンプルを育てていこうと思います。

Keras 事はじめ

Kerasを使ってCSVから読み込んだデータを元にしてmodelの学習及びserver化を実行してみる。

https://keras.io/ja/

train.py

データはcsvから読み込んでみました。tensorflowの場合はload_csv_with_headeというメソッドからcsvを読み込んでいましたが、kerasには専用のmehodが用意されていないようなので、numpyのgenfromtxtの機能を使って読み込んでみる。load_csv_with_headeと同じように、最終行を正解値として設定。dtype=intとしているのだけど、float型が混じっていた場合どうでるべきなのだろうか、ひとまず今回はint型のみで完結するデータを作成してみました。

X = genfromtxt('./some.csv',
               delimiter=',',
               skip_header=1,
               usecols=(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14),
               dtype=int)
Y = genfromtxt('./some.csv',
               delimiter=',',
               skip_header=1,
               usecols=(15),
               dtype=int)

input_dimデータ形式に従って15に設定、output_dimは30に、ここはチューニグが必要そう、今回のデータ量ではoutputの値によって精度が変わっている様子は見受けられなかったので、全体的な把握がまだできていないかもしれない。

model.add(Dense(input_dim=15, output_dim=30))

学習したmodelを使って、predictを実行、5000回のepochでそこそこ精度はでるようになりました。

results = model.predict_proba(np.array(
    [
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    ]
))

学習データを保存する為にsave_weightsでデータを保存、HDF5形式のファイルで保存される。ただ、詳細はわかっていないのだけど、互換性のあるデータなのだろうか。

model.save_weights('./learnedModel')

server.py

まず、作成済みのモデル定義を読み込み。

 Sequential.from_config()

次に、学習済みの重みを読み込み。

model.load_weights

以上の手順で無事server化に成功。 学習データを再現したAPIサーバーも手軽に立てる事ができそうです。

github.com