ラベル Bitcoin の投稿を表示しています。 すべての投稿を表示
ラベル Bitcoin の投稿を表示しています。 すべての投稿を表示

2015年12月31日木曜日

Swapbotを利用してSpells of Genesisのレアカードを販売してみる


Spells of Genesisのカードを結構集めたのですが、このリスキーかつ流動性の低い資産が、ポートフォリオの結構な比率を占めていることに気づき、若干危機感を感じてきました。

まぁBTCが上げてきてるので、結果的に関連サービスへの投資がBTCのショートポジションに見えてきてしまい、少しBTCに戻しておきたいという意味合いもあります。

CounterpartyのDEXでいくらか捌こうかとも思ったのですが、DEXでの出来高が少ないのと、直接BTCで販売出来ないという問題があり、Swapbotについて調べてみました。
(単にSoGが盛り上がってないだけという説もありますが。)

ということで、今回はSpells of Genesisのカード購入でよく利用するSwapbotで、レアカードの自動販売機を設置してみます。

SwapbotにアクセスしてSwapbot Administrationを選択します。

利用にはTokenlyアカウントが必要なので、Login or Sign Up Nowからログインページを開きます。

Registerから登録ページを開きます。
画面右上にもあります。

Name、Username、Email address、Passwordを入力します。
例にSatoshi Nakamotoが出てくるあたり、Bitcoin業界でのSatoshiのネームバリューの大きさを感じます。

Tokenlyアカウントの登録が完了すると、Swapbotがユーザー情報へのアクセスを求めてくるので許可します。

ダッシュボードが表示されるので、Create a new Swapbotを選択します。

Create a New Swapbotの画面が表示されるので、まずはLook and Feelの部分でBot Name、Bot URL Slug、Bot Descriptionを決めます。
URL SlugはURLの最後の文字列です。

Custom Background Imageなどは、今回はすっ飛ばします。

次にSwaps Selling Tokensの部分で販売方法や価格を決めます。
Swap TypeをSwaps By Rate、Swaps By Fixed Amounts、Swaps By USD Amount paid in BTC or Tokensの3つあります。

Swaps By Rateだと1.2トークン購入など半端な金額が設定出来てしまうので、今回はSwaps By Fixed Amountsを使います。

Swaps Purchasing Tokensは購入用、Advanced Swap Rulesは値引きなどの設定用なので今回は無視します。

なお、一か所で複数のトークンの販売をしようとした場合、受取りの通貨が同じものだと、おすすめしないとワーニングが出ます。

同一トークンの販売で複数通貨の受け入れか、複数トークン販売でそれぞれ受け入れ通貨が別ならOKなようです。

最後にIncome Forwardingの部分で、一定量たまると自動で送金するよう設定出来るので、一応設定しておきます。
GOX怖い。

Other SettingsはConfirmationsに関するものと、ブラックリスト、ホワイトリストに関するものなので、これも無視してSave Botで設定完了です。

Please send a monthly paymentと出てきました。
monthly paymentってなんすか?

なんとなく勝手に、売買が成立した時に手数料徴収するシステムかと思っていましたが、月額利用料を支払ってレンタルするイメージのようです。

でもいくら払えばいいのかどこにも書いてないんすけど。。

で、問い合わせてみたところ一つのbotを借りるのに約7ドル/月とのこと。

ついでに詳細なマニュアルのありかを教えてくれました。
https://docs.google.com/document/d/19jvcg5VPa9BoVo8Y2_2kbmX9QsBEOh6PgyZeeMuxe8k



まぁわざわざ教えてもらっといてアレですが、とりあえずPublic Bot Addressにアクセスするといつもの画面が表示されたので、アクティブにしないまま満足してそっと閉じましたとさ。


Read More...

2015年8月18日火曜日

Counterpartyのトランザクションを解読してみる(Send)


今回もCounterpartyの勉強のために、Counterpartyのトランザクションを読んでみます。

題材は、前回と同じSpells of Genesis関連のトランザクションの中から選択した、トークンの送金を行うSendというトランザクションタイプです。

エンコード方法も前回と同じくmultisigを使ったものを選択しました。

https://www.blockscan.com/txInfo/11635040

  • データの準備
まずはvoutの一つ目のscriptPubKeyから以下を抜き出します。

OP_1
033f2f85f4c4c200d2a6ae3c300b4a1976e86eba833cdc6b96aa653426850723d9
0296a3f26419b9e6cbc794c67c874ec3d0dca008da66427fdbc9fbd45bf24b0249
02076aee3ebdd93955b70ee616de7867aa451a990ad53e0eaad0893626f231721d
OP_3
OP_CHECKMULTISIG

前回と同じくデコードしていきます。

前半2つのダミー公開鍵を、それぞれ前後1byteずつ削って結合させます。
3f2f85f4c4c200d2a6ae3c300b4a1976e86eba833cdc6b96aa65342685072396a3f26419b9e6cbc794c67c874ec3d0dca008da66427fdbc9fbd45bf24b02

これは暗号化されているので、複合化するためにvinの最初のtxidを探してきます。
810a4dd8e0756a715c6248a78c2d29a8c0985841243eb436318a234145847c29

見つけてきたtxidをパスワードとして、ARC4でデコードします。
1c434e5452505254590000000000000000039ff05d000000000bebc200000000000000000000000000000000000000000000000000000000000000000000

  • 不要なデータ?
はじめのbyteは無視します。
1c

  • CNTRPRTY
次の8byteは「CNTRPRTY」という文字列を16進コード文字列に変換したもので、Counterpartyのトランザクションには必ずある決まり文句です。
434e545250525459

  • トランザクションタイプ
次の4byteがトランザクションタイプです。
00000000

0はSENDを指します。

  • Asset_ID
次の8byteはAsset_IDです。
00000000039ff05d

10進数に直すと60813405で、前回と同じように変換します。

60813405 / 26 = 2338977 余り 3 D
2338977 / 26 = 89960 余り 17 R
89960 / 26 = 3460 余り 0 A
3460 / 26 = 133 余り 2 C
133 / 26 = 5 余り 3 D
5 / 26 = 0 余り 5 F

出来上がったDRACDFを反転したものがAsset名になります。

FDCARD

  • Quantity
次の8byteはQuantityです。
000000000bebc200

10進数に直すと200000000で単位がsatoshiなので、2FDCARDになります。


意外とシンプルな構造になっているようです。


Read More...

Counterpartyのトランザクションを解読してみる(Issuance)


Counterpartyの勉強のために、Counterpartyのトランザクションを読んでみます。

今回の題材はSpells of Genesis関連のトランザクションの中から選択した、独自トークンの発行を行うIssuanceというトランザクションタイプです。

エンコード方法は何パターンかあるようなのですが、今回は以下のmultisigを使ったものを選択しました。

https://www.blockscan.com/txInfo/11603601

  • データの準備
まずはvoutの一つ目のscriptPubKeyから以下を抜き出します。

OP_1
02a8d23b56ec9dfad3ffd52f83ac86bef27fc6b11775fec2f682a7d16e31c0272e
03a5998b49075640bd89ff6f0e849b693d99aafbf1145eea9bb2e1f2753fa4e3da
02076aee3ebdd93955b70ee616de7867aa451a990ad53e0eaad0893626f231721d
OP_3
OP_CHECKMULTISIG


2行目から4行目に公開鍵の様なものが3つありますが、この内、最初の2つはダミーで、Counterpartyで利用するデータが格納されています。

2つのダミー公開鍵を、それぞれ前後1byteずつ削って結合させます。
a8d23b56ec9dfad3ffd52f83ac86bef27fc6b11775fec2f682a7d16e31c027a5998b49075640bd89ff6f0e849b693d99aafbf1145eea9bb2e1f2753fa4e3

これは暗号化されているので、複合化するためにvinの最初のtxidを探してきます。
24b10dd846507572b21e15a78c990cf7f993f13ec8623ca738cf9fe1f12ddf99

見つけてきたtxidをパスワードとして、ARC4でデコードします。
これがCounterparty用の生データです。
3d434e5452505254590000001400000000039ff05d00000006fc23ac0001000000000000000000265370656c6c73206f662047656e657369732f4d6f6f6e

  • 不要なデータ?
はじめのbyteは無視します。
3d

  • CNTRPRTY
次の8byteは「CNTRPRTY」という文字列を16進コード文字列に変換したもので、Counterpartyのトランザクションには必ずある決まり文句です。
434e545250525459

  • トランザクションタイプ
次の4byteがトランザクションタイプです。
00000014

0x14=20はISSUANCEを指します。

  • Asset_ID
次の8byteはAsset_IDです。
00000000039ff05d

10進数に直すと60813405で、これが1ならXCPで、1ではない場合は以下のように変換します。

まず、AからZまでが入った配列を用意し、ここからindexが0ならA、1ならBという具合にアルファベットを取り出します。

IDを26で割った余りがindex、余りを切り捨てた整数値が次の計算用データとなり、次の計算用データが0になるまで繰り返します。

60813405 / 26 = 2338977 余り 3 D
2338977 / 26 = 89960 余り 17 R
89960 / 26 = 3460 余り 0 A
3460 / 26 = 133 余り 2 C
133 / 26 = 5 余り 3 D
5 / 26 = 0 余り 5 F

出来上がったDRACDFを反転したものがAsset名になります。

FDCARD

  • Quantity
次の8byteはQuantityです。
00000006fc23ac00

10進数に直すと30000000000で単位がsatoshiなので、300FDCARDになります。

  • Description
Quantityの後ろには簡単な説明文的なものを埋め込めるようです。
01000000000000000000265370656c6c73206f662047656e657369732f4d6f6f6e

内、頭の11byteは文字数などが入っているようなので、それ以降を文字列に変換します。
Spells of Genesis/Moon

なお、文字数が足りないときはvoutを2つ持たせて、追加のDescriptionデータに使えるようです。

OP_1 038dd23b56ec9dfad3ffb24ea3dbe7cc965fa3419508b88eb2c75bf2c231c127a6 02a5998b49075640bdafac1f6be8f71a1df6ccdbb671308fe8db92dd3850cb8d4f 02076aee3ebdd93955b70ee616de7867aa451a990ad53e0eaad0893626f231721d OP_3 OP_CHECKMULTISIG

18434e5452505254596761206361726420666f7220464c444300000000000000000000000000000000000000000000000000000000000000000000000000

2つ目のデータを同じ様にデコードし、本来トランザクションタイプが入る10byte以降の部分を文字列に変換すると以下になります。

ga card for FLDC


一つ目のDescriptionと連結するとDescriptionが完成します。

Spells of Genesis/Moonga card for FLDC


以下ブロックエクスプローラのAsset Infoを確認すると、Descriptionが正しくデコードされていることが分かります。
https://www.blockscan.com/assetInfo/FDCARD


これで基本的なCounterpartyのトランザクションデータの作りが分かりました。
multisig以外のエンコード方法や、LOCKのトランザクションについては、また別の機会に検証してみたいと思います。


Read More...

2015年8月10日月曜日

Monacoinでマルチシグネチャアドレスを作成する


Counterpartyについて調べていたところ、マルチシグネチャという単語が出てきました。

また、Spells of Genesisでも資金持ち逃げ、使い込みなどの防止に、マルチシグネチャを利用しているようです。

ということで、今後、暗号通貨界隈の常識になりそうなマルチシグネチャについて、Monacoinでも動くのかを試してみます。

具体的には、2-of-3マルチシグネチャアドレスを作成し、送金してみます。
3つの署名のうち、2つあれば出金できるというヤツですね。

  • アドレスの作成
getnewaddressで署名するためのアドレスを3つ作成します。

後で確認しやすいようにアカウントを設定しておきます。
$ monacoind getnewaddress  "monamultisig"
MGQuGAWjYKcRYWKZndTBocxevJMsvRDkLm

$ monacoind getnewaddress  "monamultisig"
MAe39gF7wwh2g5MMYwmwiEYpSqjgFw7g83

$ monacoind getnewaddress  "monamultisig"
MVe4ucgqSPRkR1yescuuX17D7t5vcikznd

getaddressesbyaccountでちゃんと作成できているか確認します。
$ monacoind getaddressesbyaccount "monamultisig"
[
    "MAe39gF7wwh2g5MMYwmwiEYpSqjgFw7g83",
    "MVe4ucgqSPRkR1yescuuX17D7t5vcikznd",
    "MGQuGAWjYKcRYWKZndTBocxevJMsvRDkLm"
]

  • 公開鍵の確認
validateaddressで各アドレスの公開鍵を確認します。
monacoind validateaddress MAe39gF7wwh2g5MMYwmwiEYpSqjgFw7g83
{
    "isvalid" : true,
    "address" : "MAe39gF7wwh2g5MMYwmwiEYpSqjgFw7g83",
    "ismine" : true,
    "isscript" : false,
    "pubkey" : "020ac51c1293db7576d703d4c4a79eac4ba7bd3a4141bc6265bc93742f6666b03a",
    "iscompressed" : true,
    "account" : "monamultisig"
}

monacoind validateaddress MVe4ucgqSPRkR1yescuuX17D7t5vcikznd
{
    "isvalid" : true,
    "address" : "MVe4ucgqSPRkR1yescuuX17D7t5vcikznd",
    "ismine" : true,
    "isscript" : false,
    "pubkey" : "03e0b36973abfa94708e393e1f68ca5f600646696ed41bcabf3822ed5155c405ca",
    "iscompressed" : true,
    "account" : "monamultisig"
}

monacoind validateaddress MGQuGAWjYKcRYWKZndTBocxevJMsvRDkLm
{
    "isvalid" : true,
    "address" : "MGQuGAWjYKcRYWKZndTBocxevJMsvRDkLm",
    "ismine" : true,
    "isscript" : false,
    "pubkey" : "035df97df1f5ff93e4ba4df6b9a2f7aa2c2f7f9909ca2609b0714e1a0d6c6fb438",
    "iscompressed" : true,
    "account" : "monamultisig"
}

ちなみに他人のアドレスに対してvalidateaddressを実行しても、結果には公開鍵は含まれず、有効であることだけ分かります。
monacoind validateaddress MR2j3u5oNWZzAAxeHtSinHUEVNiSbkn8zJ
{
    "isvalid" : true,
    "address" : "MR2j3u5oNWZzAAxeHtSinHUEVNiSbkn8zJ",
    "ismine" : false
}

  • マルチシグネチャアドレスの作成
createmultisigを使ってマルチシグネチャアドレスを作成します。

先ほど作成したアドレスの公開鍵を利用して作成し、一番目の引数が出金時に必要な署名の数です。
$ monacoind createmultisig 2 '["020ac51c1293db7576d703d4c4a79eac4ba7bd3a4141bc6265bc93742f6666b03a", "03e0b36973abfa94708e393e1f68ca5f600646696ed41bcabf3822ed5155c405ca", "035df97df1f5ff93e4ba4df6b9a2f7aa2c2f7f9909ca2609b0714e1a0d6c6fb438"]'
{
    "address" : "3BUVYHpNB6J9X4GsXUo51d7UkfM322SspM",
    "redeemScript" : "5221020ac51c1293db7576d703d4c4a79eac4ba7bd3a4141bc6265bc93742f6666b03a2103e0b36973abfa94708e393e1f68ca5f600646696ed41bcabf3822ed5155c405ca21035df97df1f5ff93e4ba4df6b9a2f7aa2c2f7f9909ca2609b0714e1a0d6c6fb43853ae"
}

redeemScriptは後で使います。

ちなみに公開鍵ではなく、アドレスからも作れるようで、以下のように同じ結果になります。
$ monacoind createmultisig 2 '["MAe39gF7wwh2g5MMYwmwiEYpSqjgFw7g83", "MVe4ucgqSPRkR1yescuuX17D7t5vcikznd", "MGQuGAWjYKcRYWKZndTBocxevJMsvRDkLm"]'
{
    "address" : "3BUVYHpNB6J9X4GsXUo51d7UkfM322SspM",
    "redeemScript" : "5221020ac51c1293db7576d703d4c4a79eac4ba7bd3a4141bc6265bc93742f6666b03a2103e0b36973abfa94708e393e1f68ca5f600646696ed41bcabf3822ed5155c405ca21035df97df1f5ff93e4ba4df6b9a2f7aa2c2f7f9909ca2609b0714e1a0d6c6fb43853ae"
}

  • マルチシグネチャアドレスへの送金
先ほど作成したアドレス宛に、sendtoaddressで送金してみます。
$ monacoind sendtoaddress 3BUVYHpNB6J9X4GsXUo51d7UkfM322SspM 0.1
64e87a959a46cad0e25b9536ce0f996b56f89807a9215229d278a4e220ae68ac


ブロックエクスプローラを見ると、しっかりと着金しています。

  • マルチシグネチャアドレス宛送金トランザクションの確認
