DC4

今よく言われてる「草食系」にはなったらあかん! 野獣のような「肉食系」になるため、今は肉ばっかり食べてるよ。

未使用アウトプットに基づくトランザクションの生成/署名/送信

Mastering Bitcoinの「未使用アウトプットに基づくトランザクションの生成/署名/送信」を実際にコマンドを実行しながら確認します。

環境は前回作成したDocker環境を使用します。

Bitcoin Coreを試すためのDocker環境を作った。 - DC4

Raw Transaction の受取先アドレスを作成します。

# アドレスの作成
root@56451b900162:/# bitcoin-cli -regtest getnewaddress testuser1
mrmcNKkhippXe8WTm7BbLNSoy5CydCZHhV

Raw Transaction に含めるUTXOを選択

#未使用のアウトプット(UTXO)を確認
bitcoin-cli -regtest listunspent 
...
  {
    "txid": "5f76f24fe419f09e7da5010d8e3d110db4189f3b51f797026d619a7ca95416f8",
    "vout": 0,
    "address": "mzLCAPscRZtYZysh2RjUz8XEgXZuAU7e9v",
    "scriptPubKey": "2103562423e4bd01816ee0e06df4b327970b6f5f04ac817ad9e66ab039d20bd34db7ac",
    "amount": 50.00000000,
    "confirmations": 147,
    "spendable": true,
    "solvable": true,
    "safe": true
  }
...

Raw Transaction の作成

# > bitcoin-cli createrawtransaction "[{\"txid\":\"myid\",\"vout\":0}]" "{\"address\":0.01}"
# `txid` 、`vout` に 上記のUTXO、受取先アドレス、送金額(10BTC) / お釣り(39.9995BTC) (手数料: 0.0005) を指定する。
root@56451b900162:/# bitcoin-cli -regtest createrawtransaction "[{\"txid\":\"5f76f24fe419f09e7da5010d8e3d110db4189f3b51f797026d619a7ca95416f8\",\"vout\":0}]" "{\"mrmcNKkhippXe8WTm7BbLNSoy5CydCZHhV\":10,  \"mzLCAPscRZtYZysh2RjUz8XEgXZuAU7e9v\":39.9995}"
020000000100cc5d9cf910e58d423e4e686d67c9719e6e300eb93be1ecdc92ab53e274b2310000000000ffffffff0200ca9a3b000000001976a9145e4973ba22b718b8336c53cc70504ed16e07caf688acb0646aee000000001976a914ce6164048e09beba6beb0ea63fc9a7edc501393e88ac00000000

vout・・・1つのトランザクションを分割する際の番号

出力された16進数をデコードして内容を確認します。

bitcoin-cli -regtest decoderawtransaction 020000000100cc5d9cf910e58d423e4e686d67c9719e6e300eb93be1ecdc92ab53e274b2310000000000ffffffff0200ca9a3b000000001976a9145e4973ba22b718b8336c53cc70504ed16e07caf688acb0646aee000000001976a914ce6164048e09beba6beb0ea63fc9a7edc501393e88ac00000000
{
  "txid": "086065375607d9afd95a105eda40c362dec067bff7d2ba1cedc7002a5b27ce1e",
  "hash": "086065375607d9afd95a105eda40c362dec067bff7d2ba1cedc7002a5b27ce1e",
  "size": 119,
  "vsize": 119,
  "version": 2,
  "locktime": 0,
  "vin": [
    {
      "txid": "31b274e253ab92dcece13bb90e306e9e71c9676d684e3e428de510f99c5dcc00",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 10.00000000,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 5e4973ba22b718b8336c53cc70504ed16e07caf6 OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a9145e4973ba22b718b8336c53cc70504ed16e07caf688ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "mp7VodBS75f57jFgGWHb6NHNCrDH54CxNr"
        ]
      }
    },
    {
      "value": 39.99950000,
      "n": 1,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 ce6164048e09beba6beb0ea63fc9a7edc501393e OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a914ce6164048e09beba6beb0ea63fc9a7edc501393e88ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "mzLCAPscRZtYZysh2RjUz8XEgXZuAU7e9v"
        ]
      }
    }
  ]
}

scriptSigがnullなので、署名が行われていないことが確認できます。

署名の実施

root@56451b900162:/# bitcoin-cli -regtest signrawtransaction 020000000100cc5d9cf910e58d423e4e686d67c9719e6e300eb93be1ecdc92ab53e274b2310000000000ffffffff0200ca9a3b000000001976a9145e4973ba22b718b8336c53cc70504ed16e07caf688acb0646aee000000001976a914ce6164048e09beba6beb0ea63fc9a7edc501393e88ac00000000
{
  "hex": "020000000100cc5d9cf910e58d423e4e686d67c9719e6e300eb93be1ecdc92ab53e274b23100000000484730440220171a3a74c11ce5e7ffcc2a3ee6cf86957edfa955dd0ca3052ea3d1631eb616f5022054a24b3201cbf3d3b979c4d3074ef490be5cf89b8857056021933201d1f2b7e501ffffffff0200ca9a3b000000001976a9145e4973ba22b718b8336c53cc70504ed16e07caf688acb0646aee000000001976a914ce6164048e09beba6beb0ea63fc9a7edc501393e88ac00000000",
  "complete": true
}

もう一度デコードして内容を確認します。

{
  "txid": "7c7f41ccd1d0df0f3ab1009ab7993ec32ff161b9edaa3c196e6644dda54c8efb",
  "hash": "7c7f41ccd1d0df0f3ab1009ab7993ec32ff161b9edaa3c196e6644dda54c8efb",
  "size": 191,
  "vsize": 191,
  "version": 2,
  "locktime": 0,
  "vin": [
    {
      "txid": "31b274e253ab92dcece13bb90e306e9e71c9676d684e3e428de510f99c5dcc00",
      "vout": 0,
      "scriptSig": {
        "asm": "30440220171a3a74c11ce5e7ffcc2a3ee6cf86957edfa955dd0ca3052ea3d1631eb616f5022054a24b3201cbf3d3b979c4d3074ef490be5cf89b8857056021933201d1f2b7e5[ALL]",
        "hex": "4730440220171a3a74c11ce5e7ffcc2a3ee6cf86957edfa955dd0ca3052ea3d1631eb616f5022054a24b3201cbf3d3b979c4d3074ef490be5cf89b8857056021933201d1f2b7e501"
      },
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 10.00000000,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 5e4973ba22b718b8336c53cc70504ed16e07caf6 OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a9145e4973ba22b718b8336c53cc70504ed16e07caf688ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "mp7VodBS75f57jFgGWHb6NHNCrDH54CxNr"
        ]
      }
    },
    {
      "value": 39.99950000,
      "n": 1,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 ce6164048e09beba6beb0ea63fc9a7edc501393e OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a914ce6164048e09beba6beb0ea63fc9a7edc501393e88ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "mzLCAPscRZtYZysh2RjUz8XEgXZuAU7e9v"
        ]
      }
    }
  ]
}

今回は scriptSigが設定されている事が確認できます。

この状態で 署名されたhexsendrawtransaction 等を使用してブロードキャストすることができます。

Gethでetherを送金する

前回作成した環境を使い、アカウント作成/マイニング/送金まで行っていきます。

gethを試すためのDocker環境を作った。 - DC4

以下コマンドでGethのインストール後、テストネットに接続します。

$ docker-compose build
$ docker-compose up

起動後暫くはDAGのダウンロードが行われます。
DAGは ethereumのPoWに必要なもので、詳しくは以下を参照して下さい。
Ethash DAG · ethereum/wiki Wiki · GitHub

コンテナに接続後、Gethにアタッチします。

docker exec -i -t gethdockersample_geth_1 /bin/bash
geth attach ipc://eth_data/geth.ipc

アカウントの作成

以下のコマンドでアドレスを発行します。
引数に入れたパスワードを忘れるとEtherが引き出せなくなるので注意して下さい。 0xから始まる値がアドレスとなります。

