When would it be harmful to allow calculating the scalar ratio? Exploring this helped me find a CeilDiv.
<details><summary>Diff from disabling `amount / amount` and `amount % amount` while still being able to divide & mod by scalars.</summary>
diff --git a/src/consensus/amount.h b/src/consensus/amount.h
index 143d76b7b7..e42d55dedf 100644
--- a/src/consensus/amount.h
+++ b/src/consensus/amount.h
@@ -52,7 +52,7 @@ public:
{
return CAmount{m_sats - other.m_sats};
}
-
+/*
constexpr inner_type operator/(const CAmount other) const noexcept
{
return m_sats / other.m_sats;
@@ -62,7 +62,7 @@ public:
{
return m_sats % other.m_sats;
}
-
+*/
constexpr CAmount& operator+=(const CAmount other) noexcept
{
*this = CAmount{m_sats + other.m_sats};
diff --git a/src/core_io.cpp b/src/core_io.cpp
index a5ad9f618f..38988f980c 100644
--- a/src/core_io.cpp
+++ b/src/core_io.cpp
@@ -283,8 +283,8 @@ util::Result<int> SighashFromStr(const std::string& sighash)
UniValue ValueFromAmount(const CAmount amount)
{
static_assert(COIN > 1_sats);
- int64_t quotient = amount / COIN;
- int64_t remainder = amount % COIN;
+ int64_t quotient = amount.Int() / COIN.Int();
+ int64_t remainder = amount.Int() % COIN.Int();
if (amount < 0_sats) {
quotient = -quotient;
remainder = -remainder;
diff --git a/src/policy/feerate.cpp b/src/policy/feerate.cpp
index 5cacd5c4f2..ad926dde14 100644
--- a/src/policy/feerate.cpp
+++ b/src/policy/feerate.cpp
@@ -30,7 +30,7 @@ std::string CFeeRate::ToString(FeeRateFormat fee_rate_format) const
{
const CAmount feerate_per_kvb{GetFeePerK()};
switch (fee_rate_format) {
- case FeeRateFormat::BTC_KVB: return strprintf("%d.%08d %s/kvB", feerate_per_kvb / COIN, feerate_per_kvb % COIN, CURRENCY_UNIT);
+ case FeeRateFormat::BTC_KVB: return strprintf("%d.%08d %s/kvB", feerate_per_kvb / COIN.Int(), feerate_per_kvb % COIN.Int(), CURRENCY_UNIT);
case FeeRateFormat::SAT_VB: return strprintf("%d.%03d %s/vB", feerate_per_kvb / 1000, feerate_per_kvb % 1000, CURRENCY_ATOM);
} // no default case, so the compiler can warn about missing cases
assert(false);
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index 286150a834..1241e0c664 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -59,7 +59,7 @@ CTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn)
std::string CTxOut::ToString() const
{
- return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30));
+ return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue.Int() / COIN.Int(), nValue.Int() % COIN.Int(), HexStr(scriptPubKey).substr(0, 30));
}
CMutableTransaction::CMutableTransaction() : version{CTransaction::CURRENT_VERSION}, nLockTime{0} {}
diff --git a/src/util/moneystr.cpp b/src/util/moneystr.cpp
index fe488bca92..a4b9aa603e 100644
--- a/src/util/moneystr.cpp
+++ b/src/util/moneystr.cpp
@@ -22,8 +22,8 @@ std::string FormatMoney(const CAmount n)
// Note: not using straight sprintf here because we do NOT want
// localized number formatting.
static_assert(COIN > 1_sats);
- int64_t quotient = n / COIN;
- int64_t remainder = n % COIN;
+ int64_t quotient = n.Int() / COIN.Int();
+ int64_t remainder = n.Int() % COIN.Int();
if (n < 0_sats) {
quotient = -quotient;
remainder = -remainder;
diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp
index 457f6ae290..750ae51647 100644
--- a/src/wallet/coinselection.cpp
+++ b/src/wallet/coinselection.cpp
@@ -12,6 +12,7 @@
#include <util/check.h>
#include <util/log.h>
#include <util/moneystr.h>
+#include <util/overflow.h>
#include <numeric>
#include <optional>
@@ -528,7 +529,7 @@ util::Result<SelectionResult> CoinGrinder(std::vector<OutputGroup>& utxo_pool, c
best_selection_weight = curr_weight;
best_selection_amount = curr_amount;
}
- } else if (!best_selection.empty() && curr_weight + int64_t{min_tail_weight[curr_tail]} * ((total_target - curr_amount + utxo_pool[curr_tail].GetSelectionAmount() - 1_sats) / utxo_pool[curr_tail].GetSelectionAmount()) > best_selection_weight) {
+ } else if (!best_selection.empty() && curr_weight + int64_t{min_tail_weight[curr_tail]} * int64_t(CeilDiv(uint64_t((total_target - curr_amount).Int()), uint64_t(utxo_pool[curr_tail].GetSelectionAmount().Int()))) > best_selection_weight) {
// Compare minimal tail weight and last selected amount with the amount missing to gauge whether a better weight is still possible.
if (utxo_pool[curr_tail].m_weight <= min_tail_weight[curr_tail]) {
should_cut = true;