diff options
author | fanquake <fanquake@gmail.com> | 2019-12-01 11:56:52 -0500 |
---|---|---|
committer | fanquake <fanquake@gmail.com> | 2019-12-01 12:23:44 -0500 |
commit | 19698ac6bc0e6c75a92b02c8b74ae1fa51c34e08 (patch) | |
tree | df9e5c79831e18ca0dd102da7a0657ea632a1470 | |
parent | 2ecb7e1556cd970b6dccb5f101a718602487df4b (diff) | |
parent | eadd1304c81e0b89178e4cc7630bd31650850c85 (diff) |
Merge #17568: wallet: fix when sufficient preset inputs and subtractFeeFromOutputs
eadd1304c81e0b89178e4cc7630bd31650850c85 tests: Add a test for funding with sufficient preset inputs and subtractFeeFromOutputs (Andrew Chow)
ff330badd45067cb520b1cfa1844f60a4c9f2031 Default to bnb_used = false as there are many cases where BnB is not used (Andrew Chow)
Pull request description:
#17290 introduced a bug where, when we had preset inputs that covered the amount being sent and subtractFeeFrromOutputs was being used, transaction funding would result in a `Fee exceeds maximum configured by -maxtxfee` error. This was happening because we weren't setting `bnb_used = false` when the preset inputs were used as it should have been. This resulted in a too high fee because the change would go to fees accidentally.
Apparently this particular case doesn't have a test, so I've added one as well.
ACKs for top commit:
Sjors:
ACK eadd130. I can't get this new test to fail on macOS (without this PR). It passes whether or not I compile with `--enable-debug`. It does fail on Ubuntu. Yay undefined behavior... Anyway, it's a useful test.
fanquake:
ACK eadd1304c81e0b89178e4cc7630bd31650850c85
instagibbs:
utACK https://github.com/bitcoin/bitcoin/pull/17568/commits/eadd1304c81e0b89178e4cc7630bd31650850c85
Tree-SHA512: 7286c321f78666eea558cc591174630d210263594df41cab1065417510591ee514ade0e1d0cec8af09a785757da68de82592b013e8fe8d4966cec3254368706e
-rw-r--r-- | src/wallet/wallet.cpp | 11 | ||||
-rwxr-xr-x | test/functional/rpc_fundrawtransaction.py | 13 |
2 files changed, 17 insertions, 7 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index b1e1385ca3..647b381b39 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2270,12 +2270,12 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm std::vector<COutput> vCoins(vAvailableCoins); CAmount value_to_select = nTargetValue; + // Default to bnb was not used. If we use it, we set it later + bnb_used = false; + // coin control -> return all selected outputs (we want all selected to go into the transaction for sure) if (coin_control.HasSelected() && !coin_control.fAllowOtherInputs) { - // We didn't use BnB here, so set it to false. - bnb_used = false; - for (const COutput& out : vCoins) { if (!out.fSpendable) @@ -2300,14 +2300,12 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm const CWalletTx& wtx = it->second; // Clearly invalid input, fail if (wtx.tx->vout.size() <= outpoint.n) { - bnb_used = false; return false; } // Just to calculate the marginal byte size CInputCoin coin(wtx.tx, outpoint.n, wtx.GetSpendSize(outpoint.n, false)); nValueFromPresetInputs += coin.txout.nValue; if (coin.m_input_bytes <= 0) { - bnb_used = false; return false; // Not solvable, can't estimate size for fee } coin.effective_value = coin.txout.nValue - coin_selection_params.effective_fee.GetFee(coin.m_input_bytes); @@ -2318,7 +2316,6 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm } setPresetCoins.insert(coin); } else { - bnb_used = false; return false; // TODO: Allow non-wallet inputs } } @@ -2678,7 +2675,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std } // Choose coins to use - bool bnb_used; + bool bnb_used = false; if (pick_new_inputs) { nValueIn = 0; setCoins.clear(); diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py index 693051edc0..6f1ae0d3ba 100755 --- a/test/functional/rpc_fundrawtransaction.py +++ b/test/functional/rpc_fundrawtransaction.py @@ -92,6 +92,7 @@ class RawTransactionsTest(BitcoinTestFramework): self.test_option_feerate() self.test_address_reuse() self.test_option_subtract_fee_from_outputs() + self.test_subtract_fee_with_presets() def test_change_position(self): """Ensure setting changePosition in fundraw with an exact match is handled properly.""" @@ -741,5 +742,17 @@ class RawTransactionsTest(BitcoinTestFramework): # The total subtracted from the outputs is equal to the fee. assert_equal(share[0] + share[2] + share[3], result[0]['fee']) + def test_subtract_fee_with_presets(self): + self.log.info("Test fundrawtxn subtract fee from outputs with preset inputs that are sufficient") + + addr = self.nodes[0].getnewaddress() + txid = self.nodes[0].sendtoaddress(addr, 10) + vout = find_vout_for_address(self.nodes[0], txid, addr) + + rawtx = self.nodes[0].createrawtransaction([{'txid': txid, 'vout': vout}], [{self.nodes[0].getnewaddress(): 5}]) + fundedtx = self.nodes[0].fundrawtransaction(rawtx, {'subtractFeeFromOutputs': [0]}) + signedtx = self.nodes[0].signrawtransactionwithwallet(fundedtx['hex']) + self.nodes[0].sendrawtransaction(signedtx['hex']) + if __name__ == '__main__': RawTransactionsTest().main() |