getrawtransactionでトランザクションの中身を確認します。
オプションに1をつけるとrawではなくデコード済みが返ってきます。
$ monacoind getrawtransaction 64e87a959a46cad0e25b9536ce0f996b56f89807a9215229d278a4e220ae68ac 1
{
    "hex" : "0100000002ad378b21681f50fbc3cf3cc1dc5967b003733437bd0008a7bc52e44acd2ec3ce00000000fdfe0000493046022100fcdca98debaa9413cba58f2c6ef22277797e6448ee1d391d840a295cc8d65614022100ccc415a475c0a0e4d88f41e4b53f59692a7847951d171cd723f7bb803d4748f301473044022030dbe7bb6fa1271bb2dea33341497847786a74d96f8d21286f5f279ade8b9e6302207be36c17cb83e2dc441ff37ea68ce0272c5b271635de2d82c1c812c762e762b6014c6952210336e6fc63f48676949b646456adf96b1183f296bd0e700bd894174f524839798a2102ea9fa819e3e9c05580671a095ce73aee766ce39c55e084ae5ad50355a5f1d4ef2103fe8b5f8df85b57ee876c3cb4ea23dfe7063ad6fb3500c7527971c80d1c931def53aeffffffff0221976a0390f96d87a81a7941c6279fb233625f44d17dc040f594f4fd6f99d2010000006c493046022100856d3d4813fc636873ab43d13e8251ccd3e4c8e29d284d7812d2537ecf0550dd022100af0a2139aa266e52619a1ed716ebdba6239c6f4537fe3a78e4d9db6f1a1883820121020c61b05ce77a8b0d36c813d882f7e730158296c9e5ef4184ce2f30f4acab5cfcffffffff026f0a1700000000001976a9141391189829986705d972aa1b0c26de994582afb588ac809698000000000017a9146b52e73d9d62dd84f9c974c0989ebc186d90531f8700000000",
    "txid" : "64e87a959a46cad0e25b9536ce0f996b56f89807a9215229d278a4e220ae68ac",
    "version" : 1,
    "locktime" : 0,
    "vin" : [
        {
            "txid" : "cec32ecd4ae452bca70800bd37347303b06759dcc13ccfc3fb501f68218b37ad",
            "vout" : 0,
            "scriptSig" : {
                "asm" : "0 3046022100fcdca98debaa9413cba58f2c6ef22277797e6448ee1d391d840a295cc8d65614022100ccc415a475c0a0e4d88f41e4b53f59692a7847951d171cd723f7bb803d4748f301 3044022030dbe7bb6fa1271bb2dea33341497847786a74d96f8d21286f5f279ade8b9e6302207be36c17cb83e2dc441ff37ea68ce0272c5b271635de2d82c1c812c762e762b601 52210336e6fc63f48676949b646456adf96b1183f296bd0e700bd894174f524839798a2102ea9fa819e3e9c05580671a095ce73aee766ce39c55e084ae5ad50355a5f1d4ef2103fe8b5f8df85b57ee876c3cb4ea23dfe7063ad6fb3500c7527971c80d1c931def53ae",
                "hex" : "00493046022100fcdca98debaa9413cba58f2c6ef22277797e6448ee1d391d840a295cc8d65614022100ccc415a475c0a0e4d88f41e4b53f59692a7847951d171cd723f7bb803d4748f301473044022030dbe7bb6fa1271bb2dea33341497847786a74d96f8d21286f5f279ade8b9e6302207be36c17cb83e2dc441ff37ea68ce0272c5b271635de2d82c1c812c762e762b6014c6952210336e6fc63f48676949b646456adf96b1183f296bd0e700bd894174f524839798a2102ea9fa819e3e9c05580671a095ce73aee766ce39c55e084ae5ad50355a5f1d4ef2103fe8b5f8df85b57ee876c3cb4ea23dfe7063ad6fb3500c7527971c80d1c931def53ae"
            },
            "sequence" : 4294967295
        },
        {
            "txid" : "d2996ffdf494f540c07dd1445f6233b29f27c641791aa8876df990036a972102",
            "vout" : 1,
            "scriptSig" : {
                "asm" : "3046022100856d3d4813fc636873ab43d13e8251ccd3e4c8e29d284d7812d2537ecf0550dd022100af0a2139aa266e52619a1ed716ebdba6239c6f4537fe3a78e4d9db6f1a18838201 020c61b05ce77a8b0d36c813d882f7e730158296c9e5ef4184ce2f30f4acab5cfc",
                "hex" : "493046022100856d3d4813fc636873ab43d13e8251ccd3e4c8e29d284d7812d2537ecf0550dd022100af0a2139aa266e52619a1ed716ebdba6239c6f4537fe3a78e4d9db6f1a1883820121020c61b05ce77a8b0d36c813d882f7e730158296c9e5ef4184ce2f30f4acab5cfc"
            },
            "sequence" : 4294967295
        }
    ],
    "vout" : [
        {
            "value" : 0.01509999,
            "n" : 0,
            "scriptPubKey" : {
                "asm" : "OP_DUP OP_HASH160 1391189829986705d972aa1b0c26de994582afb5 OP_EQUALVERIFY OP_CHECKSIG",
                "hex" : "76a9141391189829986705d972aa1b0c26de994582afb588ac",
                "reqSigs" : 1,
                "type" : "pubkeyhash",
                "addresses" : [
                    "M9gctXWKs8hSrRbdJMRR4t9s6Yc8yHKd2s"
                ]
            }
        },
        {
            "value" : 0.10000000,
            "n" : 1,
            "scriptPubKey" : {
                "asm" : "OP_HASH160 6b52e73d9d62dd84f9c974c0989ebc186d90531f OP_EQUAL",
                "hex" : "a9146b52e73d9d62dd84f9c974c0989ebc186d90531f87",
                "reqSigs" : 1,
                "type" : "scripthash",
                "addresses" : [
                    "3BUVYHpNB6J9X4GsXUo51d7UkfM322SspM"
                ]
            }
        }
    ]
}

  • 秘密鍵の確認
dumpprivkeyで各アドレスの秘密鍵を確認します。

結果はマスクしてあります。
$ monacoind dumpprivkey MAe39gF7wwh2g5MMYwmwiEYpSqjgFw7g83
xxxxprivateKey1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
noojloon@noojloon-MS-7821:~$ monacoind dumpprivkey MVe4ucgqSPRkR1yescuuX17D7t5vcikznd
xxxxprivateKey2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
noojloon@noojloon-MS-7821:~$ monacoind dumpprivkey MGQuGAWjYKcRYWKZndTBocxevJMsvRDkLm
xxxxprivateKey3xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

  • マルチシグネチャアドレスからの送金トランザクションを作成
createrawtransactionで送金トランザクションを作成します。

マルチシグネチャアドレス宛送金のtxidと、getrawtransactionで確認したデータの中身から、voutの大きいほうのnとそのscriptPubKeyhexを利用します。
$ monacoind createrawtransaction '[{"txid":"64e87a959a46cad0e25b9536ce0f996b56f89807a9215229d278a4e220ae68ac","vout":1,"scriptPubKey":"a9146b52e73d9d62dd84f9c974c0989ebc186d90531f87","redeemScript":"5221020ac51c1293db7576d703d4c4a79eac4ba7bd3a4141bc6265bc93742f6666b03a2103e0b36973abfa94708e393e1f68ca5f600646696ed41bcabf3822ed5155c405ca21035df97df1f5ff93e4ba4df6b9a2f7aa2c2f7f9909ca2609b0714e1a0d6c6fb43853ae"}]' '{"MR2j3u5oNWZzAAxeHtSinHUEVNiSbkn8zJ":0.05}'
0100000001ac68ae20e2a478d2295221a90798f8566b990fce36955be2d0ca469a957ae8640100000000ffffffff01404b4c00000000001976a914bbe8720c230325a27efff1e236bd61008dd97e1988ac00000000

この辺は普段の処理と比べるとややローレベルな処理になるため、今まで自動的に処理されていたことも自分でやる必要があります。

この例でいうとお釣りについて一切考えずに処理しているため、0.10の入金に対して0.05の出金ということになり、差額は手数料として消えるようです。

fee0.001にするには、以下のようにお釣り用のアドレスも送金先に指定します。
{"あて先":0.05,"お釣り用":0.049}

  • 送金トランザクションに署名する
signrawtransactionで先ほど作成したトランザクションに署名します。
$ monacoind signrawtransaction '0100000001ac68ae20e2a478d2295221a90798f8566b990fce36955be2d0ca469a957ae8640100000000ffffffff01404b4c00000000001976a914bbe8720c230325a27efff1e236bd61008dd97e1988ac00000000' '[{"txid":"64e87a959a46cad0e25b9536ce0f996b56f89807a9215229d278a4e220ae68ac","vout":1,"scriptPubKey":"a9146b52e73d9d62dd84f9c974c0989ebc186d90531f87","redeemScript":"5221020ac51c1293db7576d703d4c4a79eac4ba7bd3a4141bc6265bc93742f6666b03a2103e0b36973abfa94708e393e1f68ca5f600646696ed41bcabf3822ed5155c405ca21035df97df1f5ff93e4ba4df6b9a2f7aa2c2f7f9909ca2609b0714e1a0d6c6fb43853ae"}]' '["xxxxprivateKey1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"]'
{
    "hex" : "0100000001ac68ae20e2a478d2295221a90798f8566b990fce36955be2d0ca469a957ae86401000000b500483045022006265235010d34980be0054469137987a059db6b18803d2310195d24b0fac295022100a6b6c349b6378ed4ea9b9443bbcde4d2673d42f8b3bb108669e759940e1ca243014c695221020ac51c1293db7576d703d4c4a79eac4ba7bd3a4141bc6265bc93742f6666b03a2103e0b36973abfa94708e393e1f68ca5f600646696ed41bcabf3822ed5155c405ca21035df97df1f5ff93e4ba4df6b9a2f7aa2c2f7f9909ca2609b0714e1a0d6c6fb43853aeffffffff01404b4c00000000001976a914bbe8720c230325a27efff1e236bd61008dd97e1988ac00000000",
    "complete" : false
}

一つではコンプリートしないので、もう一つ署名します。
$ monacoind signrawtransaction '0100000001ac68ae20e2a478d2295221a90798f8566b990fce36955be2d0ca469a957ae86401000000b500483045022006265235010d34980be0054469137987a059db6b18803d2310195d24b0fac295022100a6b6c349b6378ed4ea9b9443bbcde4d2673d42f8b3bb108669e759940e1ca243014c695221020ac51c1293db7576d703d4c4a79eac4ba7bd3a4141bc6265bc93742f6666b03a2103e0b36973abfa94708e393e1f68ca5f600646696ed41bcabf3822ed5155c405ca21035df97df1f5ff93e4ba4df6b9a2f7aa2c2f7f9909ca2609b0714e1a0d6c6fb43853aeffffffff01404b4c00000000001976a914bbe8720c230325a27efff1e236bd61008dd97e1988ac00000000' '[{"txid":"64e87a959a46cad0e25b9536ce0f996b56f89807a9215229d278a4e220ae68ac","vout":1,"scriptPubKey":"a9146b52e73d9d62dd84f9c974c0989ebc186d90531f87","redeemScript":"5221020ac51c1293db7576d703d4c4a79eac4ba7bd3a4141bc6265bc93742f6666b03a2103e0b36973abfa94708e393e1f68ca5f600646696ed41bcabf3822ed5155c405ca21035df97df1f5ff93e4ba4df6b9a2f7aa2c2f7f9909ca2609b0714e1a0d6c6fb43853ae"}]' '["xxxxprivateKey2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"]'
{
    "hex" : "0100000001ac68ae20e2a478d2295221a90798f8566b990fce36955be2d0ca469a957ae86401000000fdff0000483045022006265235010d34980be0054469137987a059db6b18803d2310195d24b0fac295022100a6b6c349b6378ed4ea9b9443bbcde4d2673d42f8b3bb108669e759940e1ca24301493046022100e6b0a31018d371bd52bdbb5047c8a2d4978404cd300b51edbdcdd84eefd5eb54022100c20925bac763d3ebf706d0481c52f70ca49aa951086b8df1c1bf6e8780f380a2014c695221020ac51c1293db7576d703d4c4a79eac4ba7bd3a4141bc6265bc93742f6666b03a2103e0b36973abfa94708e393e1f68ca5f600646696ed41bcabf3822ed5155c405ca21035df97df1f5ff93e4ba4df6b9a2f7aa2c2f7f9909ca2609b0714e1a0d6c6fb43853aeffffffff01404b4c00000000001976a914bbe8720c230325a27efff1e236bd61008dd97e1988ac00000000",
    "complete" : true
}

コンプリートしました。

  • トランザクションの送信
二つの署名が終わったトランザクションを、sendrawtransactionで実際に送信します。
$ monacoind sendrawtransaction 0100000001ac68ae20e2a478d2295221a90798f8566b990fce36955be2d0ca469a957ae86401000000fdff0000483045022006265235010d34980be0054469137987a059db6b18803d2310195d24b0fac295022100a6b6c349b6378ed4ea9b9443bbcde4d2673d42f8b3bb108669e759940e1ca24301493046022100e6b0a31018d371bd52bdbb5047c8a2d4978404cd300b51edbdcdd84eefd5eb54022100c20925bac763d3ebf706d0481c52f70ca49aa951086b8df1c1bf6e8780f380a2014c695221020ac51c1293db7576d703d4c4a79eac4ba7bd3a4141bc6265bc93742f6666b03a2103e0b36973abfa94708e393e1f68ca5f600646696ed41bcabf3822ed5155c405ca21035df97df1f5ff93e4ba4df6b9a2f7aa2c2f7f9909ca2609b0714e1a0d6c6fb43853aeffffffff01404b4c00000000001976a914bbe8720c230325a27efff1e236bd61008dd97e1988ac00000000
4095c488fe886b66560540fb953cab44e2ab36f70c40fc5cc9e169f1e26e459b


半分手数料で持っていかれましたが、無事出金できました。


Read More...

2014年11月9日日曜日

Java EEとmonacoindでWEB Walletを作ってみた④ 動作確認


今回はここまでで作成したMonacoin WEB Walletの動作確認です。


まずはトップ画面を表示します。

ユーザ名が空の状態でログインしてみます。
@NotNullのバリデーションにひかかって、エラーが表示されます。

monacoindが起動していない状態で何か入れてログインしてみます。
当然エラーになります。

ちなみに今回は認証部分は未実装ですが、ログイン部分の判定をfalseにして認証エラーにした場合はこうなります。

monacoindを起動してログインしてみます。
新規の受信用アドレスが作成されて表示されます。
トランザクション履歴はまだないので空です。

表示されたWallet Address宛に送金してみます。
まだ認証されていないのでBalanceは0ですが、トランザクション履歴のところで送金されてきたことが確認出来ます。
また、このタイミングで新しい受信用アドレスが払い出されて表示されます。

しばらく待つと承認されてBalanceに反映されます。
トランザクション履歴のConfirmationsもちゃんと進んでいます。

続いて送金部分ですが、まず送金先アドレスが空の状態でSendボタンをクリックしてみます。
required="true"にひかかってエラーが表示されます。

おかしなアドレス宛に送金してみます。
JSON-RPCで返ってきたエラーが、Sendボタンの横に表示されます。

送金額をゼロにしてみます。
<f:validateDoubleRange minimum="0.00000001"/>にひかかってエラーが表示されます。

送金額を残高以上の金額にしてみます。
JSON-RPCで返ってきたエラーが表示されます。

送金が成功すると、成功したトランザクションIDが表示されます。
二重送信にならないよう、ここで送金先や送金額を消したほうが良さそうですね。

即、PC側のWalletに振り込まれてきました。


しばらく待つと、Confirmationsも問題なく進みました。

さすがBitcoinから延々と使いまわされてきたAPIだけあって、特に違和感なく動作します。

JSFについてはいくつか分からないところもありましたが、慣れたらなかなか効率的にWEBサービスが作れそうな感じです。


Read More...

2014年11月8日土曜日

Java EEとmonacoindでWEB Walletを作ってみた③ Walletの情報を保持するバッキングBeanを作成する


引き続き、MonacoinのWEB Walletを作成していきます。

今回はアカウントにひもづくWalletの情報を保持したり、送金処理をしたりするバッキングBeanです。

  • AccountBean

monacoindから取得したアカウントの情報をリクエストスコープで保持するバッキングBean。
リクエスト毎に最新の情報を取得して画面を更新するメソッドを持つ。
前回作成したUserBeanInjectして、アカウント名などを利用する。
受信用アドレス、残高、トランザクション履歴、送金先アドレス、送信金額を保持し、送金を実行するメソッドを持つ。


それではまずコードです。

package monawebwallet;

import java.io.IOException;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import lombok.Getter;
import lombok.Setter;
import lombok.NoArgsConstructor;

@Named(value = "accountBean")
@RequestScoped
@NoArgsConstructor
@Getter
@Setter
public class AccountBean implements Serializable {

    @Inject
    UserBean user;

    String addressStr;
    String balanceStr;

    List<Map<String, String>> transactionMapList;

    String toAddress;
    double amount;

    public void updateAccount() {
        if (user.isLogin()) {
            try {
                addressStr = CoindUtil.getaccountaddress(user.getAccountStr());
                balanceStr = CoindUtil.getbalance(user.getAccountStr());
                transactionMapList = CoindUtil.listtransactions(user.getAccountStr());
            } catch (IOException | CoindException ex) {
                user.loginFormMessage(ex.getMessage());
                clear();
            }
        } else {
            clear();
        }
    }

    public void clear() {
        user.logout();
        addressStr = "";
        balanceStr = "";
        transactionMapList = null;
    }

    public void send() {
        try {
            String txid = CoindUtil.sendfrom(user.getAccountStr(), toAddress, amount);
            user.sendFormMessage("送信成功 : " + txid);
        } catch (IOException | CoindException ex) {
            user.sendFormMessage(ex.getMessage());
        }
    }
}

まず、受信用アドレス、残高、トランザクション履歴を更新するためのupdateAccount()メソッドを作成します。

それぞれJSON-RPCmonacoindから取ってきます。
何かエラーが出たときのために、すべてを消し去るためのclear()メソッドも作成しておきます。


ちなみにこのupdateAccount()ですが、リクエスト毎に毎回実行する初期化処理のようなものですが、@PostConstructを設定しなかったのには理由があります。

どうやら@PostConstructなメソッドが呼ばれるのは、画面を更新した時で、forrmsubmitした時にも呼ばれるのですが、formaction属性に指定したメソッドが呼ばれるまえに、@PostConstructなメソッドが呼ばれるようです。

submitの結果値が変わった場合は良いのですが、action属性のメソッドで値が変わった場合は反映されません。

例えば、ログアウト処理を実行するメソッドをaction属性に指定していた場合、ログアウト処理前の状態で@PostConstructが呼ばれてしまい、一旦無駄なJSON-RPCが飛んでしまう上、ログアウト処理後の状態でもう一度呼ぶ必要があります。

また、ログイン時は認証エラーでも一旦submitされるので、認証出来てない状態でJSON-RPCが飛んでしまいます。

①submit
②バッキングBeanのプロパティへ値反映
③@PostConstructなメソッド実行
④action属性のメソッド実行
⑤action属性のメソッド実行結果反映
⑥描画

ということで、上記⑤と⑥の間に差し込むために、@PostConstructは付けずに、headタグ内のEL式でupdateAccount()を呼んでいます。


最後に送金処理ですが、送金に関する一時的な情報をココで持つのはちょっと抵抗があったのですが、h:commandButtonタグのaction属性に設定したメソッドに、h:inputTextタグのvalueを渡す方法がよく分からなかったのでこうなりました。

これは間違いなくもっと良い方法がありそうですね。

formIdUIComponentを特定して直接取ってくるとかが出来るのかな?

とりあえず今回は動いたから良しとします。


これですべて実装し終わったので、次回は動作確認です。


Read More...

2014年11月7日金曜日

Java EEとmonacoindでWEB Walletを作ってみた② ユーザー情報を保持するバッキングBeanを作成する


引き続き、MonacoinのWEB Walletを作成していきます。

今回はアカウント名を保持するバッキングBeanです。


  • UserBean

ユーザ情報としてアカウント名をセッションスコープで保持するバッキングBean。
ログイン、ログアウト、ログイン状態確認のメソッドを持つ。(認証は未実装)
エラーメッセージ表示用のメソッドもここに作成。

エラーメッセージ表示については、ここに作るのが適正なのかはちょっとよく分からないですが、このバッキングBeanをInjectしてしまえば他からも使えるので、とりあえず。


それではまずコードです。

package monawebwallet;

import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import javax.validation.constraints.NotNull;
import lombok.Getter;import lombok.Setter;

@Named(value = "userBean")
@SessionScoped
@Setter
@Getter
public class UserBean implements Serializable {

    @NotNull
    String accountStr;

    public boolean isLogin() {
        return accountStr != null && accountStr.length() > 0;
    }

    public void login() {
        if (true) {
            System.out.println("login");
        } else {
            logout();
        }
    }

    public void logout() {
        accountStr = "";
        System.out.println("logout");
    }

    public void loginFormMessage(String message) {
        message("loginForm:account", message);
    }
    
    public void sendFormMessage(String message) {
        message("sendForm:send", message);
    }

    private void message(String formId, String message) {
        FacesContext context = FacesContext.getCurrentInstance();
        UIComponent component = context.getViewRoot().findComponent(formId);
        String clientId = component.getClientId(context);
        context.addMessage(clientId, new FacesMessage(message));
    }
}

まず、この辺はおさらいですが、@NamedでCDI管理とし、EL式から参照するためにuserBeanという名前をつけます。

IDを保持させるので@SessionScopedでセッションスコープを設定します。


バッキングBeanの初期設定が終わったら、ユーザID保持用のaccountStr変数を用意します。
accountStrはnullや空文字をNGとしたいので、BeanValidationのアノテーションを設定します。

ただし、@NotNullを設定しても、デフォルトでは空文字を通してしまいます。
テキストボックスに何も入力されていない状態はnullではなく空文字です。

JSF標準のValidatorではなく、HibernateValidator@NotBlankを使う手もありますが、以下のようにweb.xmlに若干追加するだけで@NotNullでも空文字を蹴るようになります。

<context-param>
  <param-name>
    javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL
  </param-name>
  <param-value>true</param-value>
</context-param>

ただ、h:inputTextタグのrequired属性をtrueにすることで、どうやら同じことが可能なようなので、そちらのほうが良いかもしれません。
(と、後で気づいたけどせっかくなのでメモとして残しておく)


メソッドはlogin()logout()と、ログイン状態を判定するisLogin()を作成します。

現時点では認証ロジックの実装は行わず、login()メソッドを呼ぶと無条件でログイン成功とします。


最後にエラーメッセージ表示用のmessage()メソッドも作成しておきます。

formIdformタグのIDとinputタグなどのIDをコロンでつないだものです。

formIdをキーにしてUIComponentを取得し、getClientId()clientIdを取得します。

これでエラーメッセージをハンドリング出来るようになります。


まだ続きます。

Read More...

2014年11月6日木曜日

Java EEとmonacoindでWEB Walletを作ってみた① JSFでUIを作成する


前回作ったmonacoindユーティリティクラスを利用して、MonacoinのWEB Walletを作成してみます。


まず全体の構成としては、HTMLは1ページでログイン状態によって表示を変え、バッキングBeanはセッションスコープでアカウント名を保持するものと、リクエストスコープでアカウントの情報を保持するもので構成します。


  • index.xhtml

アカウント名を入力してログインボタンを押すと、受信用アドレス、残高、トランザクション履歴、送信先アドレス、送信金額欄、送信ボタンが表示される。
ログイン前はアカウント名入力欄とログインボタン以外非表示。

パスワード欄無し。(今回は実装する気が無いだけ)


それではまずコードです。

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:head>
        <title>Monacoin Web Wallet</title>
        #{accountBean.updateAccount()}
    </h:head>
    <h:body>
        <h:outputLink value="/MonaWebWallet/">トップ</h:outputLink>
        <h:form id="loginForm">
            <h:message for="account" /><br />
            <h:inputText id="account" value="#{userBean.accountStr}" rendered="#{! userBean.isLogin()}" />
            <h:commandButton value="Login" action="#{userBean.login()}" rendered="#{! userBean.isLogin()}" />
            <h:commandButton value="Logout" action="#{userBean.logout()}" rendered="#{userBean.isLogin()}" />
            <br />
        </h:form>

        <h:form rendered="#{userBean.isLogin()}">
            Account : <h:outputText value="#{userBean.accountStr}" />
            <br />
            Wallet Address : <h:outputText value="#{accountBean.addressStr}" />
            <br />
            Balance : 
            <h:outputText value="#{accountBean.balanceStr}">
                <f:convertNumber type="number" currencySymbol="#,##0.00000000" />
            </h:outputText>
            <br /><br /><br />
        </h:form>

        <h:form id="sendForm" rendered="#{userBean.isLogin()}">
            Send to : 
            <h:inputText id="sendTo" value="#{accountBean.toAddress}" size="50" maxlength="34" required="true">
                <f:validateLength maximum="34" minimum="34" />
            </h:inputText>
            <h:message for="sendTo" />
            <br />
            Amount : 
            <h:inputText id="sendAmount" value="#{accountBean.amount}" required="true">
                <f:validateDoubleRange minimum="0.00000001"/>
            </h:inputText>
            <h:message for="sendAmount" />
            <br />
            <h:commandButton id="send" value="Send" action="#{accountBean.send()}" rendered="#{userBean.isLogin()}" />
            <h:message for="send" />
            <br /><br />
        </h:form>

        <h:form rendered="#{userBean.isLogin()}">
            Transactions : <br />
            <h:dataTable border="1" var="transactionMap"
                         value="#{accountBean.transactionMapList}" rendered="#{accountBean.transactionMapList != null and ! accountBean.transactionMapList.isEmpty()}">
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="Date"/>
                    </f:facet>
                    <h:outputText value="#{transactionMap.time * 1000}">
                        <f:convertDateTime pattern="yyyy/MM/dd HH:mm:ss" timeZone="JST"/>
                    </h:outputText>
                </h:column>
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="Type"/>
                    </f:facet>
                    <h:outputText value="#{transactionMap.category}"/>
                </h:column>
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="Address"/>
                    </f:facet>
                    <h:outputText value="#{transactionMap.address}"/>
                </h:column>
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="Amount"/>
                    </f:facet>
                    <h:outputText value="#{transactionMap.amount}"/>
                </h:column>
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="Confirmations"/>
                    </f:facet>
                    <h:outputText value="#{transactionMap.confirmations}"/>
                </h:column>
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="Transaction ID"/>
                    </f:facet>
                    <h:outputText value="#{transactionMap.txid}"/>
                </h:column>
            </h:dataTable>
        </h:form>
    </h:body>
</html>


まず、ヘッダー部分にEL式でバッキングBeanのメソッドが仕込んであり、ここで初期化処理を行っています。

Javascriptで言うところの、bodyタグのonLoradのつもりで使っていますが、ここでやるのが正しいのかは良く分かりません。
何かもっとそれっぽい方法がありそうですが、色々調べたり実験したりしたのですが、これしかうまくいきませんでした。


続いて中身を見ていきますが、基本的に入力が必要なものはh:inputTextタグ、バッキングBean側から表示が必要なものはh:outputTextタグを利用しています。

トランザクション履歴については、h:dataTableタグでListtableに変換して表示します。

それぞれEL式でバッキングBeanのプロパティへバインドします。


バリデーション周りについては、アカウント名入力欄については、バッキングBean側でバリデーションをかけて入力必須にし、HTML側では特に何も設定していません。

送金先アドレスや金額欄については、f:validateLengthタグで文字列の長さ、f:validateDoubleRangeタグで数値の桁数、required属性で入力必須にしています。

入力必須にするだけであれば、後者のほうが楽なのでこっちに統一で良さそうな感じです。


エラーメッセージを表示したい場所については、h:messageタグを設置し、for属性でinput部品と関連付けます。

バリデーションのエラーを表示させたり、バッキングBeanから指定のメッセージを表示させたりします。


最後に表示非表示についてですが、ブロック毎にh:formタグで囲み、rendered属性で表示非表示を切り替えました。
やり方として正しいのか良く分かりませんが、divタグとかではrendered属性が使えないようで、コレしか思いつきませんでした。


これでUIのパーツは揃ったので、次回はバッキングBeanの作成です。


Read More...

2014年11月3日月曜日

Javaでmonacoindユーティリティクラスを作成する② WEB Walletに必要なメソッドの実装



引き続きユーティリティクラスの作成です。

Walletに最低限必要な以下4つのメソッドを実装します。

getaccountaddress
getbalance
listtransactions
sendfrom


まず、JSONRequestクラスですが、メンバ変数はString型のidmethodList<Object>型のparamsです。

idはレスポンスに同じidが含まれて返ってくるだけで、取り合えずは使わないのでハードコードしてしまいます。

methodはそれぞれのメソッド文字列を保持します。

paramsはメソッドにより異なり、sendfromでは送り先アドレスや金額もこのparamsに保持させます。

  • getaccountaddress

アカウント文字列を渡すと、アカウントの最新の受信用アドレスを返します。

public static String getaccountaddress(String accountStr) throws IOException, CoindException {
    String method = "getaccountaddress";

    List<Object> params = new ArrayList<>();
    params.add(accountStr);
    JSONResponse addressRes = connectCoind(createJSONString("1", method, params));

    return addressRes.result.toString();
}

  • getbalance

アカウント文字列を渡すと、アカウントの残高を返します。

public static String getbalance(String accountStr) throws IOException, CoindException {
    String method = "getbalance";
    List<Object> params = new ArrayList<>();
    params.add(accountStr);
    JSONResponse balanceRes = connectCoind(createJSONString("1", method, params));
    return balanceRes.result.toString();
}

  • listtransactions

アカウント文字列を渡すと、トランザクション履歴を返します。
何件目から何件目までという取得の仕方も可能ですが、今回は実装しません。

public static List<Map<String, String>> listtransactions(String accountStr) throws IOException, CoindException {
    String method = "listtransactions";
    List<Object> params = new ArrayList<>();
    params.add(accountStr);
    JSONResponse transactionsRes = connectCoind(createJSONString("1", method, params));
    return (List<Map<String, String>>) transactionsRes.result;
}

  • sendfrom

アカウント文字列、送信先アドレス、金額を渡し、成功するとそのトランザクションIDを返します。
送信先アドレスの無効、金額不足など、エラーの発生しやすいメソッドです。

public static String sendfrom(String accountStr, String toAddress, double amount) throws IOException, CoindException {
    String method = "sendfrom";
    List<Object> params = new ArrayList<>();
    params.add(accountStr);
    params.add(toAddress);
    params.add(amount);
    JSONResponse sendRes = connectCoind(createJSONString("1", method, params));

    return sendRes.result.toString();
}


ちなみにアカウント名を空文字列にすれば、アカウント名を指定しなかったことになって残高などWallet全体の数字になるかと思いきや、空文字列もアカウントとしては有効で、空文字アカウントの残高が返されます。

エラー周辺で結構ハマりましたが、これで一通り必要な機能が実装できました。


Read More...

Javaでmonacoindユーティリティクラスを作成する① JSONを扱う


今回は、JSON-RPCmonacoind操作全般を受け持つユーティリティクラスを作成します。


まずはJSONの扱いですが、2013年のJava EE7の頃に、標準のJSONライブラリが追加されたとか聞いていましたが、あんまりいけてないようです。
POJOにバインドする機能とかもないらしく、自前でマッピングしてあげないといけない?

まぁ実際のところはよく分かりませんが、無難にJacksonを使います。

公式からjackson-corejackson-databindをダウンロードしてライブラリに登録しておきます。


リクエスト用とレスポンス用のPOJOをそれぞれ作成し、Jacksonを使ってinoutstreamと直接変換します。

  • リクエスト用クラス

バージョンは1.0固定で良さそうなのでハードコードしてしまいます。
final宣言しておくと、@AllArgsConstructorアノテーションでもjsonrpc抜きのコンストラクタが作成されます。

paramsにはStringdoubleが入るので、Object型にしておきます。

@AllArgsConstructor
@Getter
@Setter
public class JSONRequest {

    final String jsonrpc = "1.0";
    String id;
    String method;
    List<Object> params;
}

  • レスポンス用クラス

errorは普段nullですが、エラーの場合にはエラー番号やエラー内容がまとめて入ってくるので、MapvalueObject型にしておきます。

@Getter
@Setter
public class JSONResponse {

    Object result;
    Map<String, Object> error;
    String id;
}

また、monacoindとの通信で発生するエラーを格納するExceptionクラスも作成しておきます。

  • monacoind用Exceptionクラス

monacoindが返してきたエラーメッセージを格納出来るようにしておきます。

@NoArgsConstructor
public class CoindException extends Exception {

    public CoindException(String msg) {
        super(msg);
    }
}

前準備は整ったので、ここからはCoindUtilクラスを作成し、必要なメソッドを実装していきます。

  • リクエスト用文字列を作成するメソッド

ObjectMapperクラスのwriteValueAsStringメソッドで、JSONRequestクラスからJSON文字列を作成します。

public static String createJSONString(String id, String method, List<Object> params) throws JsonProcessingException {
    JSONRequest jsonRequest = new JSONRequest(id, method, params);

    return new ObjectMapper().writeValueAsString(jsonRequest);
}

  • JSON文字列を受け取り、monacoindと通信するメソッド

今回はメインPCから実験用PCにアクセスしているので、monacoin.confrpcallowipでローカルホスト以外からのアクセスも許可しています。
ID、PWはmonacoin.confに設定したID、PWです。

リクエストはJSON文字列をOutputStreamPrintWriterでそのまま書き込んで送信します。

何気に、try-with-resource初めて使ったかも。


レスポンスはInputStreamを受け取って、ObjectMapperクラスのreadValueメソッドで、JSONResponseクラスに変換します。

IOExceptionはそのまま上に投げ、monacoindがエラーを返した場合は、先ほど作成したCoindExceptionにメッセージを渡してから上に投げます。

public static JSONResponse connectCoind(String json) throws IOException, CoindException {
  
    final String urlStr = "http://192.168.1.15:9359";
    final String rpcuser = "rpcuser";
    final String rpcpassword = "rpcpassword";

    URL url = new URL(urlStr);
    URLConnection connection = url.openConnection();

    Authenticator.setDefault(new Authenticator() {
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(rpcuser, rpcpassword.toCharArray());
        }
    });
    connection.setDoOutput(true);

    connection.setRequestProperty("content-type", "text/plain;");
    OutputStream out = connection.getOutputStream();

    try (PrintWriter pw = new PrintWriter(out)) {
        pw.print(json);
    }

    JSONResponse response;
    try (InputStream in = connection.getInputStream()) {
        ObjectMapper mapper = new ObjectMapper();
        response = mapper.readValue(in, JSONResponse.class);
    } catch (IOException e) {
        try (InputStream es = ((HttpURLConnection) connection).getErrorStream()) {
            ObjectMapper mapper = new ObjectMapper();
            response = mapper.readValue(es, JSONResponse.class);
        }
    }

    Optional<Map<String, Object>> errorOpt = Optional.ofNullable(response.error);
    if (errorOpt.isPresent()) {
        throw new CoindException((String) errorOpt.get().get("message"));
    }

    return response;
}


ここで死ぬほどハマったのが、cURLからだと問題無くJSONでエラーが返ってくる状況で、普通にInputStreamを取り出すと、HTTP response code: 500が返って来たことです。

エラーの内容を見たいのに、500が返ってくるとIOExceptionが投げられてしまい、InputStreamを弄れません。

そして、Google先生との長い対話の末たどり着いたのが、ErrorStreamです。

まず一度IOExceptioncatchして、URLConnectionHttpURLConnectionにキャストした上で、getErrorStream()で改めてInputStreamを取得します。

コイツを弄ってやると、ちゃんとmonacoindが返したエラーが読めました。

エラーメッセージが読めた時は感動しましたが、これ設計としてどうなんでしょうか?常識なの?
なんだか釈然としません。


そして最後にせっかくなのでJava8で導入されたOptional使ってみました。
が、ラムダ式内部からExceptionを投げるのがうまくいかなかったので、普通にif文判定。

わざわざOptionalを使った意味があるかは不明ですが、いいんです。
使いたかっただけだから。


次回は実際にmonacoindとやり取りするメソッドの実装です。

Read More...

2014年8月4日月曜日

JSON-RPCを使ってmonacoindを操作する2 WEB Walletを作るには?


Bitcoin API calls 和訳版を参考に、WEB Walletを作るには?という視点でmonacoindで色々やってみました。

流れ的には以下のような感じでしょうか。


getaccountaddressでDeposit用のアドレスを作成。
その際、ユーザ固有のアカウントをアドレスに紐付ける。

既存のものではなく、新しいアドレスを作成するには、getnewaddressで新規作成する。
アカウントのアドレスリストは、getaddressesbyaccountで取得する。

getbalanceでアカウントの残高を確認。
listtransactionsでトランザクション履歴を確認。

sendfromで指定のアドレスへWithdrawする。


では、それぞれのメソッドを確認していきます。


  • getaccountaddress

指定したアカウントに支払いを受けるための、最新のアドレスを返します。
なければ作成、あればそれを返す。

$ curl --user 'rpcuserid:rpcpassword' --data-binary '{"jsonrpc":"1.0","id":"1","method":"getaccountaddress","params":["testAc"]}' -H 'content-type:text/plain;' http://127.0.0.1:9359
{"result":"MVPMzNXWwu4db4uwUzFm3NbDLRvpjmfkSC","error":null,"id":"1"}

MVPMzNXWwu4db4uwUzFm3NbDLRvpjmfkSCがtestAcにおけるDeposit用のアドレスとなります。

  • getnewaddress

呼ぶたびに新しいアドレスを返します。(以下は2回呼んだ結果)

$ curl --user 'rpcuserid:rpcpassword' --data-binary '{"jsonrpc":"1.0","id":"1","method":"getnewaddress","params":["testAc"]}' -H 'content-type:text/plain;' http://127.0.0.1:9359

{"result":"MUh5HD2VEC1UGZxxF1TRcKKsFCbGfmjEpq","error":null,"id":"1"}
{"result":"MS6WsHkyb9cFrHrxKFmi7bARwwpvNRvhsH","error":null,"id":"1"}

内部的にどうなっているのか、先ほど使ったgetaccountaddressで確認してみます。

{"result":"MVPMzNXWwu4db4uwUzFm3NbDLRvpjmfkSC","error":null,"id":"1"}

受信用アドレスは、新しいアドレス生成前と変わっていません。


  • getaddressesbyaccount

指定したアカウントのアドレスリストを返します。

$ curl --user 'rpcuserid:rpcpassword' --data-binary '{"jsonrpc":"1.0","id":"1","method":"getaddressesbyaccount","params":["testAc"]}' -H 'content-type:text/plain;' http://127.0.0.1:9359

{"result":["MUh5HD2VEC1UGZxxF1TRcKKsFCbGfmjEpq","MS6WsHkyb9cFrHrxKFmi7bARwwpvNRvhsH","MVPMzNXWwu4db4uwUzFm3NbDLRvpjmfkSC"],"error":null,"id":"1"}

もともとのアドレスに加え、新規で生成したアドレスがアカウントに紐付いています。


ここで0.01MONAほど入金してみます。

getaddressesbyaccountで確認すると、アドレスが増えています。

{"result":["MLGDvB3UoYEV9FvWkq2xkvFrxh6bPLniQE","MUh5HD2VEC1UGZxxF1TRcKKsFCbGfmjEpq","MS6WsHkyb9cFrHrxKFmi7bARwwpvNRvhsH","MVPMzNXWwu4db4uwUzFm3NbDLRvpjmfkSC"],"error":null,"id":"1"}

getaccountaddressで確認すると、新しいアドレスが入金用アドレスに変わっています。

{"result":"MLGDvB3UoYEV9FvWkq2xkvFrxh6bPLniQE","error":null,"id":"1"}

  • getbalance

指定したアカウントの残高を返します。

$ curl --user 'rpcuserid:rpcpassword' --data-binary '{"jsonrpc":"1.0","id":"1","method":"getbalance","params":["testAc"]}' -H 'content-type:text/plain;' http://127.0.0.1:9359

{"result":0.01000000,"error":null,"id":"1"}

  • listtransactions

トランザクション履歴を返します。

