取引手数料を算出するために探した。たぶん発見したが、データをデコードできなかった。

前回まで

vinにあるtxidから入力用トランザクションを取得し、その残高を使って支払う。それは理解できた。

では、完了した取引データから手数料を算出・取得するには、どうしたらいいの? たぶんvintxidを引数にして、それに紐づくトランザクションデータを取得するAPIがあるのではないか?

今回

txidからトランザクションデータを取得する方法を調べた。

たぶんAPIは発見したが、その結果にはデコードが必要っぽい。そのためのAPIらしきものを実行するも失敗するので、本当にトランザクションデータが取得できているかどうか確認できなかった。

まとめ

getrawtransaction

おそらくtxidで指定されたトランザクション情報は以下で取得できる。

const txid = 'e1e94be2b6f541e6639d9bd1cce79ac9a668dd25b0c3bd5f48c411ade94f8003'
await window.mpurse.counterParty('get_tx_info', {tx_hex: await window.mpurse.counterParty('getrawtransaction', {tx_hash: txid})});

ただ、それで取得された値は以下のように謎の文字列である。

010000000119b25983f61ad0b58fbdcac01025be3b6f6d341cb11641b1e0d935e4f78a627b010000006b483045022100e7b36a5115a86326b91d0bf89407df78733850c63e041a51a913f3f09f6df13e022048896aaa5b71ababf66323b8bc8ed25e1b3a423ed643b5a7acf484dcf4f3afbf012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3dffffffff02c0175302000000001976a9145bef72db1e9a105cf734ead06ef87a54f1d39a3588acffe3e30c000000001976a91413bd7f2032c935652371722ae6d987f2f8135aac88ac00000000

decoderawtransaction

ネットでググるとdecoderawtransactionなるAPIがあるらしい。そいつでデコードするとJSONデータになるっぽい。

でも、そんなAPIは以下ドキュメントのどこにも書いていなかった。

一応試してみたが、やはりダメだった。

API 結果
CounterParty API そんなメソッドねーよ
CounterBlock API このエンドポイントはcouterblock apiだけだよ(いやお前がcouterblock apiじゃないのかよ。どゆこと?)

たぶんググった資料が古いとか、なんか知らない事情があるのだろう。ここで詰まった。これ以上は追えない。

CounterParty API

await window.mpurse.counterParty('decoderawtransaction', {tx_hash: '010000000119b25983f61ad0b58fbdcac01025be3b6f6d341cb11641b1e0d935e4f78a627b010000006b483045022100e7b36a5115a86326b91d0bf89407df78733850c63e041a51a913f3f09f6df13e022048896aaa5b71ababf66323b8bc8ed25e1b3a423ed643b5a7acf484dcf4f3afbf012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3dffffffff02c0175302000000001976a9145bef72db1e9a105cf734ead06ef87a54f1d39a3588acffe3e30c000000001976a91413bd7f2032c935652371722ae6d987f2f8135aac88ac00000000'});
{
    "code": -32000,
    "data": {
        "args": [
            "{\"message\": \"Method not found\", \"code\": -32601}"
        ],
        "message": "{\"message\": \"Method not found\", \"code\": -32601}",
        "type": "Exception"
    },
    "message": "Server error"
}

decoderawtransactionなんてメソッドはCounterParty APIには存在しませんよ、だってさ。

CounterBlock API

await window.mpurse.counterBlock('decoderawtransaction', {tx_hash: '010000000119b25983f61ad0b58fbdcac01025be3b6f6d341cb11641b1e0d935e4f78a627b010000006b483045022100e7b36a5115a86326b91d0bf89407df78733850c63e041a51a913f3f09f6df13e022048896aaa5b71ababf66323b8bc8ed25e1b3a423ed643b5a7acf484dcf4f3afbf012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3dffffffff02c0175302000000001976a9145bef72db1e9a105cf734ead06ef87a54f1d39a3588acffe3e30c000000001976a91413bd7f2032c935652371722ae6d987f2f8135aac88ac00000000'});
Uncaught This endpoint is the couterblock api only.

このエンドポイントはcouterblock apiだけですよ、だってさ。君がそのcouterblock apiじゃないんかい。じゃあ君は何者? mpurseの呼出メソッド名だってcounterBlockじゃん。今までずっとそう思ってたんですけど?

お手上げです。

txidからトランザクションデータの取得はたぶん成功している。あとはデコードができればいい。でも、デコードAPIがないからできない。一旦ここで諦める。

経緯

以下、結論に至るまでの経緯。

mpurse API

txidモナコインの取引トランザクションを取得する方法を調べたときのものを使う。e1e94be2b6f541e6639d9bd1cce79ac9a668dd25b0c3bd5f48c411ade94f8003

