Remove relay-only rounding

Remove rounding of transaction sizes when calculating fee minimums for relaying,
to simplify fee logic.
This commit is contained in:
Ross Nicoll 2021-08-09 23:27:38 +01:00
parent fe1bca68da
commit ce6e3d8137
8 changed files with 33 additions and 11 deletions

View file

@ -509,7 +509,7 @@ def random_transaction(nodes, amount, min_fee, fee_increment, fee_variants):
def assert_fee_amount(fee, tx_size, fee_per_kB): def assert_fee_amount(fee, tx_size, fee_per_kB):
"""Assert the fee was in range""" """Assert the fee was in range"""
target_fee = round_tx_size(tx_size) * fee_per_kB / 1000 target_fee = fee_per_kB / 1000
if fee < target_fee: if fee < target_fee:
raise AssertionError("Fee of %s BTC too low! (Should be %s BTC)"%(str(fee), str(target_fee))) raise AssertionError("Fee of %s BTC too low! (Should be %s BTC)"%(str(fee), str(target_fee)))
# allow the wallet's estimation to be at most 2 bytes off # allow the wallet's estimation to be at most 2 bytes off

View file

@ -30,6 +30,16 @@ CAmount CFeeRate::GetFee(size_t nBytes_) const
nSize = nSize + 1000 - (nSize % 1000); nSize = nSize + 1000 - (nSize % 1000);
} }
return GetRelayFee(nSize);
}
// Dogecoin: Specifically for 1.14.4 we lower accepted relay fees by removing rounding,
// in 1.14.5 we should unify the GetFee() functions again.
CAmount CFeeRate::GetRelayFee(size_t nBytes_) const
{
assert(nBytes_ <= uint64_t(std::numeric_limits<int64_t>::max()));
int64_t nSize = int64_t(nBytes_);
CAmount nFee = nSatoshisPerK * nSize / 1000; CAmount nFee = nSatoshisPerK * nSize / 1000;
if (nFee == 0 && nSize != 0) { if (nFee == 0 && nSize != 0) {

View file

@ -46,9 +46,13 @@ public:
CFeeRate(const CAmount& nFeePaid, size_t nBytes); CFeeRate(const CAmount& nFeePaid, size_t nBytes);
CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; } CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; }
/** /**
* Return the fee in satoshis for the given size in bytes. * Return the wallet fee in koinus for the given size in bytes.
*/ */
CAmount GetFee(size_t nBytes) const; CAmount GetFee(size_t nBytes) const;
/**
* Return the relay fee in koinus for the given size in bytes.
*/
CAmount GetRelayFee(size_t nBytes) const;
/** /**
* Return the fee in satoshis for a size of 1000 bytes * Return the fee in satoshis for a size of 1000 bytes
*/ */

View file

@ -46,7 +46,7 @@ CAmount GetDogecoinMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool
return 0; return 0;
} }
CAmount nMinFee = ::minRelayTxFeeRate.GetFee(nBytes); CAmount nMinFee = ::minRelayTxFeeRate.GetRelayFee(nBytes);
nMinFee += GetDogecoinDustFee(tx.vout, ::minRelayTxFeeRate); nMinFee += GetDogecoinDustFee(tx.vout, ::minRelayTxFeeRate);
if (fAllowFree) if (fAllowFree)

View file

@ -490,7 +490,7 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda
packageSigOpsCost = modit->nSigOpCostWithAncestors; packageSigOpsCost = modit->nSigOpCostWithAncestors;
} }
if (packageFees < blockMinFeeRate.GetFee(packageSize)) { if (packageFees < blockMinFeeRate.GetRelayFee(packageSize)) {
// Everything else we might consider has a lower fee rate // Everything else we might consider has a lower fee rate
return; return;
} }

View file

