仮想通貨をマイニングする その1
やること
仮想通貨をマイニングする
準備
マイニングマシン(マイニングリグ)の構築
色々なサイトを参考に以下のパーツで組んでみました。
ケース(マイニングフレーム)
ProjectM-PM-MINING-F-ver2
自作する人も多いようですが初心者なので購入しました。マザーボード
B250-MINING-EXPERT
十何枚もグラボを載せる予定はないですが複数電源をブリッジする手間がないようなのでこれにしました。CPU
Intel CPU Celeron G3930
CPUはそんなに高スペックいらないのでこのあたりで。メモリ
Crucial [Micron製] DDR4 デスク用メモリー 4GB
メモリもスペックいらないのでこのあたりで。電源
Corsair RM1000x
電源はもう少し高効率のものが良かったのですがほとんど売り切れだったのでこれで、足りなければ追加する予定です。グラフィックボード(GPU)
ASUS エイスース TURBO-GTX1080-8G
AMD系は軒並み売り切れだったので、NVIDIAのGPUにしました。Nicehashと価格コムでコスパ良さそうなのを適当に選びました。 3枚買ってみましたが電源が足りない気もするので、とりあえず2枚スタートにする予定です。ライザーカード
HENGBIRD PCI-E 1X to 16X ライザー エクステンダーカード
初めて購入しましたが、GPUをマザーボードに複数枚接続するときに使う機器です。このカードにも補助電源が必要になるのですが、PCIe8pinでも電源供給ができるのでこれにしました。サーキュレーター アイリスオーヤマ サーキュレーター PCF-HD15N-B
マイニングフレームが剥き出しなのでファン代わりにました。温度が下がらなかったらファン付ける予定です。
組み立て
部品が届きました。
フレームを組み立てて、マザーボード→CPU→メモリ→電源→GPUの順に繋いで完成。
OSはここでダウンロード版を購入したのでUSBメモリを使って起動USBを作成します。 手順は以下を参考にします。
MacでethOSのイメージをUSBメモリに焼く - Qiita
- Webで購入するとメールでダウンロードコードとリンクが送られてくるのでOSをDownloadします。回線が細いのか1時間くらいかかりました。
- ダウンロードしたethos-*.xzファイルを解凍します。
- diskutil でディスクの番号を確認してddコマンドで焼きます、かなり時間かかりました。(1日置いてみてみたら終わってました。)
ethOS起動
- ※モニタはGPUではなくてマザボに挿してください
- USBをマザボに挿して、マウスとキーボードつけて電源を入れます
- 勝手にUSBからのOS起動になりマイニングが始まるはずです ※写真はマイニングアドレス等設定後のものです
GTX1080を1枚の構成で211wくらいのようです。あと2枚追加予定ですがこれなら大丈夫かな・・?
設定ファイルの更新
設定ファイルはホームディレクトリ直下のlocal.confにあるのでこれを編集します。(左下のメニューからedit local.confでもいけます。)
バックアップとって編集します。
$ cp -p local.conf local.conf.bk $ vim local.conf
以下の内容でファイルの先頭にあるデフォルト設定を上書きます。
今回はZcashをマイニングしてみます。ethOSでは Ethereum(ETH)、Monero(XMR)、Zcash(ZEC)がマイニングできるようです。
globalminer ewbf-zcash maxgputemp 85 stratumproxy enabled proxywallet 自分のZcashのアドレス proxypool1 asia1-zcash.flypool.org:3333 proxypool2 cn1-zcash.flypool.org:3333 globalfan 85
globalminer は実際にマイニングを行うソフトでethOSに入っている中から選択します。 以下説明でグラボにGTXシリーズを使う予定なのでewbf-zcashにしてみました。
# globalminer: set global miner (ethminer sgminer-gm claymore claymore-zcash optiminer-zcash sgminer-gm-xmr cgminer-skein ewbf-zcash dstm-zcash ccminer) # NOTE: ewbf-zcash, dstm-zcash and ccminer (xmr, and others) is for nvidia; for ccminer flags, see http://ethosdistro.com/ccminer.txt )
maxgputempはGPUの温度設定でこれを超えるとマイニングが止まるらしいです。デフォルト値にしておきます。
proxywallet に設定するZcashのアドレスは事前に取得しておきます。jaxxというウォレットを使いました。 アドレスをコピペするにはローカルのMacからethOSにSSHでログインすると簡単です。
$ ethos@{画面に表示されるIPアドレス} $ live (デフォルトパスワード)
proxypool1 にはマイニングプールのサーバーを設定します。今回はflypoolというマイニングプールを使うことにしたのでそのアドレスをセットします。
※ethOSではリモートコンフィグというネットワークを通じてlocal.confを同期する機能がデフォルトONになっているのでこれをOFFにします。
$ force-local
再起動します。
$ r
再起動後に設定を確認して元の設定にロールバックしていなければOKです。
マイニング収益の確認
マイニングプールから利益が分配されるのに少し時間がかかるのでマイニングの状況を知りたい場合はマイニングプールのWebサイトで見れます。
左上のアドレスに自分のアドレスを入れるとマイニング状況が見れます。
ethOSのメニューの一番上から見れる ethOS stats panel の結果とあっていればOKです。flypoolだと0.01zecごとに収益が送金されます。
ハッシュレート
GTX1080 1枚だと500H/sくらいのレートが画面には表示されていますが、3日間の平均では480H/sくらいに落ち着いていました。
しばらく稼働させたらマイニング結果を報告します!
GCP+Mailgun+Railsでメール送信を行う
やること
Railsで作ったアプリからのメール送信をGCP(Google Cloud platform)+ Mailgunの環境で行えるようにする
GCPへのMailgun導入
公式のドキュメントがあるので以下を参考に導入してきます。
Mailgun でのメールの送信 | Compute Engine ドキュメント | Google Cloud Platform
Mailgunアカウント作成
↑のリンクからアカウントを作成するとSandbox(テスト用)ドメインが初期状態で存在していますが本番で使いたいので新規作成します。
Domains → Add New Domain と進んでドメイン名を入力します。
入力するドメインは保持しているドメインのサブドメインを使います。
(hatena.comの場合はmail.hatena.comとかにする)
GCPへの設定追加
Mailgunドメイン作成後にDNS設定内容が画面に表示されるのでこれをGCPのDNS設定画面に追加していきます。
以下のDNSレコードを追加します。
TXTレコード2つ(空白が含まれるのでダブルコーテーションで囲って入力)
MXレコード1つ(10 mxa.mailgun.org.と10 mxb.mailgun.org.の2つの値を入力)
CNAMEレコード1つ
設定が完了したらMailgunのDomainsメニューで設定の確認を行います。(DNSの伝播に少し時間がかかるので2,3分空けてください)
Check DNS Records Now を押して全てグリーンになればOKです。
Railsの設定
Gemfile
gem 'mailgun_rails'
production.rb
config.action_mailer.delivery_method = :mailgun config.action_mailer.mailgun_settings = { api_key: 'mailgunのDomains→API Keyの項目をコピー', domain: 'mailgunのDomains→一番上のDOMAINをコピー' }
メール送信をアプリから実行してみて正常に受信できれば完了です!
VSCodeのVueプラグイン(Vetur)でtemplateタグがLintエラーになる(修正済み)
Vueのソースコードを書くのにVeturというプラグインでシンタックスハイライト&Lintを付けていますがv0.11.4でtemplateタグのLint仕様が変更になったようです。
Veturのバリデーションを無効にするか、lang=htmlを付けることで治りますLintの対象外にできます。
Setting.json
{ "vetur.validation.template": false, }
<template> ↓ <template lang="html">
GithubのIssueにも上がっていました。
[vue-language-server] '<template>' should have end tag. · Issue #578 · vuejs/vetur · GitHub
追記
本日(2017/12/15)リリースされたv0.11.5で修正されました!早い!
Java(SpringBoot)でbitcoindのJSON-RPCを利用する
やること
bitcoindはJSON形式でブロックやトランザクションの情報を取得できるJSON-RPCという通信プロトコルをサポートしています。
今回はSpringBootで作成したプロジェクト上で、bitcoind JSON-RPCを呼び出すサンプル実装を行います。
事前準備
SPRING INITIALIZR を使ってテンプレートプロジェクトを作成します。
以下の環境で作業を行います。
- Java9
- SpringBoot2.0.0M6
- jsonrpc4j
実装してみる
jsonrpc4j(Java向けJSON-RPCライブラリ)
JavaでJSON-RPCを利用するのにJava用ライブラリであるjsonrpc4jを使用します。
build.gradleの依存関係に追加します。
build.gradle
dependencies { (Spring関連は省略) compile group: 'com.github.briandilley.jsonrpc4j', name: 'jsonrpc4j', version: '1.5.1' }
Configクラスの作成
JSON-RPC Clientが呼び出すURLやユーザー・パスワードの設定を行います。
Server側となるbitcoindのconf設定は以下の記事と同じ前提です。
以下のクラスを作成して適当なディレクトリに配置します。
BitcoindConfig.java
@Configuration public class BitcoindConfig { private static final String endpoint = "http://localhost:18332"; private static final String rpcuser ="username"; private static final String rpcpassword ="password"; public BitcoindConfig() { Authenticator.setDefault(new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication (rpcuser, rpcpassword.toCharArray()); } }); } @Bean public JsonRpcHttpClient jsonRpcHttpClient() { URL url = null; //You can add authentication headers etc to this map Map<String, String> map = new HashMap<>(); try { url = new URL(endpoint); } catch (Exception e) { e.printStackTrace(); } return new JsonRpcHttpClient(url, map); } @Bean public BitcoindClientAPI bitcoindClientAPI(JsonRpcHttpClient jsonRpcHttpClient) { return ProxyUtil.createClientProxy(getClass().getClassLoader(), BitcoindClientAPI.class, jsonRpcHttpClient); } }
testnet,regtestのデフォルトポートは18332、本番環境は8332です。
JSON-RPC用のインターフェースクラスの作成
次にJSON-RPC用のインターフェースクラスを作成します。
@JsonRpcMethodアノテーションでマッピングするAPIを指定することでJSON-RPCを呼び出すことができます。
呼び出したいAPIは以下を参考に引数、返り値を合わせます。
今回は getblock APIを呼び出してみるのでblockhashとverbosityを引数に設定して、返り値はverbosity=1の想定でAPI Resultに合わせたPOJOを定義しておきます。
BitcoindClientAPI.java
public interface BitcoindClientAPI { @JsonRpcMethod("getblock") GetBlockResult getBlock(@JsonRpcParam(value = "blockhash") String blockhash, @JsonRpcParam(value = "verbosity") int verbosity); }
GetBlockResult.java
@Getter @Setter public class GetBlockResult { private String hash; private int confirmations; private int size; private int strippedsize; private int weight; private int height; private int version; private String versionHex; private String merkleroot; private List<String> tx; private int time; private int mediantime; private int nonce; private String bits; private int difficulty; private String chainwork; private String previousblockhash; private String nextblockhash; }
呼び出し元コントローラーの作成
@RestController @RequestMapping("bitcoind") public class BitcoindRpcController { @Autowired private BitcoindClientAPI bitcoindClientAPI; @RequestMapping(value = "block/{blockhash}", method = RequestMethod.GET) public GetBlockResult getBlock(@PathVariable("blockhash") String blockhash) { return bitcoindClientAPI.getBlock(blockhash, 1); // verbosity = 1 } }
動作確認
./gradlew bootRunでプロセスを起動し、以下のURLを叩いてブロックの情報が取得できればOKです。 http://localhost:8080/bitcoind/block/{blockhash}
※{blockhash} の部分にはbitcoin-cliのgenerateコマンドで実際に産出されたブロックのHash値を指定してください。
Spring Webfluxで例外ハンドリングを行う
やること
SpringWebflux導入にあたって例外ハンドリングの方法を調べて実装します。
SpringMVCだとControllerAdvice+ResponseEntityExceptionHandlerを使って共通の例外ハンドリングとかを実装していると思いますが、これらが使えなくなるので替わりの方法を探します。
WebfluxのAPI実装について
このブログの内容を参考にさせていただきました。
はじめてのSpring WebFlux (その1 - Spring WebFluxを試す) - BLOG.IK.AM
Webfluxでも@Controller使った実装が使えますが、他にRouter Functionsというモデルを使って実装できるようになっています。
今回、例外ハンドリングを実装するにあたってRouter FunctionsのFilter機能を使っているので、主にRouter Functionsを使った実装になっています。
@Controller使った共通的な例外ハンドリングの仕組みはみつからなかったので今回は言及しません。
事前準備
SPRING INITIALIZR を使ってテンプレートプロジェクトを作成します。
SpringBootは2.0系を選択して、ReactiveWebをDependenciesに入れておきます。
以下の環境で作業を行います。
- Java9
- SpringBoot2.0.0M6
Router Functionsクラスの実装
ハンドラクラスの作成
/parent/child1のGETメソッドと/parent/child2へのPOSTメソッドの2つのAPIを定義したハンドラクラスを作成します。
nest()を利用することでパスのネストを定義することができます。
コメントアウトしていますが、GETなどでクエリからパラメータを取得する場合はqueryParam()で取得できます。またPOSTなどでBodyからパラメータを取得する場合はbodyToMonoで任意のMonoクラスに変換できます。
GetSampleResult、PostSampleRequest は適当なPOJO、WebfluxServiceも適当なダミーのServiceクラスです。
WebfluxHandler.java
@Component public class WebfluxHandler { @Autowired private WebfluxService webfluxService; public RouterFunction<ServerResponse> routes() { return nest(path("/parent"), route(GET("/child1"), this::getSmple) .andRoute(POST("/child2"), this::postSample) ); } private Mono<ServerResponse> getSample(ServerRequest req) { // int a = Integer.valueOf(req.queryParam("aaa").orElse("1")); // String b = req.queryParam("bbb").orElse("defaultValue"); // return ok().body(Flux.just(webfluxService.getSample(a, b)), GetSampleResult.class); return ok().build(); } private Mono<ServerResponse> postSample(ServerRequest req) { // PostSampleRequest param = req.bodyToMono(PostSampleRequest.class).block(); // webfluxService.postSample(param.getName, param.getValue()); return ok().build(); } }
WebfluxのConfigクラスでfilterを定義
先ほど作成したハンドラを呼び出すことでルーティング設定が有効になります。
併せて.filter()を呼び出すことでException発生時の挙動を定義しています。
routes().andRoute()を呼び出すことで複数ハンドラに対してfilterを設定することもできます。
WebfluxRoutesConfig.java
@Configuration public class WebfluxRoutesConfig { @Bean public RouterFunction<ServerResponse> routes(WebfluxHandler webfluxHandler ) { return webfluxHandler.routes().filter((request, next) -> { try { return next.handle(request); } catch (Exception e) { log.error("An error occured", e); return ServerResponse.badRequest().build(); } }); } }
動作確認
/gradlew bootRunでプロセスを起動して、上記のパスへのHTTPリクエストに対して期待した応答が返ればOKです。
内容確認したい場合はコメントアウトを外して任意のメッセージを返したりExceptionを発生させたりしてみてください。
Spring WebfluxのWebsocketを使ってサーバー間通信
やること
Webfluxを導入してみたので、既存のspring-bootに入っているwebsocketからwebfluxのサポートするwebsocket実装に切り替える。
サーバー間通信で使用するので、通信としてのServerもClientもJavaで実装する(ブラウザは使用しない)
事前準備
SPRING INITIALIZR を使ってテンプレートプロジェクトを作成します。
SpringBootは2.0系を選択して、ReactiveWebをDependenciesに入れておきます。
以下の環境で作業を行います。
- Java9
- SpringBoot2.0.0M6
Websocketクラスの実装
Serverサイドのマッピングの設定
FluxWebSocketConfig.java
Mappingを設定することで指定したパスでwebsocket通信が受付できるようになります。
@Configuration public class FluxWebSocketConfig { @Autowired private FluxWebSocketHandler handler; @Bean public HandlerMapping webSocketMapping() { Map<String, WebSocketHandler> map = new HashMap<>(); map.put("/path", handler); SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); mapping.setUrlMap(map); mapping.setOrder(-1); // before annotated controllers return mapping; } @Bean public WebSocketHandlerAdapter handlerAdapter() { return new WebSocketHandlerAdapter(); } }
FluxWebSocketHandler.java
Handlerでは通信後の処理を記述しています。最初の通信でhandle()がコールされるので、ここでEmitterProcessorを返却するようにしています。
セッション確立後にsendMessageを使ってメッセージを配信するようにしていますが、ここでEmitterProcessorに対してMessageを渡すことでClient側に伝播されます。
@Slf4j @Component public class FluxWebSocketHandler implements WebSocketHandler { private final EmitterProcessor<String> in = EmitterProcessor.create(); public void sendMessage(String message) { log.info("Send Message:" + message); in.onNext(message); } @Override public Mono<Void> handle(WebSocketSession session) { session.receive() .map(WebSocketMessage::getPayloadAsText) .log() .subscribe(); return session.send(Mono.just(session.textMessage("connected!"))).then(session.send(in.map(session::textMessage))); } }
session.receive()の処理はClient側からのメッセージを受けないのであれば不要です。
Clientサイドのリクエストの設定
FluxWebSocketClientSample.java
リクエスト処理は別スレッドで起動しています。(本当はWebSocketClientの機能で別スレッド起動ができるはずです。。。)
@Slf4j @Component public class FluxWebSocketClientSample { @PostConstruct private void init() { ExecutorService executor = Executors.newSingleThreadExecutor(); Runnable runner = this::connect; executor.execute(runner); } private void connect() { try { Thread.sleep(10 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } WebSocketClient client = new ReactorNettyWebSocketClient(); client.execute(URI.create("ws://localhost:8080/path"), session -> session.receive() .map(WebSocketMessage::getPayloadAsText) .log() .then() ) .subscribe(); } }
↑のサンプルではServer→Clientの送信だけですが、双方向でメッセージを送りたい場合はこちらでもEmitterProcessorを設定します。
動作確認
./gradlew bootRunでプロセスを起動して.logメソッドによるメッセージが表示されたら成功です。
適当なクラスを用意してFluxWebSocketHandler.sendMessage()を呼び出すことで任意のメッセージを伝播することができるはずです。
最後に
全般的にReactorNettyWebSocketClientやEmitterProcessorの仕様・使い方がわかりません。。。まとまっている資料やサイトがあれば教えてください。。。
Docker上のWordpressをサブディレクトリで動かす
やること
Dockerを使ってWebサイトを公開しているが、同じドメインのサブディレクトリでWordpressで作ったブログを表示させたい。
以下のような構成になるイメージです。
http://hoge.co.jp <- メインのWebサイト http://hoge.co.jp/blog <- 追加するブログ用のサブディレクトリ
WordpressのDockerfileの作成
公式のWordpressイメージのルートを変更するやり方がわからなかったのですが、以下のブログの記事を参考にさせてもらいました!
Dockerの公式WordPressイメージを使い、下層ディレクトリにある既存のWordPressを動かす - Docker入門 | ねこしすてむ
wordpress コンテナのアクセス用IPアドレスの取得
IPアドレスは固定で設定していないので直接コンテナから取得します。(コンテナ名がwordpressの場合)
$ sudo docker-compose exec wordpress bash $ ip route show | awk '/default/ {print $3}' 172.19.0.1
nginx.conf の修正
server定義に以下を追加します。
proxy_passにはwordpressコンテナのIPを設定します。
server { (省略) location ^~ /blog { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_pass http://172.19.0.1:8000; } }
/blogにアクセスしてWordpressのトップページが表示されたら完了です。