...
    "vin": [
        {
            "scriptSig": {
                "asm": "3045022100b18c83115da395e12791b717b32aff754865cac478bb4e72ddde0f0e6c28b28d0220716c20fcd5151e4aeb8c2f898b9735713a596ff8daac03d7169e207c2e4e6743[ALL] 03aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3d",
                "hex": "483045022100b18c83115da395e12791b717b32aff754865cac478bb4e72ddde0f0e6c28b28d0220716c20fcd5151e4aeb8c2f898b9735713a596ff8daac03d7169e207c2e4e6743012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3d"
            },
            "sequence": 4294967295,
            "txid": "e1e94be2b6f541e6639d9bd1cce79ac9a668dd25b0c3bd5f48c411ade94f8003",
            "vout": 1
        }
    ],
...

mpurseのREADMEからtransactionで文字列検索する。ヒットしたAPIは以下2つ。

でも、名前や戻り値からして違うっぽい。となると、難しそうな以下APIを使うことになるのだろう。

mpurse#mpchain

mpurseのREADMEからリンクをたどるとmpchainにいく。ここにAPIが網羅されている。この中からtransaction関係のものは以下2つ。

  • Send Transaction
  • Transaction

目的は取得なのでSend Transactionではない。あとはTransactionのみ。エンドポイントをみると以下。

/api/tx/{tx_index}
/api/tx/{tx_hash}

引数にしたい値はtxid。なんか違わないか?

戻り値をみてみると、すごいたくさんある。Sendがそれっぽいかな? でも宛先のアドレスがないように見える。

...
Send: {
  asset: string,
  asset_group: string,
  asset_longname: string,
  block_index: number,
  destination: string,
  fungible: boolean,
  memo: string,
  memo_hex: string,
  quantity: string,
  source: string,
  status: string,
  timestamp: number,
  tx_hash: string,
  tx_index: number,
  tx_type: string
}
...

まあいいや。とりあえず試してみよう。以下URLをブラウザで叩いてみる。

https://mpchain.info/api/tx/e1e94be2b6f541e6639d9bd1cce79ac9a668dd25b0c3bd5f48c411ade94f8003

するとエラーが返ってきた。あんれー? このAPIではないのかな?

{"error":"Transaction not found"}

mpurse#counterblock

引数をみるとアドレスになっている。txidじゃない。

get_raw_transactions(address, start_ts=None, end_ts=None, limit=500):

こちらもtsとかいう謎の値。txidじゃない。

get_transaction_stats(start_ts=None, end_ts=None)

検索するキーワードをtransactionからtxにしてみる。

名前からしてgetが目的のものだろう。createconvertは違うはず。

あれ、引数がない。txidを渡せない。

get_chain_txns_status

一応ほかの2つも見てみる。引数にtxのキーワードはある。でもtxidではない。たぶん違う。

create_armory_utx(unsigned_tx_hex, public_key_hex)
convert_armory_signedtx_to_raw_hex(signed_tx_ascii)

mpurse#counterparty

transactionをキーワードに文字列検索する。

party getrawtransaction

お、これかも?

getrawtransaction(tx_hash, verbose=false, skip_missing=false)

引数のtx_hashは、txidとは違うのかな?

tx_hash (string): The transaction hash identifier
Return:

If found, a raw transaction objects having the same format as the bitcoind getrawtransaction API call. If not found, null.

戻り値はトランザクション・オブジェクトだという。

さて、これをmpurse APIから叩くにはどうすればいいか。mpurse#counterpartyのコード例をみてみよう。

const cpParams = {address: 'MLinW5mA2Rnu7EjDQpnsrh6Z8APMBH6rAt'};
const unspentTxouts = await window.mpurse.counterParty('get_unspent_txouts', cpParams);

ん? このunspentだのtxだのoutだのっていうキーワードには見覚えがある。もしやこれ、voutをゲットするAPIでは? ちがうか。名前から察するに、まだ消耗していないUXTOデータを取得しようとしているのか。ん? それってvinにするためのトランザクションデータを取得するってことじゃないのか? もしかして支払いするときこのAPIでvinになる取引データを取得するのかな?

なんにせよ、get_unspent_txoutsは今回ほしいものじゃない。私がほしいのはvintxidを引数にして、それを取得するやつ。

とりあえず話を戻そう。getrawtransaction APIがそれかどうか確認する。以下コードでイケるんじゃないか?

const cpParams = {tx_hash: 'e1e94be2b6f541e6639d9bd1cce79ac9a668dd25b0c3bd5f48c411ade94f8003'};
const unspentTxouts = await window.mpurse.counterParty('getrawtransaction', cpParams);

これをHTTPSにアップロードしたページで開いたデベロッパツールのコンソールで実行してみる。ytyaruのプロフィールでいいだろう。ついでにワンライナーにしておく。変数に代入しないようにすれば、時間経過で表示されるはず。

await window.mpurse.counterParty('getrawtransaction', {tx_hash: 'e1e94be2b6f541e6639d9bd1cce79ac9a668dd25b0c3bd5f48c411ade94f8003'});

確かに何かが返ってきた。でも、JSONオブジェクトではなく、英数字の羅列だった。なにこれ。思ってたのと違う。次。

