前にできなかったやつが色々試したらできた。でもまだ送金はできない。
ブツ
実行
REPO=Html.MpurseAPI.CounterPartyAPI.CreateSend.20220928164021
git clone https://github.com/ytyaru/$REPO
cd $REPO/docs
./server.sh
PythonでHTTPSローカルサーバを立ててMpurse APIを実行する。
結果
開発者ツールのコンソールを開くと以下のような感じになる。
以下のようにcreate_send
APIを実行する。
const cpParams = {
source: 'MEHCqJbgiNERCH3bRAtNSSD9uxPViEX1nu',
destination: 'MEHCqJbgiNERCH3bRAtNSSD9uxPViEX1nu',
asset: 'MONA',
quantity: 11411400,
memo: null,
memo_is_hex: false,
fee_per_kb: 10 * 1000,
allow_unconfirmed_inputs: true,
extended_tx_info: true,
disable_utxo_locks: true,
};
await window.mpurse.counterParty('create_send', cpParams);
その結果、以下のようなJSONが返ってくる。
{
"btc_change": 101556960,
"btc_fee": 2250,
"btc_in": 112970610,
"btc_out": 11411400,
"tx_hex": "0100000001737a59194d5705b49f8e7c262d97d5cfd1e31ba5f6a7590402634bcbd71c53e9010000001976a91445fc13c9d3a0df34008291492c39e0efcdd220b888acffffffff02c81fae00000000001976a91445fc13c9d3a0df34008291492c39e0efcdd220b888ace0a20d06000000001976a91445fc13c9d3a0df34008291492c39e0efcdd220b888ac00000000"
}
これで送金するためのトランザクションが作成された、ということになるのだろうか? よくわからない。
このあと送金するためには何をどうしたらいいのだろう。たぶんtx_hex
を使って署名したあと、サーバにブロードキャストする。そういうキーワードだけは聞きかじっているから、いかにも理解しているふうに書いているが、何をどうするかまったく理解できてない。日本語では書けてもコードで書けない。
とにかく今回はcreate_send
APIが動かせたという話。
経緯
Mpurseは内部でmpchain APIを呼び出していた。mpchain APIはcounterParty APIやcounterBlock APIを呼び出していると思う。それを使って送金しているのだと思われる。その工程のうちのひとつにcounterParty APIのcreate_send
がある。
ブラウザでHTTPSサイトにアクセスし開発者ツールのコンソールで以下コードを実行する。
const cpParams = {
source: 'MEHCqJbgiNERCH3bRAtNSSD9uxPViEX1nu',
destination: 'MEHCqJbgiNERCH3bRAtNSSD9uxPViEX1nu',
asset: 'MONA',
quantity: 0.00000000,
memo: null,
memo_is_hex: false,
fee_per_kb: 0,
allow_unconfirmed_inputs: true,
extended_tx_info: true,
disable_utxo_locks: true,
};
await window.mpurse.counterParty('create_send', cpParams);
//const unspentTxouts = await window.mpurse.counterParty('create_send', cpParams);
以下のようなエラーが返ってきた。
{
"code": -32000,
"data": {
"args": [
"{\"message\": \"Error composing send transaction via API: Destination output is dust.\", \"code\": -32001}"
],
"message": "{\"message\": \"Error composing send transaction via API: Destination output is dust.\", \"code\": -32001}",
"type": "Exception"
},
"message": "Server error"
}
以下のようなコメントをいただいた。
トランザクションを作成する機能は counterparty-server 側の API にあります。counterblock にはありません。 API で無事トランザクションが生成されても無署名なのでブロックチェーンに投げ込んでも、無効扱いされ、手持ちの MONA は消えません。秘密鍵による署名が完了するまでは気軽に試しても問題ありません。testnet の API は存在しますが、testnet の MONA の入手は難しく、mainnet で試したほうが手間が少ないと思います。
create_send
しても手持ちのモナコインが減ることはない。だから好きなだけcreate_send
で動作確認すればいい。そういう意味だと捉えた。
前回はそれ以来なにもしてなかったが、今回いろいろ々試して成功した。
試行錯誤ログ
蛇足。試行錯誤したときのメモをほぼそのまま書いてあるのでまとまってない。
気づいたこと
前回のJSON結果を改めて読み直すといくつか気づいたことがあった。
Destination output is dust
quantity: 0.00000000,
fee_per_kb: 0,
エラーメッセージによると「出力がゴミ」と言ってる。何のことだかよくわからないがググってみると手数料が少なすぎるせいらしい。fee_per_kb
の値を上げたらいいのでは? でも出力ってたぶんquantity
のことでは? そっちを上げるべきか? いずれにせよどちらも0
なのが悪いのでは? 署名してないから手持ちのモナが減ることはないらしいので、安心してテストできるはず。色々数値を変えて試してみよう。
また、quantity
は少数値でなく整数値で入力するのが正しい気がする。以前トランザクションデータのどこかでそんなのを見た。つまり最小値0.00000001 MONA
=quantity: 1
で表す。counterParty APIのcreate_send
をみてみると引数説明のところにquantities-and-balancesリンクがあって、そこに書いてあった。
試してみた
以下2点を改善して実行してみたら成功した!
quantity
:11411400
(0.11411400 MONA
)fee_per_kb
:10
(Mpurseで設定できる最小値と同じ?)
const cpParams = {
source: 'MEHCqJbgiNERCH3bRAtNSSD9uxPViEX1nu',
destination: 'MEHCqJbgiNERCH3bRAtNSSD9uxPViEX1nu',
asset: 'MONA',
quantity: 11411400,
memo: null,
memo_is_hex: false,
fee_per_kb: 10,
allow_unconfirmed_inputs: true,
extended_tx_info: true,
disable_utxo_locks: true,
};
await window.mpurse.counterParty('create_send', cpParams);
{
"btc_change": 101559208,
"btc_fee": 2,
"btc_in": 112970610,
"btc_out": 11411400,
"tx_hex": "0100000001737a59194d5705b49f8e7c262d97d5cfd1e31ba5f6a7590402634bcbd71c53e9010000001976a91445fc13c9d3a0df34008291492c39e0efcdd220b888acffffffff02c81fae00000000001976a91445fc13c9d3a0df34008291492c39e0efcdd220b888aca8ab0d06000000001976a91445fc13c9d3a0df34008291492c39e0efcdd220b888ac00000000"
}
ちなみにquantity
が1
や1000
だとDestination output is dust
エラーになった。0.00001000 MONA
でもダメらしい。最小値0.00000001 MONA
を支払額にすることはできないようだ。なんてこったorz。使える最少額っていくらなんだろう。そこまで細かくは調べなかった。成功した
11411400
以下で、かつ失敗した1000
より大きい値なのだろう。
出力結果の解析
この出力結果おかしくない? まずbtc
ってビットコインのことだと思う。モナコインなんですけど? asset: 'MONA',
で指定したんですけど?
あとbtc_fee
が2
だったらbtc_in
は11411402
になるんじゃないの? 112970610
が送金額11411400
の10倍以上なんですけど。これって送金者が112970610
出して支払先アドレスに11411400
だけ支払ったあと、残った101559210
と手数料2
の合計101559212
は全額マイナーにトランザクション承認処理のインセンティブとして支払われちゃうのでは? (※ちがう。後述するがbtc_change
をみてない) さすがに大金すぎない? Mpurseの手数料はそんなにバカ高くなかったはず。
考えられる可能性としては以下2つ。
- 私の読み方がまちがっている
- 手数料の設定にコツがいる
Mpurseのソースコードsend.component.ts#L301を読んでみた。手数料を設定しているのは以下の部分。
new Decimal(this.feeControl.value)
.times(new Decimal(1000))
.toNumber(),
this.feeControl.value
はMpurseのUIにある手数料を決めるスライダーの値。デフォルトは101
で最小10
になるやつDecimal
は正確な浮動小数点で計算するための外部ライブラリだと思うDecimal.times()
は乗算。つまり101
などの値を1000
倍しているDecimal.toNumber()
で数値化する
Decimal
の情報源は以下。
というわけで、Mpurseに出てくる手数料101
の最小値10
を1000
倍してみる。
const cpParams = {
source: 'MEHCqJbgiNERCH3bRAtNSSD9uxPViEX1nu',
destination: 'MEHCqJbgiNERCH3bRAtNSSD9uxPViEX1nu',
asset: 'MONA',
quantity: 11411400,
memo: null,
memo_is_hex: false,
fee_per_kb: 10 * 1000,
allow_unconfirmed_inputs: true,
extended_tx_info: true,
disable_utxo_locks: true,
};
await window.mpurse.counterParty('create_send', cpParams);
{
"btc_change": 101556960,
"btc_fee": 2250,
"btc_in": 112970610,
"btc_out": 11411400,
"tx_hex": "0100000001737a59194d5705b49f8e7c262d97d5cfd1e31ba5f6a7590402634bcbd71c53e9010000001976a91445fc13c9d3a0df34008291492c39e0efcdd220b888acffffffff02c81fae00000000001976a91445fc13c9d3a0df34008291492c39e0efcdd220b888ace0a20d06000000001976a91445fc13c9d3a0df34008291492c39e0efcdd220b888ac00000000"
}
お、btc_fee
の値が2250
になった。これはMpurseの手数料スライダーで10
にしたとき表示される0.00002250 MONA
の整数値版2250
と一致する。
それはいいのだが、btc_in
がおかしくない? 入力in
は出力out
と手数料fee
の合計以上になる値だと思うのだけど。つまり11411400 + 2250
で11413650
となり、それ以上の額を入力in
として指定するのが正しいのでは?(※まだ勘違いしてる)
out + fee <= in
11411400 + 2250 = 11413650 <= in
と思ったのだが、btc_change
とかいう謎の値がかかわっているっぽいことに気づいた。
btc_change = btc_in - (btc_out + btc_fee)
101556960 = 112970610 - (11411400 + 2250)
いや、謎じゃなかった。btc_change
は「おつり」のことだった。英語でおつりのことをchange
というらしい。そして計算してもその意味として理解できる。
でも、なぜbtc_in
をそんな巨額にする必要があるのかわからない。11411400 + 2250
で11413650
となり、おつりゼロのほうがよいのでは? そもそもbtc_in
の112970610
という値はどこからやってきたの? それを計算するための引数があるのかな?
引数disable_utxo_locks
が関係しているかとあたりをつけた。これだけがよくわからないし変数になってたので思って調べた。MpurseのソースコードからdisableUtxoLocks
で検索[]してコードを色々と眺めてみた。
create_send
するときはtrue
であり、mpchain APIでsend_tx
するときはfalse
らしい。ええと、UTXOは未使用トランザクションのことで、そのロックを無効化するフラグがtrue
ってことは、create_send
するときは未使用トランザクションのロックを無効化するってことか。で、未使用トランザクションのロックって何?
よくわかんない。たぶんAPI側が勝手にやったことだと思う。送金者アドレスが持っている未使用トランザクションの中から手数料+送金額以上のトランザクションを取得したのだろう。その金額がbtc_in
の112970610
だったのではないかと予想する。
まあいいや。とにかくcreate_send
できた。
所感
create_send
までできたのはいいとして、このあとどうしたら送金できるのか。まだまだ先は長そう。