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. 
TxSpends mapTxSpends GUARDED_BY(cs_wallet);
    void AddToSpends(const COutPoint& outpoint, const uint256& wtxid, WalletBatch* batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
    void AddToSpends(const CWalletTx& wtx, WalletBatch* batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
    /**
     * Add a transaction to the wallet, or update it.  confirm.block_* should
     * be set when the transaction was known to be included in a block.  When
     * block_hash.IsNull(), then wallet state is not updated in AddToWallet, but
     * notifications happen and cached balances are marked dirty.
     *
     * If fUpdate is true, existing transactions will be updated.
     * TODO: One exception to this is that the abandoned state is cleared under the
     * assumption that any further notification of a transaction that was considered
     * abandoned is an indication that it is not safe to be considered abandoned.
     * Abandoned state should probably be more carefully tracked via different
     * chain notifications or by checking mempool presence when necessary.
     *
     * Should be called with rescanning_old_block set to true, if the transaction is
     * not discovered in real time, but during a rescan of old blocks.
     */
    bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const SyncTxState& state, bool fUpdate, bool rescanning_old_block) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
    
    void MarkConflicted(const uint256& hashBlock, int conflicting_height, const uint256& hashTx);
    
    void MarkInputsDirty(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
    void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
    void SyncTransaction(const CTransactionRef& tx, const SyncTxState& state, bool update_tx = true, bool rescanning_old_block = false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
    
    std::atomic<uint64_t> m_wallet_flags{0};
    bool SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::string& strPurpose);