Skip to content

-maxtxfee is used as a fee and a feerate #29220

@glozow

Description

@glozow

The -maxtxfee (which is put into m_default_max_tx_fee) is documented as "the maximum total fees to use in a single wallet transaction"

argsman.AddArg("-maxtxfee=<amt>", strprintf("Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)",

This seems true in many instances when we look at the code:

bitcoin/src/wallet/spend.cpp

Lines 1293 to 1295 in 632a2bb

if (current_fee > wallet.m_default_max_tx_fee) {
return util::Error{TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED)};
}

const CAmount max_tx_fee = wallet.m_default_max_tx_fee;
if (new_total_fee > max_tx_fee) {
errors.push_back(strprintf(Untranslated("Specified or calculated fee %s is too high (cannot be higher than -maxtxfee %s)"),
FormatMoney(new_total_fee), FormatMoney(max_tx_fee)));
return feebumper::Result::WALLET_ERROR;
}

if (max_tx_fee > 0) {
// First, call ATMP with test_accept and check the fee. If ATMP
// fails here, return error immediately.
const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/ true);
if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
return HandleATMPError(result.m_state, err_string);
} else if (result.m_base_fees.value() > max_tx_fee) {
return TransactionError::MAX_FEE_EXCEEDED;
}

But there are also places where this value is used as a feerate per KvB:

bitcoin/src/wallet/wallet.cpp

Lines 3061 to 3064 in 632a2bb

if (chain && CFeeRate{max_fee.value(), 1000} < chain->relayMinFee()) {
error = strprintf(_("Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
"-maxtxfee", args.GetArg("-maxtxfee", ""), chain->relayMinFee().ToString());
return nullptr;

CFeeRate max_tx_fee_rate(pwallet->m_default_max_tx_fee, 1000);

I don't think these instances of conversions to feerate result in anything very problematic, but it doesn't make sense to just convert this fee to a feerate because not every tx is the same size. I can see why a wallet user might want a maximum fee and maximum feerate. So my suggested solution is to have both: add a -maxfeerate and put those checks under the new value.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions