Skip to content

Commit

Permalink
merge bitcoin#16257: abort when attempting to fund a transaction abov…
Browse files Browse the repository at this point in the history
…e -maxtxfee
  • Loading branch information
kwvg committed Dec 12, 2021
1 parent 05a4924 commit b2ca691
Show file tree
Hide file tree
Showing 9 changed files with 22 additions and 15 deletions.
1 change: 0 additions & 1 deletion src/policy/fees.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ enum class FeeReason {
PAYTXFEE,
FALLBACK,
REQUIRED,
MAXTXFEE,
};

/* Used to determine type of fee estimation requested */
Expand Down
4 changes: 1 addition & 3 deletions src/qt/walletmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,9 +269,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
return TransactionCreationFailed;
}

// reject absurdly high fee. (This can never happen because the
// wallet caps the fee at maxTxFee. This merely serves as a
// belt-and-suspenders check)
// Reject absurdly high fee
if (nFeeRequired > m_node.getMaxTxFee())
return AbsurdFee;

Expand Down
2 changes: 2 additions & 0 deletions src/util/error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ std::string TransactionErrorString(const TransactionError err)
return "PSBTs not compatible (different transactions)";
case TransactionError::SIGHASH_MISMATCH:
return "Specified sighash value does not match existing value";
case TransactionError::MAX_FEE_EXCEEDED:
return "Fee exceeds maximum configured by -maxtxfee";
// no default case, so the compiler can warn about missing cases
}
assert(false);
Expand Down
1 change: 1 addition & 0 deletions src/util/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ enum class TransactionError {
INVALID_PSBT,
PSBT_MISMATCH,
SIGHASH_MISMATCH,
MAX_FEE_EXCEEDED,
};

std::string TransactionErrorString(const TransactionError error);
Expand Down
1 change: 0 additions & 1 deletion src/util/fees.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ std::string StringForFeeReason(FeeReason reason) {
{FeeReason::PAYTXFEE, "PayTxFee set"},
{FeeReason::FALLBACK, "Fallback fee"},
{FeeReason::REQUIRED, "Minimum Required Fee"},
{FeeReason::MAXTXFEE, "MaxTxFee limit"}
};
auto reason_string = fee_reason_strings.find(reason);

Expand Down
9 changes: 1 addition & 8 deletions src/wallet/fees.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,7 @@ CAmount GetRequiredFee(const CWallet& wallet, unsigned int nTxBytes)

CAmount GetMinimumFee(const CWallet& wallet, unsigned int nTxBytes, const CCoinControl& coin_control, FeeCalculation* feeCalc)
{
CAmount fee_needed = GetMinimumFeeRate(wallet, coin_control, feeCalc).GetFee(nTxBytes);
// Always obey the maximum
const CAmount max_tx_fee = wallet.chain().maxTxFee();
if (fee_needed > max_tx_fee) {
fee_needed = max_tx_fee;
if (feeCalc) feeCalc->reason = FeeReason::MAXTXFEE;
}
return fee_needed;
return GetMinimumFeeRate(wallet, coin_control, feeCalc).GetFee(nTxBytes);
}

CFeeRate GetRequiredFeeRate(const CWallet& wallet)
Expand Down
5 changes: 5 additions & 0 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3220,6 +3220,11 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
}
}

if (nFeeRet > chain().maxTxFee()) {
strFailReason = TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED);
return false;
}

return true;
}

Expand Down
1 change: 1 addition & 0 deletions test/functional/rpc_fundrawtransaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,7 @@ def run_test(self):
result = self.nodes[3].fundrawtransaction(rawtx) # uses min_relay_tx_fee (set by settxfee)
result2 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee})
result3 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 10*min_relay_tx_fee})
assert_raises_rpc_error(-4, "Fee exceeds maximum configured by -maxtxfee", self.nodes[3].fundrawtransaction, rawtx, {"feeRate": 1})
result_fee_rate = result['fee'] * 1000 / count_bytes(result['hex'])
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)
Expand Down
13 changes: 11 additions & 2 deletions test/functional/rpc_psbt.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import os
import json
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error, find_output
from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, find_output

# Create one-input, one-output, no-fee transaction:
class PSBTTest(BitcoinTestFramework):
Expand All @@ -26,7 +26,7 @@ def skip_test_if_missing_module(self):
self.skip_if_no_wallet()

def run_test(self):
# Create and fund a raw tx for sending 10 BTC
# Create and fund a raw tx for sending 10 DASH
psbtx1 = self.nodes[0].walletcreatefundedpsbt([], {self.nodes[2].getnewaddress():10})['psbt']

# Node 1 should not be able to add anything to it but still return the psbtx same as before
Expand Down Expand Up @@ -69,6 +69,15 @@ def run_test(self):
assert_equal(walletprocesspsbt_out['complete'], True)
self.nodes[1].sendrawtransaction(self.nodes[1].finalizepsbt(walletprocesspsbt_out['psbt'])['hex'])

# feeRate of 0.1 DASH / KB produces a total fee slightly below -maxtxfee (~0.06650000):
res = self.nodes[1].walletcreatefundedpsbt([{"txid":txid,"vout":p2pkh_pos},{"txid":txid,"vout":p2sh_pos},{"txid":txid,"vout":p2pkh_pos}], {self.nodes[1].getnewaddress():29.99}, 0, {"feeRate": 0.1})
assert_greater_than(res["fee"], 0.06)
assert_greater_than(0.07, res["fee"])

# feeRate of 10 DASH / KB produces a total fee well above -maxtxfee
# previously this was silenty capped at -maxtxfee
assert_raises_rpc_error(-4, "Fee exceeds maximum configured by -maxtxfee", self.nodes[1].walletcreatefundedpsbt, [{"txid":txid,"vout":p2pkh_pos},{"txid":txid,"vout":p2sh_pos},{"txid":txid,"vout":p2pkh_pos}], {self.nodes[1].getnewaddress():29.99}, 0, {"feeRate": 10})

# partially sign multisig things with node 1
psbtx = self.nodes[1].walletcreatefundedpsbt([{"txid":txid,"vout":p2sh_pos}], {self.nodes[1].getnewaddress():9.99})['psbt']
walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(psbtx)
Expand Down

0 comments on commit b2ca691

Please sign in to comment.