> personal.newAccount("hoge1")
> 0x3f10fa5b63d60f1bc89783a11c415b99fe5aac3a

送金受信用としてもう一つアカウントを作成します。

> personal.newAccount("hoge2")
> 0xf7637d91ab359f567e97e901bf4ef75142fb6e96

ここで作成されたアドレスの情報はkeystore配下に格納されています。
以下ファイルを移動する事で別のノードへアドレスを移動することができます。

root@943656414d81:/# ll eth_private_net/keystore/
total 16
drwx------ 2 root root 4096 Aug 12 15:49 ./
drwxr-xr-x 5 root root 4096 Aug 12 15:49 ../
-rw------- 1 root root  491 Aug 12 15:49 UTC--2017-08-12T06-49-18.310228365Z--3f10fa5b63d60f1bc89783a11c415b99fe5aac3a
-rw------- 1 root root  491 Aug 12 15:49 UTC--2017-08-12T06-49-22.989639328Z--f7637d91ab359f567e97e901bf4ef75142fb6e96

マイニング

以下コマンドでマイニング開始/終了が行われます。

> miner.start()
true
> miner.stop()
true

暫く待つと最初に作成されたアドレスにマイニング報酬が付与されます。

> eth.coinbase
"0x3f10fa5b63d60f1bc89783a11c415b99fe5aac3a"

> eth.getBalance(eth.coinbase)
9.575e+21

f:id:Yasun:20170812172900p:plain

送金

マイング報酬を持つアドレス 0x3f10fa5b63d60f1bc89783a11c415b99fe5aac3a から 0xf7637d91ab359f567e97e901bf4ef75142fb6e96 へEtherを送金してみます。

送信元アドレスのロックを解除します。

> personal.unlockAccount(eth.coinbase)
Unlock account 3f10fa5b63d60f1bc89783a11c415b99fe5aac3a
Passphrase:
true

10ETHを送金します。実行後にトランザクションのアドレスが発行されます。

> eth.sendTransaction({from: eth.coinbase, to: "0xf7637d91ab359f567e97e901bf4ef75142fb6e96", value: web3.toWei(10, "ether")})
"0x161da21dfe25da7920bd084c33f66863dedac0248dd92ccb84bdd11e09c33e58"

直後に受取側の残高を確認します。

> eth.getBalance('0xf7637d91ab359f567e97e901bf4ef75142fb6e96')
0

この時点ではまだ送金トランザクションがブロックに取り込まれていないため、残高が反映されていません。 マイニングを開始し、残高を確認します。

> miner.start()
> true
> eth.getBalance('0xf7637d91ab359f567e97e901bf4ef75142fb6e96')
10000000000000000000

10000000000000000000wei がアドレスに反映されています。
weiとはetherの最小単位であり、1weiは1etherの10^-18です。

10etherを受け取ったアドレスから5etherを送り返します。

> eth.sendTransaction({from: "0xf7637d91ab359f567e97e901bf4ef75142fb6e96", to: eth.coinbase , value: web3.toWei(5, "ether")})
"0x5e92caf1391a234aefa768dc8dcd32692da4412523c8c97912d3bb4227c9f4aa"

> eth.getBalance('0xf7637d91ab359f567e97e901bf4ef75142fb6e96')
4999580000000000000

5etherに加えて送金手数料として0.00042etherが余分に支払われていることがわかります。

手数料の内訳を確認するため、送金トランザクションの詳細を確認します。

> eth.getTransaction('0x5e92caf1391a234aefa768dc8dcd32692da4412523c8c97912d3bb4227c9f4aa')
{
  blockHash: "0x1e7127bdba210c3a8f75d26e5508dc9ab00a51f1534543670b7b6aedcedd7435",
  blockNumber: 1924,
  from: "0xf7637d91ab359f567e97e901bf4ef75142fb6e96",
  gas: 90000,
  gasPrice: 20000000000,
  hash: "0x5e92caf1391a234aefa768dc8dcd32692da4412523c8c97912d3bb4227c9f4aa",
  input: "0x",
  nonce: 0,
  to: "0x3f10fa5b63d60f1bc89783a11c415b99fe5aac3a",
  transactionIndex: 0,
  value: 5000000000000000000
}

上記で手数料に関係するのは gasgasPrice の値です。

少しややこしいのですが gas とはトランザクション処理時の最大の 手数料値 です。
実際に発生する料金ではなく、最大で発生する可能性のある料金です。
この値は実行されるトランザクションの内容によって変動し、estimageGasメソッドを用いて見積もる事が可能です。

gasPriceとは 1 gasが何weiかを表す値です。
この値は常に変動しており、gasPriceメソッド等を用いて確認することができます。
Ethereum Average GasPrice Chart

上記の場合は、90000(gas) * 20000000000wei(gasPrice) となり、 最大で0.0018etherの手数料が発生する可能性がある、ということになります。

今回はここまで。

gethを試すためのDocker環境を作った。

こちらも環境構築が面倒だったので作成しました。

github.com

Ver 1.3.6です。

Bitcoin Coreを試すためのDocker環境を作った。

環境構築が面倒だったので作成しました。

github.com

bitcoind -regtest -deamon で起動するのですぐにチュートリアルが開始できると思います。

Developer Examples - Bitcoin

最近試しているRails+Reactの構成

最近試しているRails+Reactの構成について。

Rails + React

Rails上でReactを使用する方法は大きく分けて3パターンに分けることができると考えています。

www.openmindedinnovations.com

  1. react-rails 等のGemを用いてRails内で使用する。
  2. frontendディレクトリ等を作成し、一部JS実装部分をRailsから切り離して yarn/npm/webpack 等で管理する。
  3. APIサーバとクライントで完全に分離する。

フロントエンドの実装ボリュームによってどの構成を選択するかが変わってくると思います。

今回の要望

新規Railsプロジェクトを作成する際の要望は以下でした。

  • フロントエンド専任はいない。
  • SPAにしない。
  • なるべくレールに乗りたい。
  • 複雑な箇所、非同期処理の部分はReactを使いたい。
  • Reduxを使うほどの複雑さでもない。でもFlux的な事はしたい。
  • 適宜jQueryも使いたい。
  • ES6を使いたい。
  • JSライブラリの管理はGemでしたくない。

試している構成

検討した結果、現在はパターン2 の構成で試しています。

Railsプロジェクト内にfrontendディレクトリを作成し、npm/webpack/babel でフロントエンドの開発を行い、その成果物をreact-railsでDOMにマウントしています。

frontend/
├── package.json
├── src
│   ├── components
│   │   ├── hoge-container
│   │   │   └── index.js
│   │   └── huga-container
│   │       └── index.js
│   └── entry.js
└── webpack.config.js

react-railsを使用してDOMにマウントするため、各コンポーネントをグローバルから参照できるようにしておきます。

frontend/src/components/hoge-container/index.js

import MicroContainer from 'react-micro-container';
import React, { Component } from 'react';

export default class HogeContainer extends MicroContainer {
  constructor(props) {
    super(props);
  }
.....
}

frontend/src/entry.js

import HogeContainer from './components/hoge-container';
window.HogeContainer = HogeContainer;

webpackので依存関係を解決したjsファイルを/app/assets/javascripts/配下に配置します。

app/assets/javascripts/
├── application.js
├── cable.js
├── channels
└── entry.bundle.js

View内で react-railsのヘルパーメソッド react_component を使用してマウントします。

....
<%= react_component('HogeContainer') %>
....

Flux的なこと。

react-micro-containerを利用しています。

GitHub - hokaccha/react-micro-container: Micro framework for React

所感

RailsとReactの恩恵をどちらも受けれるので、フロント実装が多くないプロジェクトならやっていけるのではないかなと感じています。

部分的にReactを導入できるので今回のようにフロントエンジニア不在の環境下でも現実的な気がしています。