010000000119b25983f61ad0b58fbdcac01025be3b6f6d341cb11641b1e0d935e4f78a627b010000006b483045022100e7b36a5115a86326b91d0bf89407df78733850c63e041a51a913f3f09f6df13e022048896aaa5b71ababf66323b8bc8ed25e1b3a423ed643b5a7acf484dcf4f3afbf012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3dffffffff02c0175302000000001976a9145bef72db1e9a105cf734ead06ef87a54f1d39a3588acffe3e30c000000001976a91413bd7f2032c935652371722ae6d987f2f8135aac88ac00000000

party getrawtransaction_batch

getrawtransaction_batch(txhash_list, verbose=false, skip_missing=false)

名前や引数txhash_listからして複数形っぽい。違うな。

party search_raw_transactions

search_raw_transactions(address, unconfirmed=true)

これは違う。指定したアドレスの全トランザクションを取得するやつ。前に使ったから知ってる。

あんれー? どこにあるの?

txをキーワードに探してみる

party get_unspent_txouts

get_unspent_txouts(address, unconfirmed=false, unspent_tx_hash=null)

引数がアドレス。txidじゃない。

戻り値は以下。

A list of objects, with each entry in the dict having the following properties:
- **amount**: The amount of the UTXO (e.g. 0.12345678)
- **value**: The value of the UTXO in satoshis (e.g. 12345678)
- **height**: The block height of the UTXO
- **confirmations**: Number of confirmations since the UTXO was created
- **txid**: The txid (hash) that the UTXO was included in
- **vout**: The vout number in the specified txid for the UTXO

UXTOという覚えたての用語を発見。txidもあった。でも戻り値じゃんか。あ、でもtxid (hash)って書いてる。やはりtxidhashで、tx_hashのことだと思っていいのかな?

なんにせよ、このAPIではなさそう。

party get_tx_info

これかもしれん。

get_tx_info(tx_hex, block_index=null)

引数はtx_hex。たぶんtxidだろう。そして戻り値もなんかそれっぽい。feeは手数料だし。btc_amountはビットコイン量のことだろう。モナコインだとどうなるか知らないけど。とにかくそれっぽい雰囲気。

A list with the following items (in order as listed below):

- `source`
- `destination`
- `btc_amount`
- `fee`
- `data`: The embedded raw protocol data, in hexadecimal-serialized format

こいつをmpurse APIで叩いてみる。

await window.mpurse.counterParty('get_tx_info', {tx_hash: 'e1e94be2b6f541e6639d9bd1cce79ac9a668dd25b0c3bd5f48c411ade94f8003'});

エラーが返ってきた。

{
    "code": -32000,
    "data": {
        "args": [
            "get_tx_info() got an unexpected keyword argument 'tx_hash'"
        ],
        "message": "get_tx_info() got an unexpected keyword argument 'tx_hash'",
        "type": "Exception"
    },
    "message": "Server error"
}

tx_hashが予期しないキーワード引数だと? どういうことだ。ならblock_indexにしてみるか。

await window.mpurse.counterParty('get_tx_info', {block_index: 'e1e94be2b6f541e6639d9bd1cce79ac9a668dd25b0c3bd5f48c411ade94f8003'});
{
    "code": -32000,
    "data": {
        "args": [
            "get_tx_info() missing 1 required positional argument: 'tx_hex'"
        ],
        "message": "get_tx_info() missing 1 required positional argument: 'tx_hex'",
        "type": "Exception"
    },
    "message": "Server error"
}

必須引数tx_hexをよこせ、だってさ。なら以下でいいのか?

await window.mpurse.counterParty('get_tx_info', {tx_hex: 'e1e94be2b6f541e6639d9bd1cce79ac9a668dd25b0c3bd5f48c411ade94f8003'});
{
    "code": -32000,
    "data": {
        "args": [
            "Asked to read 32 bytes, but only got 27"
        ],
        "message": "Asked to read 32 bytes, but only got 27",
        "type": "Exception"
    },
    "message": "Server error"
}

32バイト必要なのに27バイトしかねーぞゴルァ! だそうです。知らんがな。この長ったらしいtxidは65文字あるんですけどねぇ。32だの27だの、一体何の数字なの?

ていうか、引数名がそれぞれ何を指しているのかわからん。網羅してみよう。

  • txid
  • tx_hex
  • tx_hash
  • tx_index
  • block_index

ああ、最初のミスはtx_hextx_hashと勘違いしていたせいか。でも、名前を正してもダメだった。そもそもtx_hexとやらはtxidと同じって認識でいいの? 違うんだろうなぁ。じゃあ一体なんなんだ? どうしたらvinにあったtxidから金額をゲットできるの? そこから手数料を算出したかったのに。

見返してみたら、getrawtransactionの戻り値って16進数じゃないか?

await window.mpurse.counterParty('getrawtransaction', {tx_hash: 'e1e94be2b6f541e6639d9bd1cce79ac9a668dd25b0c3bd5f48c411ade94f8003'});
010000000119b25983f61ad0b58fbdcac01025be3b6f6d341cb11641b1e0d935e4f78a627b010000006b483045022100e7b36a5115a86326b91d0bf89407df78733850c63e041a51a913f3f09f6df13e022048896aaa5b71ababf66323b8bc8ed25e1b3a423ed643b5a7acf484dcf4f3afbf012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3dffffffff02c0175302000000001976a9145bef72db1e9a105cf734ead06ef87a54f1d39a3588acffe3e30c000000001976a91413bd7f2032c935652371722ae6d987f2f8135aac88ac00000000

もしやこれ、tx_hexというやつでは? hexって16進数のことだし。ということは、以下のようにしてみたらイケるかも?

await window.mpurse.counterParty('get_tx_info', {tx_hex: '010000000119b25983f61ad0b58fbdcac01025be3b6f6d341cb11641b1e0d935e4f78a627b010000006b483045022100e7b36a5115a86326b91d0bf89407df78733850c63e041a51a913f3f09f6df13e022048896aaa5b71ababf66323b8bc8ed25e1b3a423ed643b5a7acf484dcf4f3afbf012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3dffffffff02c0175302000000001976a9145bef72db1e9a105cf734ead06ef87a54f1d39a3588acffe3e30c000000001976a91413bd7f2032c935652371722ae6d987f2f8135aac88ac00000000'});

え、525エラーだと。

Uncaught StatusCodeError: 525 - {"data":"Server is not caught up. Please try again later.","message":"Server error","code":-32000}

もう一回。

{
    "code": -32602,
    "data": {
        "args": [
            "argument of type 'NoneType' is not iterable"
        ],
        "message": "argument of type 'NoneType' is not iterable",
        "type": "TypeError"
    },
    "message": "Invalid params"
}

え、無効な引数? なんでNoneType? nullになってるの? ちゃんと文字列渡したじゃん。

そういえば、32バイト必要っていってたな。引数のtx_hexは32バイトの16進数値ってこと? それってtxidから取得できるの?

読み返すと、counterBlockのほうに以下のようなAPIがあった。

convert_armory_signedtx_to_raw_hex(signed_tx_ascii)

mpurse APIを介して実行するなら以下。引数signed_tx_asciiがなんなのか知らないが、txidを渡してみる。

await window.mpurse.counterBlock('convert_armory_signedtx_to_raw_hex', {signed_tx_ascii: 'e1e94be2b6f541e6639d9bd1cce79ac9a668dd25b0c3bd5f48c411ade94f8003'});
{
    "code": -32000,
    "data": {
        "args": [
            "Got call_jsonrpc_api request error: result is None -- is the 'http://armory-utxsvr:6590/' endpoint operational?"
        ],
        "message": "Got call_jsonrpc_api request error: result is None -- is the 'http://armory-utxsvr:6590/' endpoint operational?",
        "type": "Exception"
    },
    "message": "Server error"
}
call_jsonrpc_apiリクエストエラーが発生しました:結果はNoneです-「http:// armory-utxsvr:6590 /」エンドポイントは機能していますか?

お前は何を言っているんだ? まるでわからん。たぶんconvert_armory_signedtx_to_raw_hex APIの中でcall_jsonrpc_apiというAPIを呼び出しているのだろう。で、そのホストサーバがhttp://armory-utxsvr:6590/だけど機能してなくね? ってことかな?

armory、武器庫って意味らしいが。これ暗号通貨の用語でいうと何を指す語なんだ? ウォレットのことではないのだろうし。トランザクション情報を保存する場所のことかな? わからん。

もしやビットコインとモナコインの保存サーバが違うから取り出せないとか?

だめだ。わからん。

最初にもどってみる

ここで私の取引データを取得する。以下APIで。

await window.mpurse.counterParty('search_raw_transactions', {address: 'MEHCqJbgiNERCH3bRAtNSSD9uxPViEX1nu'});

その結果、取引データのひとつの中にvinがあり、その要素にtxidがある。これはらいうさんが私に送金したとき、その入力として使ったトランザクションデータ。らいうさんの所持金が入っていたはず。

...
    "vin": [
        {
            "scriptSig": {
                "asm": "3045022100b18c83115da395e12791b717b32aff754865cac478bb4e72ddde0f0e6c28b28d0220716c20fcd5151e4aeb8c2f898b9735713a596ff8daac03d7169e207c2e4e6743[ALL] 03aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3d",
                "hex": "483045022100b18c83115da395e12791b717b32aff754865cac478bb4e72ddde0f0e6c28b28d0220716c20fcd5151e4aeb8c2f898b9735713a596ff8daac03d7169e207c2e4e6743012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3d"
            },
            "sequence": 4294967295,
            "txid": "e1e94be2b6f541e6639d9bd1cce79ac9a668dd25b0c3bd5f48c411ade94f8003",
            "vout": 1
        }
    ],
...

