aboutsummaryrefslogtreecommitdiff
path: root/qa/rpc-tests/fundrawtransaction.py
diff options
context:
space:
mode:
Diffstat (limited to 'qa/rpc-tests/fundrawtransaction.py')
-rwxr-xr-xqa/rpc-tests/fundrawtransaction.py70
1 files changed, 70 insertions, 0 deletions
diff --git a/qa/rpc-tests/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py
index 82e148c55a..b97e9aecdf 100755
--- a/qa/rpc-tests/fundrawtransaction.py
+++ b/qa/rpc-tests/fundrawtransaction.py
@@ -660,5 +660,75 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_fee_amount(result2['fee'], count_bytes(result2['hex']), 2 * result_fee_rate)
assert_fee_amount(result3['fee'], count_bytes(result3['hex']), 10 * result_fee_rate)
+ ######################################
+ # Test subtractFeeFromOutputs option #
+ ######################################
+
+ # Make sure there is exactly one input so coin selection can't skew the result
+ assert_equal(len(self.nodes[3].listunspent(1)), 1)
+
+ inputs = []
+ outputs = {self.nodes[2].getnewaddress(): 1}
+ rawtx = self.nodes[3].createrawtransaction(inputs, outputs)
+
+ result = [self.nodes[3].fundrawtransaction(rawtx), # uses min_relay_tx_fee (set by settxfee)
+ self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": []}), # empty subtraction list
+ self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": [0]}), # uses min_relay_tx_fee (set by settxfee)
+ self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee}),
+ self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee, "subtractFeeFromOutputs": [0]})]
+
+ dec_tx = [self.nodes[3].decoderawtransaction(tx['hex']) for tx in result]
+ output = [d['vout'][1 - r['changepos']]['value'] for d, r in zip(dec_tx, result)]
+ change = [d['vout'][r['changepos']]['value'] for d, r in zip(dec_tx, result)]
+
+ assert_equal(result[0]['fee'], result[1]['fee'], result[2]['fee'])
+ assert_equal(result[3]['fee'], result[4]['fee'])
+ assert_equal(change[0], change[1])
+ assert_equal(output[0], output[1])
+ assert_equal(output[0], output[2] + result[2]['fee'])
+ assert_equal(change[0] + result[0]['fee'], change[2])
+ assert_equal(output[3], output[4] + result[4]['fee'])
+ assert_equal(change[3] + result[3]['fee'], change[4])
+
+ inputs = []
+ outputs = {self.nodes[2].getnewaddress(): value for value in (1.0, 1.1, 1.2, 1.3)}
+ keys = list(outputs.keys())
+ rawtx = self.nodes[3].createrawtransaction(inputs, outputs)
+
+ result = [self.nodes[3].fundrawtransaction(rawtx),
+ # split the fee between outputs 0, 2, and 3, but not output 1
+ self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": [0, 2, 3]})]
+
+ dec_tx = [self.nodes[3].decoderawtransaction(result[0]['hex']),
+ self.nodes[3].decoderawtransaction(result[1]['hex'])]
+
+ # Nested list of non-change output amounts for each transaction
+ output = [[out['value'] for i, out in enumerate(d['vout']) if i != r['changepos']]
+ for d, r in zip(dec_tx, result)]
+
+ # List of differences in output amounts between normal and subtractFee transactions
+ share = [o0 - o1 for o0, o1 in zip(output[0], output[1])]
+
+ # output 1 is the same in both transactions
+ assert_equal(share[1], 0)
+
+ # the other 3 outputs are smaller as a result of subtractFeeFromOutputs
+ assert_greater_than(share[0], 0)
+ assert_greater_than(share[2], 0)
+ assert_greater_than(share[3], 0)
+
+ # outputs 2 and 3 take the same share of the fee
+ assert_equal(share[2], share[3])
+
+ # output 0 takes at least as much share of the fee, and no more than 2 satoshis more, than outputs 2 and 3
+ assert_greater_than_or_equal(share[0], share[2])
+ assert_greater_than_or_equal(share[2] + Decimal(2e-8), share[0])
+
+ # the fee is the same in both transactions
+ assert_equal(result[0]['fee'], result[1]['fee'])
+
+ # the total subtracted from the outputs is equal to the fee
+ assert_equal(share[0] + share[2] + share[3], result[0]['fee'])
+
if __name__ == '__main__':
RawTransactionsTest().main()