Branch data Line data Source code
# 1 : : // Copyright (c) 2021 The Bitcoin Core developers
# 2 : : // Distributed under the MIT software license, see the accompanying
# 3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
# 4 : :
# 5 : : #include <consensus/amount.h>
# 6 : : #include <policy/fees.h>
# 7 : : #include <validation.h>
# 8 : : #include <wallet/coincontrol.h>
# 9 : : #include <wallet/spend.h>
# 10 : : #include <wallet/test/util.h>
# 11 : : #include <wallet/test/wallet_test_fixture.h>
# 12 : :
# 13 : : #include <boost/test/unit_test.hpp>
# 14 : :
# 15 : : namespace wallet {
# 16 : : BOOST_FIXTURE_TEST_SUITE(spend_tests, WalletTestingSetup)
# 17 : :
# 18 : : BOOST_FIXTURE_TEST_CASE(SubtractFee, TestChain100Setup)
# 19 : 1 : {
# 20 : 1 : CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
# 21 : 1 : auto wallet = CreateSyncedWallet(*m_node.chain, m_node.chainman->ActiveChain(), m_args, coinbaseKey);
# 22 : :
# 23 : : // Check that a subtract-from-recipient transaction slightly less than the
# 24 : : // coinbase input amount does not create a change output (because it would
# 25 : : // be uneconomical to add and spend the output), and make sure it pays the
# 26 : : // leftover input amount which would have been change to the recipient
# 27 : : // instead of the miner.
# 28 : 4 : auto check_tx = [&wallet](CAmount leftover_input_amount) {
# 29 : 4 : CRecipient recipient{GetScriptForRawPubKey({}), 50 * COIN - leftover_input_amount, true /* subtract fee */};
# 30 : 4 : CTransactionRef tx;
# 31 : 4 : CAmount fee;
# 32 : 4 : int change_pos = -1;
# 33 : 4 : bilingual_str error;
# 34 : 4 : CCoinControl coin_control;
# 35 : 4 : coin_control.m_feerate.emplace(10000);
# 36 : 4 : coin_control.fOverrideFeeRate = true;
# 37 : : // We need to use a change type with high cost of change so that the leftover amount will be dropped to fee instead of added as a change output
# 38 : 4 : coin_control.m_change_type = OutputType::LEGACY;
# 39 : 4 : FeeCalculation fee_calc;
# 40 : 4 : BOOST_CHECK(CreateTransaction(*wallet, {recipient}, tx, fee, change_pos, error, coin_control, fee_calc));
# 41 : 4 : BOOST_CHECK_EQUAL(tx->vout.size(), 1);
# 42 : 4 : BOOST_CHECK_EQUAL(tx->vout[0].nValue, recipient.nAmount + leftover_input_amount - fee);
# 43 : 4 : BOOST_CHECK_GT(fee, 0);
# 44 : 4 : return fee;
# 45 : 4 : };
# 46 : :
# 47 : : // Send full input amount to recipient, check that only nonzero fee is
# 48 : : // subtracted (to_reduce == fee).
# 49 : 1 : const CAmount fee{check_tx(0)};
# 50 : :
# 51 : : // Send slightly less than full input amount to recipient, check leftover
# 52 : : // input amount is paid to recipient not the miner (to_reduce == fee - 123)
# 53 : 1 : BOOST_CHECK_EQUAL(fee, check_tx(123));
# 54 : :
# 55 : : // Send full input minus fee amount to recipient, check leftover input
# 56 : : // amount is paid to recipient not the miner (to_reduce == 0)
# 57 : 1 : BOOST_CHECK_EQUAL(fee, check_tx(fee));
# 58 : :
# 59 : : // Send full input minus more than the fee amount to recipient, check
# 60 : : // leftover input amount is paid to recipient not the miner (to_reduce ==
# 61 : : // -123). This overpays the recipient instead of overpaying the miner more
# 62 : : // than double the necessary fee.
# 63 : 1 : BOOST_CHECK_EQUAL(fee, check_tx(fee + 123));
# 64 : 1 : }
# 65 : :
# 66 : : static void TestFillInputToWeight(int64_t additional_weight, std::vector<int64_t> expected_stack_sizes)
# 67 : 9 : {
# 68 : 9 : static const int64_t EMPTY_INPUT_WEIGHT = GetTransactionInputWeight(CTxIn());
# 69 : :
# 70 : 9 : CTxIn input;
# 71 : 9 : int64_t target_weight = EMPTY_INPUT_WEIGHT + additional_weight;
# 72 : 9 : BOOST_CHECK(FillInputToWeight(input, target_weight));
# 73 : 9 : BOOST_CHECK_EQUAL(GetTransactionInputWeight(input), target_weight);
# 74 : 9 : BOOST_CHECK_EQUAL(input.scriptWitness.stack.size(), expected_stack_sizes.size());
# 75 [ + + ]: 22 : for (unsigned int i = 0; i < expected_stack_sizes.size(); ++i) {
# 76 : 13 : BOOST_CHECK_EQUAL(input.scriptWitness.stack[i].size(), expected_stack_sizes[i]);
# 77 : 13 : }
# 78 : 9 : }
# 79 : :
# 80 : : BOOST_FIXTURE_TEST_CASE(FillInputToWeightTest, BasicTestingSetup)
# 81 : 1 : {
# 82 : 1 : {
# 83 : : // Less than or equal minimum of 165 should not add any witness data
# 84 : 1 : CTxIn input;
# 85 : 1 : BOOST_CHECK(!FillInputToWeight(input, -1));
# 86 : 1 : BOOST_CHECK_EQUAL(GetTransactionInputWeight(input), 165);
# 87 : 1 : BOOST_CHECK_EQUAL(input.scriptWitness.stack.size(), 0);
# 88 : 1 : BOOST_CHECK(!FillInputToWeight(input, 0));
# 89 : 1 : BOOST_CHECK_EQUAL(GetTransactionInputWeight(input), 165);
# 90 : 1 : BOOST_CHECK_EQUAL(input.scriptWitness.stack.size(), 0);
# 91 : 1 : BOOST_CHECK(!FillInputToWeight(input, 164));
# 92 : 1 : BOOST_CHECK_EQUAL(GetTransactionInputWeight(input), 165);
# 93 : 1 : BOOST_CHECK_EQUAL(input.scriptWitness.stack.size(), 0);
# 94 : 1 : BOOST_CHECK(FillInputToWeight(input, 165));
# 95 : 1 : BOOST_CHECK_EQUAL(GetTransactionInputWeight(input), 165);
# 96 : 1 : BOOST_CHECK_EQUAL(input.scriptWitness.stack.size(), 0);
# 97 : 1 : }
# 98 : :
# 99 : : // Make sure we can add at least one weight
# 100 : 1 : TestFillInputToWeight(1, {0});
# 101 : :
# 102 : : // 1 byte compact size uint boundary
# 103 : 1 : TestFillInputToWeight(252, {251});
# 104 : 1 : TestFillInputToWeight(253, {83, 168});
# 105 : 1 : TestFillInputToWeight(262, {86, 174});
# 106 : 1 : TestFillInputToWeight(263, {260});
# 107 : :
# 108 : : // 3 byte compact size uint boundary
# 109 : 1 : TestFillInputToWeight(65535, {65532});
# 110 : 1 : TestFillInputToWeight(65536, {21842, 43688});
# 111 : 1 : TestFillInputToWeight(65545, {21845, 43694});
# 112 : 1 : TestFillInputToWeight(65546, {65541});
# 113 : :
# 114 : : // Note: We don't test the next boundary because of memory allocation constraints.
# 115 : 1 : }
# 116 : :
# 117 : : BOOST_AUTO_TEST_SUITE_END()
# 118 : : } // namespace wallet
|