もしや、らいうさんの全トランザクションデータの中から探せばいいのか?

たとえばさっきの取引データの中にあるvoutにはhexがある。これとさっきのtxidが一致するやつがあるのでは? でもこれscriptPubKeyって書いてあるし。なんだよscriptPubKeyって。

というか、過去のデータって、もうなくなっているのでは? vinとして使ったのだから、その取引により支払額と手数料が差し引かれたはずだし。この方法はダメな気がする。

    "vout": [
        {
            "n": 0,
            "scriptPubKey": {
                "addresses": [
                    "MEHCqJbgiNERCH3bRAtNSSD9uxPViEX1nu"
                ],
                "asm": "OP_DUP OP_HASH160 45fc13c9d3a0df34008291492c39e0efcdd220b8 OP_EQUALVERIFY OP_CHECKSIG",
                "hex": "76a91445fc13c9d3a0df34008291492c39e0efcdd220b888ac",
                "reqSigs": 1,
                "type": "pubkeyhash"
            },
            "value": 1.14114
        },
        {
            "n": 1,
            "scriptPubKey": {
                "addresses": [
                    "M9hY5XcC7MSD54DfqcEojiKm9QMgXeQhGK"
                ],
                "asm": "OP_DUP OP_HASH160 13bd7f2032c935652371722ae6d987f2f8135aac OP_EQUALVERIFY OP_CHECKSIG",
                "hex": "76a91413bd7f2032c935652371722ae6d987f2f8135aac88ac",
                "reqSigs": 1,
                "type": "pubkeyhash"
            },
            "value": 1.02124906
        }
    ],

一応やってみる。らいうさんのアドレスを引数にして全トランザクションを取得する。

const transactions = await window.mpurse.counterParty('search_raw_transactions', {address: 'M9hY5XcC7MSD54DfqcEojiKm9QMgXeQhGK'});
transactions.length;

実行時点で292件の取引があるようだ。その中からhextxide1e94be2b6f541e6639d9bd1cce79ac9a668dd25b0c3bd5f48c411ade94f8003と同じものを探す。もしあれば1件だけ存在するはず。

const transactions = await window.mpurse.counterParty('search_raw_transactions', {address: 'M9hY5XcC7MSD54DfqcEojiKm9QMgXeQhGK'});
transactions.filter(t=>0<t.vout.filter(o=>o.scriptPubKey.hex=='e1e94be2b6f541e6639d9bd1cce79ac9a668dd25b0c3bd5f48c411ade94f8003').length);

空だった。ゼロ件。なし。

やっぱりないか。つまりscriptPubKeyhextxidは別物なんだろう。

じゃあ、txidというのをキーにして、どうやって取引データを取得すればいい? それがわからない。その取引の手数料がいくらだったかをどうやって取得・算出すればいいの?

ググる

ググってみた。するとgetrawtransactionの結果をdecoderawtransactionでデコードすればJSONになるらしい。

ただ、decoderawtransactionというAPIはドキュメントに載ってなかったと思うのだが。

とりあえずgetrawtransactionすると、なんかよくわからん文字列が返ってくる。

await window.mpurse.counterParty('getrawtransaction', {tx_hash: 'e1e94be2b6f541e6639d9bd1cce79ac9a668dd25b0c3bd5f48c411ade94f8003'});
010000000119b25983f61ad0b58fbdcac01025be3b6f6d341cb11641b1e0d935e4f78a627b010000006b483045022100e7b36a5115a86326b91d0bf89407df78733850c63e041a51a913f3f09f6df13e022048896aaa5b71ababf66323b8bc8ed25e1b3a423ed643b5a7acf484dcf4f3afbf012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3dffffffff02c0175302000000001976a9145bef72db1e9a105cf734ead06ef87a54f1d39a3588acffe3e30c000000001976a91413bd7f2032c935652371722ae6d987f2f8135aac88ac00000000

こいつをdecoderawtransactionに渡す。

await window.mpurse.counterParty('decoderawtransaction', {tx_hash: '010000000119b25983f61ad0b58fbdcac01025be3b6f6d341cb11641b1e0d935e4f78a627b010000006b483045022100e7b36a5115a86326b91d0bf89407df78733850c63e041a51a913f3f09f6df13e022048896aaa5b71ababf66323b8bc8ed25e1b3a423ed643b5a7acf484dcf4f3afbf012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3dffffffff02c0175302000000001976a9145bef72db1e9a105cf734ead06ef87a54f1d39a3588acffe3e30c000000001976a91413bd7f2032c935652371722ae6d987f2f8135aac88ac00000000'});
{
    "code": -32000,
    "data": {
        "args": [
            "{\"message\": \"Method not found\", \"code\": -32601}"
        ],
        "message": "{\"message\": \"Method not found\", \"code\": -32601}",
        "type": "Exception"
    },
    "message": "Server error"
}

やっぱり「そんなメソッドねーよ」って怒られるじゃん。どうすりゃいいの。

一応、CounterBlock APIのほうでも実行してみたが。

await window.mpurse.counterBlock('decoderawtransaction', {tx_hash: '010000000119b25983f61ad0b58fbdcac01025be3b6f6d341cb11641b1e0d935e4f78a627b010000006b483045022100e7b36a5115a86326b91d0bf89407df78733850c63e041a51a913f3f09f6df13e022048896aaa5b71ababf66323b8bc8ed25e1b3a423ed643b5a7acf484dcf4f3afbf012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3dffffffff02c0175302000000001976a9145bef72db1e9a105cf734ead06ef87a54f1d39a3588acffe3e30c000000001976a91413bd7f2032c935652371722ae6d987f2f8135aac88ac00000000'});
Uncaught This endpoint is the couterblock api only.

「このエンドポイントは couterblock api のみです」だと? え、君がそのCounterBlock APIではなかったの? わけわかめ。

CounterParty APIdecoderawtransactionを試す

mpchain APIで指定したアドレスの全トランザクションを取得する方法を調べたとき、mpurse APIでなく生のCounterParty APIを実行した。

curl -X POST -H "Content-Type: application/json" -d '{"id":0,"jsonrpc":"2.0","method":"proxy_to_counterpartyd","params":{"method":"search_raw_transactions", "params":{"address":"MEHCqJbgiNERCH3bRAtNSSD9uxPViEX1nu"}}}' https://mpchain.info/api/cb/

そのときのコマンドである上記を参考に、以下のようにしてみた。

curl -X POST -H "Content-Type: application/json" -d '{"id":0,"jsonrpc":"2.0","method":"proxy_to_counterpartyd","params":{"method":"decoderawtransaction", "params":{"tx_hash":"010000000119b25983f61ad0b58fbdcac01025be3b6f6d341cb11641b1e0d935e4f78a627b010000006b483045022100e7b36a5115a86326b91d0bf89407df78733850c63e041a51a913f3f09f6df13e022048896aaa5b71ababf66323b8bc8ed25e1b3a423ed643b5a7acf484dcf4f3afbf012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3dffffffff02c0175302000000001976a9145bef72db1e9a105cf734ead06ef87a54f1d39a3588acffe3e30c000000001976a91413bd7f2032c935652371722ae6d987f2f8135aac88ac00000000"}}}' https://mpchain.info/api/cb/
{"error":{"code":-32000,"data":{"args":["{\"message\": \"Method not found\", \"code\": -32601}"],"message":"{\"message\": \"Method not found\", \"code\": -32601}","type":"Exception"},"message":"Server error"},"id":0,"jsonrpc":"2.0"}

やはりmpurse APIでCounterParty APIを実行したときと同じエラー。

CounterBlock APIdecoderawtransactionを試す

では、mpurseのソースコードutil.mpchain.ts#L209を参考にして、今度はCounterBlock APIをcurlで叩いてみよう。

curl -X POST -H "Content-Type: application/json" -d '{"id":0,"jsonrpc":"2.0","method":"decoderawtransaction","params":{"tx_hash":"010000000119b25983f61ad0b58fbdcac01025be3b6f6d341cb11641b1e0d935e4f78a627b010000006b483045022100e7b36a5115a86326b91d0bf89407df78733850c63e041a51a913f3f09f6df13e022048896aaa5b71ababf66323b8bc8ed25e1b3a423ed643b5a7acf484dcf4f3afbf012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3dffffffff02c0175302000000001976a9145bef72db1e9a105cf734ead06ef87a54f1d39a3588acffe3e30c000000001976a91413bd7f2032c935652371722ae6d987f2f8135aac88ac00000000"}}' https://mpchain.info/api/cb/
{"error":"This endpoint is the couterblock api only."}

やはりCounterBlock APImpurse API経由で叩いたときと同じ結果になった。

引数調整

もう一度ググったときのURL先をみてみる。

curl --user yourAuth  --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "decoderawtransaction", "params": ["0100000000010115a16270d3ee7ccc58a0757c1d8e1763790f223d4e4c3823948fb3dfdf9865180100000000ffffffff023f3256000000000017a9142915a7db6c6df171fd0436c7cec0042195dad01c8738ee4647000000001600140aad95e932ba045c2daf31a04c36683d39efe91002473044022002537539ac9586fdd8b5947fa0a47dc002ebe57502608433e103efe2740f93d4022023b1ade7bdf0f002a8fdc4ec6d534588d2132ab88850ac426ea413b4adb465260121031ef964af6923a2111e4916afcc87c73a8980322cc761dd3648714dfda99e72c400000000"] }' -H 'content-type: text/plain;' http://yourEndPoint

なんか引数が微妙に違う。上にあわせてみる。