@ -19,7 +19,7 @@ BOOST_AUTO_TEST_CASE(GetFeeTest)
BOOST_CHECK_EQUAL(feeRate.GetFee(1e5), 0); BOOST_CHECK_EQUAL(feeRate.GetFee(1e5), 0);
feeRate = CFeeRate(1000); feeRate = CFeeRate(1000);
// Must always just return the arg // Wallet fees are rounded up
BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0); BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);
BOOST_CHECK_EQUAL(feeRate.GetFee(1), 1000); BOOST_CHECK_EQUAL(feeRate.GetFee(1), 1000);
BOOST_CHECK_EQUAL(feeRate.GetFee(121), 1000); BOOST_CHECK_EQUAL(feeRate.GetFee(121), 1000);
@ -27,6 +27,14 @@ BOOST_AUTO_TEST_CASE(GetFeeTest)
BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), 1000); BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), 1000);
BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), 9000); BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), 9000);
// Relay fees must always just return the arg
BOOST_CHECK_EQUAL(feeRate.GetRelayFee(0), 0);
BOOST_CHECK_EQUAL(feeRate.GetRelayFee(1), 1);
BOOST_CHECK_EQUAL(feeRate.GetRelayFee(121), 121);
BOOST_CHECK_EQUAL(feeRate.GetRelayFee(999), 999);
BOOST_CHECK_EQUAL(feeRate.GetRelayFee(1e3), 1e3);
BOOST_CHECK_EQUAL(feeRate.GetRelayFee(9e3), 9e3);
feeRate = CFeeRate(-1000); feeRate = CFeeRate(-1000);
// Must always just return -1 * arg // Must always just return -1 * arg
BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0); BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);

View file

@ -121,7 +121,7 @@ void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey,
// Calculate a fee on child transaction that will put the package just // Calculate a fee on child transaction that will put the package just
// below the block min tx fee (assuming 1 child tx of the same size). // below the block min tx fee (assuming 1 child tx of the same size).
CAmount feeToUse = blockMinFeeRate.GetFee(2*freeTxSize) - 1; CAmount feeToUse = blockMinFeeRate.GetRelayFee(2*freeTxSize) - 1;
tx.vin[0].prevout.hash = hashFreeTx; tx.vin[0].prevout.hash = hashFreeTx;
tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse; tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse;
@ -158,7 +158,7 @@ void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey,
// This tx can't be mined by itself // This tx can't be mined by itself
tx.vin[0].prevout.hash = hashFreeTx2; tx.vin[0].prevout.hash = hashFreeTx2;
tx.vout.resize(1); tx.vout.resize(1);
feeToUse = blockMinFeeRate.GetFee(freeTxSize); feeToUse = blockMinFeeRate.GetRelayFee(freeTxSize);
tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse; tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse;
uint256 hashLowFeeTx2 = tx.GetHash(); uint256 hashLowFeeTx2 = tx.GetHash();
mempool.addUnchecked(hashLowFeeTx2, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); mempool.addUnchecked(hashLowFeeTx2, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));

View file

@ -786,10 +786,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false, return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false,
strprintf("%d", nSigOpsCost)); strprintf("%d", nSigOpsCost));
CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize); CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetRelayFee(nSize);
if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) { if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) {
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee)); return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee));
} else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nModifiedFees < ::minRelayTxFeeRate.GetFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) { } else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nModifiedFees < ::minRelayTxFeeRate.GetRelayFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) {
// Require that free transactions have sufficient priority to be mined in the next block. // Require that free transactions have sufficient priority to be mined in the next block.
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority"); return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
} }
@ -966,14 +966,14 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// Finally in addition to paying more fees than the conflicts the // Finally in addition to paying more fees than the conflicts the
// new transaction must pay for its own bandwidth. // new transaction must pay for its own bandwidth.
CAmount nDeltaFees = nModifiedFees - nConflictingFees; CAmount nDeltaFees = nModifiedFees - nConflictingFees;
if (nDeltaFees < ::incrementalRelayFee.GetFee(nSize)) if (nDeltaFees < ::incrementalRelayFee.GetRelayFee(nSize))
{ {
return state.DoS(0, false, return state.DoS(0, false,
REJECT_INSUFFICIENTFEE, "insufficient fee", false, REJECT_INSUFFICIENTFEE, "insufficient fee", false,
strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s", strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s",
hash.ToString(), hash.ToString(),
FormatMoney(nDeltaFees), FormatMoney(nDeltaFees),
FormatMoney(::incrementalRelayFee.GetFee(nSize)))); FormatMoney(::incrementalRelayFee.GetRelayFee(nSize))));
} }
} }