test_wallet_vertical: add test for batch tx fee increase
Adds unittest to check the fee increase when adding outputs to a base tx. Supposed to prevent creating transactions that don't get accepted like in this traceback: ``` broadcast_transaction error [DO NOT TRUST THIS MESSAGE]: "RPCError(1, 'the transaction was rejected by network rules.\\n\\ninsufficient fee, rejecting replacement ceeaef5ac7f82286e42ebd530e965fa4c7a6c11933d6b89d6d6f0ee2c69db839; new feerate 0.00001109 BTC/kvB <= old feerate 0.00001110 BTC/kvB ```
This commit is contained in:
@@ -1262,6 +1262,11 @@ class TestWalletSending(ElectrumTestCase):
|
||||
await self._rbf_batching(
|
||||
simulate_moving_txs=simulate_moving_txs,
|
||||
config=config)
|
||||
with TmpConfig() as config:
|
||||
with self.subTest(msg="_rbf_sufficient_fee_increase_adding_outputs_to_base_tx", simulate_moving_txs=simulate_moving_txs):
|
||||
await self._rbf_sufficient_fee_increase_adding_outputs_to_base_tx(
|
||||
simulate_moving_txs=simulate_moving_txs,
|
||||
config=config)
|
||||
with TmpConfig() as config:
|
||||
with self.subTest(msg="_bump_fee_when_not_all_inputs_are_ismine_subcase_some_outputs_are_ismine_but_not_all", simulate_moving_txs=simulate_moving_txs):
|
||||
await self._bump_fee_when_not_all_inputs_are_ismine_subcase_some_outputs_are_ismine_but_not_all(
|
||||
@@ -2063,6 +2068,64 @@ class TestWalletSending(ElectrumTestCase):
|
||||
wallet.adb.receive_tx_callback(tx, tx_height=TX_HEIGHT_UNCONFIRMED)
|
||||
self.assertEqual((0, 3_900_000, 0), wallet.get_balance())
|
||||
|
||||
async def _rbf_sufficient_fee_increase_adding_outputs_to_base_tx(self, *, simulate_moving_txs, config):
|
||||
"""
|
||||
Initial tx1: 2 inputs of our wallet -> 2 external p2wsh outputs + 1 change output
|
||||
-> let make_unsigned_tx add one external output and another input -> tx2
|
||||
Compare fee of tx1 and tx2, is the fee increase sufficient to satisfy relay policy?
|
||||
"""
|
||||
wallet: Abstract_Wallet = self.create_standard_wallet_from_seed('frost repair depend effort salon ring foam oak cancel receive save usage',
|
||||
config=config, gap_limit=3)
|
||||
|
||||
# bootstrap wallet, creates three utxos for wallet
|
||||
funding_tx = Transaction('020000000001012cdd7dfc38d14f2c95425bb0afc4ee93df4c7b46e9f8bd8d43d845382f88b2b60100000000fdffffff0420a10700000000001600141ab4b6d2f79cb0a1b5be5a2372eb668bc09261f820a107000000000016001483c3bc7234f17a209cc5dcce14903b54ee4dab9020a1070000000000160014d4ca56fcbad98fb4dcafdc573a75d6a6fffb09b7303b0c0100000000160014da837c758fa0bce9eb845f240a06484f8dfb862c0247304402201b47c7fe41a9b5b196f1ee628d8e5065d85cba4caa44a0f8199a603cb0ee40a80220159eb66a66a5a3a396922aa3ffd7101224de75b1b57dc0c4732e284cdd228c63012102d63196184adaa312705ec7f0d8c9565261e4c19a6746f5ac3ad30cc0b932501cc7d24900')
|
||||
funding_txid = funding_tx.txid()
|
||||
self.assertEqual('615080b19e3bd1da18bcdbf74a9bcc94fe4f2348e1115a9028e5667d2c1c2b03', funding_txid)
|
||||
wallet.adb.receive_tx_callback(funding_tx, tx_height=TX_HEIGHT_UNCONFIRMED)
|
||||
|
||||
tx1 = tx_from_any('70736274ff0100d10200000002032b1c2c7d66e528905a11e148234ffe94cc9b4af7dbbc18dad13b9eb18050610000000000fdffffff032b1c2c7d66e528905a11e148234ffe94cc9b4af7dbbc18dad13b9eb18050610100000000fdffffff0378d4030000000000220020f381d0d2c633cdd890015bb438c8e73e9960b21defa126c594e5cf67bd06419f78d40300000000002200204a1c25db1aa7165cb655638fb32319a945262fee7c8ce6f2f17f1223679bb0b84072070000000000160014f0fe5c1867a174a12e70165e728a072619455ed5000000000001011f20a10700000000001600141ab4b6d2f79cb0a1b5be5a2372eb668bc09261f80100fd1c01020000000001012cdd7dfc38d14f2c95425bb0afc4ee93df4c7b46e9f8bd8d43d845382f88b2b60100000000fdffffff0420a10700000000001600141ab4b6d2f79cb0a1b5be5a2372eb668bc09261f820a107000000000016001483c3bc7234f17a209cc5dcce14903b54ee4dab9020a1070000000000160014d4ca56fcbad98fb4dcafdc573a75d6a6fffb09b7303b0c0100000000160014da837c758fa0bce9eb845f240a06484f8dfb862c0247304402201b47c7fe41a9b5b196f1ee628d8e5065d85cba4caa44a0f8199a603cb0ee40a80220159eb66a66a5a3a396922aa3ffd7101224de75b1b57dc0c4732e284cdd228c63012102d63196184adaa312705ec7f0d8c9565261e4c19a6746f5ac3ad30cc0b932501cc7d24900220603565a3904c7d2d6a6c2cf3fcdf89d9e5c60b509483104992cfdf85b196665170c10e8a903980000008000000000020000000001011f20a107000000000016001483c3bc7234f17a209cc5dcce14903b54ee4dab900100fd1c01020000000001012cdd7dfc38d14f2c95425bb0afc4ee93df4c7b46e9f8bd8d43d845382f88b2b60100000000fdffffff0420a10700000000001600141ab4b6d2f79cb0a1b5be5a2372eb668bc09261f820a107000000000016001483c3bc7234f17a209cc5dcce14903b54ee4dab9020a1070000000000160014d4ca56fcbad98fb4dcafdc573a75d6a6fffb09b7303b0c0100000000160014da837c758fa0bce9eb845f240a06484f8dfb862c0247304402201b47c7fe41a9b5b196f1ee628d8e5065d85cba4caa44a0f8199a603cb0ee40a80220159eb66a66a5a3a396922aa3ffd7101224de75b1b57dc0c4732e284cdd228c63012102d63196184adaa312705ec7f0d8c9565261e4c19a6746f5ac3ad30cc0b932501cc7d24900220602a6ff1ffc189b4776b78e20edca969cc45da3e610cc0cc79925604be43fee469f10e8a90398000000800000000001000000000000220202105dd9133f33cbd4e50443ef9af428c0be61f097f8942aaa916f50b530125aea10e8a9039800000080010000000000000000')
|
||||
if simulate_moving_txs:
|
||||
partial_tx = tx1.serialize_as_bytes().hex()
|
||||
self.assertEqual('70736274ff0100d10200000002032b1c2c7d66e528905a11e148234ffe94cc9b4af7dbbc18dad13b9eb18050610000000000fdffffff032b1c2c7d66e528905a11e148234ffe94cc9b4af7dbbc18dad13b9eb18050610100000000fdffffff0378d4030000000000220020f381d0d2c633cdd890015bb438c8e73e9960b21defa126c594e5cf67bd06419f78d40300000000002200204a1c25db1aa7165cb655638fb32319a945262fee7c8ce6f2f17f1223679bb0b84072070000000000160014f0fe5c1867a174a12e70165e728a072619455ed5000000000001011f20a10700000000001600141ab4b6d2f79cb0a1b5be5a2372eb668bc09261f80100fd1c01020000000001012cdd7dfc38d14f2c95425bb0afc4ee93df4c7b46e9f8bd8d43d845382f88b2b60100000000fdffffff0420a10700000000001600141ab4b6d2f79cb0a1b5be5a2372eb668bc09261f820a107000000000016001483c3bc7234f17a209cc5dcce14903b54ee4dab9020a1070000000000160014d4ca56fcbad98fb4dcafdc573a75d6a6fffb09b7303b0c0100000000160014da837c758fa0bce9eb845f240a06484f8dfb862c0247304402201b47c7fe41a9b5b196f1ee628d8e5065d85cba4caa44a0f8199a603cb0ee40a80220159eb66a66a5a3a396922aa3ffd7101224de75b1b57dc0c4732e284cdd228c63012102d63196184adaa312705ec7f0d8c9565261e4c19a6746f5ac3ad30cc0b932501cc7d24900220603565a3904c7d2d6a6c2cf3fcdf89d9e5c60b509483104992cfdf85b196665170c10e8a903980000008000000000020000000001011f20a107000000000016001483c3bc7234f17a209cc5dcce14903b54ee4dab900100fd1c01020000000001012cdd7dfc38d14f2c95425bb0afc4ee93df4c7b46e9f8bd8d43d845382f88b2b60100000000fdffffff0420a10700000000001600141ab4b6d2f79cb0a1b5be5a2372eb668bc09261f820a107000000000016001483c3bc7234f17a209cc5dcce14903b54ee4dab9020a1070000000000160014d4ca56fcbad98fb4dcafdc573a75d6a6fffb09b7303b0c0100000000160014da837c758fa0bce9eb845f240a06484f8dfb862c0247304402201b47c7fe41a9b5b196f1ee628d8e5065d85cba4caa44a0f8199a603cb0ee40a80220159eb66a66a5a3a396922aa3ffd7101224de75b1b57dc0c4732e284cdd228c63012102d63196184adaa312705ec7f0d8c9565261e4c19a6746f5ac3ad30cc0b932501cc7d24900220602a6ff1ffc189b4776b78e20edca969cc45da3e610cc0cc79925604be43fee469f10e8a90398000000800000000001000000000000220202105dd9133f33cbd4e50443ef9af428c0be61f097f8942aaa916f50b530125aea10e8a9039800000080010000000000000000',
|
||||
partial_tx)
|
||||
tx1 = tx_from_any(partial_tx) # simulates moving partial txn between cosigners
|
||||
wallet.sign_transaction(tx1, password=None)
|
||||
wallet.adb.receive_tx_callback(tx1, tx_height=TX_HEIGHT_UNCONFIRMED)
|
||||
|
||||
self.assertTrue(tx1.is_complete())
|
||||
self.assertTrue(tx1.is_segwit())
|
||||
self.assertEqual(2, len(tx1.inputs()))
|
||||
self.assertEqual(3, len(tx1.outputs()))
|
||||
|
||||
tx2_additional_output = [
|
||||
PartialTxOutput.from_address_and_value("tb1qnp9z33k8dz22dfklvyusv95hp7n3gc0yamzp6mj9y9es636ekrxs5mjmzp", 510_000)
|
||||
]
|
||||
tx2 = wallet.make_unsigned_transaction(
|
||||
base_tx=tx1,
|
||||
outputs=tx2_additional_output,
|
||||
fee_policy=FixedFeePolicy(1_000), # lower fee
|
||||
BIP69_sort=False,
|
||||
)
|
||||
if simulate_moving_txs:
|
||||
partial_tx = tx2.serialize_as_bytes().hex()
|
||||
self.assertEqual('70736274ff0100fd25010200000003032b1c2c7d66e528905a11e148234ffe94cc9b4af7dbbc18dad13b9eb18050610000000000fdffffff032b1c2c7d66e528905a11e148234ffe94cc9b4af7dbbc18dad13b9eb18050610100000000fdffffff032b1c2c7d66e528905a11e148234ffe94cc9b4af7dbbc18dad13b9eb18050610200000000fdffffff0478d4030000000000220020f381d0d2c633cdd890015bb438c8e73e9960b21defa126c594e5cf67bd06419f78d40300000000002200204a1c25db1aa7165cb655638fb32319a945262fee7c8ce6f2f17f1223679bb0b830c8070000000000220020984a28c6c76894a6a6df61390616970fa71461e4eec41d6e4521730d4759b0cd8d3a070000000000160014f0fe5c1867a174a12e70165e728a072619455ed5000000000001011f20a10700000000001600141ab4b6d2f79cb0a1b5be5a2372eb668bc09261f80100fd1c01020000000001012cdd7dfc38d14f2c95425bb0afc4ee93df4c7b46e9f8bd8d43d845382f88b2b60100000000fdffffff0420a10700000000001600141ab4b6d2f79cb0a1b5be5a2372eb668bc09261f820a107000000000016001483c3bc7234f17a209cc5dcce14903b54ee4dab9020a1070000000000160014d4ca56fcbad98fb4dcafdc573a75d6a6fffb09b7303b0c0100000000160014da837c758fa0bce9eb845f240a06484f8dfb862c0247304402201b47c7fe41a9b5b196f1ee628d8e5065d85cba4caa44a0f8199a603cb0ee40a80220159eb66a66a5a3a396922aa3ffd7101224de75b1b57dc0c4732e284cdd228c63012102d63196184adaa312705ec7f0d8c9565261e4c19a6746f5ac3ad30cc0b932501cc7d24900220603565a3904c7d2d6a6c2cf3fcdf89d9e5c60b509483104992cfdf85b196665170c10e8a903980000008000000000020000000001011f20a107000000000016001483c3bc7234f17a209cc5dcce14903b54ee4dab900100fd1c01020000000001012cdd7dfc38d14f2c95425bb0afc4ee93df4c7b46e9f8bd8d43d845382f88b2b60100000000fdffffff0420a10700000000001600141ab4b6d2f79cb0a1b5be5a2372eb668bc09261f820a107000000000016001483c3bc7234f17a209cc5dcce14903b54ee4dab9020a1070000000000160014d4ca56fcbad98fb4dcafdc573a75d6a6fffb09b7303b0c0100000000160014da837c758fa0bce9eb845f240a06484f8dfb862c0247304402201b47c7fe41a9b5b196f1ee628d8e5065d85cba4caa44a0f8199a603cb0ee40a80220159eb66a66a5a3a396922aa3ffd7101224de75b1b57dc0c4732e284cdd228c63012102d63196184adaa312705ec7f0d8c9565261e4c19a6746f5ac3ad30cc0b932501cc7d24900220602a6ff1ffc189b4776b78e20edca969cc45da3e610cc0cc79925604be43fee469f10e8a903980000008000000000010000000001011f20a1070000000000160014d4ca56fcbad98fb4dcafdc573a75d6a6fffb09b70100fd1c01020000000001012cdd7dfc38d14f2c95425bb0afc4ee93df4c7b46e9f8bd8d43d845382f88b2b60100000000fdffffff0420a10700000000001600141ab4b6d2f79cb0a1b5be5a2372eb668bc09261f820a107000000000016001483c3bc7234f17a209cc5dcce14903b54ee4dab9020a1070000000000160014d4ca56fcbad98fb4dcafdc573a75d6a6fffb09b7303b0c0100000000160014da837c758fa0bce9eb845f240a06484f8dfb862c0247304402201b47c7fe41a9b5b196f1ee628d8e5065d85cba4caa44a0f8199a603cb0ee40a80220159eb66a66a5a3a396922aa3ffd7101224de75b1b57dc0c4732e284cdd228c63012102d63196184adaa312705ec7f0d8c9565261e4c19a6746f5ac3ad30cc0b932501cc7d249002206028d4c44ca36d2c4bff3813df8d5d3c0278357521ecb892cd694c473c03970e4c510e8a9039800000080000000000000000000000000220202105dd9133f33cbd4e50443ef9af428c0be61f097f8942aaa916f50b530125aea10e8a9039800000080010000000000000000',
|
||||
partial_tx)
|
||||
tx2 = tx_from_any(partial_tx) # simulates moving partial txn between cosigners
|
||||
wallet.sign_transaction(tx2, password=None)
|
||||
|
||||
self.assertTrue(tx2.is_complete())
|
||||
self.assertTrue(tx2.is_segwit())
|
||||
self.assertEqual(3, len(tx2.inputs()))
|
||||
self.assertEqual(4, len(tx2.outputs()))
|
||||
|
||||
relayfee_sat_vb = bitcoin.relayfee() / 1000 # assume relayfee is equal to incrementalrelayfee
|
||||
minimal_accepted_new_fee = int(tx1.get_fee() + tx2.estimated_size() * relayfee_sat_vb)
|
||||
self.assertGreaterEqual(tx2.get_fee(), minimal_accepted_new_fee)
|
||||
|
||||
tx1_feerate_sat_vb = tx1.get_fee() / tx1.estimated_size()
|
||||
tx2_feerate_sat_vb = tx2.get_fee() / tx2.estimated_size()
|
||||
self.assertGreater(tx2_feerate_sat_vb, tx1_feerate_sat_vb, msg="tx2 feerate lower than tx1")
|
||||
|
||||
def _create_cause_carbon_wallet(self):
|
||||
data = read_test_vector('cause_carbon_wallet.json')
|
||||
ks = keystore.from_seed(data['seed'], passphrase='', for_multisig=False)
|
||||
|
||||
Reference in New Issue
Block a user