$ curl --user 'rpcuserid:rpcpassword' --data-binary '{"jsonrpc":"1.0","id":"1","method":"listtransactions","params":["testAc"]}' -H 'content-type:text/plain;' http://127.0.0.1:9359

{"result":[{"account":"testAc","address":"MVPMzNXWwu4db4uwUzFm3NbDLRvpjmfkSC","category":"receive","amount":0.01000000,"confirmations":6,"blockhash":"d4dd988599a7649897a80ed94dd5f9e3642c9be33d76fa067bda3dcf352802b0","blockindex":18,"blocktime":1407077735,"txid":"9ee8386695853db90dd2d37abc46e65874a68db51e4daf2721e1ce1a3441156b","normtxid":"0e36640249a1b732c99311e8babbc85a7db43f7640b136188e5a78853b014d6f","time":1407077288,"timereceived":1407077288}],"error":null,"id":"1"}

categoryreceiveのトランザクション履歴が確認出来ます。


  • sendfrom

指定したアカウントから送金します。

$ curl --user 'rpcuserid:rpcpassword' --data-binary '{"jsonrpc":"1.0","id":"1","method":"sendfrom","params":["testAc","MR2j3u5oNWZzAAxeHtSinHUEVNiSbkn8zJ",0.001]}' -H 'content-type:text/plain;' http://127.0.0.1:9359

{"result":"92828b7bf40b85b41f7deeb4e8f90ed2a14ced8efa83875132ca9319967f771f","error":null,"id":"1"}

listtransactionsで再度トランザクション履歴を確認してみます。

{"result":[{"account":"testAc","address":"MVPMzNXWwu4db4uwUzFm3NbDLRvpjmfkSC","category":"receive","amount":0.01000000,"confirmations":7,"blockhash":"d4dd988599a7649897a80ed94dd5f9e3642c9be33d76fa067bda3dcf352802b0","blockindex":18,"blocktime":1407077735,"txid":"9ee8386695853db90dd2d37abc46e65874a68db51e4daf2721e1ce1a3441156b","normtxid":"0e36640249a1b732c99311e8babbc85a7db43f7640b136188e5a78853b014d6f","time":1407077288,"timereceived":1407077288},{"account":"testAc","address":"MR2j3u5oNWZzAAxeHtSinHUEVNiSbkn8zJ","category":"send","amount":-0.00100000,"fee":-0.00100000,"confirmations":0,"txid":"92828b7bf40b85b41f7deeb4e8f90ed2a14ced8efa83875132ca9319967f771f","normtxid":"8a13b422a5c0adbe08b4b410d22457e1570142bfde66068a708ec19eddc8aee4","time":1407078088,"timereceived":1407078088}],"error":null,"id":"1"}

categorysendのトランザクションが増えました。


WEB Walletなんてのは実装としては意外と簡単なんですね。

セキュリティとか考えなければ、ですが。

Read More...

2014年8月3日日曜日

JSON-RPCを使ってmonacoindを操作する


JSON-RPCの動きを検証するために、jqueryなどを使って適当なJavascriptでテストページを作ったのですが、クロスオリジンの問題でうまく動きません。

ポートが異なるだけで別オリジン扱いのようなので、どうしようもないのかな?と思っていたところ、動きをテストするだけならもっと簡単な方法がありました。

cURLという、様々なプロトコルでデータを送受信できるユーティリティを使います。

試しにインストールして使ってみましょう。

$ sudo apt-get install curl
$ curl http://monacoin.org/ja/

これでだーっと標準出力にサイトのソースが表示されます。


では実際にmonacoindを操作してみましょう。

monacoindとJSON-RPCを使って会話をするために必要なIDとPWは、初回起動時にmonacoin.confに設定しているはずです。

そのIDとPWを使ってデフォルトのrpcportにアクセスすると、ちゃんと返事があります。

$ curl --user 'rpcuserid:rpcpassword' --data-binary '{"jsonrpc":"1.0","id":"curltext","method":"getinfo","params":[]}' -H 'content-type:text/plain;' http://127.0.0.1:9402

{"result":{"version":80700,"protocolversion":70002,"walletversion":60000,"balance":0.01800000,"blocks":208195,"timeoffset":44,"connections":8,"proxy":"","difficulty":1105.55691097,"testnet":false,"keypoololdest":1405931648,"keypoolsize":104,"paytxfee":0.00000000,"mininput":0.00001000,"errors":""},"error":null,"id":"curltext"}


monacoin.confの他の設定項目についても見てみます。

いくつかある設定項目の内、重要なのはrpcallowipとrpcportです。
server、listenについては設定しなくても返事があるので、qtを使う時に必要な設定なのか、デフォルトが有効な設定のようです。

まずrpcportを設定すると、待ち受けるポートをデフォルトの9402から変更出来ます。

rpcport=9359

monacoin.confで上記のように設定すると、以下のように9359ポートで動いているのが分かります。

$ curl --user 'rpcuserid:rpcpassword' --data-binary '{"jsonrpc":"1.0","id":"curltext","method":"getinfo","params":[]}' -H 'content-type:text/plain;' http://127.0.0.1:9359

{"result":{"version":80700,"protocolversion":70002,"walletversion":60000,"balance":0.01800000,"blocks":208196,"timeoffset":44,"connections":6,"proxy":"","difficulty":938.68052376,"testnet":false,"keypoololdest":1405931648,"keypoolsize":104,"paytxfee":0.00000000,"mininput":0.00001000,"errors":""},"error":null,"id":"curltext"}

次に、rpcallowipを設定すると、別のIPからでもアクセス出来るようになります。

以下のコメントアウトした1行目のように設定にすると、ネットワークごとアクセス許可が出来ます。

が、基本的にはlocalhostからのみの接続とすべきでしょう。
そうであれば、デフォルトでlocalhost限定なので、わざわざ設定しなくても良さそうですが、設定しろとよく書いてあるので、念のため。

#rpcallowip=192.168.0.*
rpcallowip=127.0.0.1

ちなみにrpcpasswordを間違えると、以下のようにHTMLでレスポンスがあります。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
<HTML>
<HEAD>
<TITLE>Error</TITLE>
<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>
</HEAD>
<BODY><H1>401 Unauthorized.</H1></BODY>
</HTML>


Read More...

2014年7月21日月曜日

意外と簡単に動いた! monacoindのビルドから実行まで


何か暗号通貨関連でサービスを作りたいと思い立ち、準備運動としてWalletのビルドを前回やったので、次にデーモンのビルドを試してみます。

最近TVで報道されたり、暴騰したりで話題のMonacoinのmonacoindをビルドしてみます。


前回Walletをビルドする際に、必要そうなパッケージはあらかた突っ込んだので、今回は非常にシンプルです。
$ git clone git://github.com/monacoinproject/monacoin.git
$ cd monacoin/src
$ make -f makefile.unix

ビルドし終わったら、「/usr/local/bin」あたりに放り込んで実行します。
$ monacoind
Error: To use monacoind, you must set a rpcpassword in the configuration file:
It is recommended you use the following random password:
rpcuser=monacoinrpc
rpcpassword=EvCj7irBs1egMX33HixQ6Hv481neRF9Jm8qmFwRKdUJy
(you do not need to remember this password)
The username and password MUST NOT be the same.
If the file does not exist, create it with owner-readable-only file permissions.
It is also recommended to set alertnotify so you are notified of problems;
for example: alertnotify=echo %s | mail -s "Monacoin Alert" admin@foo.com

なんか怒られました。

設定ファイルでrpcpasswordを設定しろとのことです。
オーナーのみ読み込み可能なように設定するべきと書いてあります。

ということで、指定どおりファイルを作成し編集する。
$ touch monacoin.conf
$ vi monacoin.conf

#中身は言われた通りに設定してみる。
rpcuser=monacoinrpc
rpcpassword=EvCj7irBs1egMX33HixQ6Hv481neRF9Jm8qmFwRKdUJy

#同じく指示通りオーナーのみ読み込み可能に。
$ chmod 400 monacoin.conf

#実行する。
$ monacoind

初めてmonacoindを実行すると、debug.logがモリモリ増量していきます。
初回の同期処理をしてるんだと思いますが、100M超えたあたりで不安になりました。。

不安なのでdebug.logを監視してみます。
$ tail -f debug.log

height(何ブロック目まで読み込んだか)の値が少しずつ大きくなっていっているので何か動いている風です。
しばらく待って、最新のブロックまで読み込んだ後、再起動したところdebug.logは200kぐらいになりました。

実際のデータはblocksディレクトリの中だと思われます。


では、実際にAPIを叩いて動作しているか確認してみます。

monacoindをデーモンとして起動します。
$ monacoind -daemon
Monacoin server starting

いくつかAPIを呼んでみます。

  • ヘルプ

$ monacoind help
だーっとヘルプが表示されます。


  • monacoindを停止

$ monacoind stop
Monacoin server stopping

#この状態でAPIを呼ぶと当然エラー
$ monacoind help
error: couldn't connect to server


  • 再起動してから残高を表示

$ monacoind -daemon
Monacoin server starting
$ monacoind getbalance
0.00000000


  • 最新のブロック番号を表示

$ monacoind getblockcount
197067


  • 現在のdifficultyを表示

$ monacoind getdifficulty
227.03475154


  • もろもろの情報をまとめて表示

$ monacoind getinfo
{
    "version" : 80700,
    "protocolversion" : 70002,
    "walletversion" : 60000,
    "balance" : 0.00000000,
    "blocks" : 197069,
    "timeoffset" : 26,
    "connections" : 8,
    "proxy" : "",
    "difficulty" : 168.17490151,
    "testnet" : false,
    "keypoololdest" : 1405931648,
    "keypoolsize" : 101,
    "paytxfee" : 0.00000000,
    "mininput" : 0.00001000,
    "errors" : ""
}


  • 受信用アドレスの情報を表示
