Replace By Fee (RFB) 기능
Replace By Fee
만약 Bitcoin 트랜잭션이 낮은 Transaction Fee를 가지고 있어서 MemPool 에 Stuck 되어 있다면, 사용자는 오랜 시간 동안 트랜잭션이 처리되기를 기다리게 된다. 이런 경우 Transaction Fee를 올려 트랜잭션을 수정할 수 있는데, 이를 Replace By Fee (RFB) 기능이라 한다. Replace By Fee는 BIP-125 에 의해 도입된(v0.12에서 처음 도입) 기능으로 v0.14 에서 완전히 구현되었다.
Replace By Fee 기능을 사용하기 위해서는 Transaction Input에 있는 Sequence 필드를 1 ~ (0xffffffff-2) 사이의 값으로 설정하여야 한다. Sequence 필드는 비트코인 초기에 어떤 목적을 위해 사용하려 하였으나, 실제로는 사용되지 않았다. 이후 개발자들이 Time lock 이나 Replace By Fee 기능을 위해 이 필드를 활용하였다. Replace By Fee 기능을 사용하기 위해 그리고 Time lock과의 충돌을 피하기 위해, 일반적으로 Sequence 필드에 1 을 지정하거나 0xf0000000 ~ (0xffffffff-2) 범위의 값을 사용한다.
참고로, bitcoind가 실행될 때 -walletrfb 파라미터를 지정하거나 bitcoin.conf에 walletrbf=1 을 지정하면 Replace By Fee 기능이 디폴트로 On 된다. 즉, 이 RBF 플래그가 사용되면 Sequence 가 자동으로 Replace By Fee 기능을 사용하도록 설정된다.
#bitcoin.conf walletrbf=1
Replace By Fee 기능이 사용되면 Unconfirmed Transaction 에서 bip125-replaceable = yes 로 설정된다. 물론 Transaction이 confirm 되면, 더 이상 Replace 되지 않기 때문에 gettransaction 에서 bip125-replaceable = no 로 표시된다.
Replace By Fee 사용
Bitcoin Core 0.14 부터 bumpfee 명령을 사용하여 Fee를 상향 조정할 수 있다. 얼마만큼 Fee를 올리는 지는 bitcoind 가 구성파일에 지정된 값들을 참조하여 결정한다.
$ bitcoin-cli -named bumpfee txid=db495a167e173267c54e722a920a88c41dcfcd6b5aab0635c3fd5cefee6ce5c4
Low level에서 보다 정교하게 Replace By Fee 기능을 사용하기 위해서는 Raw Transaction을 사용한다.
예를 들어, 0.00111 BTC에서 0.00110800 을 보내면, Fee는 200 Sats가 된다. createrawtransaction으로 트랜잭션을 생성할 때, Replace By Fee 기능을 사용하기 위해 (구성파일 설정이 없는 경우) "sequence": 1 을 지정한다.
$ bitcoin-cli -named createrawtransaction inputs='[{"txid": "21449bb9f74511003ffcd0de1f8300b86903fc65338370fd64adcb4ffd9c371e", "vout": 0, "sequence": 1 }]' outputs='[{"tb1qr78u2cm7dspt3m065kknfarm562m2lamfjfnz2":0.00110800}]' $ bitcoin-cli signrawtransactionwithwallet 02000000011e379cfd4fcbad64fd708333... $ bitcoin-cli sendrawtransaction 42100000000000100000001d4e...
생성된 트랜잭션을 보면 bip125-replaceable이 yes로 설정된 것을 볼 수 있다.
$ bitcoin-cli gettransaction db495a167e173267c54e7... { "amount": 0.00000000, "fee": -0.00000200, "confirmations": 0, "trusted": true, "walletconflicts": [ ], "time": 1646162420, "timereceived": 1646162420, "bip125-replaceable": "yes", *** ... ... }
위와 같이 낮은 Fee를 갖는 트랜잭션이 Stuck 되어 있다면, 좀 더 높은 Fee를 갖는 새 트랜잭션을 만들어 다시 보낼 수 있다. 아래 예제에서는 임의로 0.0011 BTC 을 보내면서 Fee를 1000 sats 로 만들고 있다.
$ bitcoin-cli -named createrawtransaction inputs='[{"txid": "21449bb9f74511003ffcd0de1f8300b86903fc65338370fd64adcb4ffd9c371e", "vout": 0, "sequence": 1 }]' outputs='[{"tb1qr78u2cm7dspt3m065kknfarm562m2lamfjfnz2":0.0011}]' $ bitcoin-cli signrawtransactionwithwallet ... $ bitcoin-cli sendrawtransaction ...
새로 생성된 트랜잭션을 보면, Fee가 1000 sats 로 되고, walletconflicts 에 낮은 Fee를 갖는 원래 트랜잭션이 표시된다. Fee를 여러번 올리면, 이전 트랜잭션들이 여기에 표시된다.
$ bitcoin-cli gettransaction 4617282399aeeaebe... { "amount": 0.00000000, "fee": -0.00001000, *** Fee "confirmations": 0, "trusted": true, "walletconflicts": [ "db495a167e173267c54e7..." *** conflict txid ], "time": 1646162620, "timereceived": 1646162620, "bip125-replaceable": "yes", ... ...
RFB가 사용되면 Miner는 높은 Fee의 트랜잭션을 블럭에 포함하여 Confirm 하게 된다. 이때 낮은 Fee의 트랜잭션은 Confirmation 필드가 음수값을 갖게 되는데, 이는 높은 Fee 트랜잭션이 Confirm 된 시점으로부터 역계산되어 음수값으로 표신된 것이다. 이 낮은 Fee 트랜잭션을 시간이 지남에 따라 결국 MemPool에서 삭제된다.
$ bitcoin-cli gettransaction db495a167e173267c... { "amount": 0.00000000, "fee": -0.00000162, "confirmations": -2, *** 음수값 "trusted": false, ... ...