Bitcoinをやりとりする際にネックになるのが、ブロードキャストしたトランザクションがブロックに入るまでの待ち時間。通常、10分くらいすれば入るのだけど、トランザクションの優先度によっては、いつまで経ってもなかなかブロック入らないケースもある。
トランザクションの優先度は以前書いた↓のルールで決まる。
techmedia-think.hatenablog.com
やりとりするBitcoinの量や手数料が充分高ければすぐに取り込まれるけど、トランザクションの優先度が低いとなかなか取り込まれない。普通にBitcoinを送付する分には問題になることは少ないが、トランザクションサイズが大きい割りに手数料が高くないケースとかだとブロックに入るまでに結構な時間がかかる。
Bitcoin 2.0系のようなBitcoinのブロックチェーンのプロトコルを拡張するプロトコルではOP_RETURNを使ってメタ情報を加えることでトランザクションサイズは大きくなるし、1つのトランザクションでUTXOの分割や多数のアドレス宛にBitcoinを送るようなケースも同様にトランザクションサイズは大きくなる。 そういうケースを考慮するとトランザクションの単位サイズあたりの手数料の目安を決め、作成するトランザクションのサイズによって手数料を決定する方が望ましい。
そうはいっても、トランザクションをブロードキャストした後では後の祭りになるが、そんなケースを救済する Replace-by-Feeという仕組み↓がある。
bips/bip-0125.mediawiki at master · bitcoin/bips · GitHub
Bitcoin Core :: Opt-in RBF FAQ
Transaction replacement - Bitcoin Wiki
Bitcoin Coreでは0.12.0からOpt-in Replace-by-Feeが導入されている。
Opt-in Replace-by-Feeについて
トランザクションの置換自体は最初のBitcoinのリリースに含まれている機能で、トランザクションは非最大のシーケンス番号をセットすることで交換可能であると自分自身にマーキングし、シーケンス番号の大小を比較してトランザクションの置換を行っていた。ただこの方法は攻撃者が低コストでフルノード間の帯域を占有するDoS攻撃の手段となりえたので、後に(0.3.12で)無効化されることになった。またこの段階では、マイナーにとって、このルールに従うインセンティブは無かった。(置換前のトランザクションの方が高い手数料だったかもしれないし)
2013年にPeter Toddが、置換をするには高い手数料率を設定することを提案し、これによってDoS攻撃の問題とインセンティブの問題両方が解消された。
この機能を利用することで、なかなかブロックに入らないトランザクションを手数料を高く設定したトランザクションと置換しブロックに取り込まれるスピードを上げることができる。
Opt-in Replace-by-Feeのアクティベーションについて
Opt-in Replace-by-Feeの仕組みはBitcoinのコンセンサスの外のことなので明示的に機能をアクティベーションするようなことは発生しない。ローカルポリシーによるものなので、RBFに対応したソフトウェアを導入すれば利用できる。既にネットワーク上のノードにはさまざまな方法でRBFを行うノードは存在していると。
(Bitcoin Coreでは0.12.0から)
既存のトランザクションへの影響
Opt-in Replace-by-Feeは利用してしないトランザクションには影響を与えることは無いし、使用を強制されることもない。またトランザクションがconfirmされた後は何の影響も与えられない。
ただ受信者はシーケンス番号が非最大のトランザクションについてはconfirmされるまでは安全ではないものとして扱う必要がある(置換されてる可能性があるから)。
Opt-in Replace-by-Feeを設定する方法
Bitcoin Core 0.12.0で導入されたOpt-in Replace-by-Feeの機能の詳細についてはBIP-125に記載されている。
置換可能なトランザクションとしてマーキングする方法は2種類ある。
- Explicit signaling
トランザクションの各入力のいずれかのシーケンス番号が(0xffffffff - 1)より小さいものがあれば、そのトランザクションは置換可能なトランザクションであると認識される。 - Inherited signaling
Explicit signalingのように明示的に置換可能とマーキングされていないが、その親のトランザクションが未confirmで置換可能な場合、そのトランザクションも置換可能であると認識される。
(要はそのトランザクションの入力が参照しているトランザクションがまだ未confirmでかつ置換可能な場合)
※ Explicit signalingによるマーキングの仕組みは複数の署名を行う際に使われている。トランザクションの各入力には4バイトのシーケンス番号(sequence)がセットされており、通常のトランザクションであればこの値にはunsigned integerの最大値(4294967295)がセットされてる。 このシーケンス番号は複数の署名者がトランザクションに署名を行い更新するために使われており、トランザクションの更新が終わると、各入力のシーケンス番号に4バイトのunsigned な最大値(0xffffffff = 4294967295)をセットする。トランザクションの全入力のシーケンス番号が最大値の場合locktimeは無効と判断されるので、locktimeを使用する場合必ずトランザクション内の入力の内最低1つはシーケンス番号が最大値より下である必要がある。
詳細な実装
以下の条件を満たす場合、現在メモリプール内のトランザクションは同じインプットを1つ以上もつ別のトランザクションに置き換えられる。
- 置換元のトランザクションが上記のように明示的または継承によって置換可能なトランザクションであるとマーキングされている。
- 置換先のトランザクションには、未承認のインプットが、置換元のトランザクションの1つに含まれている場合にのみ含まれる可能性がある。
- 置換先のトランザクションでは、少なくとも置換元の総手数料額の手数料を支払う必要がある。
- 置換先のトランザクションは元のトランザクションが支払った金額に加えて、そのトランザクションを伝搬するための中継手数料を支払う必要がある。
例えば、最小の中継手数料が1バイトあたり1satoshiで置換用のトランザクションサイズが500バイトだとすると、置換用のトランザクションは元のトランザクションより少なくとも500satoshi高い料金を支払う必要がある。 - 置換される元のトランザクションの数とメモリプールから追い出されるそれらのトランザクションの子孫の合計が100トランザクションを超えてはいけない。
(1〜4は置換するトランザクションを作る側のルールで5は置換したトランザクションを承認するマイナー側のルール?)
受信するウォレットのポリシー
ユーザに未confirmのトランザクションを表示したり、自動化したシステムに未確認のトランザクションを提供する際にウォレットは以下のいずれかを検討する必要がある。
- Opt-in full-RBFについての注意を促す
- confirmされるまでOpt-in トランザクションを無視する
子供(未confirmのRBFなトランザクションを入力(親)とする)のトランザクションもこのポリシーで置換可能な可能性があるため、親のトランザクションがconfirmされていない間は、 Opt-in full-RBF トランザクションへの影響は子供のトランザクションにも影響を与える。
使用するウォレットのポリシー
ウォレットは、置換可能なトランザクションとしてマーキングしたくない場合、トランザクションの入力のシーケンス番号に最大値(0xffffffff)をセットするか(locktimeを使用する場合は)最大値-1=(0xffffffff - 1)をセットする必要がある。また、confirmされていない置換可能なトランザクションについては使用しないよう注意する必要がある(現在ほとんどのウォレットは自分が作成したものを除いて、confirmされていないUTXOは使われない)。
置換可能なトランザクションを作成したい場合は、↑の詳細な実装で記載してるルールを満たすexplicit signalingなトランザクションを作成する必要がある。
Opt-in Replace-by-Feeとlocktimeの組み合わせ
面白いアプローチが、Opt-in Replace-by-Feeとlocktimeの組み合わせ。
例えば現在のブロックが100だとして3ブロック以内にトランザクションをconfirmさせたい場合、3ブロック内にcomfirmできるであろうな手数料を見積もりトランザクションをブロードキャストすると同時に、104,105,106,107..ブロックに入れられるようそれぞれ手数料を1.5倍にし対象のブロック高までロックするようなlocktimeを設定したトランザクションをブロードキャストすることで、103までのブロックに入らいないケースでも自動的に1.5倍された手数料を適用することができる。