Since #13666 our fee calculation assumes that ECSDA signatures are a maximum of 71 bytes, rather than 72. However, not all hardware wallets implement R-value grinding.

This can cause us to underpay fees when using an external signer. That's especially problematic when the user picks 1 sat/vbyte as the fee, because it won't even get into our own mempool.

The easiest solution would be to modify `ExternalSignerScriptPubKeyMan` to assume 72 bytes for ECSDA signatures.

Slightly more advanced would be to expand HWI to keep track of which devices and firmware versions (if any) support R-value grinding. We'd then have to store that in the wallet in some new field. Personally I'd rather work on better Taproot support, which thanks to Schnorr avoids this issue altogether. 
if (!batch.WriteActiveScriptPubKeyMan(static_cast<uint8_t>(type), id, internal)) {
        throw stdruntime_error(stdstring(__func__) + " writing active ScriptPubKeyMan id failed");
    }
    LoadActiveScriptPubKeyMan(id, type, internal);
}
void CWalLoadActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
{
    // Activating ScriptPubKeyManager for a given output and change type is incompatible with legacy wals.
    // Legacy wals have only one ScriptPubKeyManager and it's active for all output and change types.
    Assert(IsWalFlagSet(WALLET_FLAG_DESCRIPTORS));
    WalLogPrintf("Setting spkMan to active id = %s, type = %s, internal = %s\n", id.ToString(), FormatOutputType(type), internal ? "true"  "false");
    auto& spk_mans = internal ? m_internal_spk_managers  m_external_spk_managers;
    auto& spk_mans_other = internal ? m_external_spk_managers  m_internal_spk_managers;
    auto spk_man = m_spk_managers.at(id).get();
    spk_mans[type] = spk_man;
    const auto it = spk_mans_other.find(type);
    if (it != spk_mans_other.end() && it->second == spk_man) {
        spk_mans_other.erase(type);
    }
    NotifyCanGetAddressesChanged();
}
void CWalDeactivateScriptPubKeyMan(uint256 id, OutputType type, bool internal)
{
    auto spk_man = GetScriptPubKeyMan(type, internal);
    if (spk_man != nullptr && spk_man->GetID() == id) {
        WalLogPrintf("Deactivate spkMan id = %s, type = %s, internal = %s\n", id.ToString(), FormatOutputType(type), internal ? "true"  "false");
        WalBatch batch(GetDatabase());
        if (!batch.EraseActiveScriptPubKeyMan(static_cast<uint8_t>(type), internal)) {
            throw stdruntime_error(stdstring(__func__) + " erasing active ScriptPubKeyMan id failed");
        }