curl -X POST -H "Content-Type: application/json" -d '{"id":"curltest","jsonrpc":"1.0","method":"decoderawtransaction","params":["010000000119b25983f61ad0b58fbdcac01025be3b6f6d341cb11641b1e0d935e4f78a627b010000006b483045022100e7b36a5115a86326b91d0bf89407df78733850c63e041a51a913f3f09f6df13e022048896aaa5b71ababf66323b8bc8ed25e1b3a423ed643b5a7acf484dcf4f3afbf012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3dffffffff02c0175302000000001976a9145bef72db1e9a105cf734ead06ef87a54f1d39a3588acffe3e30c000000001976a91413bd7f2032c935652371722ae6d987f2f8135aac88ac00000000"]}' https://mpchain.info/api/cb/
{"error":"This endpoint is the couterblock api only."}

ダメだ。変わらない。これ以上は追えない。降参。お手上げ。まいりました。

まとめ

おそらくtxidで指定されたトランザクション情報は以下で取得できる。

const txid = 'e1e94be2b6f541e6639d9bd1cce79ac9a668dd25b0c3bd5f48c411ade94f8003'
await window.mpurse.counterParty('get_tx_info', {tx_hex: await window.mpurse.counterParty('getrawtransaction', {tx_hash: txid})});

ただ、それで取得された値は以下のように謎の文字列である。

010000000119b25983f61ad0b58fbdcac01025be3b6f6d341cb11641b1e0d935e4f78a627b010000006b483045022100e7b36a5115a86326b91d0bf89407df78733850c63e041a51a913f3f09f6df13e022048896aaa5b71ababf66323b8bc8ed25e1b3a423ed643b5a7acf484dcf4f3afbf012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3dffffffff02c0175302000000001976a9145bef72db1e9a105cf734ead06ef87a54f1d39a3588acffe3e30c000000001976a91413bd7f2032c935652371722ae6d987f2f8135aac88ac00000000

ネットでググるとdecoderawtransactionなるAPIがあるらしい。そいつでデコードするとJSONデータになるっぽい。

でも、そんなAPIは以下ドキュメントのどこにも書いていなかった。

一応試してみたが、やはりダメだった。

API 結果
CounterParty API そんなメソッドねーよ
CounterBlock API このエンドポイントはcouterblock apiだけだよ(いやお前がcouterblock apiじゃないのかよ。どゆこと?)
await window.mpurse.counterParty('decoderawtransaction', {tx_hash: '010000000119b25983f61ad0b58fbdcac01025be3b6f6d341cb11641b1e0d935e4f78a627b010000006b483045022100e7b36a5115a86326b91d0bf89407df78733850c63e041a51a913f3f09f6df13e022048896aaa5b71ababf66323b8bc8ed25e1b3a423ed643b5a7acf484dcf4f3afbf012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3dffffffff02c0175302000000001976a9145bef72db1e9a105cf734ead06ef87a54f1d39a3588acffe3e30c000000001976a91413bd7f2032c935652371722ae6d987f2f8135aac88ac00000000'});
{
    "code": -32000,
    "data": {
        "args": [
            "{\"message\": \"Method not found\", \"code\": -32601}"
        ],
        "message": "{\"message\": \"Method not found\", \"code\": -32601}",
        "type": "Exception"
    },
    "message": "Server error"
}
await window.mpurse.counterBlock('decoderawtransaction', {tx_hash: '010000000119b25983f61ad0b58fbdcac01025be3b6f6d341cb11641b1e0d935e4f78a627b010000006b483045022100e7b36a5115a86326b91d0bf89407df78733850c63e041a51a913f3f09f6df13e022048896aaa5b71ababf66323b8bc8ed25e1b3a423ed643b5a7acf484dcf4f3afbf012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3dffffffff02c0175302000000001976a9145bef72db1e9a105cf734ead06ef87a54f1d39a3588acffe3e30c000000001976a91413bd7f2032c935652371722ae6d987f2f8135aac88ac00000000'});
Uncaught This endpoint is the couterblock api only.

データはたぶん取得できているから、あとはデコードができればいい。でも、デコードAPIがないからできない。

以上。

追記

コメント頂きました。ありがとうございます!

Counterparty や Counterblock は、セカンドレイヤ・チェーン (Counterparty やモナパーティ)のために存在します。 ファーストレイヤー (Bitcoin やモナコイン) の情報は一部しか提供しません。

そうだったのですね。私はそれすら知りませんでした。L1:MONA, L2:XMPという区切りがあるのは以前、別の記事のコメントで教えていただきましたが、今やっていることがその境界線上にあることだっとは。

仰る「手数料」がモナコインの採掘手数料を指すなら、

そうです。

モナコインを対象とするブロックチェーン・エクスプローラを利用する必要があります。たとえば https://blockbook.electrum-mona.org/ です。API の使い方は GitHub にあります。https://github.com/trezor/blockbook/blob/master/docs/api.md#get-transaction

ブロックチェーン・エクスプローラというのがあるのですね。これも知りませんでした。

リンク先を見て、リクエストURLを作り、試してみます。

https://blockbook.electrum-mona.org/api/v2/tx/e1e94be2b6f541e6639d9bd1cce79ac9a668dd25b0c3bd5f48c411ade94f8003
{"txid":"e1e94be2b6f541e6639d9bd1cce79ac9a668dd25b0c3bd5f48c411ade94f8003","version":1,"vin":[{"txid":"7b628af7e435d9e0b14116b11c346d6f3bbe2510c0cabd8fb5d01af68359b219","vout":1,"sequence":4294967295,"n":0,"addresses":["M9hY5XcC7MSD54DfqcEojiKm9QMgXeQhGK"],"isAddress":true,"value":"255284356","hex":"483045022100e7b36a5115a86326b91d0bf89407df78733850c63e041a51a913f3f09f6df13e022048896aaa5b71ababf66323b8bc8ed25e1b3a423ed643b5a7acf484dcf4f3afbf012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3d"}],"vout":[{"value":"39000000","n":0,"hex":"76a9145bef72db1e9a105cf734ead06ef87a54f1d39a3588ac","addresses":["MGHGa55FH7CcaJdNqJZZb3YCPuZAn2iMUF"],"isAddress":true},{"value":"216261631","n":1,"spent":true,"hex":"76a91413bd7f2032c935652371722ae6d987f2f8135aac88ac","addresses":["M9hY5XcC7MSD54DfqcEojiKm9QMgXeQhGK"],"isAddress":true}],"blockHash":"f413585659148cdfc442975bb9bd9de8dddfafe2ccaad1fa3f394280988ae7b1","blockHeight":2633653,"confirmations":72901,"blockTime":1649863002,"value":"255261631","valueIn":"255284356","fees":"22725","hex":"010000000119b25983f61ad0b58fbdcac01025be3b6f6d341cb11641b1e0d935e4f78a627b010000006b483045022100e7b36a5115a86326b91d0bf89407df78733850c63e041a51a913f3f09f6df13e022048896aaa5b71ababf66323b8bc8ed25e1b3a423ed643b5a7acf484dcf4f3afbf012103aedd2422519c7ea14e48116b571903c16d2b4657d4a3ffc0e35646cd7e53be3dffffffff02c0175302000000001976a9145bef72db1e9a105cf734ead06ef87a54f1d39a3588acffe3e30c000000001976a91413bd7f2032c935652371722ae6d987f2f8135aac88ac00000000"}

キタ━━━━(゚∀゚)━━━━!!

ちゃんとJSONです。アドレスもそれっぽい。

けど、valueがおかしい。たぶん金額だと思うけど、少数でなく整数になっている。

らいうさんに教えていただいたURLの内容と見比べてみるで。こちらは小数点だし、単位がMONAになっている。

アドレス 金額 今回value
M9hY5XcC7MSD54DfqcEojiKm9QMgXeQhGK 2.55284356 MONA 255261631, 255284356
MGHGa55FH7CcaJdNqJZZb3YCPuZAn2iMUF 0.39 MONA 39000000
M9hY5XcC7MSD54DfqcEojiKm9QMgXeQhGK 2.16261631 MONA 216261631
(Fee) 0.00022725 MONA 22725
  • voutの配列のうち最後の要素にvinvalueと同じ値のvalueInがある
  • valueIn - value = fees
  • feesは手数料。すでに計算されてJSONのプロパティとして存在している

たしかモナコインの最小単位は小数点以下8桁。それを整数にした値がvalueだと思われる。たぶん浮動小数点だと誤差が出るから整数にした、とかそんな理由だと予想する。あるいは、valueMONAとは別の単位なのかもしれない。サトシだかワタナベだが、そんな感じの単位があるってMasteringBitcoin日本語訳PDFに書いてあったような。それかな? でも8桁も違ったっけ?

とにかくfees0.000000001を掛けた値がモナになると思われる。つまり以下の式。

fees * (0.1 ** 8) = ? MONA

話を最初に戻す。まとめてみよう。

モナコインの取引トランザクションを取得する方法を調べたの方法で、指定アドレスの全トランザクション情報を取得する。取引一件あたりvinがある。それは支払に使うデータであり「支払額+手数料」以上の額が入った取引データである。実際のデータは入っておらず参照用IDのみ。それはtxidで示されている。

このtxidから実際の取引データを取得するには「ブロックチェーン・エクスプローラ」を使う。そのAPIによってtxidに相当する取引データをJSONで取得できる。そこにはすでにトランザクション手数料をあらわすfeesプロパティが存在する。ただしその金額は謎の単位である。MONAに変換するには0.1**8倍する必要がある。

こんな感じかな。

  • 今まで支払った手数料の全額は、全取引データのvinの中にあるtxidから、今回の方法で取得したものを合算すればいい

でも、それをやったら取引件数だけリクエストすることになる。サーバへの負荷は大丈夫なのだろうか。

ところで、マイナーのアドレスは取得できないのかな? この手数料はどのアドレスに支払われたのだろう。それを取得できそうな値はJSON内に無さそう。

トランザクション情報の取得って思った以上に大変なんだなぁ。