以下だと取引の発生していないアドレスは表示されません。

$ monacoind listreceivedbyaddress
[
]


  • すべての受信用アドレスの情報を表示
取引の発生していないアドレスも表示されます。

$ monacoind listreceivedbyaddress 0 true
[
    {
        "address" : "MENrRKiTwgXSGxczz62Jk7AFq67pLYpdWV",
        "account" : "",
        "amount" : 0.00000000,
        "confirmations" : 0,
        "txids" : [
        ]
    }
]


  • 取引発生後の受信用アドレス
別のWalletから上記アドレスに0.01MONA送金後、こんどはオプション無しで表示されました。

$ monacoind listreceivedbyaddress
[
    {
        "address" : "MENrRKiTwgXSGxczz62Jk7AFq67pLYpdWV",
        "account" : "",
        "amount" : 0.01000000,
        "confirmations" : 7,
        "txids" : [
            "f1a4f98965f45d69abbced94c94e0daa6c4b8106593b8836f2d3d8dc2244d1e6"
        ]
    }
]


  • 取引発生後のすべての受信用アドレス
取引発生後、内部的に新しいアドレスが追加された模様。

$ monacoind listreceivedbyaddress 0 true
[
    {
        "address" : "MENrRKiTwgXSGxczz62Jk7AFq67pLYpdWV",
        "account" : "",
        "amount" : 0.01000000,
        "confirmations" : 7,
        "txids" : [
            "f1a4f98965f45d69abbced94c94e0daa6c4b8106593b8836f2d3d8dc2244d1e6"
        ]
    },
    {
        "address" : "MNVb8W1dHD4jNGRtCayhiMzojGontESw8r",
        "account" : "",
        "amount" : 0.00000000,
        "confirmations" : 0,
        "txids" : [
        ]
    }
]


  • 送金テスト
0.001MONAを送金してみます。

$ monacoind sendtoaddress MR2j3u5oNWZzAAxeHtSinHUEVNiSbkn8zJ 0.001
02f4ab46964f9a55dd0554a5764725e10513b1ad402b939a96e2273d531c9773

早速Windowsに入れているWalletに0.001MONA届きました。


ちなみに激しく貧乏なのは、1MONAが7円ぐらいに跳ね上がった時に、焦って全部Bitcoinにしてしまったためです。。
まさかあそこから30円突破まで行くとは。。


ということで、なんかサービス作るのでMonacoinで寄付下さいw

MR2j3u5oNWZzAAxeHtSinHUEVNiSbkn8zJ


Read More...

2014年6月1日日曜日

Linux用walletをビルドする


そういえば、一度もWalletを自分でビルドしたことが無かったので、Walletのビルドを試してみました。
ビルドの実験はVMware上のUbuntuで作業しました。


まずは最近無事完全PoSへ移行したRingoで試します。

GitHub
https://github.com/dkwzjw/ringo


「INSTALL」を見ると以下のような記載があります。

Building Ringo

See doc/readme-qt.rst for instructions on building Ringo QT,the intended-for-end-users, nice-graphical-interface, reference implementation of Ringo.


まずはdoc/readme-qt.rstを見ろと書いてあり、見ると以下のように記載されています。

First, make sure that the required packages for Qt5 development of your distribution are installed, for Debian and Ubuntu these are:

apt-get install qt5-default qt5-qmake qtbase5-dev-tools qttools5-dev-tools build-essential libboost-dev libboost-system-dev libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev libssl-dev libdb++-dev

then execute the following:
qmake
make

Qt(キュートと読む)というのは、アプリケーション開発フレームワークで、クロスプラットフォーム対応が楽な設計になっているとか。

事前準備として、そのQt開発に必要なパッケージをインストールします。
$ apt-get install qt5-default qt5-qmake qtbase5-dev-tools qttools5-dev-tools build-essential libboost-dev libboost-system-dev libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev libssl-dev libdb++-dev

次にgitをインストールします。
$ sudo apt-get install git

次にringoのリポジトリを複製します。
今回は/tmpで作業。
$ cd /tmp
$ mkdir ringo
$ cd ringo
$ git clone git://github.com/dkwzjw/ringo.git ./

git cloneしてあげると、GitHubからringoのソースコードをごっそり持ってくるので、Makefileを作成し、makeします。
configureじゃなくてqmakeなんですね。
$ qmake
$ make

なにやらエラーを吐きました。
src/net.cpp:19:32: fatal error: miniupnpc/miniwget.h: そのようなファイルやディレクトリはありません
 #include <miniupnpc/miniwget.h>
                                ^

以下で必要なパッケージをインストールしたらいけました。
$ sudo apt-get install libminiupnpc-dev libminiupnpc8


が、思いっきり文字化けw


既にコンソールに日本語が出ていたので、ロケール設定には問題ないはず。
$ env | grep LANG
LANG=ja_JP.UTF-8

やはり問題無いですね。

フォントがインストールされてないだけか?ということで、IPAフォントを入れてみます。
$ sudo apt-get install fonts-ipafont

うーん、あと一歩w漢字が表示出来ない。。


よく分からないですが、動作には問題なさそうなので、文字化け問題は一旦放置して、Vertcoinでもやってみます。

基本的な作りは本当に皆同じなんですね。

ほぼ同じように作業したところ、Makefile作るときに、なにやらエンコードか何かのエラーが出ましたが、とりあえずうまくいきました。

ちなみに、ホームディレクトリにringoフォルダや、vertcoinフォルダが出来ているんですが、隠しディレクトリです。
lsコマンドに「-a」オプションを付ければ見えます。


ちなみに、BAMTでも試してみたのですが、ビルドは出来たんですが、容量不足とか言われて同期出来ませんでした。
たしかに、結構容量喰うんですよね。
Read More...

Fujicoin始まりました


Fujicoinが日本時間の6/1 6:00にローンチしました。

Fujicoinの情報
http://www.fujicoin.org/index-ja.html
http://www55.atpages.jp/~cctj/index.php?topic=5.0


Ringo祭りには参加出来なかったので、今回は参加しておきます。

5分前にUPされたWalletをダウンロードしてみたところ、ノートン先生から警告。

様々な暗号通貨をインストールしてきましたが、これ出たの初めてです。

いつもは、Suspicious.Cloud.9とか、「なんか怪しいよー」ぐらいのしか出たことが無かったので、ちょっと怖いです。

単純に暗号通貨の採掘アルゴリズムが入ってるという意味なのか、知らないうちに誰かのためにせっせと働かされるという意味なのか。

まぁ誤検知なんでしょうが、Walletのインストールは後回しにして、ひとまずは世界中の人柱様達に一旦はお任せすることにします。


ローンチ後1時間のブロック報酬は1コインとのことなので、6時台から堀りはじめても電気代の無駄なのですが、とりあえず試しにPoolで掘ってみます。

あれ??

まだ6時台ですが、モリモリとUnconfirmedが増えていきます。

Crypto Coin Talk Japanを見ると、以下の記述が。

S-Curve報酬は既に始まっています

ローンチと同時に一気にブロックが進みました。現在1000くらい。
S-Curveはブロック500から始まるのですが、想定外に早く始まりました。
多分エポックタイムからの遅れを取り戻すように動作しているんですね。
知りませんでした。


どうやら、開発者の方も想定外だったようです。

しかし、今7:20の時点で、Poolの表示でNet Hashrate 15.39 MH/s です。

ガチな人達はあまり参入していないということなのか、いくらScrypt-Nだからと言って、ちょっと低すぎる気がします。

まぁせっかくローンチから堀りはじめたので、部屋の暑さに負けるまでは、掘り続けようかと思います。

もう負けそうだけど。。


Read More...

2014年5月21日水曜日

部屋が暑くて挫けそう。。 暗号方式とGPU温度と効率


人類は、太陽を手に入れた。

そして、我が家はMining Rigを手に入れた。

結構な熱源が常に猛威を振るっている我が家から、暗号方式とGPU温度と効率についてお届けします。


まずは、MonacoinやLitecoinなどのScryptの通貨。

こいつらを掘っていると、GPU温度はかなり高くなります。
最も温度が高いGPUが73℃ということで、冬は暖房要らずでした。

次にQuarkcoinのクローンのKumacoin。
最も温度が高いGPUが55℃で、Monacoinと比較して18℃も低い。

最後はDarkcoinなどのX11。
最も温度が高いGPUが59℃で、Kumacoinよりも4℃高い。


ということで、Scryptはやはり温度が高く、また消費電力も大きいっぽい。

そして、QuarkやX11は比較すると温度が低く、Quarkの方がさらに温度が低い。
ワットチェッカーなどで計っては無いものの、恐らく消費電力も小さいんだと予想できます。


そしてScryptで2Mhash/sの我が家のMining Rigによる、Bitcoin入手効率を考えてみます。

まぁグラボで掘っているので、電気代で基本的には赤字ですが。。


Monacoinの場合は、1日で手に入るBitcoinは0.006~0.007BTCほどで安定。

ちょっと前にかなりの高効率だったKumacoinは、バグやらBlock timeの変更などを経て、20分の1ぐらいまで値下がりしているので、せいぜい0.003BTC程度。

X11のコインをマルチプールで掘った場合は、タイミングによって大きく変わるものの、0.006~0.012BTCほど。
これは同じマルチプールで掘った場合、Scryptのコインでも同じぐらいでした。


ということで、この暑さに耐えながら現状続けるのであれば、新規コイン狙いを続けるか、GPU温度、電気代を考えて、マルチプールでX11を掘り続けるしかなさそうです。

マジで暑いです。


Read More...