bitcoin(Ruby実装)のAPIに、トランザクション手数料の最小値を計算する機能や見積をする機能が提供されています。
ただ、これらの機能はトランザクションオブジェクトのインスタンスメソッドとして実装されているため、トランザクションを作る前に手数料が知りたい場合は、自力で計算するしかありません。
ということで、作ってみましたので、その備忘録を書いておきます。
動くプログラムはこちら。
ご注意:厳密な計算ロジックではありません。歴史的なトランザクションや、手数料無料条件の扱いなどは、考慮できていません。
計算式
トランザクションのサイズ(Bytes)に、FeeRate(satoshis/KBytes)をかけたもの。
(Ruby実装を見ると、Kは1024でなく、1000の模様)
トランザクションのサイズ
148 * number_of_inputs + 34 * number_of_outputs + 10
出典: http://bitcoinfees.com/
参考: http://bitcoin.stackexchange.com/questions/1195/how-to-calculate-transaction-size-before-sending
FeeRate
最小値: 10,000 satoshis/KBytes
推奨値: estimatefee(1) # <= bitcoin-apiのコマンド
estimatefeeは、私の環境(bitcoin 0.12.1/testnet)では、常に-1が帰ってきて、残念な感じです。
osada@mbp16a% bitcoin-cli -testnet estimatefee 1
-1
-1は、estimateするために十分なトランザクションがないためだとか、どうとか。。。
ということで、十分なトランザクションがあるところを参照する場合は以下がおすすめ。
https://bitcoinfees.github.io/
WebAPIを提供してくれるサイトもあります。
JSONで返してくれる。統計値。ただし、5000リクエスト制限などあるみたい。要例外処理。
https://bitcoinfees.21.co/
http://bitcoinexchangerate.org/fees
手数料の表現方法
手数料のトランザクションはない。vinとvoutのそれぞれの総量の差がそれになる。
例えば、vinが100円。voutが40円と50円ならば、手数料は100-(40*50)=10円となる。
この10円は、トランザクションのどこにもでてこない。
デバッグなどで確認したい場合は、bitcoin-cliの"gettransaction "などで確認するとよい。
osada@mbp16a% bitcoin-cli -regtest gettransaction 43f30f35619578f3d139db412015761bc16a32f85e564491617195bcf96c1235
{
"amount": 0.00000000,
"fee": -0.00010000,
"confirmations": 0,
"trusted": true,
"txid": "43f30f35619578f3d139db412015761bc16a32f85e564491617195bcf96c1235",
"walletconflicts": [
],
"time": 1465268167,
"timereceived": 1465268167,
"bip125-replaceable": "no",
"details": [
{
"account": "",
"address": "n3Wz3fZRtizbeWTkrswypefib4xHxndTHW",
"category": "send",
"amount": -0.00023300,
"label": "",
"vout": 1,
"fee": -0.00010000,
"abandoned": false
},
{
"account": "",
"address": "n3Wz3fZRtizbeWTkrswypefib4xHxndTHW",
"category": "receive",
"amount": 0.00023300,
"label": "",
"vout": 1
}
],
"hex": "010000000125327ed5fe6f570a3522ecd77a542e33bb670b7f82139b9885e06b2b3c957160020000006b483045022100e67cdd5871b269d6ffa02a9dfbe38d0e2e46cc23d37bbddcc0faaf4ca759017f022054ab24ef46c5a6dd48bc50cd32457bf16de216c86bd260dc2738cc80d595cbe50121024fd6eb64bce08081e7afce2f972e4c21428ee4e7665a1f07b5c1611925761934ffffffff02f002052a010000001976a9146584ba1dad4419569213a0198b2d364afdc6173388ac045b0000000000001976a914f1543acc094bc709373b41e116727b905b24c09e88ac00000000"
}
bitcoin-rubyを見てみる
leave-feeというかたちで、設定。inputとoutputの差が自動的にfeeになる。
https://github.com/lian/bitcoin-ruby
# add another output spending the remaining amount back to yourself
# if you want to pay a tx fee, reduce the value of this output accordingly
# if you want to keep your financial history private, use a different address
t.output do |o|
o.value 49000000 # 0.49 BTC, leave 0.01 BTC as fee
o.script {|s| s.recipient key.addr }
end
実装の考え方
手数料を計算するときには、txを作る前からサイズを知る必要がある。
(txを作るためには、手数料によって変わる「お釣り」の情報が不可欠のため)
<楽しい堂々巡り>
1. feeを計算するためには、txのサイズが必要。
2. txを計算するためには、vinの数とvoutの数が必要。
3. vinを計算するためには、voutの内容が必要。
4. voutの内容を知るには、feeが必要(お釣りの計算のため)
5. feeが支払えなければ、vinを増やす必要あり(txサイズ変更により再度1に戻る)
厳密な計算は諦めて、voutとvinともに、1~2個くらい多めにあると仮定して、計算をやってしまうのも手。
参考
実効レート
(何回目のconfirmで取り込まれるか)
https://bitcoinfees.github.io/
xconfirmtarget 2 (blocks)
mintxfee 0.00001 (BTC/kB) =
- bitcoin-cliのgettransactionを読む -> bitcoin/src/wallet/rpcwallet.cpp