LoginSignup
11
5

More than 5 years have passed since last update.

bitcoin(Ruby版)のトランザクション手数料(Transaction Fee)の計算

Posted at

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個くらい多めにあると仮定して、計算をやってしまうのも手。

参考

xconfirmtarget 2 (blocks)
mintxfee 0.00001 (BTC/kB) =

  • bitcoin-cliのgettransactionを読む -> bitcoin/src/wallet/rpcwallet.cpp
11
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
5