Skip to content

Conversation

achow101
Copy link
Member

#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.

if (res) {
bnb_used = false;
} else {
res = value_to_select <= 0 ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why leave this case here when we know it is false?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, forgot to delete that.

@DrahtBot
Copy link
Contributor

DrahtBot commented Nov 23, 2019

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #17526 (Use Single Random Draw In addition to knapsack as coin selection fallback by achow101)
  • #17331 (Use effective values throughout coin selection by achow101)
  • #17211 (Allow fundrawtransaction and walletcreatefundedpsbt to take external inputs by achow101)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@meshcollider
Copy link
Contributor

The new test passes on current master without the code change

@achow101
Copy link
Member Author

The new test passes on current master without the code change

Not for me:

2019-11-23T05:27:14.580000Z TestFramework (INFO): Test fundrawtxn subtract fee from outputs with preset inputs that are sufficient
2019-11-23T05:27:14.637000Z TestFramework (ERROR): JSONRPC error
Traceback (most recent call last):
  File "/home/andy/bitcoin/bitcoin/test/functional/test_framework/test_framework.py", line 111, in main
    self.run_test()
  File "test/functional/rpc_fundrawtransaction.py", line 95, in run_test
    self.test_subtract_fee_with_presets()
  File "test/functional/rpc_fundrawtransaction.py", line 753, in test_subtract_fee_with_presets
    fundedtx = self.nodes[0].fundrawtransaction(rawtx, {'subtractFeeFromOutputs': [0]})
  File "/home/andy/bitcoin/bitcoin/test/functional/test_framework/coverage.py", line 47, in __call__
    return_val = self.auth_service_proxy_instance.__call__(*args, **kwargs)
  File "/home/andy/bitcoin/bitcoin/test/functional/test_framework/authproxy.py", line 141, in __call__
    raise JSONRPCException(response['error'], status)
test_framework.authproxy.JSONRPCException: Fee exceeds maximum configured by -maxtxfee (-4)
2019-11-23T05:27:14.694000Z TestFramework (INFO): Stopping nodes
2019-11-23T05:27:14.849000Z TestFramework (WARNING): Not cleaning up dir /tmp/bitcoin_func_test_rpwug9f9
2019-11-23T05:27:14.849000Z TestFramework (ERROR): Test failed. Test logging available at /tmp/bitcoin_func_test_rpwug9f9/test_framework.log
2019-11-23T05:27:14.849000Z TestFramework (ERROR): Hint: Call /home/andy/bitcoin/bitcoin/test/functional/combine_logs.py '/tmp/bitcoin_func_test_rpwug9f9' to consolidate all logs

@laanwj
Copy link
Member

laanwj commented Nov 23, 2019

I've tested this.
When running the new test on current master's binary, the "rpc_fundrawtransaction.py" test gives me a "test_framework.authproxy.JSONRPCException: Fee exceeds maximum configured by -maxtxfee (-4)" consistently.
After recompile with this patch, it passes.

This is really strange, I wonder what causes the difference in behavior for @meshcollider .

@darosior
Copy link
Member

FWIW the test pass on master for me as well (without the code change).

@meshcollider
Copy link
Contributor

meshcollider commented Nov 24, 2019

samuel@hansome-pc:~/git/bitcoin$ git diff master
diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py
index 693051edc..6f1ae0d3b 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()
samuel@hansome-pc:~/git/bitcoin$ make -j5
Making all in src
make[1]: Entering directory '/home/samuel/git/bitcoin/src'
make[2]: Entering directory '/home/samuel/git/bitcoin/src'
  CXX      libbitcoinconsensus_la-arith_uint256.lo
  CXX      libbitcoinconsensus_la-hash.lo
  CXX      libbitcoinconsensus_la-pubkey.lo
  CXX      libbitcoinconsensus_la-uint256.lo
...  
  CXX      qt/qt_libbitcoinqt_a-moc_walletview.o
  CXX      qt/qt_libbitcoinqt_a-qrc_bitcoin.o
  CXX      qt/qt_libbitcoinqt_a-qrc_bitcoin_locale.o
  CXXLD    bitcoind
  CXXLD    test/test_bitcoin
  CXXLD    bench/bench_bitcoin
  AR       qt/libbitcoinqt.a
  CXXLD    qt/bitcoin-qt
  CXXLD    qt/test/test_bitcoin-qt
make[2]: Leaving directory '/home/samuel/git/bitcoin/src'
make[1]: Leaving directory '/home/samuel/git/bitcoin/src'
Making all in doc/man
make[1]: Entering directory '/home/samuel/git/bitcoin/doc/man'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/home/samuel/git/bitcoin/doc/man'
make[1]: Entering directory '/home/samuel/git/bitcoin'
make[1]: Nothing to be done for 'all-am'.
make[1]: Leaving directory '/home/samuel/git/bitcoin'
samuel@hansome-pc:~/git/bitcoin$ ./test/functional/test_runner.py rpc_fundrawtransaction.py
Temporary test directory at /tmp/test_runner_?_??_20191124_180027
Remaining jobs: [rpc_fundrawtransaction.py]
1/1 - rpc_fundrawtransaction.py passed, Duration: 13 s

TEST                      | STATUS    | DURATION

rpc_fundrawtransaction.py | ? Passed  | 13 s

ALL                       | ? Passed  | 13 s (accumulated)
Runtime: 13 s

Clean branch, up to date master, fresh build. Ubuntu 18.04.1. Idk why it passes but yours doesn't.

Also tested with Travis, (https://travis-ci.org/meshcollider/bitcoin/builds/616192547) - jobs .4 and .8 passed rpc_fundrawtransaction.py

@achow101
Copy link
Member Author

I figured out why we are getting different test results on master.

It's because bnb_used is not initialized, so the access is undefined behavior and changes depending on the optimizations used. I always configured with --enable-debug which disables all optimizations. Presumably this results in bnb_used having some value that corresponds to true. After configuring without --enable-debug and thus allowing optimizations, the test passes on master. I assume this is because some optimization gives bnb_used the false value by default.


I've pushed another commit which should completely address this type of issue, at least until we merge #17331 which gets rid of that variable entirely. Instead of setting it at each of the non-BnB cases that can occur, we just default assume bnb_used = false and let it be set to true after BnB selection succeeds.

@meshcollider
Copy link
Contributor

meshcollider commented Nov 25, 2019

Ah, good find.

Code review ACK d3ca0b4

Copy link
Member

@darosior darosior left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 4b0d19b

@Sjors
Copy link
Member

Sjors commented Nov 25, 2019

@practicalswift spotted a similar issue in #13546. Let's also actually initialize this thing, as @promag suggested:

bool bnb_used;

Copy link
Member

@instagibbs instagibbs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second commit needs a rework of the commit message since it's just an additional test now.

@achow101
Copy link
Member Author

Changed bnb_used to be initialized to false. Also updated the commit message.

@instagibbs
Copy link
Member

utACK eadd130

@Sjors
Copy link
Member

Sjors commented Nov 27, 2019

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.

Copy link
Member

@fanquake fanquake left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK eadd130

SelectCoins() is only called in CreateTransaction(). bnb_used is set to false before that call (and again inside SelectCoins()) which is before any calls to SelectCoinsMinConf().

Looking forward to something like #17331 which not only removes bnb_used but simplifies the wallet.cpp logic. As we've currently got code like this:

// Choose coins to use
bool bnb_used = false;
if (pick_new_inputs) {
    <snip>
} else {
    bnb_used = false;
}

and are doing similar things with coin_selection_params.use_bnb.

fanquake added a commit that referenced this pull request Dec 1, 2019
…eeFromOutputs

eadd130 tests: Add a test for funding with sufficient preset inputs and subtractFeeFromOutputs (Andrew Chow)
ff330ba 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 eadd130
  instagibbs:
    utACK eadd130

Tree-SHA512: 7286c321f78666eea558cc591174630d210263594df41cab1065417510591ee514ade0e1d0cec8af09a785757da68de82592b013e8fe8d4966cec3254368706e
@fanquake fanquake merged commit eadd130 into bitcoin:master Dec 1, 2019
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Dec 1, 2019
…btractFeeFromOutputs

eadd130 tests: Add a test for funding with sufficient preset inputs and subtractFeeFromOutputs (Andrew Chow)
ff330ba Default to bnb_used = false as there are many cases where BnB is not used (Andrew Chow)

Pull request description:

  bitcoin#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 eadd130
  instagibbs:
    utACK bitcoin@eadd130

Tree-SHA512: 7286c321f78666eea558cc591174630d210263594df41cab1065417510591ee514ade0e1d0cec8af09a785757da68de82592b013e8fe8d4966cec3254368706e
@promag
Copy link
Contributor

promag commented Dec 1, 2019

@Sjors thanks for the mention.

Code review ACK eadd130.

jasonbcox pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Sep 30, 2020
…eeFromOutputs

Summary:
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.

Backport of Core [[bitcoin/bitcoin#17568 | PR17568]]

Depends on D7688

Test Plan:
```
ninja check
test_runner.py rpc_fundrawtransaction
```

Reviewers: #bitcoin_abc, majcosta

Reviewed By: #bitcoin_abc, majcosta

Differential Revision: https://reviews.bitcoinabc.org/D7691
sidhujag pushed a commit to syscoin-core/syscoin that referenced this pull request Nov 10, 2020
…btractFeeFromOutputs

eadd130 tests: Add a test for funding with sufficient preset inputs and subtractFeeFromOutputs (Andrew Chow)
ff330ba Default to bnb_used = false as there are many cases where BnB is not used (Andrew Chow)

Pull request description:

  bitcoin#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 eadd130
  instagibbs:
    utACK bitcoin@eadd130

Tree-SHA512: 7286c321f78666eea558cc591174630d210263594df41cab1065417510591ee514ade0e1d0cec8af09a785757da68de82592b013e8fe8d4966cec3254368706e
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Dec 16, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants